如何设计一个可扩展的优惠券功能

news2024/11/16 23:33:26

本文主要分享了如何设计一个可扩展的优惠券功能。

一、功能特性介绍

1.每个条件的代码独立,相当于单独的实现类实现接口,就能通过配置添加到优惠券条件校验当中,支持多种条件灵活组合

2.新增一种使用条件可以不修改核心流程代码,不需要增加数据库表字段

3.可实现优惠券区分客户端展示,比如在APP可见可用,在小程序不可见不可用

4.可实现优惠券查询适用的商品列表

二、核心代码架构图

三、代码实现

1.数据库表结构设计

CREATE TABLE `mk_coupon_use_condition` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `bean_name` varchar(64) NOT NULL DEFAULT '' COMMENT 'bean名称(UseCondition的实现类)',
  `descrpition` varchar(255) DEFAULT NULL COMMENT '描述',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uniq_beanname` (`bean_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券使用条件';

CREATE TABLE `mk_coupon_template` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(128) NOT NULL DEFAULT '' COMMENT '优惠券名称',
  `max_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '最大优惠金额(元)',
  `discount` decimal(12,2) NOT NULL DEFAULT '1.00' COMMENT '折扣',
  `condition_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '满X元可用',
  `begin_time` datetime NOT NULL COMMENT '发放开始时间',
  `end_time` datetime NOT NULL COMMENT '发放结束时间',
  `period_type` varchar(8) NOT NULL DEFAULT '' COMMENT '有效期计算方式(fix:领券起X小时内有效,ps:固定开始时间-结束时间)',
  `total_num` int(11) NOT NULL DEFAULT '0' COMMENT '发放量',
  `left_num` int(11) NOT NULL DEFAULT '0' COMMENT '剩余量',
  `limit_num` int(11) NOT NULL DEFAULT '1' COMMENT '每用户限领量',
  `use_description` text COMMENT '使用说明',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券模板';

CREATE TABLE `mk_coupon_template_condition` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `coupon_template_id` int(11) NOT NULL COMMENT 'mk_coupon_template.id',
  `use_condition` varchar(32) NOT NULL DEFAULT '' COMMENT '使用条件(bean名称,mk_coupon_use_condition.bean_name)',
  `use_condition_value` varchar(255) DEFAULT '' COMMENT '使用条件值',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_coupontemplateid` (`coupon_template_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券模板-使用条件';

CREATE TABLE `mk_user_coupon` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `user_id` int(11) NOT NULL COMMENT 'bu_user_info.id',
  `coupon_template_id` int(11) NOT NULL COMMENT 'mk_coupon_template.id',
  `name` varchar(128) NOT NULL DEFAULT '' COMMENT '优惠券名称',
  `max_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '最大优惠金额',
  `discount` decimal(12,2) NOT NULL DEFAULT '1.00' COMMENT '折扣',
  `condition_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '满X金额可用',
  `begin_time` datetime NOT NULL COMMENT '有效期开始时间',
  `end_time` datetime NOT NULL COMMENT '有效期结束时间',
  `status` varchar(8) NOT NULL DEFAULT '' COMMENT '状态(nouse:未使用/已使用/已过期/未激活/已失效)',
  `max_num` int(11) NOT NULL COMMENT '最大叠加数',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_userid` (`user_id`),
  KEY `idx_coupontemplateid` (`coupon_template_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户优惠券';

表说明:

mk_coupon_use_condition:主要是记录有哪些使用条件,代码中配置优惠券模板时有用

mk_coupon_template:优惠券发给用户前得先有个模板做配置

mk_coupon_template_condition:某个优惠券模板的使用条件(1对多),条件组合配置就是利用该表

mk_user_coupon:实际给到用户的优惠券,有未使用/已使用等状态,冗余了一部分券模板的数据

数据样例说明:

优惠券模板

优惠券模板使用条件

1)优惠券1只有1个条件CouponBaseCondition,可以理解为全场通用券,只要满足了基本条件就可以使用

2)优惠券2除了条件CouponBaseCondition,还有PlatformCondition,说明除了满足基本条件,还需要满足平台是app才能使用

3)优惠券3除了条件CouponBaseCondition,还有ProductCodeCondition,说明除了满足基本条件,还需要满足指定的商品编码AB3301或AB3302才能使用

2.抽象使用条件,定义一个接口,核心是canUse方法,另外2个方法有其他用途

UseParam说明:

例:如下为‘自动为用户选择最优的优惠券’的代码调用,runtimeAttach设计为Map就是为了灵活接收各种参数:

特殊业务场景说明:

canSee方法:用于解决某张优惠券只有在APP能使用,但是在小程序不能使用的业务场景,利用canSee方法返回true/false决定是否展示该张优惠券,例

