From e96422a47eaf68d0346b843d2939dee091635c7a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 26 Nov 2022 18:40:51 +0800 Subject: [PATCH] =?UTF-8?q?trade=EF=BC=9A=E5=AE=8C=E6=88=90=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E6=88=90=E5=8A=9F=E5=90=8E=E7=9A=84=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E8=AE=A2=E5=8D=95=E4=B8=BA=E5=B7=B2?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 8 +- .../enums/order/TradeOrderStatusEnum.java | 13 +++ .../app/order/AppTradeOrderController.java | 8 +- .../dal/dataobject/order/TradeOrderDO.java | 27 +++--- .../dal/mysql/order/TradeOrderMapper.java | 7 ++ .../service/order/TradeOrderService.java | 9 ++ .../service/order/TradeOrderServiceImpl.java | 93 ++++++++++++++++++- .../service/order/TradeOrderServiceTest.java | 39 ++++++-- .../src/test/resources/sql/create_tables.sql | 6 +- .../module/pay/api/order/PayOrderApi.java | 11 ++- .../pay/api/order/dto/PayOrderRespDTO.java | 48 ++++++++++ .../module/pay/enums/ErrorCodeConstants.java | 10 +- .../pay/enums/order/PayOrderStatusEnum.java | 12 +++ .../module/pay/api/order/PayOrderApiImpl.java | 11 ++- .../pay/convert/order/PayOrderConvert.java | 6 +- .../pay/dal/dataobject/order/PayOrderDO.java | 2 +- 16 files changed, 267 insertions(+), 43 deletions(-) create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 2a399c641..ebe2cea51 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -20,8 +20,12 @@ public interface ErrorCodeConstants { ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在"); ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); - ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000010, "交易订单不存在"); - ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000011, "交易订单项更新售后状态失败,请重试"); + ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000011, "交易订单不存在"); + ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000012, "交易订单项更新售后状态失败,请重试"); + ErrorCode ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1011000013, "交易订单更新支付状态失败,订单不是【未支付】状态"); + ErrorCode ORDER_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1011000014, "交易订单更新支付状态失败,支付单编号不匹配"); + ErrorCode ORDER_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1011000015, "交易订单更新支付状态失败,支付单状态不是【支付成功】状态"); + ErrorCode ORDER_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1011000016, "交易订单更新支付状态失败,支付单金额不匹配"); // ========== After Sale 模块 1-011-000-000 ========== ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java index 7bfa61f74..a234bcca5 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java @@ -42,6 +42,19 @@ public enum TradeOrderStatusEnum implements IntArrayValuable { return ARRAYS; } + // ========== 问:为什么写了很多 isXXX 和 haveXXX 的判断逻辑呢? ========== + // ========== 答:方便找到某一类判断,哪些业务正在使用 ========== + + /** + * 判断指定状态,是否正处于【未付款】状态 + * + * @param status 指定状态 + * @return 是否 + */ + public static boolean isUnpaid(Integer status) { + return ObjectUtil.equal(PAID.getStatus(), status); + } + /** * 判断指定状态,是否正处于【已取消】状态 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 764a88b8b..003892512 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + @Api(tags = "用户 App - 交易订单") @RestController @RequestMapping("/trade/order") @@ -49,13 +51,15 @@ public class AppTradeOrderController { String clientIp = ServletUtil.getClientIP(servletRequest); // 创建交易订单,预支付记录 Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO); - return CommonResult.success(orderId); + return success(orderId); } @PostMapping("/update-paid") @ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob") public CommonResult updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { - return null; + tradeOrderService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()), + notifyReqDTO.getPayOrderId()); + return success(true); } @GetMapping("/get") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index cf4c2276f..4d0d14f45 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -95,6 +95,13 @@ public class TradeOrderDO extends BaseDO { private String remark; // ========== 价格 + 支付基本信息 ========== + + /** + * 支付订单编号 + * + * 对接 pay-module-biz 支付服务的支付订单编号,即 PayOrderDO 的 id 编号 + */ + private Long payOrderId; /** * 是否已支付 * @@ -106,6 +113,12 @@ public class TradeOrderDO extends BaseDO { * 付款时间 */ private LocalDateTime payTime; + /** + * 支付成功的支付渠道 + * + * 对应 PayChannelEnum 枚举 + */ + private String payChannelCode; // ========== 价格 + 支付基本信息 ========== // 价格文档 - 淘宝:https://open.taobao.com/docV3.htm?docId=108471&docType=1 @@ -156,18 +169,6 @@ public class TradeOrderDO extends BaseDO { * + {@link #adjustPrice} */ private Integer payPrice; - /** - * 支付订单编号 - * - * 对接 pay-module-biz 支付服务的支付订单编号,即 PayOrderDO 的 id 编号 - */ - private Long payOrderId; - /** - * 支付成功的支付渠道 - * - * 对应 PayChannelEnum 枚举 - */ - private Integer payChannel; // ========== 收件 + 物流基本信息 ========== /** @@ -206,7 +207,7 @@ public class TradeOrderDO extends BaseDO { /** * 收件人地区编号 */ - private Long receiverAreaId; + private Integer receiverAreaId; /** * 收件人邮编 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java index a62746b1b..1f89788f1 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java @@ -2,8 +2,15 @@ package cn.iocoder.yudao.module.trade.dal.mysql.order; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface TradeOrderMapper extends BaseMapperX { + + default int updateByIdAndStatus(Long id, Integer status, TradeOrderDO update) { + return update(update, new LambdaUpdateWrapper() + .eq(TradeOrderDO::getId, id).eq(TradeOrderDO::getStatus, status)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index be101bbe6..5c59e1c88 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java @@ -33,6 +33,14 @@ public interface TradeOrderService { */ TradeOrderDO getOrder(Long userId, Long orderId); + /** + * 更新交易订单已支付 + * + * @param id 交易订单编号 + * @param payOrderId 支付订单编号 + */ + void updateOrderPaid(Long id, Long payOrderId); + // =================== Order Item =================== /** @@ -54,4 +62,5 @@ public interface TradeOrderService { */ void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index fe8ce878a..3c5b59509 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -3,13 +3,17 @@ package cn.iocoder.yudao.module.trade.service.order; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; @@ -30,6 +34,7 @@ import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -42,6 +47,7 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** @@ -51,6 +57,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; * @since 2022-08-26 */ @Service +@Slf4j public class TradeOrderServiceImpl implements TradeOrderService { @Resource @@ -110,6 +117,84 @@ public class TradeOrderServiceImpl implements TradeOrderService { return order; } + @Override + public void updateOrderPaid(Long id, Long payOrderId) { + // 校验并获得交易订单 + KeyValue orderResult = validateOrderPaid(id, payOrderId); + TradeOrderDO order = orderResult.getKey(); + PayOrderRespDTO payOrder = orderResult.getValue(); + + // 更新 TradeOrderDO 状态为已支付,等待发货 + int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayed(true) + .setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode())); + if (updateCount == 0) { + throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + + // TODO 芋艿:发送订单变化的消息 + + // TODO 芋艿:发送站内信 + + // TODO 芋艿:OrderLog + } + + /** + * 校验交易订单满足被支付的条件 + * + * 1. 交易订单未支付 + * 2. 支付单已支付 + * + * @param id 交易订单编号 + * @param payOrderId 支付订单编号 + * @return 交易订单 + */ + private KeyValue validateOrderPaid(Long id, Long payOrderId) { + // 校验订单是否存在 + TradeOrderDO order = tradeOrderMapper.selectById(id); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 校验订单未支付 + if (TradeOrderStatusEnum.isUnpaid(order.getStatus())) { // 状态 + log.error("[validateOrderPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]", + id, JsonUtils.toJsonString(order)); + throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); + } + // 校验支付订单匹配 + if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 + log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(order)); + throw exception(ORDER_UPDATE_PAID_PAY_ORDER_ID_ERROR); + } + + // 校验支付单是否存在 + PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); + if (payOrder == null) { + log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); + throw exception(PAY_ORDER_NOT_FOUND); + } + // 校验支付单已支付 + if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { + log.error("[validateOrderPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS); + } + // 校验支付金额一致 + if (ObjectUtil.notEqual(payOrder.getAmount(), order.getPayPrice())) { + log.error("[validateOrderPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_PAY_PRICE_NOT_MATCH); + } + // 校验支付订单匹配(二次) + if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) { + log.error("[validateOrderPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]", + id, payOrderId, JsonUtils.toJsonString(payOrder)); + throw exception(ORDER_UPDATE_PAID_PAY_ORDER_ID_ERROR); + } + return new KeyValue<>(order, payOrder); + } + /** * 校验商品 SKU 是否可出售 * @@ -120,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { List skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId)); // SKU 不存在 if (items.size() != skus.size()) { - throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_NOT_FOUND); + throw exception(ORDER_CREATE_SKU_NOT_FOUND); } // 校验是否禁用 or 库存不足 Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); @@ -233,13 +318,15 @@ public class TradeOrderServiceImpl implements TradeOrderService { // 创建支付单,用于后续的支付 PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); - Long payOrderId = payOrderApi.createPayOrder(payOrderCreateReqDTO); + Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO); // 更新到交易单上 tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); } - // =================== Order =================== + + + // =================== Order Item =================== @Override public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index a5e472e9a..77d34e494 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; @@ -109,7 +111,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { // mock 方法(用户收件地址的校验) AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") .setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村"); - when(addressApi.getAddress(eq(userId), eq(10L))).thenReturn(addressRespDTO); + when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO); // mock 方法(价格计算) PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50) @@ -131,7 +133,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { return true; }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder)); // mock 方法(创建支付单) - when(payOrderApi.createPayOrder(argThat(createReqDTO -> { + when(payOrderApi.createOrder(argThat(createReqDTO -> { assertEquals(createReqDTO.getAppId(), 888L); assertEquals(createReqDTO.getUserIp(), userIp); assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空 @@ -169,7 +171,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderDO.getAdjustPrice(), 0); assertEquals(tradeOrderDO.getPayPrice(), 80); assertEquals(tradeOrderDO.getPayOrderId(), 1000L); - assertNull(tradeOrderDO.getPayChannel()); + assertNull(tradeOrderDO.getPayChannelCode()); assertNull(tradeOrderDO.getDeliveryTemplateId()); assertNull(tradeOrderDO.getExpressNo()); assertFalse(tradeOrderDO.getDeliveryStatus()); @@ -177,7 +179,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { assertNull(tradeOrderDO.getReceiveTime()); assertEquals(tradeOrderDO.getReceiverName(), "芋艿"); assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300"); - assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L); + assertEquals(tradeOrderDO.getReceiverAreaId(), 3306); assertEquals(tradeOrderDO.getReceiverPostCode(), 85757); assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村"); assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus()); @@ -241,11 +243,30 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(reqDTO.getOrderId(), tradeOrderId); return true; })); -// //mock 支付订单信息 -// when(payOrderApi.createPayOrder(any())).thenReturn(1L); - -// //价格 -// assertEquals(calculateRespDTO.getOrder().getItems().get(0).getPresentPrice(), tradeOrderItemDO.getPresentPrice()); } + @Test + public void updateOrderPaid() { + // mock 数据(TradeOrder) + TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> { + o.setId(1L).setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); + o.setPayOrderId(10L).setPayPrice(100).setPayTime(null); + }); + tradeOrderMapper.insert(order); + // 准备参数 + Long id = 1L; + Long payOrderId = 10L; + // mock 方法(支付单) + when(payOrderApi.getOrder(eq(10L))).thenReturn(randomPojo(PayOrderRespDTO.class, + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()).setChannelCode("wx_pub") + .setMerchantOrderId("1")).setAmount(100)); + // 调用 + tradeOrderService.updateOrderPaid(id, payOrderId); + // 断言 + TradeOrderDO dbOrder = tradeOrderMapper.selectById(id); + assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.PAID.getStatus()); + assertTrue(dbOrder.getPayed()); + assertNotNull(dbOrder.getPayTime()); + assertEquals(dbOrder.getPayChannelCode(), "wx_pub"); + } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql index 4b78084e7..d107d04cd 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql @@ -21,9 +21,9 @@ CREATE TABLE IF NOT EXISTS "trade_order" ( "adjust_price" int NOT NULL, "pay_price" int NOT NULL, "pay_order_id" int, - "pay_channel" int, - "delivery_template_id" int, - "express_no" int, + "pay_channel_code" varchar, + "delivery_template_id" bigint, + "express_no" varchar, "delivery_status" bit NOT NULL, "delivery_time" datetime, "receive_time" datetime, diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java index f6cf7be30..5c1905ebe 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.pay.api.order; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; import javax.validation.Valid; @@ -18,6 +19,14 @@ public interface PayOrderApi { * @param reqDTO 创建请求 * @return 支付单编号 */ - Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO); + Long createOrder(@Valid PayOrderCreateReqDTO reqDTO); + + /** + * 获得支付单 + * + * @param id 支付单编号 + * @return 支付单 + */ + PayOrderRespDTO getOrder(Long id); } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java new file mode 100644 index 000000000..1a053f68e --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.pay.api.order.dto; + +import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; +import lombok.Data; + +/** + * 支付单信息 Response DTO + * + * TODO 芋艿:还没定好字段 + * + * @author 芋道源码 + */ +@Data +public class PayOrderRespDTO { + + /** + * 订单编号,数据库自增 + */ + private Long id; + /** + * 渠道编码 + * + * 枚举 PayChannelEnum + */ + private String channelCode; + + // ========== 商户相关字段 ========== + /** + * 商户订单编号 + * 例如说,内部系统 A 的订单号。需要保证每个 PayMerchantDO 唯一 + */ + private String merchantOrderId; + + // ========== 订单相关字段 ========== + /** + * 支付金额,单位:分 + */ + private Integer amount; + /** + * 支付状态 + * + * 枚举 {@link PayOrderStatusEnum} + */ + private Integer status; + + // ========== 渠道相关字段 ========== + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java index 203cb0703..9a68b9bc4 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java @@ -28,9 +28,9 @@ public interface ErrorCodeConstants { ErrorCode CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL = new ErrorCode(1007001007,"微信渠道v3版本apiclient_key.pem不可为空"); ErrorCode CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL = new ErrorCode(1007001008,"微信渠道v3版本中apiclient_cert.pem不可为空"); ErrorCode PAY_CHANNEL_NOTIFY_VERIFY_FAILED = new ErrorCode(1007001009, "渠道通知校验失败"); - /** - * ========== ORDER 模块 1-007-002-000 ========== - */ + + // ========== ORDER 模块 1-007-002-000 ========== + ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在"); ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); @@ -57,8 +57,4 @@ public interface ErrorCodeConstants { ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在"); ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除"); - - - - } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java index ab542a97c..b4a5b2b98 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java @@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Objects; + /** * 支付订单的状态枚举 * @@ -26,4 +28,14 @@ public enum PayOrderStatusEnum implements IntArrayValuable { return new int[0]; } + /** + * 判断是否支付成功 + * + * @param status 状态 + * @return 是否支付成功 + */ + public static boolean isSuccess(Integer status) { + return Objects.equals(status, SUCCESS.getStatus()); + } + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java index c3995e6f0..d7299926b 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.pay.api.order; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; +import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import org.springframework.stereotype.Service; @@ -18,8 +21,14 @@ public class PayOrderApiImpl implements PayOrderApi { private PayOrderService payOrderService; @Override - public Long createPayOrder(PayOrderCreateReqDTO reqDTO) { + public Long createOrder(PayOrderCreateReqDTO reqDTO) { return payOrderService.createPayOrder(reqDTO); } + @Override + public PayOrderRespDTO getOrder(Long id) { + PayOrderDO order = payOrderService.getOrder(id); + return PayOrderConvert.INSTANCE.convert2(order); + } + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java index ce8f00f4e..0c2b3fec5 100755 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.order; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderDetailsRespVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExcelVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO; @@ -41,13 +42,14 @@ public interface PayOrderConvert { List convertList02(List list); /** - * 订单DO转自定义分页对象 + * 订单 DO 转自定义分页对象 * * @param bean 订单DO * @return 分页对象 */ PayOrderPageItemRespVO pageConvertItemPage(PayOrderDO bean); + // TODO 芋艿:优化下 convert 逻辑 default PayOrderExcelVO excelConvert(PayOrderDO bean) { if (bean == null) { return null; @@ -94,4 +96,6 @@ public interface PayOrderConvert { PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqDTO bean); + PayOrderRespDTO convert2(PayOrderDO bean); + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java index ad6f9ea7e..4f568ba5e 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java @@ -93,7 +93,7 @@ public class PayOrderDO extends BaseDO { /** * 支付金额,单位:分 */ - private Long amount; + private Integer amount; /** * 渠道手续费,单位:百分比 *