此处将为大家介绍关于36、生鲜电商平台-积分,优惠券,会员折扣,签到、预售、拼团、砍价、秒杀及抽奖等促销模块架构设计的详细内容,此外,我们还将为您介绍关于10、生鲜电商平台-财务系统模块的设计与架构、
此处将为大家介绍关于36、生鲜电商平台-积分,优惠券,会员折扣,签到、预售、拼团、砍价、秒杀及抽奖等促销模块架构设计的详细内容,此外,我们还将为您介绍关于10、生鲜电商平台-财务系统模块的设计与架构、13、生鲜电商平台-订单抽成模块的设计与架构、14、生鲜电商平台-搜索模块的设计与架构、15、生鲜电商平台-售后模块的设计与架构的有用信息。
本文目录一览:- 36、生鲜电商平台-积分,优惠券,会员折扣,签到、预售、拼团、砍价、秒杀及抽奖等促销模块架构设计
- 10、生鲜电商平台-财务系统模块的设计与架构
- 13、生鲜电商平台-订单抽成模块的设计与架构
- 14、生鲜电商平台-搜索模块的设计与架构
- 15、生鲜电商平台-售后模块的设计与架构
36、生鲜电商平台-积分,优惠券,会员折扣,签到、预售、拼团、砍价、秒杀及抽奖等促销模块架构设计
说明:本标题列举了所有目前社会上常见的促销方案,目前贴出实际的业务运营手段以及架构设计,包括业务说明,仅供参考
促销体系
1.1促销体系
在电商和O2O领域,促销是运营人员的一个主要的让利行为,同时促销活动期间的购买量也较之普通商品更高,不同的阶段,对于促销的要求也是不同的。
促销实质上是一种沟通活动,即营销者(信息提供者或发送者)发出作为刺激消费的各种信息,把信息传递到一个或更多的目标对象(即信息接受者,如听众、观众、读者、消费者或用户等),以影响其态度和行为。
商城促销活动的流程概述(不含优惠券):
- 在平台后台创建促销活动
- 选择促销方式,对应编辑该促销方式的设置项,选择参与活动的商品,可选择普通购买的单纯用货币支付的普通商品
- 设置具体的促销活动规则和投放设置
- 用户在商城查看商品,可看到由平台后台发布的优惠信息
- 将商品加入购物车,购物车将体现享受满减和直减后的优惠价格,最终的购买订单的实付金额为享受促销活动后的价格。
- 可在后台查看到已创建的活动以及活动的效果,关于用户购买订单相关的数据也将展示其享受到的优惠信息。
1.2促销系统
将模块拆分,主要分为三部分:
- 促销活动:活动投放的设置管理,负责提供活动方式和商品内容
- 促销规则:发布促销活动时选择,负责提供促销玩法,例如限时折扣、满额减等
- 优惠券:提供一种相对独立的促销形式
从大的维度来看,优惠券也属于促销的一种方式,在促销规则也和优惠劵的使用有一定关联。这里我们把优惠券也归类到促销系统中,关于优惠券业务将在下次进行迭代
1.3促销活动
活动状态:
- 未开始,还未到活动开始时间,此状态的活动可进行编辑和的删除,删除活动为逻辑删除
- 活动中,正在进行中的活动,此状态的活动不能编辑,只能提前结束,结束之后的活动变更为已失效的状态
- 已失效,已经过了活动结束时间,被删除的以及被取消的活动
从促销类型分为:
- 直减类:限时折扣、新用户专享等
- 满减类:满额减、满额折、满件减、满件折、满件免等
- 赠券类:买单赠券、免费领券等(下次迭代)
- 组合优惠类(暂不考虑):套餐
- 送赠品类(暂不考虑):满赠
- 换购类(暂不考虑):加价购
- 预订类(暂不考虑):预售价
直减类(优先实现):
主要设置项包括:
- 活动名称:方便运营人员识别活动
- 促销方式:可选限时折扣、新用户专享
- 商品选择:参加促销的商品以及促销的价格(只选择单纯用货币购买的普通商品)
- 投放时间选择:选择开始时间和结束时间
- 打标签:商品打促销标识,前端显示促销标签,可选择现有标签或者选择自定义新增
- 目标群体(不可编辑): 针对全部用户(限时折扣)、未下单过的新用户(新用户专享)
满减类:
主要设置项包括:
- 活动名称:方便运营人员识别活动
- 促销方式:满额减、满额折、满件减、满件折、满件免件
- 商品选择:参加促销的商品((只选择单纯用货币购买的实际商品,可选择全场、按品类、或者自主选择多个商品,由于虚拟商品不能加入购物车,所以虚拟商品的满减类虽然可以添加多个SKU,但是最终享受该优惠的虚拟商品订单只会包含一个SKU)
- 金额/件数设置:满XX减(折、免)XX,可设置多层级的满减活动(支持两种货币类型的情况)
- 投放时间选择:选择开始时间和结束时间
- 打标签:商品打促销标识,前端显示促销标签,可选择现有标签或者选择自定义新增
- 目标群体: 针对全部用户、未下单过的新用户
二、促销业务逻辑
2.1创建多个活动
方案1:实现此方案,一个商品只能关联到一个正在进行的活动,已经被添加至一个活动的时候,可以先解绑再将其添加至另一个活动
方案2:同类型促销可创建多个活动,同个商品可参与多个同类型的活动,但是一个商品不能同时被添加至多个活动时间重叠的活动(考虑这样处理逻辑会比较清晰)
一笔订单不能同时享受两个及以上相同类型的优惠。(这里的类型指的是直减类、满减类)
2.2订单金额计算
方案1:本次实现此方案,一个用户一笔订单只能享受一种优惠,如果一笔订单有多个优惠活动,用户可进行选择其中一个。
方案2:促销方式有很多,针对商品或订单的满减、折扣、优惠券等,对这些促销类型进行任意组合,将会有非常多样化的场景,为了防止系统发生重叠甚至冲突的情况,从整体上设计促销逻辑才能保证各子系统流程顺畅流转。
将促销视为订单金额的变化,将促销活动区分为三种类型:改商品价格、改商品小计价格、改订单价格,无论什么促销都可以描述成改价格。
判断条件:
- 上面的流程图,是否可享受的判断条件是只要有优惠活动就享受
- (讨论是否在这一阶段加上多活动时的控制)通用设置或者是针对于活动的设置,同一笔订单是否可以同时享受多个不同类型的促销,即同时可以享受修改商品的优惠(直减类),修改商品小计的集合(满减类)或修改订单的价格(优惠券)
具体例子:(京东)
- 享受商品价格的活动,这里是秒杀价单品价格24.9元
- 计算商品小计之后,引入针对指定商品的价格,满2件总价打5折,24.9*28件*0.5=348.6元
- 累计商品小计价格之后,介入针对于订单的促销:优惠券
优惠券为全品类满200减10,满足条件,即最终订单价格(免邮)为348.9-10=338.6元
所以最终这笔订单先后享受了三重优惠。
2.2.1修改商品价格
一笔订单被提交时,系统必然首先查找出订单中的所有商品,并判断此商品是否具备特殊价格(促销价格)。如果没有,则取正常的商品零售价;如果有,则取当前商品所处促销活动价格。
直减类:限时折扣、新用户专享等
遵循促销核心原则:同类型促销通过同一实体进行互斥、不同类型促销可以叠加。这里的实体指的是商品,类型指的是前文说到的值减类、满减类、赠券类,下文也是,不再说明。
所以这条原则也可以表述为:不同商品可以享受相同的(限时折扣、新用户专享)活动;但是相同商品进行互斥,同一个商品不可以同时享受同一类型的活动,例如:同一个SKU不可以同时享受(限时折扣、新用户专享)活动。
2.2.2修改商品小计的集合价格
当系统完成了对商品价格的查找之后,就需要将查找出的商品价格分别乘以订单中的每个商品数量,从而计算出每个商品的小计金额。当系统计算出所有商品的小计金额之后,这时候,就可以介入一些促销活动,例如指定商品的:满额减、满额折等。
满减类:满额减、满额折、满件减、满件折、满件免件
例如:全场生鲜类,满100减10,满200减30;就是第二种类型活动,因为它是针对某种/某类商品的小计金额来匹配满足哪种类型的活动,并在满足活动的商品小计金额基础上进行减、折、免。
同类型通过实体进行互斥、不同类型可以相互叠加。此处的实体是商品,所以这对第二种类型的促销活动,我们就可以得出以下结论:
同一个商品,不能同时享受指定商品的(满减、满赠、折扣 等)活动,不同的商品没有限制。
例如:SKUA 不能同时享受多个满减、满赠、折扣;但是SKUA 享受满减,SKUB享受满赠 这种是被允许的。
而不同类型可以相互叠加,也就是说,同一个商品虽然不能同时享受同种类型的活动,但是却可以同时享受不同类型的促销活动,例如:SKUA 可以同时享受限时折扣和指定SKUA的满减活动,也就是折上折。
2.2.3修改订单金额
当系统完成了对商品小计金额的计算之后,就会将所有优惠后的商品小计金额进行叠加,生成一个初步的订单总金额,当系统得到初步的订单总金额之后,又可以介入一些促销活动,例如指定订单的:优惠券等。
针对订单类的:优惠券(下次迭代)
例如:京东招牌活动全场满88包邮;就是典型的第三种类型营销活动,因为它是针对订单的总金额来匹配满足那种类型的活动,并在满足活动的订单金额基础上进行减、折、优惠券和包邮券等。
同类型通过实体进行互斥、不同类型可以相互叠加,此处的实体就是订单。
所以,针对第三种类型的促销活动,我们就可以得出以下结论:同一笔订单只能使用一张针对于订单的优惠券。
三、功能需求清单(促销活动)
转载自-- https://www.cnblogs.com/jurendage/p/9165594.html
10、生鲜电商平台-财务系统模块的设计与架构
前言:任何一个平台也好,系统也好,挣钱养活团队这个是无可厚非的,那么对于一个生鲜B2B平台盈利模式( 查看:http://www.cnblogs.com/jurendage/p/9016411.html)而言,
其中财务模块无论是对于买家而言还是卖家而言都至关重要,老百姓对钱的看重是没有经历的人想不到的,一句话说清楚了:一分钱也不能少。
买家或者卖家对财务模块的要求很简单:
1. 账清楚明白。
2. 消费清清楚楚。
3. 计算准确无误。
对平台而言:财务的要求是每笔资金的输入与输出,有理有据,真真实实。
我们分两个模块来讨论,买家与卖家我们称为客户财务模块,平台我们称为公司财务模块
1. 客户财务模块
1.1 买家需要查看任何一天的消费记录。数据按照时间的倒叙排列,根据时间进入某天的消费记录,需要查看当天的历史订单数据。
业务中按照时间来分组,数据是来源于订单表:
相关业务核心代码如下:

/**
* 订单列表
*
* @description 1.用户的所有订单列表。 2.支付状态 3.交易状态.
* @param request
* @param response
* @param orderStatus
* 0 待支付 1待送达 2已完成
* @return
*/
@RequestMapping(value = "/order/list", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult buyerOrderList(HttpServletRequest request, HttpServletResponse response, Long buyerId,
int orderStatus) {
List<OrderListVo> listVo = new ArrayList<OrderListVo>();
// 需要顺序
Map<String, List<OrderInfoVo>> resultMap = new TreeMap<String, List<OrderInfoVo>>(new Comparator<String>() {
public int compare(String obj1, String obj2) {
// 降序排序
return obj2.compareTo(obj1);
}
});
try {
List<OrderInfo> orderList = orderInfoService.getAllOrderInfo(buyerId, orderStatus);
// 判断是否有订单
if (CollectionUtils.isEmpty(orderList)) {
return new JsonResult(JsonResultCode.SUCCESS, "订单查询成功", listVo);
}
// 组装Map对象
for (OrderInfo order : orderList) {
List<OrderInfoVo> resultList = new ArrayList<OrderInfoVo>();
OrderInfoVo orderInfoVo = transform(order);
String time = DateUtil.dateToString(order.getCreateTime(), "yyyy-MM-dd");
if (resultMap.get(time) == null) {
resultList.add(orderInfoVo);
resultMap.put(time, resultList);
} else {
List<OrderInfoVo> mapList = resultMap.get(time);
mapList.add(orderInfoVo);
resultMap.put(time, mapList);
}
}
// 组装VO
Set<String> keys = resultMap.keySet();
for (String data : keys) {
OrderListVo vo = new OrderListVo();
vo.setDate(data);
vo.setList(resultMap.get(data));
listVo.add(vo);
}
return new JsonResult(JsonResultCode.SUCCESS, "订单查询成功", listVo);
} catch (Exception ex) {
logger.error("[OrderController][buyerOrderList] exception :", ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试", "");
}
}

说明:买家而言其实就是待支付,已经支付等订单的明细查询,根据时间进行分组,根据时间(按照天来计算,查看自己的明细。),然后查询出整个订单明细即可。
相关运营截图如下:
1.2 对于卖家而言,他肯定想知道每天具体卖了多少东西,多少钱,但是不是针对某一个买家而言,是针对整个统计而言。
比如:他想知道我今天卖了土豆多少共多少斤,白菜多少斤,萝卜多少斤,花菜多少斤等等,同时他自己会算出今天的利润多少。
补充说明:其实系统是可以算出来今天他挣钱多少的,但是客户很讨厌输入进货价,相当于把自己的“秘密”出卖了一样,整个系统架构中
先前是有的,但是实际运营发现,不是我们的那个样子,最终是去掉了。
相关的业务核心代码如下:(数据也是来源于订单明细表中)
订单主表的列表:

/**
* 查询买家需要确认的订单列表
*/
@RequestMapping(value = "/order/list", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult orderList(HttpServletRequest request, HttpServletResponse response,Integer type,Long saleId) {
try {
List<OrderVo> orderList = orderService.getOrderList(type, saleId);
return new JsonResult(JsonResultCode.SUCCESS, "查询信息成功", orderList);
} catch (Exception ex) {
logger.error("[OrderController][orderList] exception :", ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试", "");
}
}

根据订单号获取订单明细:

/**
* 查询买家需要确认的订单列表
*/
@RequestMapping(value = "/order/detail", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult getOrderDetail(HttpServletRequest request, HttpServletResponse response,Long orderId) {
try {
OrderDetailVo odv = orderService.getOrderDetail(orderId);
return new JsonResult(JsonResultCode.SUCCESS, "查询信息成功", odv);
} catch (Exception ex) {
logger.error("[OrderController][getOrderDetail] exception :", ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试", "");
}
}

订单明细VO:对象:

/**
* 订单详情VO
*/
public class OrderDetailVo implements java.io.Serializable {
private static final long serialVersionUID = 1L;
/**
* 订单主表id,order_info表的order_id
*/
private Long orderId;
/**
* 唯一订单号
*/
private String orderNumber;
/**
* 买家ID
*/
private Long buyerId;
/**
* 买家店铺名称
*/
private String buyerName;
/**
* 买家店铺图片
*/
private String buyerLogo;
/**
* 买家地址
*/
private String buyerAddress;
/**
* 买家姓名
*/
private String bossName;
/**
* 买家手机
*/
private String bossTel;
/**
* 收货人的最佳送货时间
*/
private String bestTime;
/**
* 订单创建时间
*/
private String createTime;
/**
* 商品列表
*/
private List<OrderGoodsVo> goodsList;
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public Long getBuyerId() {
return buyerId;
}
public void setBuyerId(Long buyerId) {
this.buyerId = buyerId;
}
public String getBuyerName() {
return buyerName;
}
public void setBuyerName(String buyerName) {
this.buyerName = buyerName;
}
public String getBuyerLogo() {
return buyerLogo;
}
public void setBuyerLogo(String buyerLogo) {
this.buyerLogo = buyerLogo;
}
public String getBuyerAddress() {
return buyerAddress;
}
public void setBuyerAddress(String buyerAddress) {
this.buyerAddress = buyerAddress;
}
public String getBossName() {
return bossName;
}
public void setBossName(String bossName) {
this.bossName = bossName;
}
public String getBossTel() {
return bossTel;
}
public void setBossTel(String bossTel) {
this.bossTel = bossTel;
}
public String getBestTime() {
return bestTime;
}
public void setBestTime(String bestTime) {
this.bestTime = bestTime;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public List<OrderGoodsVo> getGoodsList() {
return goodsList;
}
public void setGoodsList(List<OrderGoodsVo> goodsList) {
this.goodsList = goodsList;
}
}

相关SQL核心:

<!-- 订单详情 -->
<select id="getOrderDetail" resultMap="orderDetailMap">
select
o.order_id,o.order_number,o.buyer_id,b.buyer_name,b.buyer_logo,b.buyer_address,b.boss_name,b.boss_tel,
date_format(o.best_time,''%Y-%m-%d %H:%i'') as best_time,date_format(o.create_time,''%Y-%m-%d %H:%i'') as create_time,
oi.item_id,oi.remark,g.goods_id,g.goods_name,g.goods_brand,g.goods_label,
gf.format_id,gf.format_name,u.unit_id,u.unit_name,gf.format_num,
pm.method_id,pm.method_name,oi.goods_price,oi.goods_number,oi.goods_amount,
gp.pic_id,gp.pic_url,gp.is_main,gp.pic_seq
from order_item oi
inner join order_info o on o.order_id=oi.order_id
inner join buyer b on b.buyer_id=o.buyer_id
inner join goods_format gf on gf.format_id=oi.format_id
inner join goods g on gf.goods_id=g.goods_id
inner join unit u on gf.unit_id=u.unit_id
left join process_method pm on pm.method_id=oi.method_id
left join goods_picture gp on g.goods_id=gp.goods_id
where oi.order_id=#{orderId}
order by gp.is_main desc
</select>

疑问一:为什么会贴出如此多的代码吗?尤其是SQL?
理由只有一点:的确这块比较复杂,很多都是基于SQL语句的查询,需要SQL功底。
相关的业务运营截图如下:
下面的核心的历史收益这块,卖家可以扔掉自己的手抄本了。根据这个平台就可以方便的明细的账单记录
补充说明:数据报表有金额,有数据,有统计,有分析,包括以后的折线图,柱状图等等报表分析,让用户明确的知道今天挣钱多少,明天预警备货多少,一切清楚明了。
总结:我的经验是所有的人心与人性都是相同的,你需要功能的客户其实也想看到,对于这种模式的采用,我们是经历了很多都经验后才总结出来的,
看起来很简单,其实背后的努力不简单。一起努力做好生鲜电商。
转载自-- https://www.cnblogs.com/jurendage/p/9049318.html
13、生鲜电商平台-订单抽成模块的设计与架构
说明:订单抽成指的是向卖家收取相应的信息服务费.(目前市场上有两种抽成方式,一种是按照总额的抽成比率,另外一种是按照订单明细的抽成比率)
由于生鲜电商的垂直领域的特殊性质,总额抽成不切合实际,所以按照订单的明细抽成。
1. 订单抽成,是按照一个区的维度,以及菜品的二级分类类抽点的。
举例说明:比如武汉光谷区,佛祖岭区,虽然都是属于东湖高新,但是光谷区的物价以及消费水平肯定是高于佛祖岭区的,因此它是按照一个区的维度来分的。
但是有些卖家挣的钱多,有的卖家挣的钱少,虽然同属于一个菜市场,但是挣钱少的跟挣钱多的一样抽成,他们也不乐意,因此又按照卖家的ID进行抽查。
最终根据业务的形态以及我们的市场调查结果,采用以商户为基准,按照菜品的二级分类来抽成的一种盈利模式。
2. 数据库系统架构设计如下:
卖家抽点配置信息表:

CREATE TABLE `order_percentage_config` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ''主键,自动增加ID'',
`region_id` bigint(20) NOT NULL COMMENT ''区域id'',
`seller_id` bigint(20) DEFAULT NULL COMMENT ''卖家id'',
`category_id` bigint(20) DEFAULT NULL COMMENT ''商品二级分类的ID'',
`percentage` decimal(12,2) DEFAULT NULL COMMENT ''平台抽点率 '',
`status` tinyint(1) DEFAULT NULL COMMENT ''状态: 0禁用 ,1启用'',
`create_time` datetime DEFAULT NULL COMMENT ''创建时间 '',
`update_time` datetime DEFAULT NULL COMMENT ''修改时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=144 DEFAULT CHARSET=utf8 COMMENT=''订单抽点配置信息表'';

说明:按照卖家的所属二级分类进行抽点,不同的抽点率也是不一样的。
2. 卖家抽点明细表。(系统需要精确的记录,那个菜品进行了抽点,抽点多少,原来的多少钱,抽点后多少钱,需要明明白白的,让卖家清清楚楚的有一笔账)

CREATE TABLE `order_percentage` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''自动增加ID'',
`order_item_id` bigint(20) DEFAULT NULL COMMENT ''订单item的ID'',
`order_number` varchar(64) DEFAULT NULL COMMENT ''所属订单号'',
`seller_id` bigint(20) DEFAULT NULL COMMENT ''卖家id'',
`order_total_amount` decimal(12,2) DEFAULT NULL COMMENT ''订单金额'',
`order_percentage` decimal(12,2) DEFAULT NULL COMMENT ''抽点比率'',
`order_percentage_amount` decimal(12,2) DEFAULT NULL COMMENT ''抽点金额'',
`order_reality_money` decimal(12,2) DEFAULT NULL COMMENT ''订单最终金额即用户最终收到的金额'',
`create_time` datetime DEFAULT NULL COMMENT ''所属时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=47226 DEFAULT CHARSET=utf8 COMMENT=''抽点信息总表'';

补充说明:1. 由于的是对某一个明细进行抽点。所以需要卖家ID,订单明细ID以及抽点比率等,最终算出抽点金额。
3. 何时进行抽点呢、
回答:每天早上6点30进行昨天的抽点,形成自己的账单。
相关的核心代码如下:采用spring task做定时器

/**
* 计算订单抽成 每天早上6:30点执行
*/
@Scheduled(cron = "0 30 6 * * ?")
protected void makeOrderPercentage() {
try {
logger.info("TasksQuartz.makeOrderPercentage.start");
// 计算订单抽成,并生成抽成数据
orderPercentageService.batchSaveOrderPercentage();
logger.info("TasksQuartz.makeOrderPercentage.end");
} catch (Exception ex) {
logger.error("TasksQuartz.makeOrderPercentage.exception", ex);
}
}

业务核心代码:

@Service
public class OrderPercentageserviceImpl implements OrderPercentageService {
private static final Logger logger = LoggerFactory.getLogger(OrderPercentageserviceImpl.class);
@Autowired
private OrderItemDao orderItemDao;
@Autowired
private OrderPercentageConfigDao orderPercentageConfigDao;
@Autowired
private OrderPercentageDao orderPercentageDao;
/**
* 批量新增数据
*/
@Override
public void batchSaveOrderPercentage() {
// 1.获取昨天12:00到今天早上6:00的所有的订单明细
Map<String, Object> dateMap = DateUtil.getTradeTime(0);
List<OrderItem> orderItems = orderItemDao.getOrderItemsByDate(dateMap);
List<OrderPercentage> list = new ArrayList<OrderPercentage>();
if (CollectionUtils.isEmpty(orderItems)) {
return;
}
for (OrderItem item : orderItems) {
try {
Long formatId = item.getFormatId();
Long sellerId = item.getSellerId();
OrderPercentageConfig config = orderPercentageConfigDao.getOrderPercentageConfig(formatId, sellerId);
if (config == null) {
logger.error("batchSaveOrderPercentage.config.isEmpty:" + "formatId:" + formatId + " sellerId:"
+ sellerId);
continue;
}
OrderPercentage orderPercentage = new OrderPercentage();
// 订单总额
BigDecimal orderTotalAmount = item.getGoodsAmount();
// 抽点比率
BigDecimal percentage = config.getPercentage();
// 抽点金额
BigDecimal orderPercentageAmount = orderTotalAmount.multiply(percentage)
.multiply(new BigDecimal("0.01")).setScale(3, BigDecimal.ROUND_UP);
// 卖家最终所得
BigDecimal orderRealityMoney = orderTotalAmount.subtract(orderPercentageAmount).setScale(3,
BigDecimal.ROUND_UP);
orderPercentage.setCreateTime(new Date());
orderPercentage.setOrderItemId(item.getId());
orderPercentage.setOrderNumber(item.getOrderNumber());
orderPercentage.setOrderTotalAmount(orderTotalAmount);
orderPercentage.setOrderPercentage(percentage);
orderPercentage.setOrderPercentageAmount(orderPercentageAmount);
orderPercentage.setOrderRealityMoney(orderRealityMoney);
orderPercentage.setSellerId(sellerId);
list.add(orderPercentage);
} catch (Exception ex) {
logger.error("batchSaveOrderPercentage.exception", ex);
}
}
try {
orderPercentageDao.batchSaveOrderPercentage(list);
} catch (Exception ex) {
logger.error("batchSaveOrderPercentage", ex);
}
}
}

相关后台运营截图如下;
转载自-- https://www.cnblogs.com/jurendage/p/9059304.html
14、生鲜电商平台-搜索模块的设计与架构
说明:搜索模块针对的是买家用户,在找菜品找的很费劲下的一种查询方面。目前也是快速的检索商品。
对于移动端的APP买家用户而言,要求的速度在3秒内完成。支持模糊查询,由于业务实战表面,整个搜索频率不到18%-25%之间
同时业务也不算很大,所以并没采用java全文检索技术.(lucene等)。这里采用的就是基本的模糊查询。
1. 搜索维度的是思考。
1.1 买家搜索的内容很有可能是针对菜品的本身属性而言,所以涉及到的内容有商品名称,商品别名,商品标签,商品描述,规格的名称,加工方式等。
1.2 我们知道模糊搜索会导致索引失效,同时整个查询性能也是有影响的。
1.3 业务形态显示有些热点的词语与内容可以做JVM缓存以提高整个单品的购买率。比如土豆现在分析出很多人要,如果我们可以跟某个商家谈好,一天
需要10w斤土豆的量进行供应,那么整个页面会出现这个关键字的默认显示。这个是后端灵活配置的。
2. 对于买家搜索的关键字,我们需要数据库进行记录,这样可以从系统级别算出买家会需要什么,可以进行针对性的营销.
相关数据库表的设计如下:

CREATE TABLE `buyer_search` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''自动增加ID'',
`buyer_id` bigint(20) DEFAULT NULL COMMENT ''买家ID'',
`words` bigint(20) DEFAULT NULL COMMENT ''卖家ID'',
`create_time` datetime DEFAULT NULL COMMENT ''创建时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=''买家搜索记录表'';

补充说明:目的其实是很明确的,就是记录买家搜索的关键字以便分析与研究用。为了更好的体验用户。
相关业务代码如下:

/**
* APP全文搜索 新
* @param request
* @param response
* @param keyword
* @return
*/
@RequestMapping(value = "/search/new", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult newSearchGoods(HttpServletRequest request, HttpServletResponse response,Long userId,Long regionId,String keyword){
try{
logger.info("SearchController.search.keyword:搜索内容:" + keyword);
//搜索结果按商家显示
//List<SellerVo> list = sellerService.searchSeller(regionId,keyword);
//搜索结果按商品显示
List<NewSearchVo> list = goodsService.newSearchGoods(userId,regionId,keyword);
return new JsonResult(JsonResultCode.SUCCESS, "查询信息成功", list);
}catch(Exception ex){
logger.error("[SearchController][newSearchGoods] exception :",ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试","");
}
}

VO对象如下:

/**
* 搜索显示类(APP全局搜索)
*/
public class NewSearchVo implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 来源于users的ID
*/
private Long sellerId;
/**
* 店铺名称
*/
private String sellerName;
/**
* 店铺别名,可以理解为简称
*/
private String sellerAlias;
/**
* 店铺logo
*/
private String sellerLogo;
/**
* 店铺评级,默认为0
*/
private int sellerRank;
/**
* 店铺评分
*/
private Double sellerGrade;
/**
* 搜索后商品列表
*/
private List<GoodsVo> searchItemList;
public Long getSellerId() {
return sellerId;
}
public void setSellerId(Long sellerId) {
this.sellerId = sellerId;
}
public String getSellerName() {
return sellerName;
}
public void setSellerName(String sellerName) {
this.sellerName = sellerName;
}
public String getSellerAlias() {
return sellerAlias;
}
public void setSellerAlias(String sellerAlias) {
this.sellerAlias = sellerAlias;
}
public String getSellerLogo() {
return sellerLogo;
}
public void setSellerLogo(String sellerLogo) {
this.sellerLogo = sellerLogo;
}
public int getSellerRank() {
return sellerRank;
}
public void setSellerRank(int sellerRank) {
this.sellerRank = sellerRank;
}
public Double getSellerGrade() {
return sellerGrade;
}
public void setSellerGrade(Double sellerGrade) {
this.sellerGrade = sellerGrade;
}
public List<GoodsVo> getSearchItemList() {
return searchItemList;
}
public void setSearchItemList(List<GoodsVo> searchItemList) {
this.searchItemList = searchItemList;
}
}

3, 数据查询性能暂时的基本满足要求,也贴出来给大家一起参考,目的是共同学习与思考.

<!-- 全局搜索商品 新-->
<select id="newSearchGoods" resultMap="newSearchResult">
<include refid="newSearchSelect" />
<include refid="newSearchFrom" />
<include refid="searchWhere" />
<if test=" keyword != null">
and (g.goods_name like concat(''%'',#{keyword},''%'')
or g.goods_as like concat(''%'',#{keyword},''%'')
or g.goods_label like concat(''%'',#{keyword},''%'')
or g.goods_brand like concat(''%'',#{keyword},''%'')
or g.goods_desc like concat(''%'',#{keyword},''%'')
or gf.format_name like concat(''%'',#{keyword},''%'')
or pm.method_name like concat(''%'',#{keyword},''%'')
or s.seller_name like concat(''%'',#{keyword},''%'')
or exists(select 1 from category where category_id = g.category_id and category_name like concat(''%'',#{keyword},''%'') )
)
</if>
<include refid="searchOrderBy" />
</select>

总结,由于搜索这块所涉及的业务相对而言比较少,功能也比较单一,含金量不是很高,所以互相学习。
对于扩展方案,如果这块的业务发现很大,可以采用中文分词记录,进行数据的挖掘,已经冷热点数据的一个分离等等,这个后期大家有需要的话,我们再研究。
相关业务运营截图如下:
转载自-- https://www.cnblogs.com/jurendage/p/9062649.html
15、生鲜电商平台-售后模块的设计与架构
说明:任何一个的电商平台都有售后服务系统,那么对于我们这个生鲜的电商平台,售后系统需要思考以下几个维度。
1. 买家的需求维度
说明:买家在平台上没找到自己想要的东西,我们需要提供给他一个入口,告诉我们他有这个需求,我们进行改进。系统需要有记录这种情况,同时也有回复客户的情况。
2. 投诉入口
说明:有客户性子比较急,他有问题,就会马上打电话给客服,客服需要解答与回答,维护客户关系。对于系统而言,需要记录这种情况,然后分析问题与解决问题。
3. IM聊天入口
说明:客户有时候也不想写信息,也不想打电话,能否有一个时刻的IM聊天记录呢?对于系统而言需要记录这种信息,我们目前系统没处理,采用的是微信,以及销售人员的反馈机制。
4. 退货问题
说明:售后系统中,退货问题是最繁琐的,买家存在以下两种情况。
4.1 买家要钱不要货。顾名思义,有些买家就是不要货了,他需要我们退钱给他,这个配送端有一个一件退货功能,钱退到买家的余额里面,下次可以继续购买。
4.2 买家要货不要钱,顾名思义,有些买家的确需要这个货物,对于我们退钱给他,他是不接受的,因为他真的需要这种东西,你让他再去买,客户体验非常差,可能 就没有下次购物了。对于这种情况,我们用时间轴来继续整个过程。(说明,由于这个系统设计到生鲜电商方面,其他的电商方面可能会不一样。)
相关数据库的设计与架构如下:
1. 买家平台建议信息表

CREATE TABLE `suggestion` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''自动增加ID'',
`suggestion_content` varchar(1024) DEFAULT NULL COMMENT ''建议内容'',
`suggestion_imgs` varchar(255) DEFAULT NULL COMMENT ''多张图片'',
`user_id` bigint(20) DEFAULT NULL COMMENT ''所属用户ID'',
`create_time` datetime DEFAULT NULL COMMENT ''创建时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8 COMMENT=''用户对平台的建议'';

说明: 平台建议表,是买家对平台的建议以及自己的需求的一个入口,可以是图片与内容两点。
比如说:他说我们送的菜有问题,很多烂的,那么他是需要拍图片证明的。
2. 平台回复信息表

CREATE TABLE `suggestion_reply` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''自动增加ID'',
`suggestion_id` bigint(20) DEFAULT NULL COMMENT ''客户的建议ID'',
`content` varchar(512) DEFAULT NULL COMMENT ''回复的内容'',
`create_time` datetime DEFAULT NULL COMMENT ''创建时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT=''客户建议回复信息表'';

说明:作为一个平台,平台需要回复客户的信息,买家也需要看到,当然这边系统是不区分是买家还是卖家的,我们都是可以数据的处理的。
3. 售后系统时间轴的设计
说明:其实我们系统需要知道整个售后的过程的,比如买家什么时候发起的不要钱,要货,然后师傅是什么时候知道这个消息的,如何进行售后的,他们会遇到什么问题,
当然这里面有很多的问题,系统可以做的事情其实是很少的,而我们需要做的是更多的事情。

CREATE TABLE `order_timeline` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT ''自动增加ID'',
`item_id` bigint(20) DEFAULT NULL COMMENT ''订单项ID'',
`remarks` varchar(256) DEFAULT NULL COMMENT ''备注'',
`create_time` datetime DEFAULT NULL COMMENT ''创建时间'',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1980 DEFAULT CHARSET=utf8 COMMENT=''售后模块,退换货时间轴,针对的是某一个订单项'';

相关时间轴运营截图如下:
整个业务不算复杂,需要的一种思路与解决思路的方案:
关于补货流程:

补货需求
业务需求:
当卖家主动点击缺货,则配送师傅看到这个异常订单项,然后他有两种选择,
第一种补货(有货,他也想补或者客户说要货不要钱)
第二种不补货(无货可补,他不想补或者客户说退钱等等)
第一种补货业务:
1. 当配送师傅点击已补货,则把这个订单项对应的金额从买家中直接扣除,前提是线上付款,如果这个订单是线下付款,则不用处理扣款逻辑,直接修改状态即可。同时记录时间轴日志。
第二种不补货业务:
2. 当师傅点击不补货,则这个订单项不做任何扣款逻辑,不管线下还是线上,直接修改状态即可,同时记录时间轴日志。
补充说明:补货与不补货属于互斥操作,即已补货后不允许再出现不补货,不补货后不再允许出现补货。按照规则来处理。

相关业务核心代码如下:

/**
* 订单项退货*/
@RestController
@RequestMapping("/delivery")
public class OrderReturnController extends BaseController {
private static final Logger logger = LoggerFactory.getLogger(OrderReturnController.class);
@Autowired
private OrderItemService orderItemService;
@Autowired
private OrderReturnService orderReturnService;
/**
* 订单项退货
*
*/
@RequestMapping(value = "/order/return/item", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult orderReturnItem(HttpServletRequest request, HttpServletResponse response,
@Param("itemId") Long itemId, @Param("deliveryId") Long deliveryId, @Param("status") int status) {
try {
if (itemId == null) {
return new JsonResult(JsonResultCode.FAILURE, "item参数有误", "");
}
OrderItem orderItem = orderItemService.getOrderItemByItemId(itemId);
if (orderItem == null) {
return new JsonResult(JsonResultCode.FAILURE, "无此订单项", "");
}
String returnMsg = "";
if(status == BuyerStatus.THREE){
returnMsg = TimelineTemplate.return_MSG;
}if(status == BuyerStatus.FOUR){
returnMsg = TimelineTemplate.BACK_MSG;
}if(status == BuyerStatus.ZERO){
returnMsg = TimelineTemplate.OFF_MSG;
}
orderItemService.updateOrderItemStatus(itemId, status, deliveryId, returnMsg);
return new JsonResult(JsonResultCode.SUCCESS, "操作成功", "");
} catch (Exception ex) {
logger.error("[OrderReturnController][orderReturnItem] exception :", ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试", "");
}
}
/**
* 退还列表
*/
@RequestMapping(value = "/order/return/list", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult orderReturnList(HttpServletRequest request, HttpServletResponse response,@Param("deliveryId") Long deliveryId, @Param("status") int status) {
try
{
// 组装成为最终的列表结果
List<OrderReturnVo> listResult = new ArrayList<OrderReturnVo>();
List<OrderGoodsVo> goodsList = orderReturnService.getReturnOrderGoodsList(deliveryId,status);
if (CollectionUtils.isEmpty(goodsList)) {
return new JsonResult(JsonResultCode.SUCCESS, "查询完成", listResult);
}
// 临时参数,判断时间
Map<String, List<OrderReturnEntity>> paramTimeMap = new HashMap<String, List<OrderReturnEntity>>();
// 过滤卖家
Map<String, List<OrderGoodsVo>> paramSellerMap = new HashMap<String, List<OrderGoodsVo>>();
for (OrderGoodsVo vo : goodsList) {
String bestTime = DateUtil.dateToString(vo.getBestTime(), "yyyy-MM-dd");
// 时间相同
if (paramTimeMap.get(bestTime) != null) {
List<OrderReturnEntity> mapOrderReturnEntity = paramTimeMap.get(bestTime);
// 组装时间
OrderReturnVo resultVo = new OrderReturnVo();
resultVo.setBestTime(bestTime);
// 判断是否是同一个卖家的
if (paramSellerMap.get(vo.getSellerName()) != null)
{
OrderReturnEntity entity = new OrderReturnEntity();
List<OrderGoodsVo> listVo = paramSellerMap.get(vo.getSellerName());
listVo.add(vo);
entity.setListOrderGoodsVo(listVo);
resultVo.setListOrderReturnEntity(mapOrderReturnEntity);
}else
{
//不同买家
OrderReturnEntity entity = new OrderReturnEntity();
entity.setSellerName(vo.getSellerName());
List<OrderGoodsVo> listVo =new ArrayList<OrderGoodsVo>();
listVo.add(vo);
entity.setListOrderGoodsVo(listVo);
mapOrderReturnEntity.add(entity);
paramSellerMap.put(vo.getSellerName(), listVo);
}
} else {
// 组装时间
OrderReturnVo resultVo = new OrderReturnVo();
resultVo.setBestTime(bestTime);
OrderReturnEntity entity = new OrderReturnEntity();
entity.setSellerName(vo.getSellerName());
List<OrderGoodsVo> paramOrderGoodsVo = new ArrayList<OrderGoodsVo>();
paramOrderGoodsVo.add(vo);
entity.setListOrderGoodsVo(paramOrderGoodsVo);
List<OrderReturnEntity> listOrderReturnEntity = new ArrayList<OrderReturnEntity>();
listOrderReturnEntity.add(entity);
resultVo.setListOrderReturnEntity(listOrderReturnEntity);
listResult.add(resultVo);
paramSellerMap.put(vo.getSellerName(), paramOrderGoodsVo);
paramTimeMap.put(bestTime, listOrderReturnEntity);
}
}
return new JsonResult(JsonResultCode.SUCCESS, "查询信息成功", listResult);
} catch (Exception ex) {
logger.error("[OrderReturnController][orderReturnItem] exception :", ex);
return new JsonResult(JsonResultCode.FAILURE, "系统错误,请稍后重试", "");
}
}

APP运营截图相对而言比较简单,我这边就不贴出来了。
转载自-- https://www.cnblogs.com/jurendage/p/9066307.html
关于36、生鲜电商平台-积分,优惠券,会员折扣,签到、预售、拼团、砍价、秒杀及抽奖等促销模块架构设计的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于10、生鲜电商平台-财务系统模块的设计与架构、13、生鲜电商平台-订单抽成模块的设计与架构、14、生鲜电商平台-搜索模块的设计与架构、15、生鲜电商平台-售后模块的设计与架构等相关知识的信息别忘了在本站进行查找喔。
本文标签: