当前位置:数据分析 > 商城系统架构设计与实现

商城系统架构设计与实现

  • 发布:2023-10-05 13:41

目录

  1. 背景
  2. 商场整体结构
  3. 订单系统
  4. 产品体系
  5. 促销系统
  6. 支付系统
  7. 推荐系统
  8. 积分系统
  9. 会员制度
  10. 总结

1。背景

随着互联网技术的广泛应用,各行各业都依托网络平台开展业务活动。小到个人带货,大到企业的商业活动,都离不开网上交易。因此,商场的影响力随处可见。无论是加盟淘宝、京东、拼多多等大型电商平台,还是企业自建商城平台,目的基本都是为了拓展业务渠道、销售商品以增加业绩收入。

说说我们基于我们公司自建商城平台的商城建筑设计方案。

2。商场整体结构

一般来说,如果商城系统按照单一的服务方案来构思的话,会按模块来划分,至少包括:商品、订单、会员、促销、支付、积分、仓储、物流、风控、内部ERP 、金融系统等。

公司原有的技术架构是SpringCloud微服务架构,所以商城系统也是在这个系统下。同时,根据我公司实际业务的特殊性和复杂性,将各个模块划分为微服务,将业务领域划分为多个业务中平台数据中平台

设计商城整体结构如下:

一个完整的商城架构相对复杂,涉及很多相关系统和子系统模块。

采用分层设计。从系统分层设计的角度来看,可以分为:前端接入层、应用表示层、中间服务、后端服务层、基础服务层。

3。订单系统

2.1、订单系统边界

在构建企业订单系统之前,需要梳理好整体业务系统以及订单系统上下游关系。只有明确划分业务系统的边界,才能确定订单系统的职责和功能,从而保证系统之间的效率。简单的工作。

外部服务展示企业外部用户使用的所有系统都在这一层,包括普通用户使用的WEB和C端,以及商户使用的商户后台以及各个销售渠道的分销系统比如和银行信用卡中心的合作以及微信的合作,在合作伙伴的平台上展示这个产品。这类系统站在与客户接触的最前沿,是企业实现商业模式的桥头堡。

中后台系统,每个C端业务形态都会有对应的系统模块,比如负责管理平台交易的订单系统、管理优惠信息的促销系统、生产商品系统管理平台上所有产品的内容系统(CMS),管理外部系统上显示的所有内容等。

基础服务体系,随着企业发展,信息化建设达到一定程度,企业需要将通用功能转化为服务和平台,以保证应用架构的合理性,提高服务效率。此类系统主要为其他应用系统提供基础服务能力支持。

可以看到,订单系统接收用户信息,将用户信息转化为产品订单,同时管理和跟踪订单信息和数据,承载着整个交易线路的重要客户环节。

下一个连接产品系统、促销系统、仓储系统、会员系统、积分系统、支付系统等,在整个电商平台中起到承上启下的作用。

2.2、订单系统业务架构

订购服务。该模块主要功能是用户日常使用的服务和页面,包括订单列表、订单明细、在线订单等,还包括为公共业务模块提供的多维度订单数据服务。

订单逻辑作为订单系统的核心,起着至关重要的作用。订单系统负责管理订单创建、订单支付、订单生产、订单确认、订单完成、订单取消等订单流程。还涉及复杂的订单状态规则、订单金额计算规则、库存增减规则等

在底层服务方面,信息化建设达到一定水平的企业,一般会将产品等公共服务模块化、集中化,构建相应的产品系统,代码、数据库、接口等相对独立。但这也带来了一个问题,比如:订单创建场景中需要获取的信息分散在各个系统中。组装信息的时候会比较麻烦。

如果需要从各个中端系统调用:一是需要大量的时间,二是代码的维护成本非常高。因此,订单系统接入所需的公共服务模块聚合接口,即可完成订单系统中连接公共系统的服务。

2.3、订单核心功能

功能脑图

为了订单系统能够高效、准确地管理和跟踪订单,订单系统会存储一系列有关产品、折扣、用户、支付信息等的实时订单数据,以便与下游系统进行通信,如:促销、仓储、物流互动。

以一般B2C商城的订单为例,其中包含的信息如下:

这里需要注意的是订单类型。随着平台业务的不断发展,品类丰富、交易方式丰富,需要对订单进行多维度分类管理。同时订单类型有利于订单系统的可扩展性。每个订单类型都会对应一组流程和一组状态,方便对订单进行分类、管理和复用。

2.4、订单转发流程

2.4.1。创建订单

用户下订单后,系统需要生成订单。这时就需要先获取订单所涉及的产品信息,然后再获取与产品相关的优惠信息。如果产品不参与优惠信息,则没有此步骤。

然后获得该账号的会员权益。这里需要注意的是:折扣信息和会员权益的区别。例如:商品满折就是折扣信息,会员9.2折就是会员权益。一是为了货物。另一种是用于账户的。二是优惠活动叠加规则和优先规则。

