电商所谓营销,归根结底都是订单金额的变化;如果我们清楚的知道订单金额的计算流程是怎样的,那么我们只需要顺着系统的计算流程做促销,就不用担心各种促销类型之间产生重叠或者冲突的情况了。

当我们知道这个关系后,就可以将营销活动区分为三种类型:改商品价格、改商品小计价格、改订单价格,因为无论什么营销归根结底都是可以描述成改价格。

购物车中任何增删查改都要重新计算促销,所以促销的计算变得尤为重要,感觉京东已经把促销做到了极致。

从模式上来讲,我们公司的促销就相当于京东自营,所以很多也都是参考京东自营的,但我们还没法做到像京东促销那样强大。

这里,将我们做的促销跟大家分享一下,只涉及后台接口逻辑部分。

接口的功能就是输入商品列表,返回加了促销分组后的商品列表。

首先要声明几点:

一、不是通用的促销设计,只是我们公司目前支持的促销设计及逻辑;

二、作者水平有限,不会画图,所以图画得比较丑,也很粗,希望大家不要介意;

三、不谈性能

废话就不多说了,下面正式开始。。。

促销类型

前面说了,促销归根结底是改价格。在我们这里其它单品促销就是改商品价格;而条件促销就相当于改小计的价格;至于赠品促销不设计改价格,可以认为是单品促销的一种类型。

主流程

同类型通过实体进行互斥、不同类型可以相互叠加。”这是别人总结的设计电商促销系统的基本原则,我也比较认同。

上面接口主流程就是先应用单品促销,再应用条件促销。稍微再细化一点儿就是这样的:

先处理赠品促销,将赠品挂载到主商品(原先用户添加的购物车中的商品我称之为主商品)上,再应用单品促销。另外,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

在进行单品促销的时候,很有可能同一个商品命中多个单品促销。这个时候只能取一个促销,此处的计算逻辑是这样的:

  • 优惠力度最大的优先

  • 优惠力度相同时,取最新创建的那个(创建时间最新)

例如:

商品A命中四条促销,分别是:【促销1】直降2元,【促销2】折扣8折,【促销3】直降1元。假设A的原价时10元,那么经过计算【促销1】8元,【促销2】8元,【促销3】9元。

这个时候,【促销3】应该被剔除,假设【促销2】的创建时间比【促销1】要晚,那么应该取【促销2】。即商品A最终命中【促销2】。原价10元,促销价8元。

计算商品价格流程

稍微解释一下:

  • 特价:商品A原价12元,今日特价9.9元。

  • 折扣:商品打几折。

  • 直降:商品A原价12元,今日直降3元,所以最终9元。且当促销价低于原价的70%时恢复原价。

限购流程

这里有两点需要说明:

  1. 限购的话需要查订单系统,但是刚才说了购物车中的任意增删查改都要重新计算促销,所以如果这里直接调订单的话可能订单的顶不住(技术实力还比较薄弱,无奈!!!),考虑到这里我们冗余了订单数据,每次从本地数据库去查。当然,这样肯定不准,但是我们只保证90%的情况就可以了,所以这里我们采用这种方式。

  2. 拆商品行。还是用上面的例子,商品A命中了【促销2】,假设【促销2】限购每人每单1件,而现在A 的数量时3,那么我们会拆成2行,第一行商品A售价8元数量1件,第二行商品A售价10元数量2件。

条件促销分组

同一个商品可能会命中多个条件促销,而最终每个商品只能应用一个条件促销(即每个商品最终只能属于一个组)

我们说,同种类型的促销不能叠加,不同类型的促销可以叠加。在我们这里,单品促销和单品促销不能叠加,条件促销与条件促销不能叠加,单品与条件可以叠加。

程序走到这里,我们已经完成了单品促销的处理,接下来处理条件促销。在决定商品应该最终应用哪个条件促销时,我们的原则是这样的:

1、优先考虑满足条件的促销

这句话的意思是,假设商品A,商品B满足【促销1】满100减20这个阶梯,同时A和B又都命中了【促销2】但是不满足【促销2】的条件,因为假设【促销2】的最小阶梯是满150减30。那么这个时候,虽然A和B都同时命中【促销1】和【促销2】,但A和B一起正好符合【促销1】满100减20的条件,所以这个时候促销A和B应该最终取【促销2】

2、同时满足多个条件促销时,取后创建的那个(创建时间最近)

还是上面的例子,假设A和B的总金额加起来是160元,那么它们都满足【促销1】和【促销2】,假设【促销2】是后创建的,所以此时它们最终命中的条件促销应该取【促销2】。并且,之后应该讲它们从【促销1】的商品组中剔除(PS:因为一个商品只能属于一个组,即只能应用一个条件促销)。京东在这里对每种促销做了计算,把最终用哪个促销的决定权交给用户去选,我们这里不搞这么复杂。

