trade:完成支付成功后的回调,更新订单为已支付

pull/2/head
YunaiV 2022-11-26 18:40:51 +08:00
parent 1cd9085c59
commit e96422a47e
16 changed files with 267 additions and 43 deletions

View File

@ -20,8 +20,12 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在"); ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在");
ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在");
ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000010, "交易订单不存在"); ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000011, "交易订单不存在");
ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = 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 ========== // ========== After Sale 模块 1-011-000-000 ==========
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");

View File

@ -42,6 +42,19 @@ public enum TradeOrderStatusEnum implements IntArrayValuable {
return ARRAYS; return ARRAYS;
} }
// ========== 问:为什么写了很多 isXXX 和 haveXXX 的判断逻辑呢? ==========
// ========== 答:方便找到某一类判断,哪些业务正在使用 ==========
/**
*
*
* @param status
* @return
*/
public static boolean isUnpaid(Integer status) {
return ObjectUtil.equal(PAID.getStatus(), status);
}
/** /**
* *
* *

View File

@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "用户 App - 交易订单") @Api(tags = "用户 App - 交易订单")
@RestController @RestController
@RequestMapping("/trade/order") @RequestMapping("/trade/order")
@ -49,13 +51,15 @@ public class AppTradeOrderController {
String clientIp = ServletUtil.getClientIP(servletRequest); String clientIp = ServletUtil.getClientIP(servletRequest);
// 创建交易订单,预支付记录 // 创建交易订单,预支付记录
Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO); Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO);
return CommonResult.success(orderId); return success(orderId);
} }
@PostMapping("/update-paid") @PostMapping("/update-paid")
@ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob") @ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob")
public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
return null; tradeOrderService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
notifyReqDTO.getPayOrderId());
return success(true);
} }
@GetMapping("/get") @GetMapping("/get")

View File

@ -95,6 +95,13 @@ public class TradeOrderDO extends BaseDO {
private String remark; private String remark;
// ========== 价格 + 支付基本信息 ========== // ========== 价格 + 支付基本信息 ==========
/**
*
*
* pay-module-biz PayOrderDO id
*/
private Long payOrderId;
/** /**
* *
* *
@ -106,6 +113,12 @@ public class TradeOrderDO extends BaseDO {
* *
*/ */
private LocalDateTime payTime; private LocalDateTime payTime;
/**
*
*
* PayChannelEnum
*/
private String payChannelCode;
// ========== 价格 + 支付基本信息 ========== // ========== 价格 + 支付基本信息 ==========
// 价格文档 - 淘宝https://open.taobao.com/docV3.htm?docId=108471&docType=1 // 价格文档 - 淘宝https://open.taobao.com/docV3.htm?docId=108471&docType=1
@ -156,18 +169,6 @@ public class TradeOrderDO extends BaseDO {
* + {@link #adjustPrice} * + {@link #adjustPrice}
*/ */
private Integer payPrice; 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;
/** /**
* *
*/ */

View File

@ -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.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> { public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
default int updateByIdAndStatus(Long id, Integer status, TradeOrderDO update) {
return update(update, new LambdaUpdateWrapper<TradeOrderDO>()
.eq(TradeOrderDO::getId, id).eq(TradeOrderDO::getStatus, status));
}
} }

View File

@ -33,6 +33,14 @@ public interface TradeOrderService {
*/ */
TradeOrderDO getOrder(Long userId, Long orderId); TradeOrderDO getOrder(Long userId, Long orderId);
/**
*
*
* @param id
* @param payOrderId
*/
void updateOrderPaid(Long id, Long payOrderId);
// =================== Order Item =================== // =================== Order Item ===================
/** /**
@ -54,4 +62,5 @@ public interface TradeOrderService {
*/ */
void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus,
Integer newAfterSaleStatus, Integer refundPrice); Integer newAfterSaleStatus, Integer refundPrice);
} }

View File

