feat: 重新梳理订单支付流程

pull/1121/head
梁宇奇 2025-04-10 18:07:44 +08:00
parent 6cdd1c1592
commit 5cb0a8e0bf
14 changed files with 274 additions and 89 deletions

View File

@ -9,6 +9,7 @@ import com.ruoyi.xkt.domain.AlipayCallback;
import com.ruoyi.xkt.domain.StoreOrder; import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.enums.EProcessStatus; import com.ruoyi.xkt.enums.EProcessStatus;
import com.ruoyi.xkt.manager.impl.AliPaymentMangerImpl; import com.ruoyi.xkt.manager.impl.AliPaymentMangerImpl;
import com.ruoyi.xkt.service.IAlipayCallbackService;
import com.ruoyi.xkt.service.IStoreOrderService; import com.ruoyi.xkt.service.IStoreOrderService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -37,6 +38,8 @@ public class AlipayController extends XktBaseController {
@Autowired @Autowired
private IStoreOrderService storeOrderService; private IStoreOrderService storeOrderService;
@Autowired @Autowired
private IAlipayCallbackService alipayCallbackService;
@Autowired
private AliPaymentMangerImpl paymentManger; private AliPaymentMangerImpl paymentManger;
/** /**
@ -85,7 +88,25 @@ public class AlipayController extends XktBaseController {
return FAILURE; return FAILURE;
} }
//5. 处理支付宝回调信息 //5. 处理支付宝回调信息
paymentManger.processAlipayCallback(alipayCallback); AlipayCallback info = alipayCallbackService.getByNotifyId(alipayCallback.getNotifyId());
if (info == null) {
//保存到数据库
info = alipayCallback;
alipayCallbackService.insertAlipayCallback(info);
}
if (!"TRADE_SUCCESS".equals(info.getTradeStatus())) {
//非交易支付成功的回调不处理
return SUCCESS;
}
if (info.getRefundFee() != null && !NumberUtil.equals(info.getRefundFee(), BigDecimal.ZERO)) {
//如果有退款金额,可能是部分退款的回调,这里不做处理
return SUCCESS;
}
if (EProcessStatus.INIT.getValue().equals(info.getProcessStatus())) {
alipayCallbackService.processOrderPay(info);
} else {
logger.warn("支付回调重复请求处理: {}", info.getId());
}
return SUCCESS; return SUCCESS;
} else { } else {
logger.info("支付宝验签未通过:{}", params); logger.info("支付宝验签未通过:{}", params);

View File

@ -11,9 +11,10 @@ import com.ruoyi.web.controller.xkt.vo.order.StoreOrderAddReqVO;
import com.ruoyi.web.controller.xkt.vo.order.StoreOrderPayReqVO; import com.ruoyi.web.controller.xkt.vo.order.StoreOrderPayReqVO;
import com.ruoyi.web.controller.xkt.vo.order.StoreOrderPayRespVO; import com.ruoyi.web.controller.xkt.vo.order.StoreOrderPayRespVO;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO; import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResult;
import com.ruoyi.xkt.dto.order.StoreOrderInfo; import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.enums.EPayChannel; import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EPayFrom; import com.ruoyi.xkt.enums.EPayPage;
import com.ruoyi.xkt.manager.PaymentManager; import com.ruoyi.xkt.manager.PaymentManager;
import com.ruoyi.xkt.service.IStoreOrderService; import com.ruoyi.xkt.service.IStoreOrderService;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List; import java.util.List;
/** /**
@ -44,28 +46,30 @@ public class StoreOrderController extends XktBaseController {
@PreAuthorize("@ss.hasPermi('system:order:add')") @PreAuthorize("@ss.hasPermi('system:order:add')")
@Log(title = "订单", businessType = BusinessType.INSERT) @Log(title = "订单", businessType = BusinessType.INSERT)
@ApiOperation("创建订单并发起支付") @ApiOperation("创建订单")
@PostMapping("create") @PostMapping("create")
public R<StoreOrderPayRespVO> create(@RequestBody StoreOrderAddReqVO vo) { public R<StoreOrderPayRespVO> create(@Valid @RequestBody StoreOrderAddReqVO vo) {
StoreOrderAddDTO dto = BeanUtil.toBean(vo, StoreOrderAddDTO.class); StoreOrderAddDTO dto = BeanUtil.toBean(vo, StoreOrderAddDTO.class);
dto.setOrderUserId(SecurityUtils.getUserId()); dto.setOrderUserId(SecurityUtils.getUserId());
//初始化订单 //创建订单并根据参数决定是否发起支付
StoreOrderInfo orderInfo = storeOrderService.createOrder(dto); StoreOrderAddResult result = storeOrderService.createOrder(dto, vo.getBeginPay(),
//发起支付 EPayChannel.of(vo.getPayChannel()), EPayPage.of(vo.getPayFrom()));
PaymentManager paymentManager = getPaymentManager(EPayChannel.of(vo.getPayChannel()));
String rtnStr = paymentManager.payForOrder(orderInfo.getOrder().getId(), EPayFrom.of(vo.getPayFrom()));
//返回信息 //返回信息
StoreOrderPayRespVO respVO = new StoreOrderPayRespVO(orderInfo.getOrder().getId(), rtnStr); StoreOrderPayRespVO respVO = new StoreOrderPayRespVO(result.getOrderInfo().getOrder().getId(),
result.getPayRtnStr());
return success(respVO); return success(respVO);
} }
@PreAuthorize("@ss.hasPermi('system:order:add')") @PreAuthorize("@ss.hasPermi('system:order:add')")
@Log(title = "订单", businessType = BusinessType.OTHER) @Log(title = "订单", businessType = BusinessType.OTHER)
@ApiOperation("重新发起订单支付") @ApiOperation("支付订单")
@PostMapping("pay") @PostMapping("pay")
public R<StoreOrderPayRespVO> pay(@RequestBody StoreOrderPayReqVO vo) { public R<StoreOrderPayRespVO> pay(@Valid @RequestBody StoreOrderPayReqVO vo) {
PaymentManager paymentManager = getPaymentManager(EPayChannel.of(vo.getPayChannel())); PaymentManager paymentManager = getPaymentManager(EPayChannel.of(vo.getPayChannel()));
String rtnStr = paymentManager.payForOrder(vo.getStoreOrderId(), EPayFrom.of(vo.getPayFrom())); //订单支付状态->支付中
StoreOrderInfo storeOrderInfo = storeOrderService.preparePayOrder(vo.getStoreOrderId());
//调用支付
String rtnStr = paymentManager.payOrder(storeOrderInfo, EPayPage.of(vo.getPayFrom()));
StoreOrderPayRespVO respVO = new StoreOrderPayRespVO(vo.getStoreOrderId(), rtnStr); StoreOrderPayRespVO respVO = new StoreOrderPayRespVO(vo.getStoreOrderId(), rtnStr);
return success(respVO); return success(respVO);
} }

View File

@ -4,6 +4,9 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -17,6 +20,7 @@ public class StoreOrderAddReqVO {
/** /**
* ID * ID
*/ */
@NotNull(message = "档口ID不能为空")
@ApiModelProperty(value = "档口ID") @ApiModelProperty(value = "档口ID")
private Long storeId; private Long storeId;
/** /**
@ -27,41 +31,49 @@ public class StoreOrderAddReqVO {
/** /**
* ID * ID
*/ */
@NotNull(message = "物流ID不能为空")
@ApiModelProperty(value = "物流ID") @ApiModelProperty(value = "物流ID")
private Long expressId; private Long expressId;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人名称不能为空")
@ApiModelProperty(value = "收货人-名称") @ApiModelProperty(value = "收货人-名称")
private String destinationContactName; private String destinationContactName;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人电话不能为空")
@ApiModelProperty(value = "收货人-电话") @ApiModelProperty(value = "收货人-电话")
private String destinationContactPhoneNumber; private String destinationContactPhoneNumber;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人省编码不能为空")
@ApiModelProperty(value = "收货人-省编码") @ApiModelProperty(value = "收货人-省编码")
private String destinationProvinceCode; private String destinationProvinceCode;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人市编码不能为空")
@ApiModelProperty(value = "收货人-市编码") @ApiModelProperty(value = "收货人-市编码")
private String destinationCityCode; private String destinationCityCode;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人区县编码不能为空")
@ApiModelProperty(value = "收货人-区县编码") @ApiModelProperty(value = "收货人-区县编码")
private String destinationCountyCode; private String destinationCountyCode;
/** /**
* - * -
*/ */
@NotEmpty(message = "收货人详细地址不能为空")
@ApiModelProperty(value = "收货人-详细地址") @ApiModelProperty(value = "收货人-详细地址")
private String destinationDetailAddress; private String destinationDetailAddress;
/** /**
* [1: 2:] * [1: 2:]
*/ */
@NotNull(message = "发货方式不能为空")
@ApiModelProperty(value = "发货方式[1:货其再发 2:有货先发]") @ApiModelProperty(value = "发货方式[1:货其再发 2:有货先发]")
private Integer deliveryType; private Integer deliveryType;
/** /**
@ -72,12 +84,20 @@ public class StoreOrderAddReqVO {
/** /**
* *
*/ */
@Valid
@NotEmpty(message = "订单明细不能为空")
@ApiModelProperty(value = "明细列表") @ApiModelProperty(value = "明细列表")
private List<Detail> detailList; private List<Detail> detailList;
@NotNull(message = "是否发起支付不能为空")
@ApiModelProperty(value = "是否发起支付")
private Boolean beginPay;
@NotNull(message = "支付渠道不能为空")
@ApiModelProperty(value = "支付渠道[1:支付宝]") @ApiModelProperty(value = "支付渠道[1:支付宝]")
private Integer payChannel; private Integer payChannel;
@NotNull(message = "支付来源不能为空")
@ApiModelProperty(value = "支付来源[1:电脑网站 2:手机网站]") @ApiModelProperty(value = "支付来源[1:电脑网站 2:手机网站]")
private Integer payFrom; private Integer payFrom;
@ -85,9 +105,11 @@ public class StoreOrderAddReqVO {
@Data @Data
public static class Detail { public static class Detail {
@NotNull(message = "商品颜色尺码ID不能为空")
@ApiModelProperty(value = "商品颜色尺码ID") @ApiModelProperty(value = "商品颜色尺码ID")
private Long storeProdColorSizeId; private Long storeProdColorSizeId;
@NotNull(message = "商品数量不能为空")
@ApiModelProperty(value = "商品数量") @ApiModelProperty(value = "商品数量")
private Integer goodsQuantity; private Integer goodsQuantity;
} }

View File

@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotNull;
/** /**
* @author liangyq * @author liangyq
* @date 2025-04-07 18:16 * @date 2025-04-07 18:16
@ -12,12 +14,15 @@ import lombok.Data;
@Data @Data
public class StoreOrderPayReqVO { public class StoreOrderPayReqVO {
@NotNull(message = "订单ID不能为空")
@ApiModelProperty(value = "订单ID") @ApiModelProperty(value = "订单ID")
private Long storeOrderId; private Long storeOrderId;
@NotNull(message = "支付渠道不能为空")
@ApiModelProperty(value = "支付渠道[1:支付宝]") @ApiModelProperty(value = "支付渠道[1:支付宝]")
private Integer payChannel; private Integer payChannel;
@NotNull(message = "支付来源不能为空")
@ApiModelProperty(value = "支付来源[1:电脑网站 2:手机网站]") @ApiModelProperty(value = "支付来源[1:电脑网站 2:手机网站]")
private Integer payFrom; private Integer payFrom;
} }

View File

@ -1,23 +1,27 @@
package com.ruoyi.common.utils; package com.ruoyi.common.utils;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.PatternMatchUtils;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.PatternMatchUtils;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/** /**
* *
* *
* @author ruoyi * @author ruoyi
*/ */
@Slf4j
public class SecurityUtils public class SecurityUtils
{ {
@ -66,6 +70,25 @@ public class SecurityUtils
} }
} }
/**
*
*
* @return
*/
public static String getUsernameSafe() {
String username = null;
try {
Authentication auth = getAuthentication();
if (auth != null) {
LoginUser user = (LoginUser) auth.getPrincipal();
username = Optional.ofNullable(user).map(LoginUser::getUsername).orElse(null);
}
} catch (Exception e) {
log.error("获取用户账户异常", e);
}
return username;
}
/** /**
* *
**/ **/

