|
@@ -10,13 +10,16 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.dubbo.config.annotation.DubboReference;
|
|
import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
|
|
+import org.dromara.common.core.enums.OrderPayType;
|
|
|
import org.dromara.common.core.enums.OrderStatus;
|
|
import org.dromara.common.core.enums.OrderStatus;
|
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
import org.dromara.common.redis.utils.SequenceUtils;
|
|
import org.dromara.common.redis.utils.SequenceUtils;
|
|
|
|
|
+import org.dromara.customer.api.RemoteCustomerSalesService;
|
|
|
import org.dromara.customer.api.RemoteCustomerService;
|
|
import org.dromara.customer.api.RemoteCustomerService;
|
|
|
|
|
+import org.dromara.customer.api.domain.vo.RemoteCustomerSalesVo;
|
|
|
import org.dromara.order.domain.OrderMain;
|
|
import org.dromara.order.domain.OrderMain;
|
|
|
import org.dromara.order.domain.OrderProduct;
|
|
import org.dromara.order.domain.OrderProduct;
|
|
|
import org.dromara.order.domain.bo.OrderMainBo;
|
|
import org.dromara.order.domain.bo.OrderMainBo;
|
|
@@ -60,6 +63,9 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
@DubboReference
|
|
@DubboReference
|
|
|
private RemoteCustomerService remoteCustomerService;
|
|
private RemoteCustomerService remoteCustomerService;
|
|
|
|
|
|
|
|
|
|
+ @DubboReference
|
|
|
|
|
+ private RemoteCustomerSalesService remoteCustomerSalesService;
|
|
|
|
|
+
|
|
|
private final OrderMainMapper baseMapper;
|
|
private final OrderMainMapper baseMapper;
|
|
|
|
|
|
|
|
private final OrderProductMapper orderProductMapper;
|
|
private final OrderProductMapper orderProductMapper;
|
|
@@ -303,9 +309,25 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
// 4. 转换并填充子订单商品
|
|
// 4. 转换并填充子订单商品
|
|
|
List<OrderProduct> orderProducts = orderProductBos.stream()
|
|
List<OrderProduct> orderProducts = orderProductBos.stream()
|
|
|
.map(productBo -> {
|
|
.map(productBo -> {
|
|
|
|
|
+ BigDecimal unitPrice = productBo.getOrderPrice();
|
|
|
|
|
+ Long quantity = productBo.getOrderQuantity();
|
|
|
|
|
+
|
|
|
|
|
+ // 防御性校验
|
|
|
|
|
+ if (unitPrice == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品单价不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (quantity == null || quantity <= 0) {
|
|
|
|
|
+ throw new IllegalArgumentException("商品数量必须大于0");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
|
|
OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
|
|
|
- product.setOrderId(orderId); // 关联主单ID
|
|
|
|
|
- product.setOrderNo(orderNo); // 关联订单号
|
|
|
|
|
|
|
+ product.setOrderId(orderId);
|
|
|
|
|
+ product.setOrderNo(orderNo);
|
|
|
|
|
+
|
|
|
|
|
+ // 小计 = 单价 × 数量
|
|
|
|
|
+ BigDecimal subtotal = unitPrice.multiply(BigDecimal.valueOf(quantity));
|
|
|
|
|
+ product.setSubtotal(subtotal);
|
|
|
|
|
+
|
|
|
return product;
|
|
return product;
|
|
|
})
|
|
})
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
@@ -442,6 +464,86 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
log.info("订单 {} 已确认,状态更新为待发货", orderId);
|
|
log.info("订单 {} 已确认,状态更新为待发货", orderId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public Boolean orderPay(Long customerId, Long orderId, String payType) {
|
|
|
|
|
+ // 参数校验
|
|
|
|
|
+ if (orderId == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (customerId == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("客户ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payType == null || !OrderPayType.CREDIT_PAY.getCode().equals(payType)) {
|
|
|
|
|
+ throw new IllegalArgumentException("仅支持信用支付方式");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询订单
|
|
|
|
|
+ OrderMainVo orderMainVo = baseMapper.selectVoById(orderId);
|
|
|
|
|
+ if (orderMainVo == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!Objects.equals(customerId, orderMainVo.getCustomerId())) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单不属于当前客户");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal totalAmount = orderMainVo.getTotalAmount();
|
|
|
|
|
+ if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ throw new IllegalArgumentException("订单金额无效");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询客户信用销售信息
|
|
|
|
|
+ RemoteCustomerSalesVo salesInfo = remoteCustomerSalesService.selectCustomerSalesInfoByCustomerId(customerId);
|
|
|
|
|
+ if (salesInfo == null) {
|
|
|
|
|
+ throw new IllegalStateException("客户信用信息未配置,无法使用信用支付");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取可用额度:剩余额度 + 临时额度
|
|
|
|
|
+ BigDecimal remainingQuota = Optional.ofNullable(salesInfo.getRemainingQuota()).orElse(BigDecimal.ZERO);
|
|
|
|
|
+ BigDecimal temporaryQuota = Optional.ofNullable(salesInfo.getTemporaryQuota()).orElse(BigDecimal.ZERO);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 临时额度可用于支付
|
|
|
|
|
+ BigDecimal availableCredit = remainingQuota.add(temporaryQuota);
|
|
|
|
|
+
|
|
|
|
|
+ // 判断额度是否足够
|
|
|
|
|
+ if (availableCredit.compareTo(totalAmount) < 0) {
|
|
|
|
|
+ throw new IllegalStateException("信用额度不足,无法完成支付");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 扣减逻辑:优先扣减临时额度,再扣剩余额度
|
|
|
|
|
+ BigDecimal newRemainingQuota = remainingQuota;
|
|
|
|
|
+ BigDecimal newTemporaryQuota = temporaryQuota;
|
|
|
|
|
+
|
|
|
|
|
+ if (temporaryQuota.compareTo(totalAmount) >= 0) {
|
|
|
|
|
+ // 临时额度足够,只扣临时额度
|
|
|
|
|
+ newTemporaryQuota = temporaryQuota.subtract(totalAmount);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 临时额度不足,先清空临时额度,再扣剩余额度
|
|
|
|
|
+ BigDecimal remainingToDeduct = totalAmount.subtract(temporaryQuota);
|
|
|
|
|
+ newTemporaryQuota = BigDecimal.ZERO;
|
|
|
|
|
+ newRemainingQuota = remainingQuota.subtract(remainingToDeduct);
|
|
|
|
|
+
|
|
|
|
|
+ // 理论上不会为负(前面已校验总额度足够),但防御性检查
|
|
|
|
|
+ if (newRemainingQuota.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
+ throw new IllegalStateException("信用额度计算异常,请联系管理员");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 更新对象
|
|
|
|
|
+ salesInfo.setRemainingQuota(newRemainingQuota);
|
|
|
|
|
+ salesInfo.setTemporaryQuota(newTemporaryQuota);
|
|
|
|
|
+
|
|
|
|
|
+ // 执行更新
|
|
|
|
|
+ boolean updated = remoteCustomerSalesService.updateCustomerSalesInfo(salesInfo);
|
|
|
|
|
+ if (!updated) {
|
|
|
|
|
+ throw new RuntimeException("信用额度更新失败,请重试");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 修改状态
|
|
* 修改状态
|
|
|
*
|
|
*
|