库存增减规则是指订单中的商品何时从库存系统中对应商品的库存中扣除。目前主流的方法有两种:

(1)下单时减少库存——即用户下单成功时减少库存数量

优点:用户体验友好,系统逻辑简单。

缺点:会导致恶意下单或者下单后不购买,让真正需要的用户无法购买,影响真实销售。

解决方案:

设置订单有效期。如果订单创建成功,N分钟内未付款,订单将被取消,库存将回滚;

购买限制,利用各种条件限制买家可以购买的商品数量,例如一个账号、一个IP、只能购买一件商品;

风险控制,从技术角度来看,屏蔽恶意账户,禁止恶意账户购买。

(2)付款后减少库存——即用户完成付款并反馈给平台后,库存数量会减少

优点:减少无效订单造成的资源损失。

缺点:由于第三方支付返回结果存在时间差,多个用户同时支付成功,会导致订单数量超过库存。商家库存不足,很容易导致缺货和投诉,成本增加。

解决方案:

付款前再次核实库存。若订单确认支付,则再次验证并友好提示用户库存不足;

新增提示信息:在商品详情页和订单步骤页提示无法及时付款、无法保证库存。

综上,两种方法各有优缺点。所以需要根据实际场景来考虑,比如闪购、抢购、促销等,可以通过下单的方式来减少库存。对于库存大、并发流量低的产品,可以通过支付方式减少库存(闪购系统的设计在单独的文档中介绍)。

将两种方式带入销售场景,关联产品类型、促销类型、供需关系等,灵活运用,充分发挥计算机系统的优势。

2.4.2、订单支付

用户支付完订单后,需要获取订单的支付信息,包括支付流水号、支付时间等。支付完订单后,就需要等待商家发货货物。但在配送过程中,根据平台的业务模式,可能会涉及到订单的拆分。

订单拆分一般分为两种:

一是用户选择的产品来自不同渠道(自营和商家、商家和商家);

另一种是在SKU层面拆分订单:不同仓库、不同运输要求的SKU、包裹重量和体积限制等因素需要拆分订单。

订单拆分也是一个相对独立的模块。可以是小计订单的形式,也可以是服务订单和订单的形式。一般来说,是1:N的关系。

2.4.3、订单生产

订单生产是指产品从企业到用户的过程概览。例如,在电子商务平台中,商家有标准化的运输流程。订单内容将被发送到仓库,仓库将进行订购、拣货、包装、交付货物(在我们的例子中,这通常是由供应商完成的)。 )。

2.4.4、订单确认

收到货后,订单系统需要提醒用户在快递签收后对货物进行评价。这里需要注意的是,确认收到货并不意味着交易成功,而是售后服务的开始。

2.4.5,订单完成

订单完成是指收到货后X天内的状态。此时订单不在售后支持时间范围内。至此,订单的转发流程就完成了。

2.4。订单逆向流程

如上所述,逆向流程包括修改订单、取消订单、退款、退货等各种操作,有必要梳理一下这些流程与正向流程的关系,才能理清完整的订单流程的订单系统。

2.4.1、订单修改

您可以对订单中的信息进行整理,并根据信息关联程度和业务需求设置订单的可修改范围。例如:客户下订单后,想要修改收货人的地址和电话号码。此时,只需更新相应的数据即可。

2.4.2,取消订单

用户提交订单后未付款。原则上,用户此时因为尚未付款而取消订单。比较简单。您只需补足提交订单时原本扣除的库存即可。促销优惠中所使用的折扣券、权益等均以平台规则为准,并会相应补充。

2.4.3,退款

用户支付成功后,客户要求退款,商户需要进行退款审核。双方达成协议后,系统应以退款订单的形式完成退款,并关联原始订单数据。由于产品不变,所以不允许考虑与库存系统的交互,只能考虑与促销系统和支付系统的交互。

2.4.4,返回

用户支付成功,客户提出退货请求后,商户需要进行退款审核。双方达成协议后,库存系统需要补充,支付系统和促销系统以退款单的形式完成退款。最后,在退款/退货流程中,需要考虑根据平台业务场景进行折扣分配的逻辑,以及发生退款/退货时如何退回折扣的处理规则和流程。

2.5,状态机设计

状态机是管理订单状态逻辑的工具。状态机可以概括为三个要素,即当前状态、动作和次要状态。

当前状态:指当前状态。

动作:动作执行后,可以移动到新的状态,也可以保持原来的状态。

次要状态:动作满足后要转移到的新状态。 “次要状态”是相对于“当前状态”而言的。一旦“次要状态”被激活,就会转变为新的“当前状态”“是的。

状态机的设计需要结合平台的实际业务场景,将状态之间的切换细化为某个动作的执行。

以B2C商城的订单系统为例。状态分类如下:

为了高效跟踪和管理订单,订单系统从订单流程中的关键节点抽象出订单状态。从不同用户的角度来看,订单状态可分为:系统订单状态、商家订单状态、买家订单状态等。

对于订单系统来说,订单状态细分的粒度越细、越清晰,订单系统管理的准确性和可靠性就越高。例如:在待支付和待发货两种状态下,订单系统后端会细分为: 订单超时取消、订单支付失败、订单支付完成

因此,在订单状态模块中,通常会维护一个状态映射表,根据不同的用户角色对系统订单状态进行重新分类,以满足不同用户的需求。

另外,随着业务的不断发展,不同的业务类型会有不同的对应订单状态。因此,订单系统中一般会存储多套状态机,以满足不同的订单类型。

2.5,关键代码片段

为原商户提供API接入接口

@Module("订购模块-C端")
@RestController
@RequestMapping(“/customer-api/v1/order”)
公共类 OrderCustomerController {
@资源
私有 OrderService orderService;
@资源
私人 OrderCreateCmdExe orderCreateCmdExe;
@资源
私人 OrderPayCmdExe orderPayCmdExe;
@资源
私人 OrderCancelCmdExe orderCancelCmdExe;
@资源
私人 RefundApplyCmdExe 退款ApplyCmdExe;
@资源
私人 OrderDeleteCmdExe orderDeleteCmdExe;
/**
* 生成订单
*
* @param cmd 命令内容
* @return订单信息
*/
@RestApi(name = "生成订单", logabled = true)
@PostMapping(“/创建”)
@检查重新提交
公共DataResponse创建(@RequestBody @Valid OrderCreateCmd cmd){OrderCreateCO orderCreateCO = orderCreateCmdExe.create(cmd);
返回 DataResponse.of(orderCreateCO);
}
/**
* s
*/
@RestApi(name = "订单支付", logabled = true)
@PostMapping(“/支付”)
@检查重新提交
公共DataResponse支付(@RequestBody @Valid OrderPayCmd cmd,HttpServletRequest请求){
OrderPaymentInfoCO paymentInfoCO = www.sychzs.cn(cmd, request);
返回 DataResponse.of( paymentInfoCO );
}
/**
* 订单列表(分页)
*
* @param cmd 查询条件
* @return 查询结果
*/
@RestApi(name = "订单列表(分页)", logabled = true)
@PostMapping(“/页”)
公共DataResponse>页面(@RequestBody OrderPageQryCmd cmd){
OrderQryDTO dto = BeanToolkit.instance().copy(cmd, OrderQryDTO.class);
dto.setPageNo(cmd.getPageNo());
dto.setPageSize(cmd.getPageSize());
dto.setCreatorId(HttpContext.getCustomerId());
dto.setCustomerDeleted(0);
自定义页面 orderDTOPage = orderService.customerPage(dto);自定义页面结果=新的自定义页面<>(orderDTOPage.getCurrent(), orderDTOPage.getSize(), orderDTOPage.getTotal());
result.setRecords(OrderConverter.converter2OrderCO(orderDTOPage.getRecords()));
返回 DataResponse.of(结果);
}
/**
* 订单详细信息
*
* @param orderId 订单ID
* @return 订单详情
*/
@RestApi(name = "主订单详细信息", logabled = true)
@GetMapping("/detail/{orderId}")
公共DataResponse详细信息(@PathVariable(“orderId”)Long orderId){
OrderDTO orderDTO = orderService.detail(orderId, TerminalEnum.CUSTOMER);
返回 DataResponse.of(OrderConverter.converter2OrderCO(orderDTO));
}
/**
* 订单状态统计
*/
@RestApi(name = "订单状态统计", logabled = true)
@GetMapping("/stateStatistics")
公共 DataResponse orderStateStatistics() {
OrderStateStatisticsCustomerCO 结果 = orderService.customerOrderStateStatistics();
返回 DataResponse.of(结果);
}
/**
* 取消订单
*
* @param cmd 取消订单
*/
@RestApi(name = "取消订单", logabled = true)
@PostMapping("/取消")公共响应取消(@RequestBody @Valid OrderCancelCmd cmd){
orderCancelCmdExe.cancel(cmd);
返回 Response.buildSuccess();
}
/**
*退/换货申请
*
* @param cmd 应用内容
*/
@RestApi(name = "退货/换货申请", logabled = true)
@PostMapping("/refundApply")
公共响应refundApply(@RequestBody @Valid RefundApplyCmd cmd){
退款ApplyCmdExe.refundApply(cmd);
返回 Response.buildSuccess();
}
/**
* 退货/换货订单列表(分页)
*
* @param qry 查询条件
* @return 查询结果
*/
@RestApi(name = "退货/换货订单列表(分页)", logabled = true)
@PostMapping(“/refundApply/page”)
公共DataResponse>refundOrderPage(@RequestBody RefundApplyQry qry){
自定义页面 orderDTOPage = orderService.refundOrderPage(qry);
自定义页面结果=新的自定义页面<>(orderDTOPage.getCurrent(), orderDTOPage.getSize(), orderDTOPage.getTotal());
result.setRecords(OrderConverter.converter2OrderCO(orderDTOPage.getRecords()));
返回 DataResponse.of(结果);
}
/**
* 删除订单
*/
@RestApi(name = "删除订单", logabled = true)@DeleteMapping("/删除")
公共响应deleteOrder(@Valid @RequestBody OrderDeleteCmd cmd){
orderDeleteCmdExe.deleteOrder(cmd);
返回 Response.buildSuccess();
}
/**
* 获取订单账单信息
*
* @param orderId 主订单ID
* @return 账单信息
*/
@RestApi(name = "获取订单账单信息", logabled = true)
@GetMapping("/orderInvoiceInfo/{orderId}")
公共 DataResponse getOrderInvoiceInfo(@PathVariable("orderId") Long orderId) {
返回 DataResponse.of(orderService.getOrderInvoiceInfo(orderId));
}
}

