|
|
@@ -0,0 +1,958 @@
|
|
|
+package com.fs.his.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.IdUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.json.JSONArray;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import com.fs.common.core.domain.R;
|
|
|
+import com.fs.common.exception.CustomException;
|
|
|
+import com.fs.common.utils.DateUtils;
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.company.domain.CompanyUser;
|
|
|
+import com.fs.company.mapper.CompanyUserMapper;
|
|
|
+import com.fs.core.utils.OrderCodeUtils;
|
|
|
+import com.fs.erp.domain.ErpOrder;
|
|
|
+import com.fs.erp.domain.ErpOrderPayment;
|
|
|
+import com.fs.erp.service.IErpOrderService;
|
|
|
+import com.fs.his.config.FsSysConfig;
|
|
|
+import com.fs.his.domain.FsExpress;
|
|
|
+import com.fs.his.domain.FsGuCoinGoods;
|
|
|
+import com.fs.his.domain.FsGuCoinOrder;
|
|
|
+import com.fs.his.domain.FsStorePayment;
|
|
|
+import com.fs.his.domain.FsUser;
|
|
|
+import com.fs.his.domain.FsUserAddress;
|
|
|
+import com.fs.his.dto.ComputeGuCoinOrderMoneyDTO;
|
|
|
+import com.fs.his.dto.ErpRemarkDTO;
|
|
|
+import com.fs.his.enums.BusinessTypeEnum;
|
|
|
+import com.fs.his.enums.PaymentMethodEnum;
|
|
|
+import com.fs.his.mapper.FsGuCoinGoodsMapper;
|
|
|
+import com.fs.his.mapper.FsGuCoinOrderMapper;
|
|
|
+import com.fs.his.mapper.FsUserAddressMapper;
|
|
|
+import com.fs.his.mapper.FsUserMapper;
|
|
|
+import com.fs.his.param.FsGuCoinCartOrderCreateParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderComputeParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderCreateParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderDoPayParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderListUParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderManuallyParam;
|
|
|
+import com.fs.his.param.FsGuCoinOrderParam;
|
|
|
+import com.fs.his.param.PayOrderParam;
|
|
|
+import com.fs.his.service.IFsExpressService;
|
|
|
+import com.fs.his.service.IFsGuCoinCartService;
|
|
|
+import com.fs.his.service.IFsGuCoinOrderService;
|
|
|
+import com.fs.his.service.IFsStorePaymentService;
|
|
|
+import com.fs.his.service.IFsUserGuCoinLogsService;
|
|
|
+import com.fs.his.utils.ConfigUtil;
|
|
|
+import com.fs.his.vo.FsGuCoinCartVO;
|
|
|
+import com.fs.qw.domain.QwUser;
|
|
|
+import com.fs.qw.mapper.QwUserMapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.sql.Timestamp;
|
|
|
+import java.text.ParseException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+
|
|
|
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 谷币商城订单Service业务层
|
|
|
+ * 谷币:谷养正道商城专属积分,无有效期
|
|
|
+ *
|
|
|
+ * @author fs
|
|
|
+ * @date 2026-07-17
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class FsGuCoinOrderServiceImpl implements IFsGuCoinOrderService
|
|
|
+{
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(FsGuCoinOrderServiceImpl.class);
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private FsGuCoinOrderMapper fsGuCoinOrderMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsGuCoinGoodsMapper fsGuCoinGoodsMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsUserMapper fsUserMapper;
|
|
|
+ @Autowired
|
|
|
+ private FsUserAddressMapper fsUserAddressMapper;
|
|
|
+ @Autowired
|
|
|
+ private CompanyUserMapper companyUserMapper;
|
|
|
+ @Autowired
|
|
|
+ private QwUserMapper qwUserMapper;
|
|
|
+ @Autowired
|
|
|
+ private IFsUserGuCoinLogsService fsUserGuCoinLogsService;
|
|
|
+ @Autowired
|
|
|
+ private IFsStorePaymentService storePaymentService;
|
|
|
+ @Autowired
|
|
|
+ private IFsGuCoinCartService fsGuCoinCartService;
|
|
|
+
|
|
|
+ /** 聚水潭固定店铺编号(与积分订单一致,从配置注入) */
|
|
|
+ @Value("${jst.shop_code:''}")
|
|
|
+ private String shopCode;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ConfigUtil configUtil;
|
|
|
+
|
|
|
+ /** 谷币订单仅推送聚水潭,直接注入JST实现 */
|
|
|
+ @Autowired
|
|
|
+ @Qualifier("JSTErpOrderServiceImpl")
|
|
|
+ private IErpOrderService jstErpOrderService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IFsExpressService expressService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public FsGuCoinOrder selectFsGuCoinOrderByOrderId(Long orderId) {
|
|
|
+ return fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderId(orderId);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public FsGuCoinOrder selectFsGuCoinOrderByOrderCode(String orderCode) {
|
|
|
+ return fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderCode(orderCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<FsGuCoinOrder> selectFsGuCoinOrderList(FsGuCoinOrderParam param) {
|
|
|
+ return fsGuCoinOrderMapper.selectFsGuCoinOrderList(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<FsGuCoinOrder> selectFsGuCoinOrderListU(FsGuCoinOrderListUParam param) {
|
|
|
+ return fsGuCoinOrderMapper.selectFsGuCoinOrderListU(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int insertFsGuCoinOrder(FsGuCoinOrder fsGuCoinOrder) {
|
|
|
+ return fsGuCoinOrderMapper.insertFsGuCoinOrder(fsGuCoinOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int updateFsGuCoinOrder(FsGuCoinOrder fsGuCoinOrder) {
|
|
|
+ return fsGuCoinOrderMapper.updateFsGuCoinOrder(fsGuCoinOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int deleteFsGuCoinOrderByOrderIds(Long[] orderIds) {
|
|
|
+ return fsGuCoinOrderMapper.deleteFsGuCoinOrderByOrderIds(orderIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 谷币订单支付金额计算
|
|
|
+ * 与积分商城 computeOrder 逻辑对称:判断 goodsId/cartIds 二选一
|
|
|
+ * 取消优惠金额逻辑(不实现 applyCoupon),discountGuCoin/discountCash 恒为 0
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R computeOrder(FsGuCoinOrderComputeParam param) {
|
|
|
+ // 查询用户,判断用户是否存在
|
|
|
+ FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
|
|
|
+ if (fsUser == null || fsUser.getIsDel() == 1) {
|
|
|
+ return R.error("用户不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (param.getGoodsId() == null && (param.getCartIds() == null || param.getCartIds().isEmpty())) {
|
|
|
+ return R.error("商品不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ ComputeGuCoinOrderMoneyDTO moneyDTO = new ComputeGuCoinOrderMoneyDTO();
|
|
|
+ List<FsGuCoinGoods> goodsItem = new ArrayList<>();
|
|
|
+
|
|
|
+ // 判断是购物车还是单商品
|
|
|
+ if (param.getGoodsId() != null) {
|
|
|
+ FsGuCoinGoods goods = fsGuCoinGoodsMapper.selectFsGuCoinGoodsByGoodsId(param.getGoodsId());
|
|
|
+ if (goods == null) {
|
|
|
+ return R.error("谷币商品不存在");
|
|
|
+ }
|
|
|
+ if (goods.getStatus() == null || goods.getStatus() != 1) {
|
|
|
+ return R.error("谷币商品已下架");
|
|
|
+ }
|
|
|
+ goods.setNum(1L);
|
|
|
+ goodsItem.add(goods);
|
|
|
+
|
|
|
+ long goodsGuCoin = goods.getGuCoin() == null ? 0L : goods.getGuCoin();
|
|
|
+ BigDecimal goodsCash = goods.getCash() == null ? BigDecimal.ZERO : goods.getCash();
|
|
|
+ moneyDTO.setTotalGuCoin(goodsGuCoin);
|
|
|
+ moneyDTO.setGuCoin(goodsGuCoin);
|
|
|
+ moneyDTO.setTotalCash(goodsCash);
|
|
|
+ moneyDTO.setCash(goodsCash);
|
|
|
+ // 谷币商城暂不实现优惠金额逻辑,discountGuCoin/discountCash 保持默认 0
|
|
|
+ } else {
|
|
|
+ // 购物车结算
|
|
|
+ List<FsGuCoinCartVO> carts = fsGuCoinCartService.getCartByIds(fsUser.getUserId(), param.getCartIds());
|
|
|
+ if (carts.isEmpty()) {
|
|
|
+ return R.error("购物车商品不存在");
|
|
|
+ }
|
|
|
+ for (FsGuCoinCartVO cart : carts) {
|
|
|
+ FsGuCoinGoods goods = fsGuCoinGoodsMapper.selectFsGuCoinGoodsByGoodsId(cart.getGoodsId());
|
|
|
+ if (Objects.isNull(goods)) {
|
|
|
+ throw new CustomException("商品不存在");
|
|
|
+ }
|
|
|
+ int num = cart.getCartNum() == null ? 1 : cart.getCartNum();
|
|
|
+ long goodsGuCoin = goods.getGuCoin() == null ? 0L : goods.getGuCoin();
|
|
|
+ BigDecimal goodsCash = goods.getCash() == null ? BigDecimal.ZERO : goods.getCash();
|
|
|
+
|
|
|
+ moneyDTO.setTotalGuCoin(moneyDTO.getTotalGuCoin() + goodsGuCoin * num);
|
|
|
+ moneyDTO.setTotalCash(moneyDTO.getTotalCash().add(goodsCash.multiply(BigDecimal.valueOf(num))));
|
|
|
+
|
|
|
+ goods.setNum((long) num);
|
|
|
+ goodsItem.add(goods);
|
|
|
+ }
|
|
|
+ moneyDTO.setGuCoin(moneyDTO.getTotalGuCoin());
|
|
|
+ moneyDTO.setCash(moneyDTO.getTotalCash());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 运费计算(谷币商城暂不实现运费模板,deliveryMoney 保持默认 0;如传了地址仅做存在性校验)
|
|
|
+ if (param.getUserAddressId() != null) {
|
|
|
+ FsUserAddress fsUserAddress = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getUserAddressId());
|
|
|
+ if (fsUserAddress == null || fsUserAddress.getIsDel() == 1
|
|
|
+ || !fsUser.getUserId().equals(fsUserAddress.getUserId())) {
|
|
|
+ return R.error("收货地址不存在");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回扣减后的支付金额
|
|
|
+ return R.ok().put("data", moneyDTO);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建订单
|
|
|
+ * 纯谷币商品(cash=0):扣减谷币,订单直接待发货(status=1)
|
|
|
+ * 混合支付商品(cash>0):扣减谷币,订单待支付(status=4),需支付现金后回调改状态
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R createOrder(FsGuCoinOrderCreateParam param) {
|
|
|
+ FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
|
|
|
+ if (user == null) {
|
|
|
+ return R.error("用户不存在");
|
|
|
+ }
|
|
|
+ FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
|
|
|
+ if (address == null) {
|
|
|
+ return R.error("收货地址不存在");
|
|
|
+ }
|
|
|
+ FsGuCoinGoods goods = fsGuCoinGoodsMapper.selectFsGuCoinGoodsByGoodsId(param.getGoodsId());
|
|
|
+ if (goods == null) {
|
|
|
+ return R.error("商品不存在");
|
|
|
+ }
|
|
|
+ if (goods.getStatus() == null || goods.getStatus() != 1) {
|
|
|
+ return R.error("商品已下架");
|
|
|
+ }
|
|
|
+ if (goods.getStock() == null || goods.getStock() <= 0) {
|
|
|
+ return R.error("库存不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ long goodsGuCoin = goods.getGuCoin() == null ? 0L : goods.getGuCoin();
|
|
|
+ BigDecimal goodsCash = goods.getCash() == null ? BigDecimal.ZERO : goods.getCash();
|
|
|
+ long userGuCoin = user.getGuCoin() == null ? 0L : user.getGuCoin();
|
|
|
+
|
|
|
+ // 谷币余额校验
|
|
|
+ if (goodsGuCoin > 0 && userGuCoin < goodsGuCoin) {
|
|
|
+ return R.error("谷币余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 减库存(并发安全,带库存校验)
|
|
|
+ if (fsGuCoinGoodsMapper.subStock(goods.getGoodsId(), 1) <= 0) {
|
|
|
+ throw new CustomException("库存不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成订单编号
|
|
|
+ String orderCode;
|
|
|
+ try {
|
|
|
+ orderCode = OrderCodeUtils.getOrderSn();
|
|
|
+ } catch (Exception e) {
|
|
|
+ orderCode = IdUtil.getSnowflake(0, 0).nextIdStr();
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(orderCode)) {
|
|
|
+ // 减库存回滚由事务处理
|
|
|
+ throw new CustomException("订单生成失败,请重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建商品快照(num=1)
|
|
|
+ goods.setNum(1L);
|
|
|
+ List<FsGuCoinGoods> goodsItem = new ArrayList<>();
|
|
|
+ goodsItem.add(goods);
|
|
|
+
|
|
|
+ FsGuCoinOrder order = new FsGuCoinOrder();
|
|
|
+ order.setOrderCode(orderCode);
|
|
|
+ order.setUserId(user.getUserId());
|
|
|
+ order.setUserName(address.getRealName());
|
|
|
+ order.setUserPhone(address.getPhone());
|
|
|
+ order.setUserAddress(org.apache.commons.lang3.StringUtils.defaultString(address.getProvince())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getCity())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDistrict())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDetail()));
|
|
|
+ order.setItemJson(JSONUtil.toJsonStr(goodsItem));
|
|
|
+ order.setTotalGuCoin(goodsGuCoin);
|
|
|
+ order.setDiscountGuCoin(0L);
|
|
|
+ order.setGuCoin(goodsGuCoin);
|
|
|
+ order.setTotalMoney(goodsCash);
|
|
|
+ order.setDiscountMoney(BigDecimal.ZERO);
|
|
|
+ order.setPayMoney(goodsCash);
|
|
|
+ order.setDeliveryMoney(BigDecimal.ZERO);
|
|
|
+ order.setBarCode(goods.getBarCode());
|
|
|
+ order.setCreateTime(new Date());
|
|
|
+
|
|
|
+ // 判断支付类型
|
|
|
+ if (goodsCash.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ // 现金+谷币
|
|
|
+ order.setPayType(goodsGuCoin > 0 ? 3 : 2);
|
|
|
+ order.setStatus(4); // 待支付
|
|
|
+ order.setIsPay(0);
|
|
|
+ } else {
|
|
|
+ // 纯谷币
|
|
|
+ order.setPayType(1);
|
|
|
+ order.setStatus(1); // 待发货
|
|
|
+ order.setIsPay(1);
|
|
|
+ order.setPayTime(new Date());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关联销售信息
|
|
|
+ Long companyUserId = param.getCompanyUserId();
|
|
|
+ if (companyUserId != null) {
|
|
|
+ order.setCompanyUserId(companyUserId);
|
|
|
+ CompanyUser companyUser = companyUserMapper.selectCompanyUserByCompanyUserId(companyUserId);
|
|
|
+ if (ObjectUtil.isNotEmpty(companyUser)) {
|
|
|
+ order.setCompanyId(companyUser.getCompanyId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 关联企微信息
|
|
|
+ if (ObjectUtil.isNotNull(user.getQwUserId())) {
|
|
|
+ QwUser qwUser = qwUserMapper.selectOne(new LambdaQueryWrapper<QwUser>()
|
|
|
+ .select(QwUser::getId, QwUser::getCompanyId, QwUser::getCompanyUserId)
|
|
|
+ .eq(QwUser::getId, user.getQwUserId()));
|
|
|
+ if (ObjectUtil.isNotNull(qwUser)) {
|
|
|
+ order.setQwUserId(qwUser.getId());
|
|
|
+ if (order.getCompanyId() == null && qwUser.getCompanyId() != null) {
|
|
|
+ order.setCompanyId(qwUser.getCompanyId());
|
|
|
+ }
|
|
|
+ if (order.getCompanyUserId() == null && qwUser.getCompanyUserId() != null) {
|
|
|
+ order.setCompanyUserId(qwUser.getCompanyUserId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 插入订单
|
|
|
+ if (fsGuCoinOrderMapper.insertFsGuCoinOrder(order) <= 0) {
|
|
|
+ throw new CustomException("订单创建失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 扣减谷币(logType=2 商城消费,businessId=订单id)
|
|
|
+ if (goodsGuCoin > 0) {
|
|
|
+ R consumeRes = fsUserGuCoinLogsService.consumeGuCoin(user.getUserId(), goodsGuCoin,
|
|
|
+ order.getOrderId().toString(), "谷币商城下单消费:" + orderCode);
|
|
|
+ if (consumeRes == null || !"200".equals(String.valueOf(consumeRes.get("code")))) {
|
|
|
+ // 谷币扣减失败,回滚事务(库存也会回滚)
|
|
|
+ String msg = consumeRes == null ? "谷币扣减失败" : String.valueOf(consumeRes.get("msg"));
|
|
|
+ throw new CustomException(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("谷币商城订单创建成功 orderCode={}, userId={}, guCoin={}, cash={}", orderCode, user.getUserId(), goodsGuCoin, goodsCash);
|
|
|
+ // 返回结构与积分商城 createOrder 对齐:返回整个 order + isPay
|
|
|
+ return R.ok("下单成功").put("order", order).put("isPay", order.getIsPay());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 购物车下单(多商品合并一单)
|
|
|
+ * 纯谷币订单直接待发货(status=1),混合支付订单待支付(status=4)
|
|
|
+ * 下单成功后清空已购买的购物车项
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R createCartOrder(FsGuCoinCartOrderCreateParam param) {
|
|
|
+ FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
|
|
|
+ if (user == null) {
|
|
|
+ return R.error("用户不存在");
|
|
|
+ }
|
|
|
+ FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
|
|
|
+ if (address == null) {
|
|
|
+ return R.error("收货地址不存在");
|
|
|
+ }
|
|
|
+ if (param.getIds() == null || param.getIds().isEmpty()) {
|
|
|
+ return R.error("请选择购物车商品");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载购物车项(按用户ID隔离)
|
|
|
+ List<FsGuCoinCartVO> carts = fsGuCoinCartService.getCartByIds(param.getUserId(), param.getIds());
|
|
|
+ if (carts.isEmpty()) {
|
|
|
+ return R.error("购物车商品不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载并校验所有商品,聚合金额
|
|
|
+ List<FsGuCoinGoods> goodsList = new ArrayList<>();
|
|
|
+ List<Long> cartIds = new ArrayList<>();
|
|
|
+ long totalGuCoin = 0L;
|
|
|
+ BigDecimal totalCash = BigDecimal.ZERO;
|
|
|
+ for (FsGuCoinCartVO cart : carts) {
|
|
|
+ FsGuCoinGoods goods = fsGuCoinGoodsMapper.selectFsGuCoinGoodsByGoodsId(cart.getGoodsId());
|
|
|
+ if (goods == null) {
|
|
|
+ return R.error("商品不存在: " + cart.getGoodsId());
|
|
|
+ }
|
|
|
+ if (goods.getStatus() == null || goods.getStatus() != 1) {
|
|
|
+ return R.error("商品已下架: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+ int num = cart.getCartNum() == null ? 1 : cart.getCartNum();
|
|
|
+ if (goods.getStock() == null || goods.getStock() < num) {
|
|
|
+ return R.error("商品库存不足: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+ // 减库存(并发安全,带库存校验)
|
|
|
+ if (fsGuCoinGoodsMapper.subStock(goods.getGoodsId(), num) <= 0) {
|
|
|
+ throw new CustomException("商品库存不足: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+
|
|
|
+ long goodsGuCoin = goods.getGuCoin() == null ? 0L : goods.getGuCoin();
|
|
|
+ BigDecimal goodsCash = goods.getCash() == null ? BigDecimal.ZERO : goods.getCash();
|
|
|
+ totalGuCoin += goodsGuCoin * num;
|
|
|
+ totalCash = totalCash.add(goodsCash.multiply(BigDecimal.valueOf(num)));
|
|
|
+
|
|
|
+ goods.setNum((long) num);
|
|
|
+ goodsList.add(goods);
|
|
|
+ cartIds.add(cart.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ long userGuCoin = user.getGuCoin() == null ? 0L : user.getGuCoin();
|
|
|
+ // 谷币余额校验
|
|
|
+ if (totalGuCoin > 0 && userGuCoin < totalGuCoin) {
|
|
|
+ return R.error("谷币余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成订单编号
|
|
|
+ String orderCode;
|
|
|
+ try {
|
|
|
+ orderCode = OrderCodeUtils.getOrderSn();
|
|
|
+ } catch (Exception e) {
|
|
|
+ orderCode = IdUtil.getSnowflake(0, 0).nextIdStr();
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(orderCode)) {
|
|
|
+ throw new CustomException("订单生成失败,请重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ FsGuCoinOrder order = new FsGuCoinOrder();
|
|
|
+ order.setOrderCode(orderCode);
|
|
|
+ order.setUserId(user.getUserId());
|
|
|
+ order.setUserName(address.getRealName());
|
|
|
+ order.setUserPhone(address.getPhone());
|
|
|
+ order.setUserAddress(org.apache.commons.lang3.StringUtils.defaultString(address.getProvince())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getCity())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDistrict())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDetail()));
|
|
|
+ order.setItemJson(JSONUtil.toJsonStr(goodsList));
|
|
|
+ order.setTotalGuCoin(totalGuCoin);
|
|
|
+ order.setDiscountGuCoin(0L);
|
|
|
+ order.setGuCoin(totalGuCoin);
|
|
|
+ order.setTotalMoney(totalCash);
|
|
|
+ order.setDiscountMoney(BigDecimal.ZERO);
|
|
|
+ order.setPayMoney(totalCash);
|
|
|
+ order.setDeliveryMoney(BigDecimal.ZERO);
|
|
|
+ if (!goodsList.isEmpty()) {
|
|
|
+ order.setBarCode(goodsList.get(0).getBarCode());
|
|
|
+ }
|
|
|
+ order.setCreateTime(new Date());
|
|
|
+
|
|
|
+ // 用户自助下单:纯谷币=待发货,混合支付=待支付(与 createOrder 一致)
|
|
|
+ if (totalCash.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ order.setPayType(totalGuCoin > 0 ? 3 : 2);
|
|
|
+ order.setStatus(4); // 待支付
|
|
|
+ order.setIsPay(0);
|
|
|
+ } else {
|
|
|
+ order.setPayType(1);
|
|
|
+ order.setStatus(1); // 待发货
|
|
|
+ order.setIsPay(1);
|
|
|
+ order.setPayTime(new Date());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关联企微信息(购物车下单无销售关联)
|
|
|
+ if (ObjectUtil.isNotNull(user.getQwUserId())) {
|
|
|
+ QwUser qwUser = qwUserMapper.selectOne(new LambdaQueryWrapper<QwUser>()
|
|
|
+ .select(QwUser::getId, QwUser::getCompanyId, QwUser::getCompanyUserId)
|
|
|
+ .eq(QwUser::getId, user.getQwUserId()));
|
|
|
+ if (ObjectUtil.isNotNull(qwUser)) {
|
|
|
+ order.setQwUserId(qwUser.getId());
|
|
|
+ if (qwUser.getCompanyId() != null) {
|
|
|
+ order.setCompanyId(qwUser.getCompanyId());
|
|
|
+ }
|
|
|
+ if (qwUser.getCompanyUserId() != null) {
|
|
|
+ order.setCompanyUserId(qwUser.getCompanyUserId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 插入订单
|
|
|
+ if (fsGuCoinOrderMapper.insertFsGuCoinOrder(order) <= 0) {
|
|
|
+ throw new CustomException("订单创建失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 扣减谷币(logType=2 商城消费,businessId=订单id)
|
|
|
+ if (totalGuCoin > 0) {
|
|
|
+ R consumeRes = fsUserGuCoinLogsService.consumeGuCoin(user.getUserId(), totalGuCoin,
|
|
|
+ order.getOrderId().toString(), "谷币商城购物车下单消费:" + orderCode);
|
|
|
+ if (consumeRes == null || !"200".equals(String.valueOf(consumeRes.get("code")))) {
|
|
|
+ String msg = consumeRes == null ? "谷币扣减失败" : String.valueOf(consumeRes.get("msg"));
|
|
|
+ throw new CustomException(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空已购买的购物车项
|
|
|
+ fsGuCoinCartService.delCartByIds(param.getUserId(), cartIds);
|
|
|
+
|
|
|
+ log.info("谷币商城购物车下单成功 orderCode={}, userId={}, guCoin={}, cash={}", orderCode, user.getUserId(), totalGuCoin, totalCash);
|
|
|
+ // 返回结构与积分商城 createOrder 对齐:返回整个 order + isPay
|
|
|
+ return R.ok("下单成功").put("order", order).put("isPay", order.getIsPay());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 销售后台手动代下单(多商品合并一单)
|
|
|
+ * 代下单统一为待发货(status=1),销售线下收款,扣减会员谷币
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R createOrderByManually(FsGuCoinOrderManuallyParam param) {
|
|
|
+ FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
|
|
|
+ if (user == null) {
|
|
|
+ return R.error("用户不存在");
|
|
|
+ }
|
|
|
+ FsUserAddress address = fsUserAddressMapper.selectFsUserAddressByAddressId(param.getAddressId());
|
|
|
+ if (address == null) {
|
|
|
+ return R.error("收货地址不存在");
|
|
|
+ }
|
|
|
+ if (param.getGoodsIds() == null || param.getGoodsIds().isEmpty()) {
|
|
|
+ return R.error("请选择至少一个商品");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载并校验所有商品
|
|
|
+ List<FsGuCoinGoods> goodsList = new ArrayList<>();
|
|
|
+ long totalGuCoin = 0L;
|
|
|
+ BigDecimal totalCash = BigDecimal.ZERO;
|
|
|
+ for (Long goodsId : param.getGoodsIds()) {
|
|
|
+ FsGuCoinGoods goods = fsGuCoinGoodsMapper.selectFsGuCoinGoodsByGoodsId(goodsId);
|
|
|
+ if (goods == null) {
|
|
|
+ return R.error("商品不存在: " + goodsId);
|
|
|
+ }
|
|
|
+ if (goods.getStatus() == null || goods.getStatus() != 1) {
|
|
|
+ return R.error("商品已下架: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+ if (goods.getStock() == null || goods.getStock() <= 0) {
|
|
|
+ return R.error("商品库存不足: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+ goods.setNum(1L);
|
|
|
+ goodsList.add(goods);
|
|
|
+ totalGuCoin += goods.getGuCoin() == null ? 0L : goods.getGuCoin();
|
|
|
+ totalCash = totalCash.add(goods.getCash() == null ? BigDecimal.ZERO : goods.getCash());
|
|
|
+ }
|
|
|
+
|
|
|
+ long userGuCoin = user.getGuCoin() == null ? 0L : user.getGuCoin();
|
|
|
+ // 谷币余额校验
|
|
|
+ if (totalGuCoin > 0 && userGuCoin < totalGuCoin) {
|
|
|
+ return R.error("谷币余额不足");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 减库存(并发安全,带库存校验)
|
|
|
+ for (FsGuCoinGoods goods : goodsList) {
|
|
|
+ if (fsGuCoinGoodsMapper.subStock(goods.getGoodsId(), 1) <= 0) {
|
|
|
+ throw new CustomException("商品库存不足: " + goods.getGoodsName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成订单编号
|
|
|
+ String orderCode;
|
|
|
+ try {
|
|
|
+ orderCode = OrderCodeUtils.getOrderSn();
|
|
|
+ } catch (Exception e) {
|
|
|
+ orderCode = IdUtil.getSnowflake(0, 0).nextIdStr();
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(orderCode)) {
|
|
|
+ throw new CustomException("订单生成失败,请重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ FsGuCoinOrder order = new FsGuCoinOrder();
|
|
|
+ order.setOrderCode(orderCode);
|
|
|
+ order.setUserId(user.getUserId());
|
|
|
+ order.setUserName(address.getRealName());
|
|
|
+ order.setUserPhone(address.getPhone());
|
|
|
+ order.setUserAddress(org.apache.commons.lang3.StringUtils.defaultString(address.getProvince())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getCity())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDistrict())
|
|
|
+ + org.apache.commons.lang3.StringUtils.defaultString(address.getDetail()));
|
|
|
+ order.setItemJson(JSONUtil.toJsonStr(goodsList));
|
|
|
+ order.setTotalGuCoin(totalGuCoin);
|
|
|
+ order.setDiscountGuCoin(0L);
|
|
|
+ order.setGuCoin(totalGuCoin);
|
|
|
+ order.setTotalMoney(totalCash);
|
|
|
+ order.setDiscountMoney(BigDecimal.ZERO);
|
|
|
+ order.setPayMoney(totalCash);
|
|
|
+ order.setDeliveryMoney(BigDecimal.ZERO);
|
|
|
+ if (!goodsList.isEmpty()) {
|
|
|
+ order.setBarCode(goodsList.get(0).getBarCode());
|
|
|
+ }
|
|
|
+ order.setCreateTime(new Date());
|
|
|
+
|
|
|
+ // 代下单统一为待发货(销售线下收款,无需在线支付)
|
|
|
+ // 支付类型仅作展示记录:纯谷币=1,纯现金=2,谷币+现金=3
|
|
|
+ if (totalCash.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ order.setPayType(totalGuCoin > 0 ? 3 : 2);
|
|
|
+ } else {
|
|
|
+ order.setPayType(1);
|
|
|
+ }
|
|
|
+ order.setStatus(1); // 待发货
|
|
|
+ order.setIsPay(1);
|
|
|
+ order.setPayTime(new Date());
|
|
|
+
|
|
|
+ // 关联销售信息
|
|
|
+ Long companyUserId = param.getCompanyUserId();
|
|
|
+ if (companyUserId != null) {
|
|
|
+ order.setCompanyUserId(companyUserId);
|
|
|
+ CompanyUser companyUser = companyUserMapper.selectCompanyUserByCompanyUserId(companyUserId);
|
|
|
+ if (ObjectUtil.isNotEmpty(companyUser)) {
|
|
|
+ order.setCompanyId(companyUser.getCompanyId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 关联企微信息
|
|
|
+ if (ObjectUtil.isNotNull(user.getQwUserId())) {
|
|
|
+ QwUser qwUser = qwUserMapper.selectOne(new LambdaQueryWrapper<QwUser>()
|
|
|
+ .select(QwUser::getId, QwUser::getCompanyId, QwUser::getCompanyUserId)
|
|
|
+ .eq(QwUser::getId, user.getQwUserId()));
|
|
|
+ if (ObjectUtil.isNotNull(qwUser)) {
|
|
|
+ order.setQwUserId(qwUser.getId());
|
|
|
+ if (order.getCompanyId() == null && qwUser.getCompanyId() != null) {
|
|
|
+ order.setCompanyId(qwUser.getCompanyId());
|
|
|
+ }
|
|
|
+ if (order.getCompanyUserId() == null && qwUser.getCompanyUserId() != null) {
|
|
|
+ order.setCompanyUserId(qwUser.getCompanyUserId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 插入订单
|
|
|
+ if (fsGuCoinOrderMapper.insertFsGuCoinOrder(order) <= 0) {
|
|
|
+ throw new CustomException("订单创建失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 扣减谷币(logType=2 商城消费,businessId=订单id)
|
|
|
+ if (totalGuCoin > 0) {
|
|
|
+ R consumeRes = fsUserGuCoinLogsService.consumeGuCoin(user.getUserId(), totalGuCoin,
|
|
|
+ order.getOrderId().toString(), "谷币商城代下单消费:" + orderCode);
|
|
|
+ if (consumeRes == null || !"200".equals(String.valueOf(consumeRes.get("code")))) {
|
|
|
+ String msg = consumeRes == null ? "谷币扣减失败" : String.valueOf(consumeRes.get("msg"));
|
|
|
+ throw new CustomException(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("谷币商城代下单创建成功 orderCode={}, userId={}, guCoin={}, cash={}", orderCode, user.getUserId(), totalGuCoin, totalCash);
|
|
|
+ return R.ok("下单成功").put("orderId", order.getOrderId()).put("orderCode", orderCode)
|
|
|
+ .put("status", order.getStatus()).put("payType", order.getPayType());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订单(还原库存+还原谷币)
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R cannelOrder(Long orderId) {
|
|
|
+ FsGuCoinOrder order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderId(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ return R.error("订单不存在");
|
|
|
+ }
|
|
|
+ // 待支付(4)或待发货(1)可取消
|
|
|
+ if (!Objects.equals(order.getStatus(), 4) && !Objects.equals(order.getStatus(), 1)) {
|
|
|
+ return R.error("当前订单状态不可取消");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新订单状态为取消
|
|
|
+ order.setStatus(5);
|
|
|
+ fsGuCoinOrderMapper.updateFsGuCoinOrder(order);
|
|
|
+
|
|
|
+ // 还原库存
|
|
|
+ if (StringUtils.isNotEmpty(order.getItemJson())) {
|
|
|
+ JSONArray jsonArray = JSONUtil.parseArray(order.getItemJson());
|
|
|
+ List<FsGuCoinGoods> goodsItem = JSONUtil.toList(jsonArray, FsGuCoinGoods.class);
|
|
|
+ for (FsGuCoinGoods g : goodsItem) {
|
|
|
+ int num = g.getNum() == null ? 1 : g.getNum().intValue();
|
|
|
+ fsGuCoinGoodsMapper.addStock(g.getGoodsId(), num);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 还原谷币(logType=3 订单退款返还)
|
|
|
+ long orderGuCoin = order.getGuCoin() == null ? 0L : order.getGuCoin();
|
|
|
+ if (orderGuCoin > 0) {
|
|
|
+ fsUserGuCoinLogsService.refundGuCoin(order.getUserId(), orderGuCoin,
|
|
|
+ order.getOrderId().toString(), "取消订单返还谷币:" + order.getOrderCode());
|
|
|
+ }
|
|
|
+ return R.ok("订单已取消");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 预支付(现金/混合支付订单发起支付)
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R payment(FsGuCoinOrderDoPayParam param, PaymentMethodEnum paymentMethod) {
|
|
|
+ FsGuCoinOrder order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderId(param.getOrderId());
|
|
|
+ if (order == null || !Objects.equals(order.getStatus(), 4)
|
|
|
+ || order.getPayMoney() == null || order.getPayMoney().compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ return R.error("非法操作");
|
|
|
+ }
|
|
|
+ PayOrderParam payOrderParam = new PayOrderParam();
|
|
|
+ payOrderParam.setOrderId(order.getOrderId());
|
|
|
+ payOrderParam.setOrderCode(order.getOrderCode());
|
|
|
+ payOrderParam.setAmount(order.getPayMoney());
|
|
|
+ payOrderParam.setUserId(order.getUserId());
|
|
|
+ payOrderParam.setCompanyId(order.getCompanyId());
|
|
|
+ payOrderParam.setCompanyUserId(order.getCompanyUserId());
|
|
|
+ payOrderParam.setPaymentMethod(paymentMethod);
|
|
|
+ payOrderParam.setBusinessType(BusinessTypeEnum.GU_COIN_ORDER);
|
|
|
+ payOrderParam.setAppId(param.getAppId());
|
|
|
+ return storePaymentService.processPayment(payOrderParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付回调(支付成功后更新订单状态为待发货)
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, int type,
|
|
|
+ String bankTransactionId, String bankSerialNo) {
|
|
|
+ log.info("谷币商城订单支付回调 orderSn: {}, payCode: {}, tradeNo: {}, type: {}", orderSn, payCode, tradeNo, type);
|
|
|
+ FsGuCoinOrder order = null;
|
|
|
+ if (type == 1) {
|
|
|
+ FsStorePayment storePayment = storePaymentService.selectFsStorePaymentByPaymentCode(payCode);
|
|
|
+ if (Objects.isNull(storePayment)) {
|
|
|
+ log.info("支付单号不存在 payCode: {}", payCode);
|
|
|
+ return R.error("支付单号不存在");
|
|
|
+ }
|
|
|
+ if (storePayment.getStatus() == 0) {
|
|
|
+ FsStorePayment paymentMap = new FsStorePayment();
|
|
|
+ paymentMap.setPaymentId(storePayment.getPaymentId());
|
|
|
+ paymentMap.setStatus(1);
|
|
|
+ paymentMap.setPayTime(new Date());
|
|
|
+ paymentMap.setTradeNo(tradeNo);
|
|
|
+ paymentMap.setBankSerialNo(bankSerialNo);
|
|
|
+ paymentMap.setBankTransactionId(bankTransactionId);
|
|
|
+ storePaymentService.updateFsStorePayment(paymentMap);
|
|
|
+ order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderId(Long.parseLong(storePayment.getBusinessId()));
|
|
|
+ }
|
|
|
+ } else if (type == 2) {
|
|
|
+ order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderCode(orderSn);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Objects.isNull(order) || order.getStatus() != 4) {
|
|
|
+ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
|
|
+ return R.error("非法操作");
|
|
|
+ }
|
|
|
+
|
|
|
+ order.setIsPay(1);
|
|
|
+ order.setStatus(1); // 待发货
|
|
|
+ order.setPayTime(new Date());
|
|
|
+ fsGuCoinOrderMapper.updateFsGuCoinOrder(order);
|
|
|
+ log.info("谷币商城订单支付成功 orderCode={}, userId={}", order.getOrderCode(), order.getUserId());
|
|
|
+ return R.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订单(按订单编号,用于发货前取消/退款返还谷币)
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public int cancelOrder(String orderCode) {
|
|
|
+ FsGuCoinOrder order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderCode(orderCode);
|
|
|
+ if (order == null) {
|
|
|
+ throw new CustomException("订单不存在");
|
|
|
+ }
|
|
|
+ if (order.getStatus() != 1 && order.getStatus() != 4) {
|
|
|
+ throw new CustomException("订单已发货或已完成,不可取消");
|
|
|
+ }
|
|
|
+ int i = fsGuCoinOrderMapper.cancelOrder(order.getOrderId());
|
|
|
+ if (i > 0) {
|
|
|
+ // 还原库存
|
|
|
+ if (StringUtils.isNotEmpty(order.getItemJson())) {
|
|
|
+ JSONArray jsonArray = JSONUtil.parseArray(order.getItemJson());
|
|
|
+ List<FsGuCoinGoods> goodsItem = JSONUtil.toList(jsonArray, FsGuCoinGoods.class);
|
|
|
+ for (FsGuCoinGoods g : goodsItem) {
|
|
|
+ int num = g.getNum() == null ? 1 : g.getNum().intValue();
|
|
|
+ fsGuCoinGoodsMapper.addStock(g.getGoodsId(), num);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 还原谷币
|
|
|
+ long orderGuCoin = order.getGuCoin() == null ? 0L : order.getGuCoin();
|
|
|
+ if (orderGuCoin > 0) {
|
|
|
+ fsUserGuCoinLogsService.refundGuCoin(order.getUserId(), orderGuCoin,
|
|
|
+ order.getOrderId().toString(), "取消订单返还谷币:" + orderCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 完成订单
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int finishOrder(String orderCode) {
|
|
|
+ FsGuCoinOrder order = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderCode(orderCode);
|
|
|
+ if (order == null) {
|
|
|
+ throw new CustomException("订单不存在");
|
|
|
+ }
|
|
|
+ order.setStatus(3); // 已完成
|
|
|
+ return fsGuCoinOrderMapper.updateFsGuCoinOrder(order);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 推送聚水潭(构建ErpOrder并批量推送,回写extendOrderId)
|
|
|
+ * 与积分订单一致:固定 shop_code、无货到付款推两次逻辑。
|
|
|
+ * 区别:按 payType 推真实支付金额。
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void createOmsGuCoinOrder(List<Long> orderIds) throws ParseException, InterruptedException {
|
|
|
+ if (orderIds == null || orderIds.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 1. 校验 ERP 开启且为聚水潭(5)
|
|
|
+ FsSysConfig sysConfig = configUtil.getSysConfig();
|
|
|
+ Integer erpOpen = sysConfig.getErpOpen();
|
|
|
+ if (erpOpen == null || erpOpen == 0) {
|
|
|
+ log.info("ERP未开启,跳过谷币订单推送聚水潭");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Integer erpType = sysConfig.getErpType();
|
|
|
+ if (erpType == null || erpType != 5) {
|
|
|
+ log.info("谷币订单仅支持聚水潭推送,当前ERP类型: {},跳过", erpType);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ErpOrder> erpOrders = new ArrayList<>();
|
|
|
+ for (Long orderId : orderIds) {
|
|
|
+ FsGuCoinOrder fsGuCoinOrder = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderId(orderId);
|
|
|
+ if (fsGuCoinOrder == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 仅推送待发货(status=1)且未推送(extendOrderId为空)的订单
|
|
|
+ if (StringUtils.isNotEmpty(fsGuCoinOrder.getExtendOrderId())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (fsGuCoinOrder.getStatus() == null || fsGuCoinOrder.getStatus() != 1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ErpOrder erpOrder = new ErpOrder();
|
|
|
+ erpOrder.setVip_code(fsGuCoinOrder.getUserId().toString());
|
|
|
+ erpOrder.setPlatform_code(fsGuCoinOrder.getOrderCode());
|
|
|
+ erpOrder.setShop_code(shopCode);
|
|
|
+ erpOrder.setSeller_memo(fsGuCoinOrder.getRemark());
|
|
|
+ erpOrder.setRemark(fsGuCoinOrder.getRemark());
|
|
|
+ erpOrder.setOrder_type_code("order");
|
|
|
+
|
|
|
+ // 支付信息:按 payType 推真实金额
|
|
|
+ List<ErpOrderPayment> payments = new ArrayList<>();
|
|
|
+ ErpOrderPayment payment = new ErpOrderPayment();
|
|
|
+ payment.setPay_type_code("weixin");
|
|
|
+ BigDecimal payMoney = fsGuCoinOrder.getPayMoney() == null ? BigDecimal.ZERO : fsGuCoinOrder.getPayMoney();
|
|
|
+ payment.setPayment(payMoney.doubleValue());
|
|
|
+ erpOrder.setBuyer_account(fsGuCoinOrder.getUserName());
|
|
|
+ Date payTime = fsGuCoinOrder.getPayTime() != null ? fsGuCoinOrder.getPayTime() : fsGuCoinOrder.getCreateTime();
|
|
|
+ if (payTime != null) {
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ Date date = sdf.parse(sdf.format(payTime));
|
|
|
+ payment.setPaytime(new Timestamp(date.getTime()));
|
|
|
+ }
|
|
|
+ payments.add(payment);
|
|
|
+ erpOrder.setPayments(payments);
|
|
|
+
|
|
|
+ // 备注追加金额明细(OMS展示用,与积分订单一致)
|
|
|
+ BigDecimal totalMoney = fsGuCoinOrder.getTotalMoney() == null ? BigDecimal.ZERO : fsGuCoinOrder.getTotalMoney();
|
|
|
+ BigDecimal deliveryMoney = fsGuCoinOrder.getDeliveryMoney() == null ? BigDecimal.ZERO : fsGuCoinOrder.getDeliveryMoney();
|
|
|
+ BigDecimal discountMoney = fsGuCoinOrder.getDiscountMoney() == null ? BigDecimal.ZERO : fsGuCoinOrder.getDiscountMoney();
|
|
|
+ ErpRemarkDTO remarkDTO = new ErpRemarkDTO();
|
|
|
+ remarkDTO.setOrderId(fsGuCoinOrder.getOrderCode());
|
|
|
+ remarkDTO.setTotalPrice(totalMoney);
|
|
|
+ remarkDTO.setPayPrice(payMoney);
|
|
|
+ remarkDTO.setPayMoney(payMoney);
|
|
|
+ remarkDTO.setCouponMoney(discountMoney);
|
|
|
+ remarkDTO.setDeliveryMoney(deliveryMoney);
|
|
|
+ remarkDTO.setYdMoney(BigDecimal.ZERO);
|
|
|
+ if (payTime != null) {
|
|
|
+ SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ remarkDTO.setPayTime(sdf2.format(payTime));
|
|
|
+ }
|
|
|
+ String remarkJson = JSONUtil.toJsonStr(remarkDTO);
|
|
|
+ erpOrder.setSeller_memo(org.apache.commons.lang3.StringUtils.defaultString(erpOrder.getSeller_memo()) + remarkJson);
|
|
|
+ erpOrder.setRemark(org.apache.commons.lang3.StringUtils.defaultString(erpOrder.getRemark()) + remarkJson);
|
|
|
+
|
|
|
+ SimpleDateFormat sdfDeal = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ erpOrder.setDeal_datetime(sdfDeal.format(new Date()));
|
|
|
+
|
|
|
+ // 收货人信息
|
|
|
+ if (StringUtils.isNotEmpty(fsGuCoinOrder.getUserName())) {
|
|
|
+ erpOrder.setReceiver_name(fsGuCoinOrder.getUserName().replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9]", ""));
|
|
|
+ }
|
|
|
+ String userPhone = fsGuCoinOrder.getUserPhone();
|
|
|
+ if (StringUtils.isNotEmpty(userPhone)) {
|
|
|
+ // 手机号长度>11视为加密存储,需解密
|
|
|
+ if (userPhone.length() > 11) {
|
|
|
+ try {
|
|
|
+ erpOrder.setReceiver_mobile(decryptPhone(userPhone));
|
|
|
+ } catch (Exception e) {
|
|
|
+ erpOrder.setReceiver_mobile(userPhone);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ erpOrder.setReceiver_mobile(userPhone);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(fsGuCoinOrder.getUserAddress())) {
|
|
|
+ erpOrder.setReceiver_address(fsGuCoinOrder.getUserAddress());
|
|
|
+ }
|
|
|
+
|
|
|
+ erpOrders.add(erpOrder);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (erpOrders.isEmpty()) {
|
|
|
+ log.info("无待推送的谷币订单");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("谷币订单推送聚水潭,待推送数量: {}", erpOrders.size());
|
|
|
+ // 推送聚水潭(回写 extendOrderId 在 JST 实现内完成)
|
|
|
+ jstErpOrderService.batchAddGuCoinOrder(erpOrders);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步聚水潭发货状态后回写订单(含快递鸟订阅)
|
|
|
+ * 仿 FsIntegralOrderServiceImpl.deliveryIntegralOrderOrder
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void deliveryGuCoinOrderOrder(String orderCode, String deliveryId, String deliverCode, String deliverName) {
|
|
|
+ FsGuCoinOrder fsGuCoinOrder = fsGuCoinOrderMapper.selectFsGuCoinOrderByOrderCode(orderCode);
|
|
|
+ if (fsGuCoinOrder == null || fsGuCoinOrder.getStatus() == null || fsGuCoinOrder.getStatus() != 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 快递公司编号映射:聚水潭 omsCode -> 系统内部 code
|
|
|
+ fsGuCoinOrder.setDeliveryName(deliverName);
|
|
|
+ FsExpress express = expressService.selectFsExpressByOmsCode(deliverCode);
|
|
|
+ if (express != null) {
|
|
|
+ fsGuCoinOrder.setDeliveryCode(express.getCode());
|
|
|
+ } else {
|
|
|
+ fsGuCoinOrder.setDeliveryCode(deliverCode);
|
|
|
+ }
|
|
|
+ fsGuCoinOrder.setStatus(2); // 待收货
|
|
|
+ fsGuCoinOrder.setDeliverySn(deliveryId);
|
|
|
+ fsGuCoinOrder.setDeliveryTime(DateUtils.getNowDate());
|
|
|
+ fsGuCoinOrderMapper.updateFsGuCoinOrder(fsGuCoinOrder);
|
|
|
+
|
|
|
+ // 订阅快递鸟物流(参数顺序与积分订单一致:orderCode, deliveryCode, deliverySn, userPhone)
|
|
|
+ try {
|
|
|
+ expressService.subscribeEspress(fsGuCoinOrder.getOrderCode(),
|
|
|
+ fsGuCoinOrder.getDeliveryCode(),
|
|
|
+ fsGuCoinOrder.getDeliverySn(),
|
|
|
+ fsGuCoinOrder.getUserPhone());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("谷币订单订阅快递鸟失败 orderCode: {}", orderCode, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|