mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-02 10:36:57 +00:00
(cashfeatier): 添加收银台支付功能
- 新增收银台类型枚举和相关参数类 - 实现收银台订单创建和支付逻辑 - 添加收银台配置管理和查询功能- 优化支付辅助服务,增加订单状态检查和限额验证
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package org.dromara.daxpay.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.dromara.daxpay.core.exception.ConfigNotExistException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 收银台类型
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CheckoutTypeEnum {
|
||||
|
||||
H5("h5", "H5"),
|
||||
PC("pc", "PC"),
|
||||
MINI_APP("app", "APP"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
|
||||
public static CheckoutTypeEnum findBuyCode(String code){
|
||||
return Arrays.stream(CheckoutTypeEnum.values())
|
||||
.filter(value -> Objects.equals(value.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new ConfigNotExistException("不支持的收银台类型"));
|
||||
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package org.dromara.daxpay.core.param.assist;
|
||||
|
||||
import org.dromara.daxpay.core.param.PaymentCommonParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 查询OpenId参数
|
||||
* @author xxm
|
||||
* @since 2024/9/19
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "查询OpenId参数")
|
||||
public class QueryAuthParam extends PaymentCommonParam {
|
||||
|
||||
@Schema(description = "标识码")
|
||||
private String queryCode;
|
||||
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
package org.dromara.daxpay.core.param.cashier;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.daxpay.core.enums.CheckoutTypeEnum;
|
||||
import org.dromara.daxpay.core.param.PaymentCommonParam;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 收银台创建参数
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "收银台创建参数")
|
||||
public class CheckoutParam extends PaymentCommonParam {
|
||||
|
||||
/**
|
||||
* 收银台类型
|
||||
* @see CheckoutTypeEnum
|
||||
*/
|
||||
@NotBlank(message = "收银台类型不可为空")
|
||||
private String checkoutType;
|
||||
|
||||
/** 商户订单号 */
|
||||
@Schema(description = "商户订单号")
|
||||
@NotBlank(message = "商户订单号不可为空")
|
||||
@Size(max = 100, message = "商户订单号不可超过100位")
|
||||
private String bizOrderNo;
|
||||
|
||||
/** 支付标题 */
|
||||
@Schema(description = "支付标题")
|
||||
@NotBlank(message = "支付标题不可为空")
|
||||
@Size(max = 100, message = "支付标题不可超过100位")
|
||||
private String title;
|
||||
|
||||
/** 支付描述 */
|
||||
@Schema(description = "支付描述")
|
||||
@Size(max = 500, message = "支付描述不可超过500位")
|
||||
private String description;
|
||||
|
||||
/** 是否开启分账 */
|
||||
@Schema(description = "是否开启分账")
|
||||
private Boolean allocation;
|
||||
|
||||
/** 自动分账 */
|
||||
@Schema(description = "自动分账")
|
||||
private Boolean autoAllocation;
|
||||
|
||||
/** 过期时间 */
|
||||
@Schema(description = "过期时间")
|
||||
@JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
|
||||
private LocalDateTime expiredTime;
|
||||
|
||||
/** 支付金额 */
|
||||
@Schema(description = "支付金额")
|
||||
@NotNull(message = "支付金额不可为空")
|
||||
@DecimalMin(value = "0.01", message = "支付金额不可小于0.01元")
|
||||
@Digits(integer = 8, fraction = 2, message = "支付金额精度到分, 且要小于一亿元")
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 支付扩展参数
|
||||
*/
|
||||
@Schema(description = "支付扩展参数")
|
||||
@Size(max = 2048, message = "支付扩展参数不可超过2048位")
|
||||
private String extraParam;
|
||||
|
||||
/** 商户扩展参数,回调时会原样返回 */
|
||||
@Schema(description = "商户扩展参数")
|
||||
@Size(max = 500, message = "商户扩展参数不可超过500位")
|
||||
private String attach;
|
||||
|
||||
/** 同步跳转地址, 支付完毕后用户浏览器返回到该地址, 不传输跳转到默认地址 */
|
||||
@Schema(description = "同步通知URL")
|
||||
@Size(max = 200, message = "同步通知URL不可超过200位")
|
||||
private String returnUrl;
|
||||
|
||||
/** 异步通知地址 */
|
||||
@Schema(description = "异步通知地址")
|
||||
@Size(max = 200, message = "异步通知地址不可超过200位")
|
||||
private String notifyUrl;
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package org.dromara.daxpay.core.param.cashier;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 收银台支付参数
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "收银台支付参数")
|
||||
public class CheckoutPayParam {
|
||||
|
||||
@Schema(description = "要支付的订单号")
|
||||
private String bizOrderNo;
|
||||
|
||||
@Schema(description = "支付配置项ID")
|
||||
private Long itemId;
|
||||
|
||||
@Schema(description = "唯一标识")
|
||||
private String openId;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package org.dromara.daxpay.core.result.cashier;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 收银台订单结算和配置信息
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "收银台订单结算和配置信息")
|
||||
public class CheckoutInfoResult {
|
||||
/** 订单信息 */
|
||||
|
||||
/** 配置信息 */
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package org.dromara.daxpay.core.result.cashier;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 收银台响应参数
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "收银台响应参数")
|
||||
public class CheckoutUrlResult {
|
||||
|
||||
@Schema(description = "收银台链接")
|
||||
private String url;
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package org.dromara.daxpay.service.controller.unipay;
|
||||
|
||||
import cn.bootx.platform.core.rest.Res;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.daxpay.core.param.cashier.CheckoutParam;
|
||||
import org.dromara.daxpay.core.param.cashier.CheckoutPayParam;
|
||||
import org.dromara.daxpay.core.result.DaxResult;
|
||||
import org.dromara.daxpay.core.result.cashier.CheckoutUrlResult;
|
||||
import org.dromara.daxpay.core.util.DaxRes;
|
||||
import org.dromara.daxpay.service.common.anno.PaymentVerify;
|
||||
import org.dromara.daxpay.service.service.cashier.CheckoutService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 收银台服务
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Tag(name = "收银台服务")
|
||||
@RestController
|
||||
@RequestMapping("/unipay/checkout")
|
||||
@RequiredArgsConstructor
|
||||
public class CheckoutController {
|
||||
private final CheckoutService checkoutService;
|
||||
|
||||
@PaymentVerify
|
||||
@Operation(summary = "创建一个收银台链接")
|
||||
@PostMapping("/creat")
|
||||
public DaxResult<CheckoutUrlResult> creat(@RequestBody CheckoutParam checkoutParam){
|
||||
return DaxRes.ok(checkoutService.creat(checkoutParam));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取收银台订单信息")
|
||||
@GetMapping("/info")
|
||||
public Result<Void> getInfo(){
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "发起支付")
|
||||
@PostMapping("/pay")
|
||||
public Result<Void> pay(@RequestBody CheckoutPayParam checkoutParam){
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package org.dromara.daxpay.service.dao.config.checkout;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.service.entity.config.checkout.CheckoutItemConfig;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* 收银台配置项
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class CheckoutItemConfigManager extends BaseManager<CheckoutItemConfigMapper, CheckoutItemConfig> {
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package org.dromara.daxpay.service.dao.config.checkout;
|
||||
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.daxpay.service.entity.config.checkout.CheckoutItemConfig;
|
||||
|
||||
/**
|
||||
* 收银台配置项
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Mapper
|
||||
public interface CheckoutItemConfigMapper extends MPJBaseMapper<CheckoutItemConfig> {
|
||||
}
|
@@ -1,9 +1,13 @@
|
||||
package org.dromara.daxpay.service.entity.config.checkout;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
|
||||
import org.dromara.daxpay.service.convert.config.CheckoutGroupConfigConvert;
|
||||
import org.dromara.daxpay.service.param.config.checkout.CheckoutGroupConfigParam;
|
||||
import org.dromara.daxpay.service.result.config.checkout.CheckoutGroupConfigResult;
|
||||
|
||||
/**
|
||||
* 收银台类目配置
|
||||
@@ -13,7 +17,7 @@ import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CheckoutGroupConfig extends MchAppBaseEntity {
|
||||
public class CheckoutGroupConfig extends MchAppBaseEntity implements ToResult<CheckoutGroupConfigResult> {
|
||||
|
||||
/** 类型 web/h5/小程序 */
|
||||
private String type;
|
||||
@@ -23,4 +27,16 @@ public class CheckoutGroupConfig extends MchAppBaseEntity {
|
||||
|
||||
/** 排序 */
|
||||
private Double sort;
|
||||
|
||||
public static CheckoutGroupConfig init(CheckoutGroupConfigParam param){
|
||||
return CheckoutGroupConfigConvert.CONVERT.toEntity(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
@Override
|
||||
public CheckoutGroupConfigResult toResult() {
|
||||
return CheckoutGroupConfigConvert.CONVERT.toResult(this);
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,15 @@
|
||||
package org.dromara.daxpay.service.entity.config.checkout;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.daxpay.core.enums.ChannelEnum;
|
||||
import org.dromara.daxpay.core.enums.PayMethodEnum;
|
||||
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
|
||||
import org.dromara.daxpay.service.convert.config.CheckoutItemConfigConvert;
|
||||
import org.dromara.daxpay.service.param.config.checkout.CheckoutItemConfigParam;
|
||||
import org.dromara.daxpay.service.result.config.checkout.CheckoutItemConfigResult;
|
||||
|
||||
/**
|
||||
* 收银台配置项
|
||||
@@ -15,7 +19,7 @@ import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CheckoutItemConfig extends MchAppBaseEntity {
|
||||
public class CheckoutItemConfig extends MchAppBaseEntity implements ToResult<CheckoutItemConfigResult> {
|
||||
|
||||
/** 类目配置Id */
|
||||
private Long classifyId;
|
||||
@@ -38,4 +42,28 @@ public class CheckoutItemConfig extends MchAppBaseEntity {
|
||||
/** 是否开启分账 */
|
||||
private boolean allocation;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
* 1. 扫码支付
|
||||
* 2. 条码支付
|
||||
* 3. 跳转链接
|
||||
* 4. 小程序支付
|
||||
* 5. 聚合支付
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public static CheckoutItemConfig init(CheckoutItemConfigParam param) {
|
||||
return CheckoutItemConfigConvert.CONVERT.toEntity(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
@Override
|
||||
public CheckoutItemConfigResult toResult() {
|
||||
return CheckoutItemConfigConvert.CONVERT.toResult(this);
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 支付订单
|
||||
* 支付订单显示对象, 不与 PayOrderResult重名
|
||||
* @author xxm
|
||||
* @since 2021/2/25
|
||||
*/
|
||||
|
@@ -0,0 +1,151 @@
|
||||
package org.dromara.daxpay.service.service.cashier;
|
||||
|
||||
import cn.bootx.platform.core.exception.ValidationFailedException;
|
||||
import cn.bootx.platform.core.util.BigDecimalUtil;
|
||||
import cn.bootx.platform.core.util.DateTimeUtil;
|
||||
import cn.bootx.platform.starter.redis.delay.service.DelayJobService;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.core.enums.PayAllocStatusEnum;
|
||||
import org.dromara.daxpay.core.enums.PayRefundStatusEnum;
|
||||
import org.dromara.daxpay.core.enums.PayStatusEnum;
|
||||
import org.dromara.daxpay.core.exception.AmountExceedLimitException;
|
||||
import org.dromara.daxpay.core.exception.TradeStatusErrorException;
|
||||
import org.dromara.daxpay.core.param.cashier.CheckoutParam;
|
||||
import org.dromara.daxpay.core.util.PayUtil;
|
||||
import org.dromara.daxpay.core.util.TradeNoGenerateUtil;
|
||||
import org.dromara.daxpay.service.code.DaxPayCode;
|
||||
import org.dromara.daxpay.service.common.context.MchAppLocal;
|
||||
import org.dromara.daxpay.service.common.local.PaymentContextLocal;
|
||||
import org.dromara.daxpay.service.dao.order.pay.PayOrderManager;
|
||||
import org.dromara.daxpay.service.entity.order.pay.PayOrder;
|
||||
import org.dromara.daxpay.service.service.order.pay.PayOrderQueryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 收银台支撑服务
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CheckoutAssistService {
|
||||
private final DelayJobService delayJobService;
|
||||
private final PayOrderManager payOrderManager;
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
|
||||
/**
|
||||
* 校验支付状态,支付成功则返回,支付失败则抛出对应的异常
|
||||
*/
|
||||
public PayOrder getOrderAndCheck(String orderNo) {
|
||||
PayOrder payOrder = payOrderQueryService.findByOrderNo(orderNo).orElse(null);
|
||||
return getOrderAndCheck(payOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验支付状态,支付成功则返回,支付失败则抛出对应的异常
|
||||
*/
|
||||
public PayOrder getOrderAndCheck(CheckoutParam param) {
|
||||
// 根据订单查询支付记录
|
||||
PayOrder payOrder = payOrderQueryService.findByBizOrderNo(param.getBizOrderNo(), param.getAppId()).orElse(null);
|
||||
return getOrderAndCheck(payOrder);
|
||||
}/**
|
||||
* 校验支付状态,支付成功则返回,支付失败则抛出对应的异常
|
||||
*/
|
||||
public PayOrder getOrderAndCheck(PayOrder payOrder) {
|
||||
if (Objects.nonNull(payOrder)) {
|
||||
// 已经支付状态
|
||||
if (PayStatusEnum.SUCCESS.getCode()
|
||||
.equals(payOrder.getStatus())) {
|
||||
throw new TradeStatusErrorException("已经支付成功,请勿重新支付");
|
||||
}
|
||||
// 支付失败类型状态
|
||||
List<String> tradesStatus = List.of(
|
||||
PayStatusEnum.FAIL.getCode(),
|
||||
PayStatusEnum.CLOSE.getCode(),
|
||||
PayStatusEnum.CANCEL.getCode());
|
||||
if (tradesStatus.contains(payOrder.getStatus())) {
|
||||
throw new TradeStatusErrorException("支付失败或已经被关闭");
|
||||
}
|
||||
// 退款类型状态
|
||||
if (Objects.equals(payOrder.getRefundStatus(), PayRefundStatusEnum.REFUNDING.getCode())) {
|
||||
throw new TradeStatusErrorException("该订单处于退款状态");
|
||||
}
|
||||
// 其他状态直接抛出兜底异常
|
||||
throw new TradeStatusErrorException("订单不是待支付状态,请重新确认订单状态");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验订单是否超过限额
|
||||
*/
|
||||
public void validationLimitAmount(CheckoutParam checkoutParam) {
|
||||
MchAppLocal mchAppInfo = PaymentContextLocal.get()
|
||||
.getMchAppInfo();
|
||||
// 总额校验
|
||||
if (BigDecimalUtil.isGreaterThan(checkoutParam.getAmount(),mchAppInfo.getLimitAmount())) {
|
||||
throw new AmountExceedLimitException("支付金额超过限额");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验订单超时时间是否正常
|
||||
*/
|
||||
public void validationExpiredTime(CheckoutParam payParam) {
|
||||
LocalDateTime expiredTime = this.getExpiredTime(payParam);
|
||||
if (Objects.nonNull(expiredTime) && DateTimeUtil.lt(expiredTime,LocalDateTime.now())) {
|
||||
throw new ValidationFailedException("支付超时时间设置有误, 请检查!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 创建支付订单并保存, 返回支付订单
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PayOrder createPayOrder(CheckoutParam checkoutParam) {
|
||||
// 订单超时时间
|
||||
LocalDateTime expiredTime = this.getExpiredTime(checkoutParam);
|
||||
// 构建支付订单对象
|
||||
PayOrder order = new PayOrder();
|
||||
BeanUtil.copyProperties(checkoutParam, order);
|
||||
order.setOrderNo(TradeNoGenerateUtil.pay())
|
||||
.setStatus(PayStatusEnum.WAIT.getCode())
|
||||
.setRefundStatus(PayRefundStatusEnum.NO_REFUND.getCode())
|
||||
.setExpiredTime(expiredTime)
|
||||
.setRefundableBalance(checkoutParam.getAmount());
|
||||
// 如果支持分账, 设置分账状态为待分账
|
||||
if (order.getAllocation()) {
|
||||
order.setAllocStatus(PayAllocStatusEnum.WAITING.getCode());
|
||||
}
|
||||
payOrderManager.save(order);
|
||||
// 注册支付超时任务
|
||||
delayJobService.registerByTransaction(order.getId(), DaxPayCode.Event.MERCHANT_PAY_TIMEOUT, order.getExpiredTime());
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取支付订单超时时间
|
||||
*/
|
||||
private LocalDateTime getExpiredTime(CheckoutParam payParam) {
|
||||
MchAppLocal mchAppLocal = PaymentContextLocal.get().getMchAppInfo();
|
||||
// 支付参数传入
|
||||
if (Objects.nonNull(payParam.getExpiredTime())) {
|
||||
return payParam.getExpiredTime();
|
||||
}
|
||||
// 根据商户应用配置计算出时间
|
||||
return PayUtil.getPaymentExpiredTime(mchAppLocal.getOrderTimeout());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
package org.dromara.daxpay.service.service.cashier;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.core.enums.CheckoutTypeEnum;
|
||||
import org.dromara.daxpay.core.exception.TradeProcessingException;
|
||||
import org.dromara.daxpay.core.exception.UnsupportedAbilityException;
|
||||
import org.dromara.daxpay.core.param.cashier.CheckoutParam;
|
||||
import org.dromara.daxpay.core.result.cashier.CheckoutUrlResult;
|
||||
import org.dromara.daxpay.service.entity.config.PlatformConfig;
|
||||
import org.dromara.daxpay.service.entity.order.pay.PayOrder;
|
||||
import org.dromara.daxpay.service.service.assist.PaymentAssistService;
|
||||
import org.dromara.daxpay.service.service.config.CheckoutConfigService;
|
||||
import org.dromara.daxpay.service.service.config.PlatformConfigService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 收银台服务
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CheckoutService {
|
||||
private final CheckoutAssistService payAssistService;
|
||||
private final LockTemplate lockTemplate;
|
||||
private final PlatformConfigService platformConfigService;
|
||||
private final PaymentAssistService paymentAssistService;
|
||||
private final CheckoutConfigService checkoutConfigService;
|
||||
|
||||
/**
|
||||
* 生成收银台链接
|
||||
*/
|
||||
public CheckoutUrlResult creat(CheckoutParam checkoutParam){
|
||||
// 校验支付限额
|
||||
payAssistService.validationLimitAmount(checkoutParam);
|
||||
// 校验超时时间, 不可早于当前
|
||||
payAssistService.validationExpiredTime(checkoutParam);
|
||||
// 获取商户订单号
|
||||
String bizOrderNo = checkoutParam.getBizOrderNo();
|
||||
// 加锁
|
||||
LockInfo lock = lockTemplate.lock("payment:pay:" + bizOrderNo,10000,200);
|
||||
if (Objects.isNull(lock)){
|
||||
log.warn("正在发起调起收银台中,请勿重复操作");
|
||||
throw new TradeProcessingException("正在发起调起收银台中,请勿重复操作");
|
||||
}
|
||||
try {
|
||||
// 查询并检查订单
|
||||
PayOrder payOrder = payAssistService.getOrderAndCheck(checkoutParam);
|
||||
// 订单已经存在直接返回链接, 不存在创建订单后返回链接
|
||||
if (Objects.isNull(payOrder)){
|
||||
// 执行支付前的保存动作, 保存支付订单和扩展记录
|
||||
payOrder = payAssistService.createPayOrder(checkoutParam);
|
||||
String checkoutUrl = this.getCheckoutUrl(payOrder.getOrderNo(), checkoutParam.getCheckoutType());
|
||||
return new CheckoutUrlResult().setUrl(checkoutUrl);
|
||||
} else {
|
||||
// 直接返回收银台链接
|
||||
String checkoutUrl = this.getCheckoutUrl(payOrder.getOrderNo(), checkoutParam.getCheckoutType());
|
||||
return new CheckoutUrlResult().setUrl(checkoutUrl);
|
||||
}
|
||||
} finally {
|
||||
lockTemplate.releaseLock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收银台链接
|
||||
*/
|
||||
public String getCheckoutUrl(String code, String checkoutType){
|
||||
CheckoutTypeEnum checkoutTypeEnum = CheckoutTypeEnum.findBuyCode(checkoutType);
|
||||
|
||||
PlatformConfig config = platformConfigService.getConfig();
|
||||
|
||||
switch (checkoutTypeEnum) {
|
||||
case H5 -> {
|
||||
return StrUtil.format("{}/checkout/{}",config.getGatewayMobileUrl(), code);
|
||||
}
|
||||
case PC -> {
|
||||
return StrUtil.format("{}/checkout/{}",config.getGatewayPcUrl(), code);
|
||||
}
|
||||
case MINI_APP -> {
|
||||
throw new UnsupportedAbilityException("暂不支持小程序收银台");
|
||||
}
|
||||
default -> throw new UnsupportedAbilityException("不支持的收银台类型");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收银台相关信息, 不需要签名和鉴权
|
||||
*/
|
||||
public void info(String orderNo){
|
||||
// 订单信息
|
||||
PayOrder orderAndCheck = payAssistService.getOrderAndCheck(orderNo);
|
||||
// 配置信息
|
||||
paymentAssistService.initMchApp(orderAndCheck.getAppId());
|
||||
// 获取相关配置
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package org.dromara.daxpay.service.service.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.daxpay.service.dao.config.checkout.CheckoutConfigManager;
|
||||
import org.dromara.daxpay.service.dao.config.checkout.CheckoutGroupConfigManager;
|
||||
import org.dromara.daxpay.service.dao.config.checkout.CheckoutItemConfigManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 收银台配置
|
||||
* @author xxm
|
||||
* @since 2024/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CheckoutConfigService {
|
||||
private final CheckoutConfigManager checkoutConfigManager;
|
||||
private final CheckoutGroupConfigManager checkoutGroupConfigManager;
|
||||
private final CheckoutItemConfigManager checkoutItemConfigManager;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -85,6 +85,7 @@ public class PayAssistService {
|
||||
.setReqTime(payParam.getReqTime())
|
||||
.setChannel(payParam.getChannel())
|
||||
.setMethod(payParam.getMethod())
|
||||
.setStatus(PayStatusEnum.PROGRESS.getCode())
|
||||
.setExtraParam(payParam.getExtraParam());
|
||||
if (!order.getAllocation()) {
|
||||
order.setAllocStatus(null);
|
||||
|
Reference in New Issue
Block a user