订单创建执行者

@Slf4j
@成分
公共类 OrderCreateCmdExe {
@资源
私人编号网关编号网关;
@资源
私人订单验证器订单验证器;
@资源
私人物品服务物品服务;
@资源
私人PointsGateway 点Gateway;
@资源
私人 CustomerMemberGateway customerMemberGateway;
@资源
私人 OrderAutoCancelPublisher orderAutoCancelPublisher;
@资源
私人 OrderDaiZhiFuNoticePublisher orderDaiZhiFuNoticePublisher;
@资源私人会员购物车网关 会员购物车网关;
/**
* 生成订单
*/
@Transactional(rollbackFor = Exception.class)
公共 OrderCreateCO 创建(OrderCreateCmd cmd){
// 1.查询商品信息
List skuIds = cmd.getGoodsList().stream().map(OrderCreateCmd.GoodsList::getSkuId).collect(Collectors.toList());
地图 skuMap = GoodsService.mapSkuCO(skuIds);
// 2.查询客户积分
BigDecimal customerIntegral = pointGateway.getCustomerIntegral(HttpContext.getCustomerId());
// 3.查询会员信息
MemberDTO memberDTO = customerMemberGateway.findByCustomerId(HttpContext.getCustomerId());
// 4. 检查订单条件
orderValidator.createOrderValidate(cmd, skuMap, customerIntegral, memberDTO);
// 5.组装订单信息
List mallOrderDOS = newMallOrderE(cmd, skuMap, memberDTO.getMemberLevel());
// 6.查看用户积分余额
orderValidator.customerIntegralValidate(mallOrderDOS.get(0), customerIntegral);
// 7.保存订单信息
MallOrderE.queryInstance().saveBatch(mallOrderDOS);
// 8、批量扣除库存。考虑到没有分布式事务,RPC最终会扣除库存。列表 updateInventoryDTOS = GoodsConverter.convert2UpdateInventoryDTO(cmd.getGoodsList());
productsService.updateInventory(updateInventoryDTOS);
// 9. 打开延迟队列
// 9.1.挂单会自动取消
OrderEvent orderEvent = new OrderEvent();
orderEvent.setMainOrderId(mallOrderDOS.get(0).getId());
orderEvent.setMainOrderCode(mallOrderDOS.get(0).getCode());
orderAutoCancelPublisher.sendMessage(orderEvent);
// 9.2.待付款订单提醒
orderDaiZhiFuNoticePublisher.sendMessage(orderEvent);
// 10.删除购物车中的商品
if (SubmitPageEnum.orderConfirm.getValue().equals(cmd.getSubmitPage())) {
删除GoodsCart(cmd.getGoodsList());
}
OrderCreateCO 结果 = new OrderCreateCO();
result.setOrderId(mallOrderDOS.get(0).getId().toString());
result.setOrderNo(mallOrderDOS.get(0).getCode());
返回结果;
}
/**
* 组装订单信息
* 返回的订单集中,index=0的为主订单
*/
private List newMallOrderE(OrderCreateCmd cmd, Map skuMap, Integer memberLevel) {
List 结果 = new ArrayList<>();
// 1.打包主订单信息MallOrderE mallOrderE = BeanToolkit.instance().copy(cmd, MallOrderE.class);
结果.add(mallOrderE);
mallOrderE.setId(numberingGateway.getNextId());
String orderCode = numberingGateway.generateOrderCode();
mallOrderE.setCode(orderCode);
mallOrderE.setStatus(OrderStatusEnum.DAI_ZHI_FU.getValue());
// 订单总价、订单总积分、订单总运费
多头总价格=0L;
长总运费=0L;
长总积分=0L;
// 2. 打包子订单信息
Queue subOrderCode = numberingGateway.generateSubOrderCode(orderCode, cmd.getGoodsList().size());
for (OrderCreateCmd.GoodsList 货物: cmd.getGoodsList()) {
SpuApiCO spu = skuMap.get(goods.getSkuId());
MallOrderE mallOrderEItem = BeanToolkit.instance().copy(cmd, MallOrderE.class);
mallOrderEItem.setId(numberingGateway.getNextId());
mallOrderEItem.setCode(subOrderCode.poll());
mallOrderEItem.setMainOrderId(mallOrderE.getId());
mallOrderEItem.setMainOrderCode(mallOrderE.getCode());
mallOrderEItem.setStatus(OrderStatusEnum.DAI_ZHI_FU.getValue());CalcPayPriceDTO calcPayPriceDTO =goodsService.calcPayPrice(spu.getSku(),goods.getCount(),memberLevel,cmd.getReceiverRegion());
mallOrderEItem.setPrice(calcPayPriceDTO.getPayPrice()); // 子订单价格
mallOrderEItem.setIntegral(calcPayPriceDTO.getGoodsTotalIntegral()); // 子订单点
mallOrderEItem.setFreight(calcPayPriceDTO.getFreight()); // 子订单运费
mallOrderEItem.setSpuId(Long.valueOf(goods.getSpuId()));
mallOrderEItem.setSkuId(Long.valueOf(goods.getSkuId()));
mallOrderEItem.setQuantity(goods.getCount());
mallOrderEItem.setGoodsName(spu.getGoodsName());
mallOrderEItem.setGoodsSupplierId(spu.getSupplierId());
mallOrderEItem.setGoodsType(spu.getGoodsType());
mallOrderEItem.setCreatorId(HttpContext.getCustomerId());
mallOrderEItem.setCreator(HttpContext.getCustomerName());
mallOrderEItem.setCreateDt(www.sychzs.cn());
mallOrderEItem.setLastUpdatorId(HttpContext.getCustomerId());
mallOrderEItem.setLastUpdator(HttpContext.getCustomerName());
mallOrderEItem.setLastUpdateDt(www.sychzs.cn());
result.add(mallOrderEItem);
totalPrice += calcPayPriceDTO.getPayPrice();
totalFreight += calcPayPriceDTO.getFreight();
totalIntegral += calcPayPriceDTO.getGoodsTotalIntegral();
}
mallOrderE.setPrice(totalPrice); // 订单总价
mallOrderE.setIntegral(totalIntegral); // 订单总积分
mallOrderE.setFreight(totalFreight); // 订单总运费
mallOrderE.setCreatorId(HttpContext.getCustomerId());
mallOrderE.setCreator(HttpContext.getCustomerName());
mallOrderE.setCreateDt(www.sychzs.cn());
mallOrderE.setLastUpdatorId(HttpContext.getCustomerId());
mallOrderE.setLastUpdator(HttpContext.getCustomerName());
mallOrderE.setLastUpdateDt(www.sychzs.cn());
return result;
}
/**
* 批量删除购物车数据
*
* @param goodsList 待删除的商品
*/
private void deleteGoodsCart(List goodsList) {
for (OrderCreateCmd.GoodsList list : goodsList) {
DeleteGoodsCartCmd deleteGoodsCartCmd = new DeleteGoodsCartCmd();
deleteGoodsCartCmd.setSpuId(Long.valueOf(list.getSpuId()));
deleteGoodsCartCmd.setSkuId(Long.valueOf(list.getSkuId()));
memberCartGateway.deleteGoodsCart(HttpContext.getCustomerId(), deleteGoodsCartCmd);
}
}
}