filterProduct方法:用于解决根据某张优惠券查询适用商品的功能,一些大型的电商平台就提供该功能,方便用户快速找到能够使用该优惠券的商品列表,如果业务中不需要用到该功能可以忽略该方法

3.核心代码(UseCouponService)中提供4个方法(此处代码过多,就不贴了,可以通过gitee查看源码)

1)用户优惠券列表(未使用、即将过期、已使用、已过期)

    应用场景:用户查看自己的优惠券列表

2)用户最优的可用优惠券

    应用场景:商品展示券后价、支付时自动为用户选择优惠券

3)用户可用优惠券列表

    应用场景:支付时展示选择优惠券的列表

4)判断优惠券能否使用

    应用场景:创建订单时校验优惠券

核心思想:遍历优惠券的多个使用条件,判断有1个条件不满足就返回优惠券无法使用

tips:此处利用CompletableFuture优化性能,实现了多线程并发判断每个使用条件,只要有1个条件不满足就立马返回。

4.如何新增1种使用条件?

1)实现接口UseCondition,重写canUse方法,以下为‘首单可用’使用条件的demo代码

把Bean名称配置到券模板使用条件表mk_coupon_template_condition即可使用该条件,无需新增其他代码。

怎么样?如果你觉得有用的话,还不快快收藏起来!!!

附:涉及的代码目录

github:GitHub - 897665787/springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

gitee:springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

springcloud-template
└── template-user
     └──controller
          └── CouponTestController -- 优惠券查询的测试代码演示
     └── coupon
          └── UseCouponService -- 优惠券查询的核心代码
          └── UseCondition -- 抽象定义使用条件
          └── UseParam -- 使用条件参数
          └── SeeParam -- 可见条件参数
          └── FilterParam -- 过滤商品参数
          └── impl -- 使用条件实现类(条件就新增到这下面)
               └── CouponBaseCondition -- 优惠券基础条件(必选)
               └── FirstOrderCondition -- 首单可用
               └── PinleiCondition -- 某商品品类可用
               └── PlatformCondition -- 仅指定平台可见可用
               └── ProductCodeCondition -- 指定商品可用
               └── TagCondition -- 某标签下的商品可用
               └── TimeRangeCondition -- 指定时间段可用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Angular 与PDF之二:打印预览的实现

如何在angular中实现打印和预览pdf的功能, 使用print.js这个包就可实现这个功能 Print.js介绍 Print.js可以打印pdf文件,html元素,图片。官网 https://printjs.crabbly.com/ Print.js使用 首先新建一个angular项目,在项目里下载print.js n…

[JS每M日N练] [格物] - 你所不知道的toString

文章目录 导读Object.prototype.toString常见类型转换结果Object.toString ! Object.prototype.toString对Object.prototype.toString.call(obj)的理解 .toString.toString TypeError误区tostring被改写了定义在原型链的什么位置上方法重写 文章小结参考资料 导读 开发过程中经…

同时使用注解和 xml 的方式引用 dubbo 服务产生的异常问题排查实战

文章目录 一、现象二、问题排查三、结论四、解决方案 一、现象 使用 nacos 作注册中心的线上 dubbo 消费端应用每隔 1 分钟就会抛出以下异常(为使描述简单化,文章中使用本地 demo 来复现),该异常表示无法连接到 172.17.0.1:20881…

JavaWeb( 二 ) URL

1.4.URL统一资源定位符 URL代表Uniform Resource Locator 统一资源定位符,也叫 URL地址 。是用于标识和定位Web上资源的地址,通常用于在Web浏览器中访问网站和文件。 URL由若干部分组成,scheme:// host : port / path 例如: htt…

Contest3111 - 计科2101~2104算法设计与分析上机作业07

问题 A: 有重复元素的排列问题 题目描述 设R{ r 1 , r 2 , …, r n }是要进行排列的n个元素。其中元素r 1 , r 2 , …, r n 可能相同。试设计一个算法, 列出R的所有不同排列。给定n 以及待排列的n 个元素。计算出这n 个元素的所有不同排列。 输入 第1 行是元素个…

android四大组件之一-Activity实现原理分析

前言: 这篇文章是我花费时间最久的一篇文章,整整的两个月。整个流程繁琐是一个方面的原因,另外一个原因是我想尽可能的把整个流程的逻辑尽可能详细的一一描述出来,以及结合到我们项目中遇到的一些问题来进行解释,毕竟…

【五一创作】VS+Qt主界面内嵌自定义控件的四种方法以及不同自定义控件数据交互