说了这么多,可能有点晕,下面举个例子

假设有A,B,C,D四个商品,促销1234是四个促销

如图,【促销1】是所有商品,所有A,B,C,D四个都命中【促销1】,换句话说【促销1】的商品组中有A,B,C,D

【促销2】的商品组中有A,C

【促销3】的商品组中有A,B

【促销4】的商品组中有A,B,C

假设促销1,2,3,4是依次创建的,也就是说4是最晚创建的,1是最早创建的

再假设,A+B+C符合【促销4】的其中一个阶梯条件,A+B符合【促销3】中的其中一个阶梯条件,A+B+C+D符合【促销1】的其中最低一级的阶梯条件

那么,最终的促销分组应该是这样的:

【促销4】的商品组有:A,B,C

【促销3】的商品组为空

【促销2】的商品组为空

【促销1】的商品组中有:D,而且不满足最低的阶梯,因为原来A+B+C+D满足最低一级的阶梯,现在只剩下D了当然不满足最低一个的阶梯

条件促销分组计算

在代码实现上,这里是两层循环:

  • 第一层是条件促销列表

  • 第二层是某个条件促销中的商品组

部分代码实现

代码可能是这样的,下面贴出条件促销部分的代码片段:

//  处理条件促销
//  算小计
for (PromotionProductDTO promotionProductDTO : promotionProductDTOList) {promotionProductDTO.setSubtotal(promotionProductDTO.getPromotionPrice().multiply(new BigDecimal(promotionProductDTO.getQuantity())));
}
List<PromotionInfoDTO> conditionPromotionInfoDTOList = promotionInfoMap.get(PromotionTypeEnum.TIAOJIAN.getType());
//  限购
List<PromotionInfoDTO> validConditionPromotionInfoDTOList = new ArrayList<>();
for (PromotionInfoDTO promotionInfoDTO : conditionPromotionInfoDTOList) {if (isMaxConditionPromotionLimit(promotionInfoDTO, userId)) {continue;}validConditionPromotionInfoDTOList.add(promotionInfoDTO);
}
conditionPromotionInfoDTOList = validConditionPromotionInfoDTOList;//  按范围初步将商品归到各个条件促销下(撒网)
for (PromotionInfoDTO promotionInfoDTO : conditionPromotionInfoDTOList) {List<PromotionProductDTO> matchedPromotionProductDTOList = new ArrayList<>();List<PromotionProductEntity> promotionProductEntityList = promotionInfoDTO.getDefinitiveProductEntityList();for (PromotionProductDTO promotionProductDTO : promotionProductDTOList) {//  商品匹配到的促销if (promotionInfoDTO.getProductRange() == PromotionPruductRangeEnum.ALL.getValue()) {matchedPromotionProductDTOList.add(promotionProductDTO);}else if (promotionInfoDTO.getProductRange() == PromotionPruductRangeEnum.CATEGORY.getValue()) {Set<String> secondCategorySet = promotionProductEntityList.stream().map(PromotionProductEntity::getProCategorySecond).collect(Collectors.toSet());if (secondCategorySet.contains(promotionProductDTO.getCategoryCode())) {matchedPromotionProductDTOList.add(promotionProductDTO);}}else if (promotionInfoDTO.getProductRange() == PromotionPruductRangeEnum.SPECIFIED.getValue()) {Set<Long> specialProductIdSet = promotionProductEntityList.stream().map(PromotionProductEntity::getProductId).collect(Collectors.toSet());if (specialProductIdSet.contains(promotionProductDTO.getId())) {matchedPromotionProductDTOList.add(promotionProductDTO);}}}//  促销匹配到的商品promotionInfoDTO.setMatchedProductDTOList(matchedPromotionProductDTOList);//  判断促销匹配的这些商品是否满足条件BigDecimal totalAmount = BigDecimal.ZERO;for (PromotionProductDTO promotionProductDTO : matchedPromotionProductDTOList) {totalAmount = totalAmount.add(promotionProductDTO.getSubtotal());}PromotionStairEntity promotionStairEntity = matchStair(promotionInfoDTO.getDefinitiveStairEntityList(), totalAmount);if (null != promotionStairEntity) {promotionInfoDTO.setPromotionStairEntity(promotionStairEntity);}
}//  按满足条件与否以及促销创建的先后顺序进一步归档商品(即分组)
//  挑选出满足条件的促销,并按照创建时间降序排序
List<PromotionInfoDTO> matchedConditionPromotionInfoDTOList = conditionPromotionInfoDTOList.stream().filter(x->null != x.getPromotionStairEntity()).sorted(Comparator.comparing(PromotionInfoDTO::getCreateTime).reversed()).collect(Collectors.toList());//  去重,以保证每个组中的商品之间无交集
int len = matchedConditionPromotionInfoDTOList.size();
for (int i = 0; i < len - 1; i++) {PromotionInfoDTO majorPromotionInfoDTO = matchedConditionPromotionInfoDTOList.get(i);for (int j = i + 1; j < len; j++) {PromotionInfoDTO minorPromotionInfoDTO = matchedConditionPromotionInfoDTOList.get(j);for (PromotionProductDTO majorMatchedPromotionProductDTO : majorPromotionInfoDTO.getMatchedProductDTOList()) {minorPromotionInfoDTO.setMatchedProductDTOList(minorPromotionInfoDTO.getMatchedProductDTOList().stream().filter(x -> !x.getId().equals(majorMatchedPromotionProductDTO.getId())).collect(Collectors.toList()));}}
}//  最终命中的促销
List<PromotionInfoDTO> ultimatePromotionInfoDTOList = new ArrayList<>();
//  重新计算各组匹配的阶梯规则
for (PromotionInfoDTO promotionInfoDTO : matchedConditionPromotionInfoDTOList) {List<PromotionProductDTO> promotionProductDTOS = promotionInfoDTO.getMatchedProductDTOList();//  过滤掉空的促销if (null == promotionProductDTOS || promotionProductDTOS.size() < 1) {continue;}ultimatePromotionInfoDTOList.add(promotionInfoDTO);BigDecimal totalAmount = BigDecimal.ZERO;for (PromotionProductDTO promotionProductDTO : promotionProductDTOS) {totalAmount = totalAmount.add(promotionProductDTO.getSubtotal());}//  查询该组商品满足的最高阶梯PromotionStairEntity promotionStairEntity = matchStair(promotionInfoDTO.getDefinitiveStairEntityList(), totalAmount);if (null != promotionStairEntity) {//  设置这组商品命中的促销的哪一个阶梯promotionInfoDTO.setPromotionStairEntity(promotionStairEntity);//  设置每个商品最终命中的唯一的条件促销for (PromotionProductDTO promotionProductDTO : promotionProductDTOS) {promotionProductDTO.setConditionpromotionInfoDTO(promotionInfoDTO);}}else {//  计算还差多少钱满足最低阶梯List<PromotionStairEntity> promotionStairList = promotionInfoDTO.getDefinitiveStairEntityList().stream().sorted(Comparator.comparing(PromotionStairEntity::getMinimumCharge)).collect(Collectors.toList());PromotionStairEntity promotionStairEntity2 = promotionStairList.get(0);BigDecimal minimumCharge = promotionStairEntity2.getMinimumCharge();BigDecimal balance = minimumCharge.subtract(totalAmount);promotionInfoDTO.setBalance(balance);}
}

返回的数据接口

最终返回的应该是一个列表,列表中的每一个元素代表一个条件促销(即分组)

接口看起来可能是这样的:

参考:

http://www.woshipm.com/pd/741573.html
http://www.woshipm.com/pd/594963.html
http://www.woshipm.com/pd/716781.html

作者:废物大师兄
来源:www.cnblogs.com/cjsblog/p/9306637.html

PS:如果觉得我的分享不错,欢迎大家随手点赞、在看。

大家一起在评论区聊聊呗~

关注微信公众号:互联网架构师,在后台回复:2T,可以获取我整理的教程,都是干货。

猜你喜欢

1、GitHub 标星 3.2w!史上最全技术人员面试手册!FackBoo发起和总结

2、如何才能成为优秀的架构师?

3、从零开始搭建创业公司后台技术栈

4、程序员一般可以从什么平台接私活?

5、37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6、滴滴业务中台构建实践,首次曝光

7、不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

8、15张图看懂瞎忙和高效的区别

9、2T架构师学习资料干货分享

电商促销后台设计,写得太好了!相关推荐

  1. 电商促销素材|设计简洁,适合小清新文艺气质的你!

    现在电商行业那么发达,想必从事此职业的设计师也不少吧? 双十一要来了,吃瓜群众忙着买买买,电商设计师都在加班吧? 优图带来电商促销素材. 计简洁,适合小清新文艺气质的你! 希望大家喜欢~ 线条彩绘热卖 ...

  2. 电商促销海报设计技巧!

    促销海报是一种比较吸引眼球的广告形式,一张好的海报可以吸引受众买家进入店铺,可以生 动地传达产品信息和各类促销活动情况,例如:打折.促销.包邮.秒杀等. 促销海报设计要点: 1.张力要强,整个画面要体 ...

  3. PSD分层模板|电商促销海报设计技巧

    线上促销海报中版式设计样式繁多,不同类型海报的侧重点也各不相同,但几乎所有的线上促销海报都会包括三个核心部分:商品层.文案层.背景层.而线上促销海报的版式设计,其设计原则就是把控和调整商品层.文案层. ...

  4. 《电商系统后台统计报表模块》需求分析与设计的课程小结

    <电商系统后台统计报表模块>需求分析与设计的课程小结 1)分工情况介绍,小组分工合作情况介绍 张顺程-选题,功能分析,建模 2)选题讨论 电商后台的统计报表也是非常重要的一个功能模块,一个 ...

  5. 插画素材模板 | 玩转电商促销季插画设计

    随着审美流行趋势的变化,电商设计的新鲜创意也层出不穷,表达手法日新月异,尤其插画应用的比重格外突出. 电商设计中,因风格或创意内容需要制作一些可爱.搞怪.梦幻.内容量庞大的超现实画面,而插画设计可以充 ...

  6. 电商促销惊喜海报设计模板,会讲故事的素材

    各大商家便纷纷在官网上更换起打折促销的banner,吸引顾客买买买.除了产品本身和打折 力度,一张板式好看的海报设计也是抓住眼球的关键--促销海报是一种比较吸引眼球的广告 形式,一张好的海报可以吸引受 ...

  7. C4D电商促销活动背景素材|设计提升,只差一个背景

    下半年往往是电商设计师最繁忙的时期,忙完双11.紧接着双12.年货节等重量级节日接踵而来.随着审美流行趋势的变化,电商设计的新鲜创意也层出不穷,有不少商家都应用了C4D来辅助视觉创意的表达.但不是每一 ...

  8. 电商促销海报PSD分层模板|创意合成,这样的设计越来越吃香!

    了解电商行业的设计师都知道,从10月份开始,各种大促活动就处于不间断放送,根本不会给你充足的时间去系统的学习,优图网 专注高品质电商素材,提前准备了创意合成的电商促销海报PSD分层模板,这样的设计越来 ...

  9. 电商促销海报PSD模板|临摹优秀,设计好的banner广告从试炼开始!

    每当你打开淘宝时,首页的banner广告总是会弹出你近期浏览过的或者是购买过的同类产品,这就是淘宝善于使用个人大数据,从而达到精准推广的效果. 而设计师在设计banner广告图之前,一般会参考之前投放 ...

  10. 小林求职记(三)一上来就围绕电商系统层层提问,我太难了....

    前传 面试官:什么是大事务?小林哥:就是 很大...的...事务?? 小林求职记(二):说好的问基础,为啥我感觉一点也不基础呢? 二面的面试官来到来我的跟前,开始对我的简历进行了一番打量然后就开始了技 ...