@ -3,13 +3,17 @@ package cn.iocoder.yudao.module.trade.service.order;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; 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.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 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.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; 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.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 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.ErrorCodeConstants;
import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.enums.order.*;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; 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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 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.*; 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 * @since 2022-08-26
*/ */
@Service @Service
@Slf4j
public class TradeOrderServiceImpl implements TradeOrderService { public class TradeOrderServiceImpl implements TradeOrderService {
@Resource @Resource
@ -110,6 +117,84 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return order; return order;
} }
@Override
public void updateOrderPaid(Long id, Long payOrderId) {
// 校验并获得交易订单
KeyValue<TradeOrderDO, PayOrderRespDTO> 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<TradeOrderDO, PayOrderRespDTO> 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 * SKU
* *
@ -120,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId)); List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId));
// SKU 不存在 // SKU 不存在
if (items.size() != skus.size()) { if (items.size() != skus.size()) {
throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_NOT_FOUND); throw exception(ORDER_CREATE_SKU_NOT_FOUND);
} }
// 校验是否禁用 or 库存不足 // 校验是否禁用 or 库存不足
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
@ -233,13 +318,15 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// 创建支付单,用于后续的支付 // 创建支付单,用于后续的支付
PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties);
Long payOrderId = payOrderApi.createPayOrder(payOrderCreateReqDTO); Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO);
// 更新到交易单上 // 更新到交易单上
tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId));
} }
// =================== Order ===================
// =================== Order Item ===================
@Override @Override
public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { public TradeOrderItemDO getOrderItem(Long userId, Long itemId) {

View File

@ -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.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 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.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.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@ -109,7 +111,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
// mock 方法(用户收件地址的校验) // mock 方法(用户收件地址的校验)
AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿")
.setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村"); .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 方法(价格计算) // mock 方法(价格计算)
PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem()
.setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50) .setSpuId(11L).setSkuId(1L).setCount(3).setOriginalPrice(150).setOriginalUnitPrice(50)
@ -131,7 +133,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
return true; return true;
}))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder)); }))).thenReturn(new PriceCalculateRespDTO().setOrder(priceOrder));
// mock 方法(创建支付单) // mock 方法(创建支付单)
when(payOrderApi.createPayOrder(argThat(createReqDTO -> { when(payOrderApi.createOrder(argThat(createReqDTO -> {
assertEquals(createReqDTO.getAppId(), 888L); assertEquals(createReqDTO.getAppId(), 888L);
assertEquals(createReqDTO.getUserIp(), userIp); assertEquals(createReqDTO.getUserIp(), userIp);
assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空 assertNotNull(createReqDTO.getMerchantOrderId()); // 由于 tradeOrderId 后生成,只能校验非空
@ -169,7 +171,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
assertEquals(tradeOrderDO.getAdjustPrice(), 0); assertEquals(tradeOrderDO.getAdjustPrice(), 0);
assertEquals(tradeOrderDO.getPayPrice(), 80); assertEquals(tradeOrderDO.getPayPrice(), 80);
assertEquals(tradeOrderDO.getPayOrderId(), 1000L); assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
assertNull(tradeOrderDO.getPayChannel()); assertNull(tradeOrderDO.getPayChannelCode());
assertNull(tradeOrderDO.getDeliveryTemplateId()); assertNull(tradeOrderDO.getDeliveryTemplateId());
assertNull(tradeOrderDO.getExpressNo()); assertNull(tradeOrderDO.getExpressNo());
assertFalse(tradeOrderDO.getDeliveryStatus()); assertFalse(tradeOrderDO.getDeliveryStatus());
@ -177,7 +179,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
assertNull(tradeOrderDO.getReceiveTime()); assertNull(tradeOrderDO.getReceiveTime());
assertEquals(tradeOrderDO.getReceiverName(), "芋艿"); assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300"); assertEquals(tradeOrderDO.getReceiverMobile(), "15601691300");
assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L); assertEquals(tradeOrderDO.getReceiverAreaId(), 3306);
assertEquals(tradeOrderDO.getReceiverPostCode(), 85757); assertEquals(tradeOrderDO.getReceiverPostCode(), 85757);
assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村"); assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus()); assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus());
@ -241,11 +243,30 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
assertEquals(reqDTO.getOrderId(), tradeOrderId); assertEquals(reqDTO.getOrderId(), tradeOrderId);
return true; 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");
}
} }

View File

@ -21,9 +21,9 @@ CREATE TABLE IF NOT EXISTS "trade_order" (
"adjust_price" int NOT NULL, "adjust_price" int NOT NULL,
"pay_price" int NOT NULL, "pay_price" int NOT NULL,
"pay_order_id" int, "pay_order_id" int,
"pay_channel" int, "pay_channel_code" varchar,
"delivery_template_id" int, "delivery_template_id" bigint,
"express_no" int, "express_no" varchar,
"delivery_status" bit NOT NULL, "delivery_status" bit NOT NULL,
"delivery_time" datetime, "delivery_time" datetime,
"receive_time" datetime, "receive_time" datetime,

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.pay.api.order; 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.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import javax.validation.Valid; import javax.validation.Valid;
@ -18,6 +19,14 @@ public interface PayOrderApi {
* @param reqDTO * @param reqDTO
* @return * @return
*/ */
Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO); Long createOrder(@Valid PayOrderCreateReqDTO reqDTO);
/**
*
*
* @param id
* @return
*/
PayOrderRespDTO getOrder(Long id);
} }

View File

@ -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;
// ========== 渠道相关字段 ==========
}

View File

@ -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_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 CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL = new ErrorCode(1007001008,"微信渠道v3版本中apiclient_cert.pem不可为空");
ErrorCode PAY_CHANNEL_NOTIFY_VERIFY_FAILED = new ErrorCode(1007001009, "渠道通知校验失败"); 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_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); 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_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除"); ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
} }

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.util.Objects;
/** /**
* *
* *
@ -26,4 +28,14 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
return new int[0]; return new int[0];
} }
/**
*
*
* @param status
* @return
*/
public static boolean isSuccess(Integer status) {
return Objects.equals(status, SUCCESS.getStatus());
}
} }

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.pay.api.order; 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.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 cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,8 +21,14 @@ public class PayOrderApiImpl implements PayOrderApi {
private PayOrderService payOrderService; private PayOrderService payOrderService;
@Override @Override
public Long createPayOrder(PayOrderCreateReqDTO reqDTO) { public Long createOrder(PayOrderCreateReqDTO reqDTO) {
return payOrderService.createPayOrder(reqDTO); return payOrderService.createPayOrder(reqDTO);
} }
@Override
public PayOrderRespDTO getOrder(Long id) {
PayOrderDO order = payOrderService.getOrder(id);
return PayOrderConvert.INSTANCE.convert2(order);
}
} }

View File

@ -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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; 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.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.PayOrderDetailsRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExcelVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExcelVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO;
@ -48,6 +49,7 @@ public interface PayOrderConvert {
*/ */
PayOrderPageItemRespVO pageConvertItemPage(PayOrderDO bean); PayOrderPageItemRespVO pageConvertItemPage(PayOrderDO bean);
// TODO 芋艿:优化下 convert 逻辑
default PayOrderExcelVO excelConvert(PayOrderDO bean) { default PayOrderExcelVO excelConvert(PayOrderDO bean) {
if (bean == null) { if (bean == null) {
return null; return null;
@ -94,4 +96,6 @@ public interface PayOrderConvert {
PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqDTO bean); PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqDTO bean);
PayOrderRespDTO convert2(PayOrderDO bean);
} }

View File

@ -93,7 +93,7 @@ public class PayOrderDO extends BaseDO {
/** /**
* *
*/ */
private Long amount; private Integer amount;
/** /**
* *
* *