前言 在Qt界面开发过程中,一个主界面或者主窗口看成是各个控件排列组合后的集合,对于一些项目而言,有些常用的控件可以封装成自己想要的控件样式并且复用,比如说,log显示控件,图像/视频显示控件等&#xf…

【ros2】ros melodic迁移到ros2 dashing过程中碰到的问题及解决方法

序言 总结踩坑经历,以利他人 1. error: forming pointer to reference type … & 报错原因: ros2回调函数的参数不能是引用形式 &,需要去除& 解决方法: 如果是指针引用,直接去除引用 void Callback(con…

【Java开发】Spring Cloud 11:Gateway 配置 ssl 证书(https、http、域名访问)

最近研究给微服务项目配置 ssl 证书,如此才可以对接微信小程序(需要使用 https 请求)。传统单体项目来说,首先往项目中添加证书文件,然后在配置文件中配置 ssl 证书路径、密码等相关信息;那么微服务这么多项…

机器学习强基计划8-5:图解局部线性嵌入LLE算法(附Python实现)

目录 0 写在前面1 流形学习2 局部线性嵌入算法2.1 什么是局部线性嵌入?2.2 算法原理推导 3 Python实现3.1 算法流程3.2 核心代码3.3 可视化 0 写在前面 机器学习强基计划聚焦深度和广度,加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的…

基于学生成绩管理系统(附源代码及数据库)

基于Ecplise,jsp的学生成绩管理系统 目录 登录页面 系统主页 管理员账号管理 学生查询 课程管理 成绩管理 后台数据库 源代码下载(含数据库) 毕设项目专栏 分为以下四大板块: 系统用户管理: 包含管理员账号管理&#…

【一起撸个DL框架】5 实现:自适应线性单元

CSDN个人主页:清风莫追欢迎关注本专栏:《一起撸个DL框架》GitHub获取源码:https://github.com/flying-forever/OurDL 文章目录 5 实现:自适应线性单元🍇1 简介2 损失函数2.1 梯度下降法2.2 补充 3 整理项目结构4 损失函…

第二十七章 Unity碰撞体Collision(下)

本章节我们继续研究碰撞体,并且探索一下碰撞体与刚体之间的联系。我们回到之前的工程,然后给我们的紫色球体Sphere1也添加一个刚体组件。如下所示 此时,两个球体都具备了碰撞体和刚体组件。接下来,我们Play运行查看效果 我们发现&…

第二十六章 Unity碰撞体Collision(上)

在游戏世界中,游戏物体之间的交互都是通过“碰撞接触”来进行交互的。例如,攻击怪物则是主角与怪物的碰撞,触发机关则是主角与机关的碰撞。在DirectX课程中,我们也大致介绍过有关碰撞检测的内容。游戏世界中的3D模型的形状是非常复…

浅谈区块链1.0-比特币

1. 比特币解决的问题 高度自治:国际经济危机无国界贸易:不同国家进行的贸易或者不同平台进行贸易 不可窜改:例如银行交易可能会被窜改数据 隐私安全:传统汇款方式会暴露你的个人信息,一旦数据库被别人入侵&#xff0c…

android基础知识复习

架构: 应用框架层(Java API Framework)所提供的主要组件: 名称功能描述Activity Manager(活动管理器)管理各个应用程序生命周期,以及常用的导航回退功能Location Manager(位置管理器…

SpringBoot整合Mybatis-plus实现多级评论

在本文中,我们将介绍如何使用SpringBoot整合Mybatis-plus实现多级评论功能。同时,本文还将提供数据库的设计和详细的后端代码,前端界面使用Vue2。 数据库设计 本文的多级评论功能将采用MySQL数据库实现,下面是数据库的设计&…

Boonz-KeygenMe#1(★★★)

运行程序 错误: 查壳 没有壳,是汇编写的程序 载入OD 前面是在读取输入内容,到这里开始做计算了 分析 首先遍历了用户名,计算结果保存在EBX,在存放到 0x40E0F8 对EBX中的值再次计算,最后结果保存到 …

JavaFX: Java音乐播放读取歌词

JavaFX: Java音乐播放读取歌词 1、lrc歌词文件2、解析lrc歌词2.1 读取每行歌词2.2 解析歌词时间标签Time-tag2.3 解析歌词标识标签ID-tags2.4 创建对象包含歌词相关信息 3、播放显示歌词** 相关文献 JavaFX: Java音乐播放 1、lrc歌词文件 lrc歌词文件的扩展名 1、标准格式&a…

图像处理:Retinex算法

目录 前言 概念介绍 Retinex算法理论 单尺度Retinex(SSR) 多尺度Retinex(MSR) 多尺度自适应增益Retinex(MSRCR) Opencv实现Retinex算法 SSR算法 MCR算法 MSRCR算法 效果展示 总结 参考文章 前…