|
|
@@ -0,0 +1,363 @@
|
|
|
+package com.xingxi.api.service.impl;
|
|
|
+
|
|
|
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
|
|
|
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
|
|
|
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
|
|
+import com.github.binarywang.wxpay.config.WxPayConfig;
|
|
|
+import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
+import com.github.binarywang.wxpay.service.WxPayService;
|
|
|
+import com.github.pagehelper.Page;
|
|
|
+import com.github.pagehelper.PageHelper;
|
|
|
+import com.xingxi.api.common.ApiException;
|
|
|
+import com.xingxi.api.common.UserContext;
|
|
|
+import com.xingxi.api.data.domain.OrderDTO;
|
|
|
+import com.xingxi.api.data.domain.OrderDetailDTO;
|
|
|
+import com.xingxi.api.data.mapper.WxApiProdInventoryMapper;
|
|
|
+import com.xingxi.api.model.*;
|
|
|
+import com.xingxi.api.service.OrderServiceI;
|
|
|
+import com.xingxi.business.Order.domain.Order;
|
|
|
+import com.xingxi.business.Order.domain.OrderDeliveryExpr;
|
|
|
+import com.xingxi.business.Order.domain.OrderDetail;
|
|
|
+import com.xingxi.business.Order.mapper.OrderDeliveryExprMapper;
|
|
|
+import com.xingxi.business.Order.mapper.OrderDetailMapper;
|
|
|
+import com.xingxi.business.Order.mapper.OrderMapper;
|
|
|
+import com.xingxi.business.PaymentInfo.domain.PaymentInfo;
|
|
|
+import com.xingxi.business.PaymentInfo.mapper.PaymentInfoMapper;
|
|
|
+import com.xingxi.business.ProdInventory.domain.ProdInventory;
|
|
|
+import com.xingxi.business.ProdInventory.domain.ProdInventoryBill;
|
|
|
+import com.xingxi.business.ProdInventory.mapper.ProdInventoryBillMapper;
|
|
|
+import com.xingxi.business.UserAddress.domain.UserAddress;
|
|
|
+import com.xingxi.common.core.domain.entity.SysUser;
|
|
|
+import com.xingxi.common.enums.EDelFlag;
|
|
|
+import com.xingxi.common.enums.EInventoryBillType;
|
|
|
+import com.xingxi.common.enums.EOrderDetailStatus;
|
|
|
+import com.xingxi.common.enums.EOrderStatus;
|
|
|
+import com.xingxi.common.exception.BusinessException;
|
|
|
+import com.xingxi.common.mq.bo.order.OrderBO;
|
|
|
+import com.xingxi.common.mq.publisher.order.OrderCreatedMqPublisher;
|
|
|
+import com.xingxi.common.utils.DateUtils;
|
|
|
+import com.xingxi.common.utils.PageUtils;
|
|
|
+import com.xingxi.common.utils.StringUtils;
|
|
|
+import com.xingxi.common.utils.bean.BeanUtils;
|
|
|
+import com.xingxi.common.utils.uuid.IdUtils;
|
|
|
+import com.xingxi.master.merchant.domain.MerchantProd;
|
|
|
+import com.xingxi.master.merchant.mapper.MerchantProdMapper;
|
|
|
+import com.xingxi.master.product.domain.Prod;
|
|
|
+import com.xingxi.master.product.domain.ProdAttrPrice;
|
|
|
+import com.xingxi.master.product.domain.ProdPic;
|
|
|
+import com.xingxi.master.product.domain.ProdVendor;
|
|
|
+import com.xingxi.master.product.mapper.*;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.validation.annotation.Validated;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Service("OrderServiceI")
|
|
|
+class OrderApiServiceImpl implements OrderServiceI {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private OrderMapper orderMapper;
|
|
|
+ @Autowired
|
|
|
+ private OrderDetailMapper orderDetailMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdPicMapper prodPicMapper;
|
|
|
+ @Autowired
|
|
|
+ private OrderDeliveryExprMapper orderDeliveryExprMapper;
|
|
|
+ @Autowired
|
|
|
+ private MerchantProdMapper merchantProdMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdMapper prodMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdAttrMapper prodAttrMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdAttrPriceMapper prodAttrPriceMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdVendorMapper prodVendorMapper;
|
|
|
+ @Autowired
|
|
|
+ private ProdInventoryBillMapper prodInventoryBillMapper;
|
|
|
+ @Autowired
|
|
|
+ private WxApiProdInventoryMapper wxApiProdInventoryMapper;
|
|
|
+
|
|
|
+ private final OrderCreatedMqPublisher createdMqPublisher;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WxPayService wxPayService;
|
|
|
+
|
|
|
+ @Value("${wx.pay.domain}")
|
|
|
+ private String domain;
|
|
|
+ @Value("${wx.pay.notifyUrl}")
|
|
|
+ private String notifyUrl;
|
|
|
+ private WxPayConfig config;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private PaymentInfoMapper paymentInfoMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public OrderQueryResponse list(UserContext userContext, OrderQueryRequest request) {
|
|
|
+
|
|
|
+ SysUser currentUser = userContext.getCurrentUser();
|
|
|
+ Long userId = currentUser.getUserId();
|
|
|
+ Integer pageNum = request.getPageNum();
|
|
|
+ Integer pageSize = request.getPageSize();
|
|
|
+ String status = request.getStatus();
|
|
|
+
|
|
|
+ Order condOrder = new Order();
|
|
|
+ condOrder.setBuyerId(userId);
|
|
|
+ condOrder.setOrderStatus(status);
|
|
|
+ condOrder.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+
|
|
|
+ PageUtils.startPage();
|
|
|
+ Page<OrderDTO> orderList = PageHelper.startPage(pageNum, pageSize)
|
|
|
+ .doSelectPage(() -> orderMapper.selectOrderList(condOrder));
|
|
|
+
|
|
|
+ if (!orderList.isEmpty()) {
|
|
|
+ for (OrderDTO order : orderList) {
|
|
|
+ OrderDetail condOderDetail = new OrderDetail();
|
|
|
+ condOderDetail.setOrderId(order.getOrderId());
|
|
|
+ List<OrderDetail> orderDetailList = orderDetailMapper.selectOrderDetailList(condOderDetail);
|
|
|
+ List<OrderDetailDTO> odDtoList = new ArrayList<>();
|
|
|
+ for (OrderDetail orderDetail : orderDetailList) {
|
|
|
+ OrderDetailDTO odDto = new OrderDetailDTO();
|
|
|
+ BeanUtils.copyBeanProp(odDto, orderDetail);
|
|
|
+
|
|
|
+ ProdPic condPic = new ProdPic();
|
|
|
+ condPic.setProdId(orderDetail.getProdId());
|
|
|
+ condPic.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ odDto.setImageDTOS(prodPicMapper.selectProdPicList(condPic));
|
|
|
+
|
|
|
+ OrderDeliveryExpr condExp = new OrderDeliveryExpr();
|
|
|
+ condExp.setOrderDetailId(orderDetail.getOrderDetailId());
|
|
|
+ odDto.setOrderDetailExprs(orderDeliveryExprMapper.selectOrderDeliveryExprList(condExp));
|
|
|
+
|
|
|
+ odDtoList.add(odDto);
|
|
|
+ }
|
|
|
+
|
|
|
+ order.setOrderDetailDTOS(odDtoList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public OrderCreateResponse create(UserContext userContext, OrderCreateRequest request) {
|
|
|
+
|
|
|
+ Date orderTime = DateUtils.getNowDate();
|
|
|
+
|
|
|
+ // C端用户信息
|
|
|
+ SysUser currentUser = userContext.getCurrentUser();
|
|
|
+ Long userId = currentUser.getUserId();
|
|
|
+
|
|
|
+ // 订单信息
|
|
|
+ List<OrderItemDTO> orderItemDTOS = request.getOrderItemDTOS();
|
|
|
+ UserAddress userAddressDTO = request.getUserAddress();
|
|
|
+
|
|
|
+ String orderNo = IdUtils.snowFlake();
|
|
|
+ String orderStatus = EOrderStatus.ORDERED.getVal();
|
|
|
+
|
|
|
+ Order order = new Order();
|
|
|
+
|
|
|
+ order.setOrderNo(orderNo);
|
|
|
+ order.setOrderTime(DateUtils.getNowDate());
|
|
|
+ order.setOrderStatus(orderStatus);
|
|
|
+ order.setBuyerId(userId);
|
|
|
+
|
|
|
+ order.setRecProv(request.getUserAddress().getProvince());
|
|
|
+ order.setRecCity(request.getUserAddress().getCity());
|
|
|
+ order.setRecDistrict(request.getUserAddress().getDistrict());
|
|
|
+ order.setRecAddress(request.getUserAddress().getAddress());
|
|
|
+ order.setRecName(request.getUserAddress().getRecipient());
|
|
|
+ order.setRecMobile(request.getUserAddress().getMobile());
|
|
|
+ order.setRemark(request.getRemark());
|
|
|
+ order.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ order.setCreateUser(userId.toString());
|
|
|
+ order.setCreateTime(orderTime);
|
|
|
+ order.setUpdateUser(userId.toString());
|
|
|
+ order.setUpdateTime(orderTime);
|
|
|
+
|
|
|
+ int cnt = orderMapper.insertOrder(order);
|
|
|
+ if (cnt <= 0) {
|
|
|
+ log.debug("创建订单失败");
|
|
|
+ throw new BusinessException("创建订单失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer prodQty = 0;
|
|
|
+ BigDecimal prodAmt = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ List<OrderDetail> orderDetailItems = new ArrayList<>();
|
|
|
+ for (OrderItemDTO orderItemDTO : orderItemDTOS) {
|
|
|
+ MerchantProd merchantProd = merchantProdMapper.selectMerchantProdByMercProdId(orderItemDTO.getMercProdId());
|
|
|
+ Prod prod = prodMapper.selectProdById(merchantProd.getProdId());
|
|
|
+ order.setSellerId(merchantProd.getMercId());
|
|
|
+
|
|
|
+ ProdVendor condPv = new ProdVendor();
|
|
|
+ condPv.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ condPv.setProdId(merchantProd.getProdId());
|
|
|
+ condPv.setProdAttrId(merchantProd.getProdAttrId());
|
|
|
+
|
|
|
+ List<ProdVendor> prodVendorList = prodVendorMapper.selectProdVendorList(condPv);
|
|
|
+ if (prodVendorList.isEmpty()) {
|
|
|
+ log.error("商户商品[" + orderItemDTO.getMercProdId() + "]无供应商");
|
|
|
+ throw new BusinessException("未查询到商品的供应商");
|
|
|
+ }
|
|
|
+
|
|
|
+ OrderDetail orderDetail = new OrderDetail();
|
|
|
+ orderDetail.setOrderId(order.getOrderId());
|
|
|
+ orderDetail.setOrderDetailStatus(EOrderDetailStatus.ORDERED.getVal());
|
|
|
+ orderDetail.setProdId(merchantProd.getProdId());
|
|
|
+ orderDetail.setProdName(prod.getProdName());
|
|
|
+ orderDetail.setProdAttrId(merchantProd.getProdAttrId());
|
|
|
+ orderDetail.setProdAttrName(prodAttrMapper.selectProdAttrByProdAttrId(merchantProd.getProdAttrId()).getAttrName());
|
|
|
+ orderDetail.setVendorId(prodVendorList.get(0).getVendorId());
|
|
|
+ orderDetail.setQuantity(orderItemDTO.getCount());
|
|
|
+
|
|
|
+ ProdAttrPrice condPrice = new ProdAttrPrice();
|
|
|
+ condPrice.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ condPrice.setProdId(merchantProd.getProdId());
|
|
|
+ condPrice.setProdAttrId(merchantProd.getProdAttrId());
|
|
|
+ condPrice.setSellerId(merchantProd.getMercId());
|
|
|
+ List<ProdAttrPrice> prodAttrPriceList = prodAttrPriceMapper.selectProdAttrPriceList(condPrice);
|
|
|
+ if (StringUtils.isEmpty(prodAttrPriceList)) {
|
|
|
+ log.error("商户商品[{}]无价格", orderItemDTO.getMercProdId());
|
|
|
+ throw new BusinessException("未查询到商品的价格");
|
|
|
+ }
|
|
|
+
|
|
|
+ orderDetail.setPrice(prodAttrPriceList.get(0).getPrice());
|
|
|
+ orderDetail.setOrderAmount(orderDetail.getPrice().multiply(new BigDecimal(orderDetail.getQuantity())));
|
|
|
+ orderDetail.setPayAmount(orderDetail.getOrderAmount());
|
|
|
+ orderDetail.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ orderDetail.setCreateUser(userId.toString());
|
|
|
+ orderDetail.setCreateTime(orderTime);
|
|
|
+ orderDetail.setUpdateUser(userId.toString());
|
|
|
+ orderDetail.setUpdateTime(orderTime);
|
|
|
+
|
|
|
+ orderDetailItems.add(orderDetail);
|
|
|
+
|
|
|
+ prodQty = prodQty + orderDetail.getQuantity();
|
|
|
+ prodAmt = prodAmt.add(orderDetail.getOrderAmount());
|
|
|
+
|
|
|
+ // 锁库
|
|
|
+ ProdInventory prodInventory = wxApiProdInventoryMapper.selectProdInventoryLock(orderDetail.getProdId(), orderDetail.getProdAttrId(), merchantProd.getMercId());
|
|
|
+ if (!(prodInventory != null && prodInventory.getAvailQty() > 0)) {
|
|
|
+ log.error("商品[{}]库存不足", prod.getProdName());
|
|
|
+ throw new BusinessException("商品[" + prod.getProdName() + "]库存不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ prodInventory.setAvailQty(orderDetail.getQuantity());
|
|
|
+ prodInventory.setUpdateTime(orderTime);
|
|
|
+ prodInventory.setUpdateUser(userId.toString());
|
|
|
+ cnt = wxApiProdInventoryMapper.updateSubtractProdStock(prodInventory);
|
|
|
+ if (cnt <= 0) {
|
|
|
+ log.error("扣减库存[{}]失败", prodInventory.getProdInventoryId());
|
|
|
+ throw new ApiException("prod.stock.out.error");
|
|
|
+ }
|
|
|
+
|
|
|
+ ProdInventoryBill inventoryBill = new ProdInventoryBill();
|
|
|
+ inventoryBill.setBillTime(orderTime);
|
|
|
+ inventoryBill.setBillType(EInventoryBillType.LOCK.getVal());
|
|
|
+ inventoryBill.setQuantity(orderItemDTO.getCount());
|
|
|
+ inventoryBill.setInventoryId(prodInventory.getProdInventoryId());
|
|
|
+ inventoryBill.setOrderId(order.getOrderId());
|
|
|
+ inventoryBill.setOrderNo(orderNo);
|
|
|
+ inventoryBill.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ inventoryBill.setCreateUser(userId.toString());
|
|
|
+ inventoryBill.setCreateTime(orderTime);
|
|
|
+ inventoryBill.setUpdateUser(userId.toString());
|
|
|
+ inventoryBill.setUpdateTime(orderTime);
|
|
|
+
|
|
|
+ cnt = prodInventoryBillMapper.insertProdInventoryBill(inventoryBill);
|
|
|
+ if (cnt <= 0) {
|
|
|
+ log.error("创建订单失败");
|
|
|
+ throw new BusinessException("创建订单失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ orderDetailMapper.batchInsertOrderDetail(orderDetailItems);
|
|
|
+ order.setOrderAmount(prodAmt);
|
|
|
+ order.setProdQuantity(prodQty);
|
|
|
+ orderMapper.updateOrder(order);
|
|
|
+
|
|
|
+ orderCreatedEvent(order);
|
|
|
+
|
|
|
+ config = wxPayService.getConfig();
|
|
|
+
|
|
|
+ WxPayUnifiedOrderV3Result.JsapiResult result = callWxpay(order,currentUser.getWxOpenId(),order.getOrderAmount().intValue(),currentUser.getLoginIp());
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void orderCreatedEvent(Order message){
|
|
|
+ OrderBO sendOrder = new OrderBO();
|
|
|
+ sendOrder.setOrderId(message.getOrderId());
|
|
|
+ sendOrder.setOrderNo(message.getOrderNo());
|
|
|
+ createdMqPublisher.sendMessage(sendOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayUnifiedOrderV3Result.JsapiResult callWxpay(Order order, String openid, int amount, String ip) {
|
|
|
+ WxPayUnifiedOrderV3Result.JsapiResult rtn = new WxPayUnifiedOrderV3Result.JsapiResult();
|
|
|
+
|
|
|
+ Date now = DateUtils.getNowDate();
|
|
|
+ WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
|
|
|
+ payer.setOpenid(openid);
|
|
|
+
|
|
|
+ WxPayUnifiedOrderV3Request.Amount payAmount = new WxPayUnifiedOrderV3Request.Amount();
|
|
|
+ payAmount.setTotal(amount); // 分
|
|
|
+ payAmount.setCurrency("CNY");
|
|
|
+
|
|
|
+ WxPayUnifiedOrderV3Request wxrequest = new WxPayUnifiedOrderV3Request();
|
|
|
+ //过期时间,15分钟
|
|
|
+ wxrequest.setTimeExpire(DateUtils.parseDateToStr(DateUtils.RFC3339, DateUtils.addMinutes(now,15))); // 示例值:2018-06-08T10:34:56+08:00
|
|
|
+
|
|
|
+ wxrequest.setDescription("谷鹿鹿Q");
|
|
|
+ wxrequest.setOutTradeNo(order.getOrderNo());
|
|
|
+ wxrequest.setAppid(config.getAppId());
|
|
|
+ wxrequest.setMchid(config.getMchId());
|
|
|
+ wxrequest.setNotifyUrl(notifyUrl);
|
|
|
+ wxrequest.setPayer(payer);
|
|
|
+ wxrequest.setAmount(payAmount);
|
|
|
+
|
|
|
+ log.info(wxrequest.toString());
|
|
|
+
|
|
|
+ WxPayUnifiedOrderV3Request.SceneInfo sceneInfo = new WxPayUnifiedOrderV3Request.SceneInfo();
|
|
|
+ sceneInfo.setPayerClientIp(ip);
|
|
|
+ wxrequest.setSceneInfo(sceneInfo);
|
|
|
+
|
|
|
+ try {
|
|
|
+
|
|
|
+ rtn = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, wxrequest);
|
|
|
+
|
|
|
+ PaymentInfo paymentInfo = new PaymentInfo();
|
|
|
+
|
|
|
+ paymentInfo.setOrderId(order.getOrderId());
|
|
|
+ paymentInfo.setOrderNo(order.getOrderNo());
|
|
|
+ paymentInfo.setPayTime(now);
|
|
|
+ paymentInfo.setSellerId(order.getSellerId());
|
|
|
+ paymentInfo.setDescription("谷鹿鹿Q");
|
|
|
+ paymentInfo.setOutTradeNo(order.getOrderNo());
|
|
|
+ paymentInfo.setNotifyUrl(notifyUrl);
|
|
|
+ paymentInfo.setAmountTotal(new BigDecimal(amount));
|
|
|
+ paymentInfo.setPayerOpenid(openid);
|
|
|
+ paymentInfo.setPrepayId(rtn.getPackageValue());
|
|
|
+ paymentInfo.setDelFlag(EDelFlag.NO.getVal());
|
|
|
+ paymentInfo.setCreateTime(now);
|
|
|
+ paymentInfo.setUpdateTime(now);
|
|
|
+ paymentInfo.setCreateUser(openid);
|
|
|
+ paymentInfo.setUpdateUser(openid);
|
|
|
+ paymentInfoMapper.insertPaymentInfo(paymentInfo);
|
|
|
+
|
|
|
+ return rtn;
|
|
|
+ } catch (WxPayException e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ throw new RuntimeException("创建支付失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|