订单取消执行器

/**
* 订单取消执行器
*
* @author cgli
* @date 2022/12/30 09:19
*/
@Component
public class OrderCancelCmdExe {
@Resource
private OrderValidator orderValidator;
@Resource
private MallOrderGateway orderGateway;
@Resource
private RollbackIntegralExe rollbackIntegralExe;
@Resource
private GoodsService goodsService;
/**
* 取消订单
*/
@Transactional(rollbackFor = Exception.class)
public void cancel(OrderCancelCmd cmd) {
MallOrderE mallOrderE = MallOrderE.queryInstance().getById(cmd.getOrderId());
orderValidator.cancelOrderValidate(mallOrderE);
List orderUpdateList = new ArrayList<>();
List inventoryUpdateList = new ArrayList<>();
//主订单状态置为"已取消"
MallOrderE mainOrderEForUpdate = new MallOrderE();
mainOrderEForUpdate.setId(mallOrderE.getId());
mainOrderEForUpdate.setStatus(OrderStatusEnum.YI_QU_XIAO.getValue());
orderUpdateList.add(mainOrderEForUpdate);
List orderDTOS = orderGateway.listByMainOrderId(cmd.getOrderId());
for (OrderDTO orderDTO : orderDTOS) {
//子订单状态置为"已取消"
MallOrderE subOrderEForUpdate = new MallOrderE();
subOrderEForUpdate.setId(orderDTO.getId());
subOrderEForUpdate.setStatus(OrderStatusEnum.YI_QU_XIAO.getValue());
orderUpdateList.add(subOrderEForUpdate);
//回滚库存
UpdateInventoryDTO updateInventoryDTO = new UpdateInventoryDTO(orderDTO.getSkuId().toString(), orderDTO.getQuantity());
inventoryUpdateList.add(updateInventoryDTO);
}
orderGateway.updateBatchById(orderUpdateList);
// 判断是否已经进行了积分支付,需要将积分回滚
rollbackIntegralExe.execute(mallOrderE, "订单取消积分返还");
// 库存回滚
goodsService.updateInventory(inventoryUpdateList);
}
}