最新文章

  1. ctypes python_对于python初学者,如何使用python定义联合(使用ctypes)
  2. 单元测试——第六周作业
  3. 企业 SOA 设计(1)–ESB 设计
  4. golang中图片转base64_golang base64编码
  5. Spring 学习笔记 3. 尚硅谷_佟刚_Spring_配置 Bean
  6. linux yum源安装
  7. 计算机如何打开无线网络适配器,win7系统下网络适配器打不开怎么解决
  8. skywalking(1) 基于opentracing规范的APM系统
  9. 每天进步一点点《ML - Sklearn库简单学习》
  10. 排队论是计算机科学新分支,(计算机科学的分支领域体系.doc
  11. android mvp 登录,Android MVP(初级篇二、登陆案例)
  12. POJ1144 Network 连通性
  13. 拓端tecdat荣获腾讯云+社区年度最佳作者奖
  14. MCSE 2012 R2之工作文件夹Word Folders(2)
  15. (原创)用cmd命令制作恶搞程序
  16. 自己挖坑自己跳 之JsonMappingException: (was java.lang.NullPointerException) (through reference chain:)...
  17. [OpenAirInterface实战-5] :OAI支持的5G gNB功能集
  18. iptables 流量统计
  19. c语言函数的省略号,c++中的省略号
  20. CXF 处理yyyy-MM-dd HH:mm:ss日期失败

热门文章

  1. Payload与form表单提交区别
  2. 读邹欣老师《师生关系》有感
  3. 通过FD耗尽实验谈谈使用HttpClient的正确姿势 1
  4. 开源MySQL数据传输中间件—DTLE
  5. Linux脚本中带有小数点的数值比较大小
  6. 聊聊springcloud的GatewayControllerEndpoint
  7. 《程序化广告实战》一 导读
  8. 升级后可能遇到的故障- -从Windows 2012升级到2016案例之3
  9. enetics v1.5.0 绿色版
  10. 商业领域中的IT技术应用之二-POS收款机及收款系统介绍