View File

@ -0,0 +1,23 @@
package com.ruoyi.xkt.dto.order;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-04-03 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StoreOrderAddResult {
/**
*
*/
private StoreOrderInfo orderInfo;
/**
*
*/
private String payRtnStr;
}

View File

@ -12,6 +12,7 @@ import lombok.Getter;
public enum EOrderAction { public enum EOrderAction {
ADD_ORDER(1, "下单"), ADD_ORDER(1, "下单"),
PAID_ORDER(2, "支付"),
; ;
private final Integer value; private final Integer value;

View File

@ -9,7 +9,7 @@ import lombok.Getter;
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum EPayFrom { public enum EPayPage {
WEB(1, "电脑网站"), WEB(1, "电脑网站"),
WAP(2, "手机网站"), WAP(2, "手机网站"),
@ -18,8 +18,8 @@ public enum EPayFrom {
private final Integer value; private final Integer value;
private final String label; private final String label;
public static EPayFrom of(Integer value) { public static EPayPage of(Integer value) {
for (EPayFrom e : EPayFrom.values()) { for (EPayPage e : EPayPage.values()) {
if (e.getValue().equals(value)) { if (e.getValue().equals(value)) {
return e; return e;
} }

View File

@ -1,7 +1,8 @@
package com.ruoyi.xkt.manager; package com.ruoyi.xkt.manager;
import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.enums.EPayChannel; import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EPayFrom; import com.ruoyi.xkt.enums.EPayPage;
/** /**
* @author liangyq * @author liangyq
@ -18,10 +19,10 @@ public interface PaymentManager {
/** /**
* *
* *
* @param storeOrderId * @param order
* @param payFrom * @param payFrom
* @return ///& * @return ///&
*/ */
String payForOrder(Long storeOrderId, EPayFrom payFrom); String payOrder(StoreOrderInfo order, EPayPage payFrom);
} }

View File

@ -1,6 +1,5 @@
package com.ruoyi.xkt.manager.impl; package com.ruoyi.xkt.manager.impl;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient; import com.alipay.api.AlipayClient;
@ -8,23 +7,18 @@ import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest; import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest; import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.xkt.domain.AlipayCallback;
import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.dto.finance.AlipayReqDTO; import com.ruoyi.xkt.dto.finance.AlipayReqDTO;
import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.enums.EPayChannel; import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EPayFrom; import com.ruoyi.xkt.enums.EPayPage;
import com.ruoyi.xkt.enums.EPayStatus;
import com.ruoyi.xkt.manager.PaymentManager; import com.ruoyi.xkt.manager.PaymentManager;
import com.ruoyi.xkt.service.IAlipayCallbackService;
import com.ruoyi.xkt.service.IStoreOrderService;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/** /**
* @author liangyq * @author liangyq
* @date 2025-04-06 19:36 * @date 2025-04-06 19:36
@ -33,6 +27,9 @@ import java.math.BigDecimal;
@Getter @Getter
@Component @Component
public class AliPaymentMangerImpl implements PaymentManager { public class AliPaymentMangerImpl implements PaymentManager {
private static final String DEFAULT_FORMAT = "json";
private static final String PAY_PRODUCT_CODE = "FAST_INSTANT_TRADE_PAY";
/** /**
* ID,APPIDAPPID * ID,APPIDAPPID
*/ */
@ -74,29 +71,25 @@ public class AliPaymentMangerImpl implements PaymentManager {
@Value("${alipay.gatewayUrl:https://openapi-sandbox.dl.alipaydev.com/gateway.do}") @Value("${alipay.gatewayUrl:https://openapi-sandbox.dl.alipaydev.com/gateway.do}")
private String gatewayUrl; private String gatewayUrl;
@Autowired
private IStoreOrderService storeOrderService;
@Autowired
private IAlipayCallbackService alipayCallbackService;
@Override @Override
public EPayChannel channel() { public EPayChannel channel() {
return EPayChannel.ALI_PAY; return EPayChannel.ALI_PAY;
} }
@Override @Override
public String payForOrder(Long storeOrderId, EPayFrom payFrom) { public String payOrder(StoreOrderInfo orderInfo, EPayPage payFrom) {
Assert.notNull(storeOrderId); Assert.notNull(orderInfo);
Assert.notNull(payFrom); Assert.notNull(payFrom);
//订单状态更新为支付中 if (!EPayStatus.PAYING.getValue().equals(orderInfo.getOrder().getPayStatus())) {
StoreOrderInfo order = storeOrderService.preparePayOrder(storeOrderId); throw new ServiceException("订单[" + orderInfo.getOrder().getOrderNo() + "]支付状态异常");
}
AlipayReqDTO reqDTO = new AlipayReqDTO(); AlipayReqDTO reqDTO = new AlipayReqDTO();
reqDTO.setOutTradeNo(order.getOrder().getOrderNo()); reqDTO.setOutTradeNo(orderInfo.getOrder().getOrderNo());
reqDTO.setTotalAmount(order.getOrder().getTotalAmount().toPlainString()); reqDTO.setTotalAmount(orderInfo.getOrder().getTotalAmount().toPlainString());
reqDTO.setSubject("代发订单" + order.getOrder().getOrderNo()); reqDTO.setSubject("代发订单" + orderInfo.getOrder().getOrderNo());
reqDTO.setProductCode("FAST_INSTANT_TRADE_PAY"); //这个是固定的 reqDTO.setProductCode(PAY_PRODUCT_CODE); //这个是固定的
String reqStr = JSON.toJSONString(reqDTO); String reqStr = JSON.toJSONString(reqDTO);
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", charset, AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, DEFAULT_FORMAT, charset,
alipayPublicKey, signType); alipayPublicKey, signType);
switch (payFrom) { switch (payFrom) {
case WEB: case WEB:
@ -126,19 +119,4 @@ public class AliPaymentMangerImpl implements PaymentManager {
} }
} }
public void processAlipayCallback(AlipayCallback alipayCallback) {
AlipayCallback info = alipayCallbackService.getByNotifyId(alipayCallback.getNotifyId());
if (info == null) {
//保存到数据库
info = alipayCallback;
alipayCallbackService.insertAlipayCallback(info);
}
if (info.getRefundFee() != null &&
!NumberUtil.equals(info.getRefundFee(), BigDecimal.ZERO)) {
//如果有退款金额,可能是部分退款的回调,这里不做处理
return;
}
//TODO
}
} }

View File

@ -24,4 +24,10 @@ public interface IAlipayCallbackService {
*/ */
int insertAlipayCallback(AlipayCallback alipayCallback); int insertAlipayCallback(AlipayCallback alipayCallback);
/**
*
*
* @param info
*/
void processOrderPay(AlipayCallback info);
} }

View File

@ -2,7 +2,10 @@ package com.ruoyi.xkt.service;
import com.ruoyi.xkt.domain.StoreOrder; import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO; import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResult;
import com.ruoyi.xkt.dto.order.StoreOrderInfo; import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EPayPage;
/** /**
* @author liangyq * @author liangyq
@ -12,10 +15,14 @@ public interface IStoreOrderService {
/** /**
* *
* *
* @param storeOrderAddDTO * @param storeOrderAddDTO
* @param beginPay
* @param payChannel
* @param payPage
* @return * @return
*/ */
StoreOrderInfo createOrder(StoreOrderAddDTO storeOrderAddDTO); StoreOrderAddResult createOrder(StoreOrderAddDTO storeOrderAddDTO, boolean beginPay, EPayChannel payChannel,
EPayPage payPage);
/** /**
* *
@ -31,4 +38,13 @@ public interface IStoreOrderService {
* @param storeOrderId * @param storeOrderId
*/ */
StoreOrderInfo preparePayOrder(Long storeOrderId); StoreOrderInfo preparePayOrder(Long storeOrderId);
/**
*
* TODO
*
* @param storeOrderId
* @return
*/
StoreOrderInfo paySuccess(Long storeOrderId);
} }

View File

@ -2,8 +2,14 @@ package com.ruoyi.xkt.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.xkt.domain.AlipayCallback; import com.ruoyi.xkt.domain.AlipayCallback;
import com.ruoyi.xkt.domain.StoreOrder;
import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.enums.EPayChannel;
import com.ruoyi.xkt.enums.EProcessStatus;
import com.ruoyi.xkt.mapper.AlipayCallbackMapper; import com.ruoyi.xkt.mapper.AlipayCallbackMapper;
import com.ruoyi.xkt.service.IAlipayCallbackService; import com.ruoyi.xkt.service.IAlipayCallbackService;
import com.ruoyi.xkt.service.IFinanceBillService;
import com.ruoyi.xkt.service.IStoreOrderService;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,6 +24,10 @@ public class AlipayCallbackServiceImpl implements IAlipayCallbackService {
@Autowired @Autowired
private AlipayCallbackMapper alipayCallbackMapper; private AlipayCallbackMapper alipayCallbackMapper;
@Autowired
private IStoreOrderService storeOrderService;
@Autowired
private IFinanceBillService financeBillService;
@Override @Override
@ -33,4 +43,18 @@ public class AlipayCallbackServiceImpl implements IAlipayCallbackService {
Assert.notNull(alipayCallback); Assert.notNull(alipayCallback);
return alipayCallbackMapper.insert(alipayCallback); return alipayCallbackMapper.insert(alipayCallback);
} }
@Transactional
@Override
public void processOrderPay(AlipayCallback info) {
//更新回调状态
info.setProcessStatus(EProcessStatus.SUCCESS.getValue());
alipayCallbackMapper.updateById(info);
//更新订单状态
StoreOrder order = storeOrderService.getByOrderNo(info.getOutTradeNo());
Assert.notNull(order);
StoreOrderInfo orderInfo = storeOrderService.paySuccess(order.getId());
//创建收款单
financeBillService.createCollectionBillAfterOrderPaid(orderInfo, info.getId(), EPayChannel.ALI_PAY);
}
} }