订单删除执行器

/**
* 订单删除执行器
*
* @author cgli
* @date 2022/12/30 09:30
*/
@Component
public class OrderDeleteCmdExe {
@Resource
private OrderValidator orderValidator;
/**
* 删除订单
*/
@Transactional(rollbackFor = Exception.class)
public void deleteOrder(OrderDeleteCmd cmd) {
MallOrderE mallOrderE = MallOrderE.queryInstance().getById(cmd.getOrderId());
orderValidator.deleteValidate(mallOrderE);
MallOrderE.queryInstance().customerDeleteByMainOrderId(mallOrderE.getId());
}
}

 订单查询服务

@Slf4j
@Service
public class OrderService extends BaseService {
@Autowired
private MallOrderGateway orderGateway;
@Autowired
private MallDeliveryGateway deliveryGateway;
@Autowired
private GoodsService goodsService;
@Autowired
private MallOrderBillGateway mallOrderBillGateway;
@Autowired
private MallInvoiceRecordGateway invoiceRecordGateway;
/**
* 订单列表(分页)
*/
public CustomizePage page(OrderQryDTO dto) {
dto.setQuerySubOrder(true);
CustomizePage page = www.sychzs.cn(dto);
Map supplierMap = goodsService.mapSupplierCO();
//查询订单物流信息
List deliveryIds = page.getRecords().stream().map(OrderDTO::getDeliveryId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
Map deliveryEMap = deliveryGateway.mapById(deliveryIds);
for (OrderDTO orderDTO : page.getRecords()) {
//整合供应商名称
SupplierDTO supplierDTO = supplierMap.get(orderDTO.getGoodsSupplierId());
if (supplierDTO != null) {
orderDTO.setGoodsSupplierName(supplierDTO.getSupplierName());
}
//转译订单状态
orderDTO.setStatusDesc(OrderStatusEnum.value2Desc(TerminalEnum.ADMIN, orderDTO.getStatus()));
// 物流信息
MallDeliveryE mallDeliveryE = deliveryEMap.get(orderDTO.getDeliveryId());
orderDTO.setDeliveryInfo(mallDeliveryE);
// 商品信息
GoodsCO goodsCO = new GoodsCO();
goodsCO.setGoodsName(orderDTO.getGoodsName());
orderDTO.setGoods(goodsCO);
}
return page;
}
/**
* 消费者端分页查询订单信息
*
* @param dto 查询条件
* @return 查询结果
*/
public CustomizePage customerPage(OrderQryDTO dto) {
dto.setQueryMainOrder(true);
CustomizePage mainOrderPage = www.sychzs.cn(dto);
if (CollUtil.isEmpty(mainOrderPage.getRecords())) {
return new CustomizePage<>(mainOrderPage.getCurrent(), mainOrderPage.getSize(), mainOrderPage.getTotal());
}
List mainOrderIds = mainOrderPage.getRecords().stream().map(OrderDTO::getId).collect(Collectors.toList());
//查询子订单信息
OrderQryDTO subOrderQry = new OrderQryDTO();
subOrderQry.setMainOrderIds(mainOrderIds);
List subOrderList = orderGateway.list(subOrderQry);
//查询商品信息
List skuIds = www.sychzs.cn().map(OrderDTO::getSkuId).map(String::valueOf).collect(Collectors.toList());
Map spuMap = goodsService.mapSkuCO(skuIds);
//查询派送信息
List deliveryIds = www.sychzs.cn().map(OrderDTO::getDeliveryId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
Map deliveryMap = deliveryGateway.mapById(deliveryIds);
//查询支付信息
Map billMap = mallOrderBillGateway.getBill(mainOrderIds, www.sychzs.cn, OrderPayWayEnum.INTEGRAL_PAY);
//整合发票信息
Map orderInvoiceMap = invoiceRecordGateway.getOrderInvoice(mainOrderIds);
//整合子母单、商品信息和物流信息
return OrderConverter.converter2OrderDTO(mainOrderPage, subOrderList, spuMap, deliveryMap, billMap, orderInvoiceMap);
}
/**
* B端订单状态统计
*/
public OrderStateStatisticsCO orderStateStatistics(OrderPageQryCmd cmd) {
return orderGateway.orderStateStatistics(cmd);
}
/**
* C端订单状态统计
*/
public OrderStateStatisticsCustomerCO customerOrderStateStatistics() {
return orderGateway.customerOrderStateStatistics(HttpContext.getCustomerId());
}
/**
* 获取订单详情
*
* @param orderId  订单ID
* @param terminal 终端类型
* @return 订单详情
*/
public OrderDTO detail(Long orderId, TerminalEnum terminal) {
OrderDTO result = null;
// 1、获取订单信息
MallOrderE mallOrderE = MallOrderE.queryInstance().getById(orderId);
if (mallOrderE.isMainOrder()) {
// 2、查看主订单维度的详情
// 2.1、查询子订单信息
List orderDTOS = orderGateway.listByMainOrderId(orderId);
// 2.2、查询商品信息
List skuIds = www.sychzs.cn().map(OrderDTO::getSkuId).map(String::valueOf).collect(Collectors.toList());
Map spuMap = goodsService.mapSkuCO(skuIds);
result = OrderConverter.converter2OrderDTO(mallOrderE, orderDTOS, spuMap, terminal);
} else {
// 3、查看子单维度的详情
// 3.1、查询母单订单信息
MallOrderE mainOrderInfo = MallOrderE.queryInstance().getById(mallOrderE.getMainOrderId());
// 3.2、查询商品信息
Map spuMap = goodsService.mapSkuCO(Collections.singletonList(String.valueOf(mallOrderE.getSkuId())));
// 4、整合订单详情
OrderDTO subOrderDTO = BeanToolkit.instance().copy(mallOrderE, OrderDTO.class);
result = OrderConverter.converter2OrderDTO(mainOrderInfo, Collections.singletonList(subOrderDTO), spuMap, terminal);
}
return result;
}
/**
* 商品销量统计
*/
public List goodsSalesStatistics(GoodsSalesStatisticsQryCmd cmd) {
return orderGateway.goodsSalesStatistics(cmd.getSkuIds(), cmd.getCreateDtBegin(), cmd.getCreateDtEnd(), cmd.getLimit());
}
/**
* 退款订单列表
*
* @param qry 查询条件
* @return 查询结果
*/
public CustomizePage refundOrderPage(RefundApplyQry qry) {
OrderQryDTO qryDTO = BeanToolkit.instance().copy(qry, OrderQryDTO.class);
qryDTO.setPageNo(qry.getPageNo());
qryDTO.setPageSize(qry.getPageSize());
qryDTO.setStatusList(Arrays.asList(www.sychzs.cn_HUO_SHEN_QING.getValue(), www.sychzs.cn_HUO_WAN_CHENG.getValue()));
qryDTO.setQuerySubOrder(true);
qryDTO.setCreatorId(HttpContext.getCustomerId());
CustomizePage page = www.sychzs.cn(qryDTO);
//查询商品信息
List skuIds = page.getRecords().stream().map(OrderDTO::getSkuId).map(String::valueOf).collect(Collectors.toList());
Map spuMap = goodsService.mapSkuCO(skuIds);
return OrderConverter.converter2OrderDTO(page, spuMap);
}
/**
* 获取导出数据
*
* @param cmd 查询条件
* @return 查询结果
*/
public List export(OrderPageQryCmd cmd) {
int exportCount = 0;    //已经处理的数据
OrderQryDTO orderQryDTO = OrderQryDTO.of(cmd);
orderQryDTO.setPageNo(1);
orderQryDTO.setPageSize(200);  //分批整合数据
CustomizePage orderPage = page(orderQryDTO);
if (CollUtil.isEmpty(orderPage.getRecords())) {
throw new DataNotFoundException();
}
List result = new ArrayList<>();
while (CollUtil.isNotEmpty(orderPage.getRecords()) && BizConstant.MAX_EXPORT_SIZE > exportCount) {
List orderExcelDTOList = OrderConverter.converter2OrderExcelDTO(orderPage.getRecords());
result.addAll(orderExcelDTOList);
//处理下一页的数据
exportCount += orderQryDTO.getPageSize();
orderQryDTO.setPageNo(orderQryDTO.getPageNo() + 1);
orderPage = page(orderQryDTO);
}
return result;
}
/**
* 获取订单退货申请记录
*
* @param orderId 订单ID
* @return 查询结果
*/
public RefundApplyInfoCO getRefundApplyInfoCO(Long orderId) {
MallRefundApplyE refundApplyE = MallRefundApplyE.queryInstance().getByOrderId(orderId);
if (refundApplyE == null) {
throw new DataNotFoundException();
}
RefundApplyInfoCO result = BeanToolkit.instance().copy(refundApplyE, RefundApplyInfoCO.class);
result.setRefundTypeDesc(OrderRefundTypeEnum.value2Desc(result.getRefundType()));
return result;
}
/**
* 获取订单列表
*
* @param cmd 查询条件
* @return 查询结果
*/
public List queryOrderList(OrderQryCmd cmd) {
OrderQryDTO subOrderQry = BeanToolkit.instance().copy(cmd, OrderQryDTO.class);
subOrderQry.setQuerySubOrder(true);
return orderGateway.list(subOrderQry);
}
/**
* 获取SKU产生的最新订单
*
* @param skuIds skuId集合
* @return 订单信息
*/
public List skuLatestSale(List skuIds) {
return orderGateway.skuLatestSale(skuIds);
}
/**
* 获取订单开票信息
*/
public OrderInvoiceInfoCO getOrderInvoiceInfo(Long orderId) {
MallOrderE mainOrderE = MallOrderE.queryInstance().getById(orderId);
if (Objects.isNull(mainOrderE)) {
throw new ServiceException("订单不存在");
}
if (!OrderStatusEnum.YI_WAN_CHENG.getValue().equals(mainOrderE.getStatus())) {
throw new ServiceException("未完成的订单无法申请开发票");
}
if (!mainOrderE.moneyPaid()) {
throw new ServiceException("该订单未进行现金支付,无法开具发票");
}
OrderInvoiceInfoCO result = new OrderInvoiceInfoCO();
result.setOrderId(mainOrderE.getId().toString());
result.setOrderCode(mainOrderE.getCode());
//开票金额,该母单的实际支付金额,部分退款则取最终收款金额
long totalRefund = orderGateway.listByMainOrderId(orderId)
.stream()
.filter(orderDTO -> www.sychzs.cn_HUO_WAN_CHENG.getValue().equals(orderDTO.getStatus()))
.mapToLong(OrderDTO::getPayPrice)
.sum();
long invoicePrice = mainOrderE.getPayPrice() - totalRefund;
result.setInvoicePrice(BigDecimalUtils.penny2yuan(invoicePrice));
return result;
}
}

 

/**
* 订单领域层服务接口
*
*/
public interface MallOrderGateway {
/**
* 分页查询
*/
CustomizePage page(OrderQryDTO dto);
/**
* 订单列表
*/
List list(OrderQryDTO dto);
/**
* 根据主订单ID获取自订单集合
*/
List listByMainOrderId(Long orderId);
List listByMainOrderIdList(List orderIdList);
/**
* 统计消费者购买的商品数量
*
* @param customerId 消费者ID
* @param skuId      skuId
* @return 统计结果
*/
Integer countBySkuId(String customerId, Long skuId);
/**
* 根据ID查询订单信息
*
* @param id 订单ID
* @return 查询结果
*/
MallOrderE getById(Long id);
/**
* 根据子单查询母单数据
*
* @param id 子单ID
* @return 母单数据
*/
MallOrderE getMainOrderBySubId(Long id);
MallOrderE getByCode(String code);
/**
* 根据ID批量查询订单信息
*
* @param ids 订单ID集合
* @return 查询结果
*/
List listById(List ids);
/**
* 批量保存订单信息
*
* @param mallOrderES 待保存内容
* @return 保存结果
*/
Boolean saveBatch(List mallOrderES);
/**
* 根据主键更新订单信息
*
* @param mallOrderE 更新内容
* @return 更新结果
*/
Boolean updateById(MallOrderE mallOrderE);
Boolean updateBatchById(List orderEList);
/**
* B端订单状态统计
*/
OrderStateStatisticsCO orderStateStatistics(OrderPageQryCmd cmd);
/**
* 消费者订单状态统计
*/
OrderStateStatisticsCustomerCO customerOrderStateStatistics(String customerId);
/**
* 商品销量统计
*
* @param skuIds 商品SKUID
* @return 统计结果
*/
List goodsSalesStatistics(List skuIds, LocalDateTime createDtBegin, LocalDateTime createDtEnd, Integer limit);
/**
* 删除主订单
*
* @param mainOrderId 主订单ID
* @return 删除结果
*/
Boolean customerDeleteByMainOrderId(Long mainOrderId);
/**
* 获取SKU产生的最新订单
*
* @param skuIds skuId集合
* @return 订单信息
*/
List skuLatestSale(List skuIds);
/**
* 根据订单ID集合批量删除订单
*
* @param ids 订单ID集合
* @return 删除结果
*/
Boolean deleteBatchById(Collection ids);
}

 

 

3. 产品商品系统

由于写在一起篇幅太长,拉上拉下的设置一格式实在不好编辑;另外各位看官看文章太长也心思看完,看久也累!故每个子系统分开写!

请看下一篇》》》》产商品系统架构设计

 

相关文章