View File

@ -13,9 +13,11 @@ import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.*; import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.express.ExpressContactDTO; import com.ruoyi.xkt.dto.express.ExpressContactDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddDTO; import com.ruoyi.xkt.dto.order.StoreOrderAddDTO;
import com.ruoyi.xkt.dto.order.StoreOrderAddResult;
import com.ruoyi.xkt.dto.order.StoreOrderInfo; import com.ruoyi.xkt.dto.order.StoreOrderInfo;
import com.ruoyi.xkt.dto.order.StoreOrderOperationRecordAddDTO; import com.ruoyi.xkt.dto.order.StoreOrderOperationRecordAddDTO;
import com.ruoyi.xkt.enums.*; import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.manager.PaymentManager;
import com.ruoyi.xkt.mapper.*; import com.ruoyi.xkt.mapper.*;
import com.ruoyi.xkt.service.IExpressService; import com.ruoyi.xkt.service.IExpressService;
import com.ruoyi.xkt.service.IOperationRecordService; import com.ruoyi.xkt.service.IOperationRecordService;
@ -40,21 +42,24 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
@Autowired @Autowired
private StoreOrderDetailMapper storeOrderDetailMapper; private StoreOrderDetailMapper storeOrderDetailMapper;
@Autowired @Autowired
private IExpressService expressService;
@Autowired
private IOperationRecordService operationRecordService;
@Autowired
private StoreProductMapper storeProductMapper; private StoreProductMapper storeProductMapper;
@Autowired @Autowired
private StoreProductColorSizeMapper storeProductColorSizeMapper; private StoreProductColorSizeMapper storeProductColorSizeMapper;
@Autowired @Autowired
private StoreProductColorPriceMapper storeProductColorPriceMapper; private StoreProductColorPriceMapper storeProductColorPriceMapper;
@Autowired @Autowired
private IExpressService expressService;
@Autowired
private IOperationRecordService operationRecordService;
@Autowired
private IVoucherSequenceService voucherSequenceService; private IVoucherSequenceService voucherSequenceService;
@Autowired
private List<PaymentManager> paymentManagers;
@Transactional @Transactional
@Override @Override
public StoreOrderInfo createOrder(StoreOrderAddDTO storeOrderAddDTO) { public StoreOrderAddResult createOrder(StoreOrderAddDTO storeOrderAddDTO, boolean beginPay, EPayChannel payChannel,
EPayPage payPage) {
Long orderUserId = storeOrderAddDTO.getOrderUserId(); Long orderUserId = storeOrderAddDTO.getOrderUserId();
Long storeId = storeOrderAddDTO.getStoreId(); Long storeId = storeOrderAddDTO.getStoreId();
Long expressId = storeOrderAddDTO.getExpressId(); Long expressId = storeOrderAddDTO.getExpressId();
@ -81,7 +86,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
orderDetail.setStoreProdColorSizeId(spcs.getId()); orderDetail.setStoreProdColorSizeId(spcs.getId());
orderDetail.setStoreProdId(spcs.getStoreProdId()); orderDetail.setStoreProdId(spcs.getStoreProdId());
orderDetail.setDetailStatus(EOrderStatus.PENDING_PAYMENT.getValue()); orderDetail.setDetailStatus(EOrderStatus.PENDING_PAYMENT.getValue());
orderDetail.setPayStatus(EPayStatus.INIT.getValue()); orderDetail.setPayStatus(beginPay ? EPayStatus.PAYING.getValue() : EPayStatus.INIT.getValue());
orderDetail.setExpressStatus(EExpressStatus.INIT.getValue()); orderDetail.setExpressStatus(EExpressStatus.INIT.getValue());
//计算明细费用 //计算明细费用
BigDecimal goodsPrice = calcPrice(orderUserId, spcs); BigDecimal goodsPrice = calcPrice(orderUserId, spcs);
@ -122,7 +127,7 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
order.setOrderNo(orderNo); order.setOrderNo(orderNo);
order.setOrderType(EOrderType.SALES_ORDER.getValue()); order.setOrderType(EOrderType.SALES_ORDER.getValue());
order.setOrderStatus(EOrderStatus.PENDING_PAYMENT.getValue()); order.setOrderStatus(EOrderStatus.PENDING_PAYMENT.getValue());
order.setPayStatus(EPayStatus.INIT.getValue()); order.setPayStatus(beginPay ? EPayStatus.PAYING.getValue() : EPayStatus.INIT.getValue());
order.setOrderRemark(storeOrderAddDTO.getOrderRemark()); order.setOrderRemark(storeOrderAddDTO.getOrderRemark());
order.setGoodsQuantity(orderGoodsQuantity); order.setGoodsQuantity(orderGoodsQuantity);
order.setGoodsAmount(orderGoodsAmount); order.setGoodsAmount(orderGoodsAmount);
@ -160,7 +165,14 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
}); });
//操作记录 //操作记录
addOperationRecords(orderId, orderDetailIdList, orderUserId, new Date(), EOrderAction.ADD_ORDER); addOperationRecords(orderId, orderDetailIdList, orderUserId, new Date(), EOrderAction.ADD_ORDER);
return new StoreOrderInfo(order, orderDetailList); StoreOrderInfo orderInfo = new StoreOrderInfo(order, orderDetailList);
String rtnStr = null;
if (beginPay) {
//发起支付
PaymentManager paymentManager = getPaymentManager(payChannel);
rtnStr = paymentManager.payOrder(orderInfo, payPage);
}
return new StoreOrderAddResult(orderInfo, rtnStr);
} }
@Override @Override
@ -178,33 +190,64 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
Assert.isTrue(EOrderType.SALES_ORDER.getValue().equals(order.getOrderType()), Assert.isTrue(EOrderType.SALES_ORDER.getValue().equals(order.getOrderType()),
"非销售订单无法发起支付"); "非销售订单无法发起支付");
Assert.isTrue(BeanValidators.exists(order), "订单不存在"); Assert.isTrue(BeanValidators.exists(order), "订单不存在");
checkPreparePayStatus(order.getPayStatus());
order.setPayStatus(EPayStatus.PAYING.getValue());
int orderSuccess = storeOrderMapper.updateById(order);
if (orderSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
}
List<StoreOrderDetail> orderDetails = storeOrderDetailMapper.selectList( List<StoreOrderDetail> orderDetails = storeOrderDetailMapper.selectList(
Wrappers.lambdaQuery(StoreOrderDetail.class) Wrappers.lambdaQuery(StoreOrderDetail.class)
.eq(StoreOrderDetail::getStoreOrderId, storeOrderId) .eq(StoreOrderDetail::getStoreOrderId, storeOrderId)
.eq(SimpleEntity::getDelFlag, Constants.UNDELETED)); .eq(SimpleEntity::getDelFlag, Constants.UNDELETED));
checkPreparePayStatus(order.getPayStatus());
StoreOrder updateOrder = new StoreOrder();
updateOrder.setId(storeOrderId);
updateOrder.setPayStatus(EPayStatus.PAYING.getValue());
updateOrder.setVersion(order.getVersion());
int orderSuccess = storeOrderMapper.updateById(updateOrder);
if (orderSuccess == 0) {
throw new ServiceException("系统繁忙请稍后再试");
}
for (StoreOrderDetail orderDetail : orderDetails) { for (StoreOrderDetail orderDetail : orderDetails) {
checkPreparePayStatus(orderDetail.getPayStatus()); checkPreparePayStatus(orderDetail.getPayStatus());
StoreOrderDetail orderDetailUpdate = new StoreOrderDetail(); orderDetail.setPayStatus(EPayStatus.PAYING.getValue());
orderDetailUpdate.setId(orderDetail.getId()); int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetail);
orderDetailUpdate.setPayStatus(EPayStatus.PAYING.getValue());
orderDetailUpdate.setVersion(orderDetail.getVersion());
int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetailUpdate);
if (orderDetailSuccess == 0) { if (orderDetailSuccess == 0) {
throw new ServiceException("系统繁忙请稍后再试"); throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
} }
} }
return new StoreOrderInfo(order, orderDetails); return new StoreOrderInfo(order, orderDetails);
} }
@Transactional
@Override
public StoreOrderInfo paySuccess(Long storeOrderId) {
Assert.notNull(storeOrderId);
StoreOrder order = storeOrderMapper.selectById(storeOrderId);
Assert.isTrue(EOrderType.SALES_ORDER.getValue().equals(order.getOrderType()),
"订单类型异常");
Assert.isTrue(BeanValidators.exists(order), "订单不存在");
Assert.isTrue(order.getPayStatus().equals(EPayStatus.PAYING.getValue()), "订单支付状态异常");
order.setPayStatus(EPayStatus.PAID.getValue());
//TODO 暂时使用总金额
order.setRealTotalAmount(order.getTotalAmount());
int orderSuccess = storeOrderMapper.updateById(order);
if (orderSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
}
List<StoreOrderDetail> orderDetails = storeOrderDetailMapper.selectList(
Wrappers.lambdaQuery(StoreOrderDetail.class)
.eq(StoreOrderDetail::getStoreOrderId, storeOrderId)
.eq(SimpleEntity::getDelFlag, Constants.UNDELETED));
List<Long> orderDetailIdList = new ArrayList<>(orderDetails.size());
for (StoreOrderDetail orderDetail : orderDetails) {
Assert.isTrue(orderDetail.getPayStatus().equals(EPayStatus.PAYING.getValue()),
"订单明细支付状态异常");
orderDetail.setPayStatus(EPayStatus.PAID.getValue());
orderDetail.setRealTotalAmount(orderDetail.getTotalAmount());
int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetail);
if (orderDetailSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
}
orderDetailIdList.add(orderDetail.getId());
}
//操作记录
addOperationRecords(storeOrderId, orderDetailIdList, null, new Date(), EOrderAction.PAID_ORDER);
return new StoreOrderInfo(order, orderDetails);
}
private void checkPreparePayStatus(Integer payStatus) { private void checkPreparePayStatus(Integer payStatus) {
if (!EPayStatus.INIT.getValue().equals(payStatus) && !EPayStatus.PAYING.getValue().equals(payStatus)) { if (!EPayStatus.INIT.getValue().equals(payStatus) && !EPayStatus.PAYING.getValue().equals(payStatus)) {
throw new ServiceException("订单状态异常无法发起支付"); throw new ServiceException("订单状态异常无法发起支付");
@ -328,4 +371,22 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
} }
return spcsMap; return spcsMap;
} }
/**
*
*
* @param payChannel
* @return
*/
private PaymentManager getPaymentManager(EPayChannel payChannel) {
if (payChannel == null) {
throw new ServiceException("请先选择支付渠道");
}
for (PaymentManager paymentManager : paymentManagers) {
if (paymentManager.channel() == payChannel) {
return paymentManager;
}
}
throw new ServiceException("未知支付渠道");
}
} }