mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-14 05:42:06 +08:00
1、新增组织购买产品接口、混合支付和异步回调;2、新增微信支付和回调基础代码;3、组织余额新增有效时长内容;4、新增过期支付单处理类;
This commit is contained in:
+3
-3
@@ -21,7 +21,7 @@ import java.time.LocalDate;
|
|||||||
public class SnowflakeIdWorker3rd {
|
public class SnowflakeIdWorker3rd {
|
||||||
/** 初始时间 (2024-01-01: 1704038400) */
|
/** 初始时间 (2024-01-01: 1704038400) */
|
||||||
// private final int twepoch = 28400640;// 1704038400000L/1000/60;
|
// private final int twepoch = 28400640;// 1704038400000L/1000/60;
|
||||||
private final int twepoch = 1704038400;
|
private final int twepoch = 28400640;
|
||||||
/** 序列在id中占位数 */
|
/** 序列在id中占位数 */
|
||||||
private final long sequenceBits = 7L;
|
private final long sequenceBits = 7L;
|
||||||
/** 时间截向左移7bit */
|
/** 时间截向左移7bit */
|
||||||
@@ -122,8 +122,8 @@ public class SnowflakeIdWorker3rd {
|
|||||||
* @return 当前时间(分钟)
|
* @return 当前时间(分钟)
|
||||||
*/
|
*/
|
||||||
protected int timeGen() {
|
protected int timeGen() {
|
||||||
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
|
String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
|
||||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
// String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||||
return Integer.valueOf(timestamp);
|
return Integer.valueOf(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+45
@@ -1,9 +1,14 @@
|
|||||||
package com.cf.imes.framework.pay.config;
|
package com.cf.imes.framework.pay.config;
|
||||||
|
|
||||||
|
import com.cf.imes.framework.common.util.encrypt.AesUtils;
|
||||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gqr
|
* @author Gqr
|
||||||
* @since 2025/4/15 16:52
|
* @since 2025/4/15 16:52
|
||||||
@@ -11,4 +16,44 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
@ConfigurationProperties(prefix = "chenfeng.pay.wechat")
|
@ConfigurationProperties(prefix = "chenfeng.pay.wechat")
|
||||||
@Data
|
@Data
|
||||||
public class ChenfengWechatPayConfig extends WxPayConfig {
|
public class ChenfengWechatPayConfig extends WxPayConfig {
|
||||||
|
@Value("${chenfeng.encrypt.publicKey:}")
|
||||||
|
private String publicKey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAppId(String appId) {
|
||||||
|
if (StringUtils.isNotEmpty(publicKey)) {
|
||||||
|
super.setAppId(AesUtils.decrypt(appId, publicKey));
|
||||||
|
} else {
|
||||||
|
super.setAppId(appId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMchId(String mchId) {
|
||||||
|
if (StringUtils.isNotEmpty(publicKey)) {
|
||||||
|
super.setMchId(AesUtils.decrypt(mchId, publicKey));
|
||||||
|
} else {
|
||||||
|
super.setMchId(mchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMchKey(String mchKey) {
|
||||||
|
if (StringUtils.isNotEmpty(publicKey)) {
|
||||||
|
super.setMchKey(AesUtils.decrypt(mchKey, publicKey));
|
||||||
|
} else {
|
||||||
|
super.setMchKey(mchKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setKeyContent(byte[] keyContent) {
|
||||||
|
if (StringUtils.isNotEmpty(publicKey)) {
|
||||||
|
String encrypted = new String(keyContent, StandardCharsets.UTF_8);
|
||||||
|
String decrypted = AesUtils.decrypt(encrypted, publicKey);
|
||||||
|
super.setKeyContent(decrypted.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} else {
|
||||||
|
super.setKeyContent(keyContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -434,6 +434,7 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode RECHARGE_ACTIVE_NAME_IS_EXIST = new ErrorCode(1_002_043_022, "当前赠送金活动名称已存在,请修改");
|
public static final ErrorCode RECHARGE_ACTIVE_NAME_IS_EXIST = new ErrorCode(1_002_043_022, "当前赠送金活动名称已存在,请修改");
|
||||||
public static final ErrorCode IMAGE_UPLOAD_ERROR = new ErrorCode(1_002_043_023, "图片上传失败,请重试或重新选择图片");
|
public static final ErrorCode IMAGE_UPLOAD_ERROR = new ErrorCode(1_002_043_023, "图片上传失败,请重试或重新选择图片");
|
||||||
public static final ErrorCode ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR = new ErrorCode(1_002_043_024, "组织充值失败,请检查组织资金数据");
|
public static final ErrorCode ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR = new ErrorCode(1_002_043_024, "组织充值失败,请检查组织资金数据");
|
||||||
|
public static final ErrorCode ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR = new ErrorCode(1_002_043_025, "发起产品支付失败,组织资金已发生改变,请刷新或稍后再发起支付");
|
||||||
|
|
||||||
//=========== 支付相关 1-002-048-000 ============
|
//=========== 支付相关 1-002-048-000 ============
|
||||||
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道");
|
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道");
|
||||||
@@ -446,6 +447,9 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode PAY_RECHARGE_LOCK_EXISTS_ERROR = new ErrorCode(1_002_048_007, "组织下存在待支付的充值订单,请稍后再试");
|
public static final ErrorCode PAY_RECHARGE_LOCK_EXISTS_ERROR = new ErrorCode(1_002_048_007, "组织下存在待支付的充值订单,请稍后再试");
|
||||||
public static final ErrorCode PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR = new ErrorCode(1_002_048_008, "支付回调缺少passback_params,请检查支付渠道");
|
public static final ErrorCode PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR = new ErrorCode(1_002_048_008, "支付回调缺少passback_params,请检查支付渠道");
|
||||||
public static final ErrorCode PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR = new ErrorCode(1_002_048_009, "不支持的支付回调tradeType:【{}】,请检查支付渠道");
|
public static final ErrorCode PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR = new ErrorCode(1_002_048_009, "不支持的支付回调tradeType:【{}】,请检查支付渠道");
|
||||||
|
public static final ErrorCode PAY_PRODUCT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "现金余额不足,请选择其他支付方式!");
|
||||||
|
public static final ErrorCode PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "赠送金余额不足,请选择其他支付方式!");
|
||||||
|
public static final ErrorCode PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "可用金(现金余额+赠送金)余额不足,请选择其他支付方式!");
|
||||||
|
|
||||||
//=========== 产品相关 1-002-045-000 ============
|
//=========== 产品相关 1-002-045-000 ============
|
||||||
public static final ErrorCode PRODUCTS_NO_EXIST = new ErrorCode(1_002_045_001, "当前产品不存在");
|
public static final ErrorCode PRODUCTS_NO_EXIST = new ErrorCode(1_002_045_001, "当前产品不存在");
|
||||||
|
|||||||
+6
@@ -48,4 +48,10 @@ public enum DurationUnitEnum implements IntArrayValuable {
|
|||||||
return Objects.equals(DAY.name, name);
|
return Objects.equals(DAY.name, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DurationUnitEnum fromStatus(Integer status) {
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(bean -> Objects.equals(bean.status, status))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,10 @@
|
|||||||
<groupId>com.cf.imes</groupId>
|
<groupId>com.cf.imes</groupId>
|
||||||
<artifactId>cf-spring-boot-starter-biz-ip</artifactId>
|
<artifactId>cf-spring-boot-starter-biz-ip</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cf.imes</groupId>
|
||||||
|
<artifactId>cf-spring-boot-starter-biz-id</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
<!-- Web 相关 -->
|
||||||
|
|
||||||
@@ -244,6 +248,10 @@
|
|||||||
<groupId>com.cf.imes</groupId>
|
<groupId>com.cf.imes</groupId>
|
||||||
<artifactId>cf-spring-boot-starter-biz-ip</artifactId>
|
<artifactId>cf-spring-boot-starter-biz-ip</artifactId>
|
||||||
</include>
|
</include>
|
||||||
|
<include>
|
||||||
|
<groupId>com.cf.imes</groupId>
|
||||||
|
<artifactId>cf-spring-boot-starter-biz-id</artifactId>
|
||||||
|
</include>
|
||||||
<include>
|
<include>
|
||||||
<groupId>com.cf.imes</groupId>
|
<groupId>com.cf.imes</groupId>
|
||||||
<artifactId>cf-spring-boot-starter-biz-operatelog</artifactId>
|
<artifactId>cf-spring-boot-starter-biz-operatelog</artifactId>
|
||||||
|
|||||||
+15
@@ -21,5 +21,20 @@ public class OrganAmountRespVO {
|
|||||||
|
|
||||||
@Schema(description = "产品有效期")
|
@Schema(description = "产品有效期")
|
||||||
private String productEfficientDate;
|
private String productEfficientDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常时间,不加赠送时间
|
||||||
|
*/
|
||||||
|
@Schema(description = "产品时长")
|
||||||
|
private String duration;
|
||||||
|
|
||||||
|
@Schema(description = "产品时长单位")
|
||||||
|
private Integer durationUnit;
|
||||||
|
|
||||||
|
@Schema(description = "赠送时长")
|
||||||
|
private String giftDuration;
|
||||||
|
|
||||||
|
@Schema(description = "赠送时长单位")
|
||||||
|
private Integer giftDurationUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.organamount.vo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/8/14 15:20
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OrganPayAmountRespVO {
|
||||||
|
/**
|
||||||
|
* 可用余额
|
||||||
|
*/
|
||||||
|
private BigDecimal availableAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金余额
|
||||||
|
*/
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送金余额
|
||||||
|
*/
|
||||||
|
private BigDecimal giftAmount;
|
||||||
|
}
|
||||||
-2
@@ -1,6 +1,5 @@
|
|||||||
package com.cf.imes.module.system.controller.admin.funds.organamount.vo;
|
package com.cf.imes.module.system.controller.admin.funds.organamount.vo;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -10,7 +9,6 @@ import java.math.BigDecimal;
|
|||||||
* @author Gqr
|
* @author Gqr
|
||||||
* @since 2025/8/13 16:46
|
* @since 2025/8/13 16:46
|
||||||
*/
|
*/
|
||||||
@Schema(description = "管理后台 - 组织充值后余额信息 Response VO")
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class OrganRechargeAmountRespVO {
|
public class OrganRechargeAmountRespVO {
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.products.vo.product;
|
||||||
|
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderDO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/8/14 15:22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProductProcessorRespVO {
|
||||||
|
/**
|
||||||
|
* 购买记录
|
||||||
|
*/
|
||||||
|
private PurchaseRecordDO purchaseRecordDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收支明细
|
||||||
|
*/
|
||||||
|
private IncomeExpenseDetailsDO incomeExpenseDetailsDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部支付信息
|
||||||
|
*/
|
||||||
|
private PayOrderDO payOrderDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组织资金
|
||||||
|
*/
|
||||||
|
private OrganAmountDO organAmountDO;
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.purchase;
|
||||||
|
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 软件购买接口
|
||||||
|
*/
|
||||||
|
public interface PurchaseService {
|
||||||
|
/**
|
||||||
|
* 查询购买记录
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
PurchaseRecordDO getRecord(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建购买记录
|
||||||
|
*
|
||||||
|
* @param purchaseRecordDO
|
||||||
|
*/
|
||||||
|
void createRecord(PurchaseRecordDO purchaseRecordDO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新购买记录为可开票
|
||||||
|
*
|
||||||
|
* @param purchaseRecordId
|
||||||
|
* @param organId
|
||||||
|
*/
|
||||||
|
void updateRecordInvoicable(Long purchaseRecordId, Long organId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询组织下最早购买产品定价规则
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
OrgEarliestPurchaseProductRespVO getOrgEarliestProductDetail(Long organId);
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.purchase;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsDetailMapper;
|
||||||
|
import com.cf.imes.module.system.dal.mysql.funds.purchase.PurchaseRecordMapper;
|
||||||
|
import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 软件购买接口 实现类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class PurchaseServiceImpl implements PurchaseService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PurchaseRecordMapper purchaseRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProductsDetailMapper productsDetailMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PurchaseRecordDO getRecord(Long id) {
|
||||||
|
return purchaseRecordMapper.selectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createRecord(PurchaseRecordDO purchaseRecordDO) {
|
||||||
|
purchaseRecordMapper.insert(purchaseRecordDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateRecordInvoicable(Long purchaseRecordId, Long organId) {
|
||||||
|
purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
|
||||||
|
.eq(PurchaseRecordDO::getId, purchaseRecordId)
|
||||||
|
.eq(PurchaseRecordDO::getOrganId, organId)
|
||||||
|
.set(PurchaseRecordDO::getIsInvocing, InvoiceStatusEnum.INVOICABLE.getStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrgEarliestPurchaseProductRespVO getOrgEarliestProductDetail(Long organId) {
|
||||||
|
// 查询购买记录中还有效的最早一条
|
||||||
|
PurchaseRecordDO purchaseRecordDO = purchaseRecordMapper.selectOne(new LambdaQueryWrapper<PurchaseRecordDO>()
|
||||||
|
.eq(PurchaseRecordDO::getOrganId, organId)
|
||||||
|
.gt(PurchaseRecordDO::getEndTime, LocalDateTime.now())
|
||||||
|
.orderByAsc(PurchaseRecordDO::getCreateTime)
|
||||||
|
.last("limit 1"));
|
||||||
|
if (ObjectUtil.isNotNull(purchaseRecordDO)) {
|
||||||
|
return new OrgEarliestPurchaseProductRespVO(purchaseRecordDO, productsDetailMapper.selectById(purchaseRecordDO.getProductDetailsId()));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cf.imes.module.system.controller.admin.funds.purchase.vo;
|
||||||
|
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询组织下最早购买产品记录和关联定价规则 response vo
|
||||||
|
*
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/8/19 17:10
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class OrgEarliestPurchaseProductRespVO {
|
||||||
|
/**
|
||||||
|
* 购买记录
|
||||||
|
*/
|
||||||
|
private PurchaseRecordDO purchaseRecordDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品定价规则
|
||||||
|
*/
|
||||||
|
private ProductsDetailDO productsDetailDO;
|
||||||
|
}
|
||||||
+7
-6
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.controller.admin.pay;
|
|||||||
|
|
||||||
import com.cf.imes.framework.common.pojo.CommonResult;
|
import com.cf.imes.framework.common.pojo.CommonResult;
|
||||||
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
||||||
import com.cf.imes.module.system.service.pay.PayOrderService;
|
import com.cf.imes.module.system.service.pay.PayOrderService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -44,12 +45,12 @@ public class PayController {
|
|||||||
return success(payOrderRespDTO);
|
return success(payOrderRespDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @PostMapping("/product")
|
@PostMapping("/product")
|
||||||
// @Operation(summary = "创建产品支付订单")
|
@Operation(summary = "创建产品支付订单")
|
||||||
// public CommonResult<PayOrderRespDTO> initiatePay(@RequestBody PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
public CommonResult<PayOrderRespDTO> initiatePay(@RequestBody PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
||||||
// payOrderService.productPay(payProductOrderUnifiedReqVO);
|
PayOrderRespDTO payOrderRespDTO = payOrderService.productPay(payProductOrderUnifiedReqVO);
|
||||||
// return success(null);
|
return success(payOrderRespDTO);
|
||||||
// }
|
}
|
||||||
|
|
||||||
@GetMapping("/order/{channelCode}/{outTradeNo}")
|
@GetMapping("/order/{channelCode}/{outTradeNo}")
|
||||||
@Operation(summary = "查询支付订单")
|
@Operation(summary = "查询支付订单")
|
||||||
|
|||||||
+7
-4
@@ -20,11 +20,14 @@ public class PayProductOrderUnifiedReqVO {
|
|||||||
* 产品定价规则编号
|
* 产品定价规则编号
|
||||||
*/
|
*/
|
||||||
@Schema(description = "产品定价规则编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "产品定价规则编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotEmpty(message = "产品定价规则编号不能为空")
|
@NotNull(message = "产品定价规则编号不能为空")
|
||||||
private Long productDetailsId;
|
private Long productDetailsId;
|
||||||
|
|
||||||
@Schema(description = "支付渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
@Schema(description = "产品支付渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||||
@PayProductChannelCodeValid
|
@PayProductChannelCodeValid
|
||||||
@NotNull(message = "支付渠道编码不能为空")
|
@NotNull(message = "产品支付渠道编码不能为空")
|
||||||
private Integer channelCode;
|
private Integer productChannelCode;
|
||||||
|
|
||||||
|
@Schema(description = "机构编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long organId;
|
||||||
}
|
}
|
||||||
|
|||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
package com.cf.imes.module.system.dal.dataobject.funds.purchase;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 购买记录表
|
||||||
|
*/
|
||||||
|
@TableName("purchase_record")
|
||||||
|
@KeySequence("purchase_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PurchaseRecordDO extends BaseDO {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组织ID
|
||||||
|
*/
|
||||||
|
private Long organId;
|
||||||
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 用户ID-发票申请人ID
|
||||||
|
// */
|
||||||
|
// private Long userId;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 用户姓名
|
||||||
|
// */
|
||||||
|
// private Long userName;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品ID
|
||||||
|
*/
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品明细ID
|
||||||
|
*/
|
||||||
|
private Long productDetailsId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品名称
|
||||||
|
*/
|
||||||
|
private String productName;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买时长
|
||||||
|
*/
|
||||||
|
private String purchaseDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买时长单位
|
||||||
|
*/
|
||||||
|
private Integer purchaseDurationUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送时长
|
||||||
|
*/
|
||||||
|
private String giftDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送时间单位
|
||||||
|
*/
|
||||||
|
private Integer giftDurationUnit;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品开始时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品结束时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付方式
|
||||||
|
*/
|
||||||
|
private Integer paymentMethod;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单总额
|
||||||
|
*/
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金余额支出
|
||||||
|
*/
|
||||||
|
private BigDecimal accountBalanceSpent;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付宝支出
|
||||||
|
*/
|
||||||
|
private BigDecimal alipaySpent;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支出
|
||||||
|
*/
|
||||||
|
private BigDecimal wechatSpent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送金
|
||||||
|
*/
|
||||||
|
private BigDecimal giftMoneySpent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 货币类型
|
||||||
|
*/
|
||||||
|
private Integer currency;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 货币单位
|
||||||
|
*/
|
||||||
|
private String currencyUnit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开票
|
||||||
|
*/
|
||||||
|
private Integer isInvocing;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -78,7 +78,7 @@ public class IncomeExpenseDetailsDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 支出/入账赠送金金额
|
* 支出/入账赠送金金额
|
||||||
*/
|
*/
|
||||||
private BigDecimal bonusAmountChange;
|
private BigDecimal giftAmountChange;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.cf.imes.module.system.dal.mysql.funds.purchase;
|
||||||
|
|
||||||
|
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买记录 Mapper
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PurchaseRecordMapper extends BaseMapperX<PurchaseRecordDO> {
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package com.cf.imes.module.system.enums.pay;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 发票状态枚举类型
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum InvoiceStatusEnum {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可开票
|
||||||
|
*/
|
||||||
|
INVOICABLE(0, "可开票"),
|
||||||
|
/**
|
||||||
|
* 待开票
|
||||||
|
*/
|
||||||
|
PENDINGINVOICING(1, "待开票"),
|
||||||
|
/**
|
||||||
|
* 已开票
|
||||||
|
*/
|
||||||
|
INVOICINGSUCCESSFUL(2,"已开票"),
|
||||||
|
/**
|
||||||
|
* 开票失败
|
||||||
|
*/
|
||||||
|
INVOICINGFAILED(3,"开票失败");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private final Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static InvoiceStatusEnum fromType(Integer status) {
|
||||||
|
if (status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (InvoiceStatusEnum value : values()) {
|
||||||
|
if (ObjectUtil.equal(value.getStatus(), status)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+6
@@ -2,10 +2,16 @@ package com.cf.imes.module.system.enums.pay;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付常量
|
* 支付常量
|
||||||
|
*
|
||||||
* @author Gqr
|
* @author Gqr
|
||||||
* @since 2025/8/12 17:49
|
* @since 2025/8/12 17:49
|
||||||
*/
|
*/
|
||||||
public class PayConstants {
|
public class PayConstants {
|
||||||
public static final String PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY = "tradeType"; //支付passback 交易类型key
|
public static final String PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY = "tradeType"; //支付passback 交易类型key
|
||||||
|
|
||||||
public static final String PAY_PASSBACK_PARAMS_KEY = "passback_params";// 回调参数passback key
|
public static final String PAY_PASSBACK_PARAMS_KEY = "passback_params";// 回调参数passback key
|
||||||
|
|
||||||
|
public static final String PAY_ORDER_PREFIX_FORMAT = "P%dO%s%s";
|
||||||
|
|
||||||
|
public static final String PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY = "purchaseRecordId"; //支付passback 购买记录key
|
||||||
}
|
}
|
||||||
+1
-1
@@ -61,6 +61,6 @@ public enum PayOrderStatusEnum {
|
|||||||
* @return 是否支付关闭
|
* @return 是否支付关闭
|
||||||
*/
|
*/
|
||||||
public static boolean isClosed(Integer status) {
|
public static boolean isClosed(Integer status) {
|
||||||
return Objects.equals(status, SUCCESS.getStatus()) || Objects.equals(status, FAIL.getStatus());
|
return Objects.equals(status, FAIL.getStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-10
@@ -14,34 +14,62 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum PayProductChannelCodeEnum {
|
public enum PayProductChannelCodeEnum {
|
||||||
|
/**
|
||||||
|
* 账户余额
|
||||||
|
*/
|
||||||
|
BALANCE_ONLY(0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送金
|
||||||
|
*/
|
||||||
|
GIFT_ONLY(1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝
|
* 支付宝
|
||||||
*/
|
*/
|
||||||
ALIPAY_PC(0),
|
ALIPAY_PC(2),
|
||||||
/**
|
/**
|
||||||
* 微信
|
* 微信
|
||||||
*/
|
*/
|
||||||
WECHAT_NATIVE(1),
|
WECHAT_NATIVE(3),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户余额
|
* 现金+赠送金
|
||||||
*/
|
*/
|
||||||
BALANCE_ONLY(2),
|
BALANCE_AND_GIFT(4),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户余额+支付宝
|
* 现金+支付宝
|
||||||
*/
|
*/
|
||||||
BALANCE_AND_ALIPAY(3),
|
BALANCE_AND_ALIPAY(5),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户余额+微信
|
* 现金+微信
|
||||||
*/
|
*/
|
||||||
BALANCE_AND_WECHAT(4);
|
BALANCE_AND_WECHAT(6),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送金+支付宝
|
||||||
|
*/
|
||||||
|
GIFT_AND_ALIPAY(7),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 赠送金+微信
|
||||||
|
*/
|
||||||
|
GIFT_AND_WECHAT(8),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金+赠送金+支付宝
|
||||||
|
*/
|
||||||
|
BALANCE_AND_GIFT_AND_ALIPAY(9),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金+赠送金+微信
|
||||||
|
*/
|
||||||
|
BALANCE_AND_GIFT_AND_WECHAT(10);
|
||||||
|
|
||||||
@EnumValue
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
public static PayProductChannelCodeEnum fromType(Integer type) {
|
public static PayProductChannelCodeEnum fromType(Integer type) {
|
||||||
for (PayProductChannelCodeEnum value : values()) {
|
for (PayProductChannelCodeEnum value : values()) {
|
||||||
if (value.getCode().equals(type)) {
|
if (value.getCode().equals(type)) {
|
||||||
@@ -50,4 +78,14 @@ public enum PayProductChannelCodeEnum {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品购买渠道是否包含支付宝支付方式
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isAliPay(Integer code) {
|
||||||
|
return code.equals(ALIPAY_PC.code) || code.equals(BALANCE_AND_ALIPAY.code) || code.equals(GIFT_AND_ALIPAY.code) || code.equals(BALANCE_AND_GIFT_AND_ALIPAY.code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-6
@@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* 属于 system 模块的 framework 封装
|
|
||||||
*
|
|
||||||
* @author 晨丰科技
|
|
||||||
*/
|
|
||||||
package com.cf.imes.module.system.framework;
|
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package com.cf.imes.module.system.framework.snowflake.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mybatis id策略配置类
|
||||||
|
*
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/8/18 17:33
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "mybatis-plus.global-config.db-config")
|
||||||
|
public class MybatisIdProperties {
|
||||||
|
private long workerId;
|
||||||
|
private long datacenterId;
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* 属于 system 模块的 framework.snowflake 封装
|
||||||
|
*
|
||||||
|
* @author 晨丰科技
|
||||||
|
*/
|
||||||
|
package com.cf.imes.module.system.framework.snowflake;
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.cf.imes.module.system.job.pay;
|
||||||
|
|
||||||
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.cf.imes.module.system.service.pay.PayOrderService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付订单的过期 Job
|
||||||
|
*
|
||||||
|
* 支付超过过期时间时,支付渠道是不会通知进行过期,所以需要定时进行过期关闭。
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class PayOrderExpireJob {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayOrderService payOrderService;
|
||||||
|
|
||||||
|
// @Scheduled(cron = "0 0/1 * * * ?")
|
||||||
|
public String execute() {
|
||||||
|
int count = payOrderService.expirePayOrder();
|
||||||
|
log.info("[execute][支付过期 ({}) 个]", count);
|
||||||
|
return CharSequenceUtil.format("支付过期 ({}) 个",count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -5,6 +5,7 @@ import com.cf.imes.framework.common.exception.ServiceException;
|
|||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
||||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||||
|
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
|
||||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.*;
|
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.*;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementDO;
|
||||||
@@ -13,7 +14,6 @@ import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementTask
|
|||||||
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
|
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
|
||||||
import com.cf.imes.module.system.mq.producer.advertisement.AdvertisementProducer;
|
import com.cf.imes.module.system.mq.producer.advertisement.AdvertisementProducer;
|
||||||
import com.cf.imes.module.system.service.dict.DictDataService;
|
import com.cf.imes.module.system.service.dict.DictDataService;
|
||||||
import com.cf.imes.module.system.util.SnowflakeIdWorker3rd;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -86,7 +86,7 @@ public class AdvertisementServiceImpl implements AdvertisementService{
|
|||||||
|
|
||||||
AssertUtils.empty(aDo,ADVERTISEMENT_NAME_IS_EXIST);
|
AssertUtils.empty(aDo,ADVERTISEMENT_NAME_IS_EXIST);
|
||||||
|
|
||||||
Long id = idWorker.nextId();
|
long id = idWorker.nextId();
|
||||||
|
|
||||||
String filePath = "";
|
String filePath = "";
|
||||||
if(createReqVO.getAdImageFile() != null) {
|
if(createReqVO.getAdImageFile() != null) {
|
||||||
|
|||||||
+18
-1
@@ -21,7 +21,7 @@ public interface OrganAmountService {
|
|||||||
OrganAmountDO validOrganAmount(Long organId);
|
OrganAmountDO validOrganAmount(Long organId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新机构余额
|
* 机构充值
|
||||||
*
|
*
|
||||||
* @param organId
|
* @param organId
|
||||||
* @param amount 充值金额
|
* @param amount 充值金额
|
||||||
@@ -29,6 +29,23 @@ public interface OrganAmountService {
|
|||||||
*/
|
*/
|
||||||
OrganRechargeAmountRespVO recharge(Long organId, BigDecimal amount);
|
OrganRechargeAmountRespVO recharge(Long organId, BigDecimal amount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组织购买产品
|
||||||
|
*
|
||||||
|
* @param organAmountDO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void productPay(OrganAmountDO organAmountDO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品外部支付失败更新余额/赠送金
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @param balance
|
||||||
|
* @param gift
|
||||||
|
*/
|
||||||
|
OrganRechargeAmountRespVO refundProductOrganAmountBalanceAndGift(Long organId, BigDecimal balance, BigDecimal gift);
|
||||||
|
|
||||||
OrganAmountRespVO getOrganAmount(Long organId);
|
OrganAmountRespVO getOrganAmount(Long organId);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+74
-1
@@ -1,15 +1,23 @@
|
|||||||
package com.cf.imes.module.system.service.funds.organamount;
|
package com.cf.imes.module.system.service.funds.organamount;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.cf.imes.framework.common.exception.ServiceException;
|
||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
||||||
|
import com.cf.imes.framework.common.util.date.DateUtils;
|
||||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||||
import com.cf.imes.module.executor.api.funds.ExecutorFundsApi;
|
import com.cf.imes.module.executor.api.funds.ExecutorFundsApi;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.purchase.PurchaseService;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
import com.cf.imes.module.system.dal.mysql.funds.organamount.OrganAmountMapper;
|
import com.cf.imes.module.system.dal.mysql.funds.organamount.OrganAmountMapper;
|
||||||
import com.cf.imes.module.system.service.organ.OrganService;
|
import com.cf.imes.module.system.service.organ.OrganService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -19,8 +27,10 @@ import jakarta.annotation.Resource;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
|
||||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_AMOUNT_NO_EXIST;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_AMOUNT_NO_EXIST;
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR;
|
||||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR;
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,10 +47,11 @@ public class OrganAmountServiceImpl implements OrganAmountService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OrganService organService;
|
private OrganService organService;
|
||||||
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ExecutorFundsApi executorFundsApi;
|
private ExecutorFundsApi executorFundsApi;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PurchaseService purchaseService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OrganAmountDO validOrganAmount(Long organId) {
|
public OrganAmountDO validOrganAmount(Long organId) {
|
||||||
@@ -85,6 +96,54 @@ public class OrganAmountServiceImpl implements OrganAmountService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void productPay(OrganAmountDO organAmountDO) {
|
||||||
|
int updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
|
||||||
|
.eq(OrganAmountDO::getOrganId, organAmountDO.getOrganId())
|
||||||
|
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
|
||||||
|
.set(OrganAmountDO::getAmount, organAmountDO.getAmount())
|
||||||
|
.set(OrganAmountDO::getGiftAmount, organAmountDO.getGiftAmount())
|
||||||
|
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
|
||||||
|
if (updated == 0) {
|
||||||
|
throw new ServiceException(ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrganRechargeAmountRespVO refundProductOrganAmountBalanceAndGift(Long organId, BigDecimal balance, BigDecimal gift) {
|
||||||
|
OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
|
||||||
|
BigDecimal newAmount = organAmountDO.getAmount().add(balance);
|
||||||
|
BigDecimal newGift = organAmountDO.getGiftAmount().add(gift);
|
||||||
|
|
||||||
|
int updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
|
||||||
|
.eq(OrganAmountDO::getOrganId, organId)
|
||||||
|
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
|
||||||
|
.set(OrganAmountDO::getAmount, newAmount)
|
||||||
|
.set(OrganAmountDO::getGiftAmount, newGift)
|
||||||
|
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
|
||||||
|
// 1. 首次更新失败,认为出现并发,再查一次再更新
|
||||||
|
if (updated == 0) {
|
||||||
|
organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
|
||||||
|
newAmount = organAmountDO.getAmount().add(balance);
|
||||||
|
newGift = organAmountDO.getGiftAmount().add(gift);
|
||||||
|
|
||||||
|
updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
|
||||||
|
.eq(OrganAmountDO::getOrganId, organId)
|
||||||
|
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
|
||||||
|
.set(OrganAmountDO::getAmount, newAmount)
|
||||||
|
.set(OrganAmountDO::getGiftAmount, newGift)
|
||||||
|
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
|
||||||
|
// 2. 第二次更新失败,资金表可能不存在
|
||||||
|
if (updated == 0) {
|
||||||
|
throw exception(ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR);
|
||||||
|
} else {
|
||||||
|
return new OrganRechargeAmountRespVO(newAmount.add(newGift), newAmount, newGift);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new OrganRechargeAmountRespVO(newAmount.add(newGift), newAmount, newGift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OrganAmountRespVO getOrganAmount(Long organId) {
|
public OrganAmountRespVO getOrganAmount(Long organId) {
|
||||||
|
|
||||||
@@ -94,6 +153,20 @@ public class OrganAmountServiceImpl implements OrganAmountService {
|
|||||||
|
|
||||||
OrganAmountRespVO organAmountRespVO = BeanUtils.toBean(organAmountDO, OrganAmountRespVO.class);
|
OrganAmountRespVO organAmountRespVO = BeanUtils.toBean(organAmountDO, OrganAmountRespVO.class);
|
||||||
|
|
||||||
|
// 查询组织最早还有效的产品购买记录
|
||||||
|
OrgEarliestPurchaseProductRespVO orgEarliestProductDetail = purchaseService.getOrgEarliestProductDetail(organId);
|
||||||
|
if (ObjectUtil.isNotNull(orgEarliestProductDetail)) {
|
||||||
|
// 购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = orgEarliestProductDetail.getPurchaseRecordDO();
|
||||||
|
// 购买记录关联的定价规则
|
||||||
|
ProductsDetailDO productsDetailDO = orgEarliestProductDetail.getProductsDetailDO();
|
||||||
|
|
||||||
|
organAmountRespVO.setProductEfficientDate(LocalDateTimeUtil.format(purchaseRecordDO.getEndTime(), NORM_DATETIME_FORMATTER));
|
||||||
|
organAmountRespVO.setDuration(productsDetailDO.getDuration());
|
||||||
|
organAmountRespVO.setDurationUnit(productsDetailDO.getDurationUnit());
|
||||||
|
organAmountRespVO.setGiftDuration(productsDetailDO.getGiftDuration());
|
||||||
|
organAmountRespVO.setGiftDurationUnit(productsDetailDO.getGiftDurationUnit());
|
||||||
|
}
|
||||||
return organAmountRespVO;
|
return organAmountRespVO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ package com.cf.imes.module.system.service.funds.products;
|
|||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
@@ -65,5 +66,5 @@ public interface ProductsDetailService {
|
|||||||
*
|
*
|
||||||
* @param productId
|
* @param productId
|
||||||
*/
|
*/
|
||||||
void validateProductExist(Long productId);
|
ProductsDO validateProductExist(Long productId);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -170,7 +170,7 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
|||||||
* @param productId
|
* @param productId
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void validateProductExist(Long productId) {
|
public ProductsDO validateProductExist(Long productId) {
|
||||||
ProductsDO productsDO = productsMapper.selectOne(new LambdaQueryWrapperX<ProductsDO>()
|
ProductsDO productsDO = productsMapper.selectOne(new LambdaQueryWrapperX<ProductsDO>()
|
||||||
.eq(ProductsDO::getId, productId)
|
.eq(ProductsDO::getId, productId)
|
||||||
.eq(ProductsDO::getDeleted, false));
|
.eq(ProductsDO::getDeleted, false));
|
||||||
@@ -180,6 +180,8 @@ public class ProductsDetailServiceImpl implements ProductsDetailService {
|
|||||||
if (productsDO.getStatus().equals(ProductStatusEnum.PRODUCT_UPDATES.getStatus())) {
|
if (productsDO.getStatus().equals(ProductStatusEnum.PRODUCT_UPDATES.getStatus())) {
|
||||||
throw exception(PRODUCTS_DETAIL_NO_UPDATE);
|
throw exception(PRODUCTS_DETAIL_NO_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return productsDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -3,12 +3,12 @@ package com.cf.imes.module.system.service.funds.recharge;
|
|||||||
import com.cf.imes.framework.common.pojo.PageResult;
|
import com.cf.imes.framework.common.pojo.PageResult;
|
||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
||||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||||
|
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
|
||||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargePageReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargePageReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeSaveReqVO;
|
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeSaveReqVO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO;
|
||||||
import com.cf.imes.module.system.dal.mysql.funds.recharge.GiftMoneyDetailsMapper;
|
import com.cf.imes.module.system.dal.mysql.funds.recharge.GiftMoneyDetailsMapper;
|
||||||
import com.cf.imes.module.system.util.SnowflakeIdWorker3rd;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ public class RechargeActiveServiceImpl implements RechargeActiveService{
|
|||||||
@Override
|
@Override
|
||||||
public Long create(RechargeSaveReqVO createReqVO) {
|
public Long create(RechargeSaveReqVO createReqVO) {
|
||||||
|
|
||||||
Long id = idWorker.nextId();
|
long id = idWorker.nextId();
|
||||||
|
|
||||||
GiftMoneyDetailsDO giftMoneyDetailsDO = giftMoneyDetailsMapper.selectOne(new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
|
GiftMoneyDetailsDO giftMoneyDetailsDO = giftMoneyDetailsMapper.selectOne(new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
|
||||||
.eq(GiftMoneyDetailsDO::getDeleted, false)
|
.eq(GiftMoneyDetailsDO::getDeleted, false)
|
||||||
|
|||||||
+8
-1
@@ -18,7 +18,7 @@ public interface PayOrderService {
|
|||||||
*
|
*
|
||||||
* @param payProductOrderUnifiedReqVO
|
* @param payProductOrderUnifiedReqVO
|
||||||
*/
|
*/
|
||||||
void productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO);
|
PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户充值支付
|
* 账户充值支付
|
||||||
@@ -44,4 +44,11 @@ public interface PayOrderService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
void doOrderNotify(Integer channelCode, Map<String, String> params, String body);
|
void doOrderNotify(Integer channelCode, Map<String, String> params, String body);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理过期订单
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int expirePayOrder();
|
||||||
}
|
}
|
||||||
|
|||||||
+191
-9
@@ -15,6 +15,7 @@ import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
|
|||||||
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
import com.cf.imes.framework.common.util.Assert.AssertUtils;
|
||||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||||
import com.cf.imes.framework.common.util.validation.ValidationUtils;
|
import com.cf.imes.framework.common.util.validation.ValidationUtils;
|
||||||
|
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
|
||||||
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
|
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
|
||||||
import com.cf.imes.framework.pay.config.ChenfengAlipayConfig;
|
import com.cf.imes.framework.pay.config.ChenfengAlipayConfig;
|
||||||
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
||||||
@@ -23,16 +24,22 @@ import com.cf.imes.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
|||||||
import com.cf.imes.framework.common.exception.PayException;
|
import com.cf.imes.framework.common.exception.PayException;
|
||||||
import com.cf.imes.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
import com.cf.imes.framework.pay.core.enums.order.PayOrderStatusRespEnum;
|
||||||
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
|
|
||||||
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
|
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.purchase.PurchaseService;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayProductOrderUnifiedReqVO;
|
||||||
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
|
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
|
||||||
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
|
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
|
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.PayConstants;
|
import com.cf.imes.module.system.enums.pay.PayConstants;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
||||||
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
||||||
|
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
||||||
import com.cf.imes.module.system.service.funds.incomeandexpense.IncomeExpenseService;
|
import com.cf.imes.module.system.service.funds.incomeandexpense.IncomeExpenseService;
|
||||||
import com.cf.imes.module.system.service.funds.organamount.OrganAmountService;
|
import com.cf.imes.module.system.service.funds.organamount.OrganAmountService;
|
||||||
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
|
||||||
@@ -52,6 +59,7 @@ import jakarta.validation.Validator;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -77,6 +85,9 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_RECHARGE_OR
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class PayOrderServiceImpl implements PayOrderService {
|
public class PayOrderServiceImpl implements PayOrderService {
|
||||||
|
|
||||||
|
// 外部payNo正则
|
||||||
|
private static final Pattern pattern = Pattern.compile("P(\\d+)O");
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayHandlerFactory payHandlerFactory;
|
private PayHandlerFactory payHandlerFactory;
|
||||||
|
|
||||||
@@ -86,8 +97,6 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
@Resource
|
@Resource
|
||||||
private Validator validator;
|
private Validator validator;
|
||||||
|
|
||||||
private static final String PAY_ORDER_PREFIX_FORMAT = "P%dO%s%s";
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ChenfengAlipayConfig alipayConfig;
|
private ChenfengAlipayConfig alipayConfig;
|
||||||
|
|
||||||
@@ -103,18 +112,78 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
@Resource
|
@Resource
|
||||||
private IncomeExpenseService incomeExpenseService;
|
private IncomeExpenseService incomeExpenseService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PurchaseService purchaseService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SnowflakeIdWorker3rd snowflakeIdWorker3rd;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MybatisIdProperties mybatisIdProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
|
||||||
|
Long organId = payProductOrderUnifiedReqVO.getOrganId();
|
||||||
|
organId = ObjectUtil.isNull(organId) ? SecurityFrameworkUtils.getUserOrganId() : organId;
|
||||||
|
|
||||||
// 主动校验一次入参
|
// 主动校验一次入参
|
||||||
ValidationUtils.validate(validator, payProductOrderUnifiedReqVO);
|
ValidationUtils.validate(validator, payProductOrderUnifiedReqVO);
|
||||||
|
|
||||||
// 校验产品和产品明细
|
// 校验产品和产品明细
|
||||||
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(payProductOrderUnifiedReqVO.getProductDetailsId());
|
ProductsDetailDO productsDetailDO = productsDetailService.validateProductDetailsExists(payProductOrderUnifiedReqVO.getProductDetailsId());
|
||||||
productsDetailService.validateProductExist(productsDetailDO.getProductId());
|
ProductsDO productsDO = productsDetailService.validateProductExist(productsDetailDO.getProductId());
|
||||||
|
|
||||||
// 查询组织余额信息
|
// 查询组织余额信息
|
||||||
OrganAmountRespVO organAmount = organAmountService.getOrganAmount(SecurityFrameworkUtils.getUserOrganId());
|
OrganAmountDO organAmount = organAmountService.validOrganAmount(organId);
|
||||||
|
|
||||||
|
// 根据购买类型做价格处理
|
||||||
|
PayProductProcessor payProductProcessor = new PayProductProcessor(productsDO, productsDetailDO, organAmount, organId, snowflakeIdWorker3rd, payConfig, mybatisIdProperties);
|
||||||
|
ProductProcessorRespVO productProcessorRespVO = payProductProcessor.processPayment(PayProductChannelCodeEnum.fromType(payProductOrderUnifiedReqVO.getProductChannelCode()));
|
||||||
|
|
||||||
|
// 记录入库,如果有外部支付发起请求二维码
|
||||||
|
// 购买记录入库
|
||||||
|
purchaseService.createRecord(productProcessorRespVO.getPurchaseRecordDO());
|
||||||
|
// 收支明细入库
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = productProcessorRespVO.getIncomeExpenseDetailsDO();
|
||||||
|
if (ObjectUtil.isNotNull(incomeExpenseDetailsDO)) {
|
||||||
|
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新组织资金,纯第三方支付不需要更新余额
|
||||||
|
OrganAmountDO finalOrganAmountDO = productProcessorRespVO.getOrganAmountDO();
|
||||||
|
if (ObjectUtil.isNotNull(finalOrganAmountDO)) {
|
||||||
|
organAmountService.productPay(finalOrganAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有外部支付,发起请求
|
||||||
|
PayOrderDO payOrder = productProcessorRespVO.getPayOrderDO();
|
||||||
|
if(ObjectUtil.isNotNull(payOrder)) {
|
||||||
|
payOrderMapper.insert(payOrder);
|
||||||
|
|
||||||
|
// 拼接充值个性化参数
|
||||||
|
Map<String, Object> passbackParams = new HashMap<>();
|
||||||
|
passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY, TradeTypeEnum.PRODUCT.getCode());// 交易类型
|
||||||
|
passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY, productProcessorRespVO.getPurchaseRecordDO().getId());// 购买记录id,用于更新开票状态
|
||||||
|
|
||||||
|
// 发起渠道方支付
|
||||||
|
PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = null;
|
||||||
|
Integer channelCode = PayProductChannelCodeEnum.isAliPay(payProductOrderUnifiedReqVO.getProductChannelCode()) ? PayChannelCodeEnum.ALIPAY_PC.getCode() : PayChannelCodeEnum.WECHAT_NATIVE.getCode();
|
||||||
|
try {
|
||||||
|
// 获取渠道方处理器
|
||||||
|
AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode);
|
||||||
|
|
||||||
|
payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams);
|
||||||
|
return payHandler.unifiedOrder(payOrderUnifiedReqDTO);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 系统异常,则包装成 PayException 异常抛出
|
||||||
|
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
|
||||||
|
channelCode, JSON.toJSONString(payOrderUnifiedReqDTO), e);
|
||||||
|
throw new PayException(PAY_ORDER_SUBMIT_CHANNEL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -164,11 +233,11 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
private PayOrderDO createPayOrder(BigDecimal price, String subject, Integer channelCode) {
|
private PayOrderDO createPayOrder(BigDecimal price, String subject, Integer channelCode) {
|
||||||
PayOrderDO payOrderDO = new PayOrderDO();
|
PayOrderDO payOrderDO = new PayOrderDO();
|
||||||
|
|
||||||
Long payOrderId = IdUtil.getSnowflake(0, 0).nextId();
|
Long payOrderId = IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId();
|
||||||
Long organId = SecurityFrameworkUtils.getUserOrganId();
|
Long organId = SecurityFrameworkUtils.getUserOrganId();
|
||||||
|
|
||||||
payOrderDO.setId(payOrderId);
|
payOrderDO.setId(payOrderId);
|
||||||
payOrderDO.setPayNo(String.format(PAY_ORDER_PREFIX_FORMAT, organId, payOrderId, DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN)));
|
payOrderDO.setPayNo(String.format(PayConstants.PAY_ORDER_PREFIX_FORMAT, organId, payOrderId, DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN)));
|
||||||
payOrderDO.setStatus(PayOrderStatusEnum.WAITING);
|
payOrderDO.setStatus(PayOrderStatusEnum.WAITING);
|
||||||
payOrderDO.setExpireTime(LocalDateTime.now().plus(payConfig.getPayExpireTime()));
|
payOrderDO.setExpireTime(LocalDateTime.now().plus(payConfig.getPayExpireTime()));
|
||||||
payOrderDO.setPrice(price);
|
payOrderDO.setPrice(price);
|
||||||
@@ -276,7 +345,6 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Long getOrganIdFromPayNo(String outTradeNo) {
|
private Long getOrganIdFromPayNo(String outTradeNo) {
|
||||||
Pattern pattern = Pattern.compile("P(\\d+)O");
|
|
||||||
Matcher matcher = pattern.matcher(outTradeNo);
|
Matcher matcher = pattern.matcher(outTradeNo);
|
||||||
|
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
@@ -333,6 +401,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
notifyRechargeOrderSuccess(order, organId);
|
notifyRechargeOrderSuccess(order, organId);
|
||||||
break;
|
break;
|
||||||
case PRODUCT:
|
case PRODUCT:
|
||||||
|
notifyProductPayOrderSuccess(organId, passbackParams);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString());
|
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString());
|
||||||
@@ -341,6 +410,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 充值成功回调
|
* 充值成功回调
|
||||||
|
*
|
||||||
* @param payOrderDO
|
* @param payOrderDO
|
||||||
* @param organId
|
* @param organId
|
||||||
*/
|
*/
|
||||||
@@ -369,6 +439,19 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品购买成功回调
|
||||||
|
* @param organId
|
||||||
|
* @param passbackParams
|
||||||
|
*/
|
||||||
|
private void notifyProductPayOrderSuccess(Long organId, Map<String, Object> passbackParams) {
|
||||||
|
// 1、更新购买记录的开票状态
|
||||||
|
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
||||||
|
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
||||||
|
purchaseService.updateRecordInvoicable(NumberUtil.parseLong(purchaseRecordIdObj.toString()), organId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付失败回调处理
|
* 支付失败回调处理
|
||||||
*
|
*
|
||||||
@@ -413,6 +496,64 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.debug("[notifyOrderClosed][order({}) 更新为支付关闭]", order.getId());
|
log.debug("[notifyOrderClosed][order({}) 更新为支付关闭]", order.getId());
|
||||||
|
|
||||||
|
// 3. 根据交易类型做对应回调处理
|
||||||
|
Map<String, Object> passbackParams = notify.getPassbackParams();
|
||||||
|
Object passbackObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY);
|
||||||
|
AssertUtils.notEmpty(passbackObj, PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR);
|
||||||
|
switch (TradeTypeEnum.fromCode(NumberUtil.parseInt(passbackObj.toString()))) {
|
||||||
|
case RECHARGE:
|
||||||
|
notifyRechargeOrderFail(order, organId);
|
||||||
|
break;
|
||||||
|
case PRODUCT:
|
||||||
|
notifyProductPayOrderFail(organId, passbackParams);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充值成功回调
|
||||||
|
*
|
||||||
|
* @param payOrderDO
|
||||||
|
* @param organId
|
||||||
|
*/
|
||||||
|
private void notifyRechargeOrderFail(PayOrderDO payOrderDO, Long organId) {
|
||||||
|
// todo 充值成功回调
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品购买失败回调
|
||||||
|
*
|
||||||
|
* @param organId
|
||||||
|
* @param passbackParams
|
||||||
|
*/
|
||||||
|
private void notifyProductPayOrderFail(Long organId, Map<String, Object> passbackParams) {
|
||||||
|
Object purchaseRecordIdObj = passbackParams.get(PayConstants.PAY_PASSBACK_PARAMS_PURCHASE_RECORD_ID_KEY);
|
||||||
|
if (ObjectUtil.isNotNull(purchaseRecordIdObj)) {
|
||||||
|
PurchaseRecordDO record = purchaseService.getRecord(NumberUtil.parseLong(purchaseRecordIdObj.toString()));
|
||||||
|
|
||||||
|
// 1、混合支付失败,退回扣除的现金和赠送金
|
||||||
|
BigDecimal accountBalanceSpent = record.getAccountBalanceSpent();
|
||||||
|
BigDecimal giftMoneySpent = record.getGiftMoneySpent();
|
||||||
|
OrganRechargeAmountRespVO organRefundProductRespVO = organAmountService.refundProductOrganAmountBalanceAndGift(organId, accountBalanceSpent, giftMoneySpent);
|
||||||
|
|
||||||
|
// 2、新增退回的收支记录
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getType())
|
||||||
|
.cashAmountChange(accountBalanceSpent)
|
||||||
|
.giftAmountChange(giftMoneySpent)
|
||||||
|
.availableAmount(organRefundProductRespVO.getAvailableAmount())
|
||||||
|
.amount(organRefundProductRespVO.getAmount())
|
||||||
|
.giftAmount(organRefundProductRespVO.getGiftAmount())
|
||||||
|
.build();
|
||||||
|
incomeExpenseDetailsDO.setCreator(record.getCreator());
|
||||||
|
incomeExpenseDetailsDO.setUpdater(record.getUpdater());
|
||||||
|
incomeExpenseService.createDetail(incomeExpenseDetailsDO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -428,4 +569,45 @@ public class PayOrderServiceImpl implements PayOrderService {
|
|||||||
}
|
}
|
||||||
return organId;
|
return organId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expirePayOrder() {
|
||||||
|
// 1、查询过期的待支付订单
|
||||||
|
List<PayOrderDO> expireOrders = payOrderMapper.selectList(new LambdaQueryWrapper<PayOrderDO>()
|
||||||
|
.eq(PayOrderDO::getStatus, PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.lt(PayOrderDO::getExpireTime, LocalDateTime.now()));
|
||||||
|
|
||||||
|
// 2、遍历处理
|
||||||
|
int count = 0;
|
||||||
|
for (PayOrderDO order : expireOrders) {
|
||||||
|
count += expireOrder(order) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步单个支付单
|
||||||
|
*
|
||||||
|
* @param order 支付单
|
||||||
|
* @return 是否已过期
|
||||||
|
*/
|
||||||
|
private boolean expireOrder(PayOrderDO order) {
|
||||||
|
try {
|
||||||
|
// 1、获取支付渠道
|
||||||
|
PayChannelCodeEnum channelCode = order.getChannelCode();
|
||||||
|
AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode.getCode());
|
||||||
|
|
||||||
|
// 2、调用三方接口,查询支付单状态,是不是已支付
|
||||||
|
PayOrderRespDTO payOrderRespDTO = payHandler.queryPayOrder(order.getPayNo());
|
||||||
|
if (PayOrderStatusEnum.isSuccess(payOrderRespDTO.getStatus())) {
|
||||||
|
notifyOrder(payOrderRespDTO);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
log.info("[expireOrder][order({}) 更新为支付关闭失败]", order.getId());
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("[expireOrder][order({}) 过期订单异常]", order.getId(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+627
@@ -0,0 +1,627 @@
|
|||||||
|
package com.cf.imes.module.system.service.pay;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.cf.imes.framework.common.exception.ServiceException;
|
||||||
|
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
|
||||||
|
import com.cf.imes.framework.pay.config.ChenfengPayConfig;
|
||||||
|
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductProcessorRespVO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
|
||||||
|
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderDO;
|
||||||
|
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayConstants;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
|
||||||
|
import com.cf.imes.module.system.enums.products.DurationUnitEnum;
|
||||||
|
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT;
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_BALANCE_INSUFFICIENT;
|
||||||
|
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品购买类型处理器
|
||||||
|
*
|
||||||
|
* @author Gqr
|
||||||
|
* @since 2025/8/14 10:54
|
||||||
|
*/
|
||||||
|
public class PayProductProcessor {
|
||||||
|
|
||||||
|
private ProductsDO productsDO;
|
||||||
|
|
||||||
|
private ProductsDetailDO productsDetailDO;
|
||||||
|
|
||||||
|
private OrganAmountDO organAmountDO;
|
||||||
|
|
||||||
|
private Long organId;
|
||||||
|
|
||||||
|
private SnowflakeIdWorker3rd snowflakeIdWorker3rd;
|
||||||
|
|
||||||
|
private ChenfengPayConfig payConfig;
|
||||||
|
|
||||||
|
private MybatisIdProperties mybatisIdProperties;
|
||||||
|
|
||||||
|
public PayProductProcessor(ProductsDO productsDO, ProductsDetailDO productsDetailDO, OrganAmountDO organAmountDO,
|
||||||
|
Long organId, SnowflakeIdWorker3rd snowflakeIdWorker3rd, ChenfengPayConfig payConfig,
|
||||||
|
MybatisIdProperties mybatisIdProperties) {
|
||||||
|
this.productsDO = productsDO;
|
||||||
|
this.productsDetailDO = productsDetailDO;
|
||||||
|
this.organAmountDO = organAmountDO;
|
||||||
|
this.organId = organId;
|
||||||
|
this.snowflakeIdWorker3rd = snowflakeIdWorker3rd;
|
||||||
|
this.payConfig = payConfig;
|
||||||
|
this.mybatisIdProperties = mybatisIdProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据产品支付类型解析出对应的信息,
|
||||||
|
*
|
||||||
|
* @param payType
|
||||||
|
*/
|
||||||
|
public ProductProcessorRespVO processPayment(PayProductChannelCodeEnum payType) {
|
||||||
|
// 需要支付的价格
|
||||||
|
BigDecimal price = productsDetailDO.getCurrentPrice();
|
||||||
|
// 当前组织的余额
|
||||||
|
BigDecimal balance = organAmountDO.getAmount();
|
||||||
|
// 当前组织的赠送金
|
||||||
|
BigDecimal gift = organAmountDO.getGiftAmount();
|
||||||
|
|
||||||
|
switch (payType) {
|
||||||
|
case BALANCE_ONLY:
|
||||||
|
return payByBalance(price, balance);
|
||||||
|
case GIFT_ONLY:
|
||||||
|
return payByGift(price, gift);
|
||||||
|
case ALIPAY_PC:
|
||||||
|
return payByAlipay(price);
|
||||||
|
case WECHAT_NATIVE:
|
||||||
|
return payByWechat(price);
|
||||||
|
case BALANCE_AND_GIFT:
|
||||||
|
return payByBalanceAndGift(price, gift, balance);
|
||||||
|
case BALANCE_AND_ALIPAY:
|
||||||
|
return payByBalanceAndExternal(price, balance, PayChannelCodeEnum.ALIPAY_PC);
|
||||||
|
case BALANCE_AND_WECHAT:
|
||||||
|
return payByBalanceAndExternal(price, balance, PayChannelCodeEnum.WECHAT_NATIVE);
|
||||||
|
case GIFT_AND_ALIPAY:
|
||||||
|
return payByGiftAndExternal(price, gift, PayChannelCodeEnum.ALIPAY_PC);
|
||||||
|
case GIFT_AND_WECHAT:
|
||||||
|
return payByGiftAndExternal(price, gift, PayChannelCodeEnum.WECHAT_NATIVE);
|
||||||
|
case BALANCE_AND_GIFT_AND_ALIPAY:
|
||||||
|
return payByBalanceAndGiftAndExternal(price, gift, balance, PayChannelCodeEnum.ALIPAY_PC);
|
||||||
|
case BALANCE_AND_GIFT_AND_WECHAT:
|
||||||
|
return payByBalanceAndGiftAndExternal(price, gift, balance, PayChannelCodeEnum.WECHAT_NATIVE);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用现金余额支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param balance
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByBalance(BigDecimal price, BigDecimal balance) {
|
||||||
|
if (balance.compareTo(price) < 0) {
|
||||||
|
throw new ServiceException(PAY_PRODUCT_BALANCE_INSUFFICIENT);
|
||||||
|
}
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.accountBalanceSpent(price)
|
||||||
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getStatus())
|
||||||
|
.build();
|
||||||
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 新增收支明细
|
||||||
|
// 现金余额减去购买金额
|
||||||
|
BigDecimal newBalance = balance.subtract(price);
|
||||||
|
BigDecimal giftAmount = organAmountDO.getGiftAmount();
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.cashAmountChange(price)
|
||||||
|
.availableAmount(newBalance.add(giftAmount))
|
||||||
|
.amount(newBalance)
|
||||||
|
.giftAmount(giftAmount)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(newBalance);
|
||||||
|
organAmountDO.setGiftAmount(giftAmount);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, null, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用赠送金余额支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param gift
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByGift(BigDecimal price, BigDecimal gift) {
|
||||||
|
if (gift.compareTo(price) < 0) {
|
||||||
|
throw new ServiceException(PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT);
|
||||||
|
}
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.accountBalanceSpent(price)
|
||||||
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getStatus())
|
||||||
|
.build();
|
||||||
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
// 新增收支明细
|
||||||
|
// 赠送金余额减去购买金额
|
||||||
|
BigDecimal newGift = gift.subtract(price);
|
||||||
|
BigDecimal amount = organAmountDO.getAmount();
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.giftAmountChange(price)
|
||||||
|
.availableAmount(amount.add(newGift))
|
||||||
|
.amount(amount)
|
||||||
|
.giftAmount(newGift)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(amount);
|
||||||
|
organAmountDO.setGiftAmount(newGift);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, null, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用支付宝支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByAlipay(BigDecimal price) {
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.alipaySpent(price)
|
||||||
|
.build();
|
||||||
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
|
||||||
|
// 新增第三方支付订单
|
||||||
|
PayOrderDO payOrderDO = goExternalPay(price, PayChannelCodeEnum.ALIPAY_PC);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, null, payOrderDO, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用微信支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByWechat(BigDecimal price) {
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_ONLY.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.wechatSpent(price)
|
||||||
|
.build();
|
||||||
|
purchaseRecordDO.setEndTime(calculateEndTime(purchaseRecordDO.getStartTime(),
|
||||||
|
purchaseRecordDO.getPurchaseDuration(), purchaseRecordDO.getPurchaseDurationUnit(),
|
||||||
|
purchaseRecordDO.getGiftDuration(), purchaseRecordDO.getGiftDurationUnit()));
|
||||||
|
|
||||||
|
// 新增第三方支付订单
|
||||||
|
PayOrderDO payOrderDO = goExternalPay(price, PayChannelCodeEnum.WECHAT_NATIVE);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, null, payOrderDO, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用现在余额+赠送金余额支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param gift
|
||||||
|
* @param balance
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByBalanceAndGift(BigDecimal price, BigDecimal gift, BigDecimal balance) {
|
||||||
|
BigDecimal remaining = price;
|
||||||
|
BigDecimal usedGift = BigDecimal.ZERO;
|
||||||
|
BigDecimal usedBalance = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_AND_GIFT.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.isInvocing(InvoiceStatusEnum.INVOICABLE.getStatus())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 先用赠送金
|
||||||
|
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedGift = remaining.min(gift);
|
||||||
|
remaining = remaining.subtract(usedGift);
|
||||||
|
purchaseRecordDO.setGiftMoneySpent(usedGift);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再用余额
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0 && balance != null && balance.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedBalance = remaining.min(balance);
|
||||||
|
remaining = remaining.subtract(usedBalance);
|
||||||
|
purchaseRecordDO.setAccountBalanceSpent(usedBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 剩下走第三方
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
throw new ServiceException(PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增收支明细
|
||||||
|
// 减去用掉的得到剩下的
|
||||||
|
BigDecimal newAmounta = balance.subtract(usedBalance);
|
||||||
|
BigDecimal newGift = gift.subtract(usedGift);
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.cashAmountChange(usedBalance)
|
||||||
|
.giftAmountChange(usedGift)
|
||||||
|
.availableAmount(newAmounta.add(newGift))
|
||||||
|
.amount(newAmounta)
|
||||||
|
.giftAmount(newGift)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(newAmounta);
|
||||||
|
organAmountDO.setGiftAmount(newGift);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, null, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用现金余额+第三方
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param balance
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByBalanceAndExternal(BigDecimal price, BigDecimal balance, PayChannelCodeEnum payChannelCodeEnum) {
|
||||||
|
BigDecimal remaining = price;
|
||||||
|
BigDecimal usedBalance = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(payChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum) ? PayProductChannelCodeEnum.BALANCE_AND_GIFT_AND_ALIPAY.getCode() : PayProductChannelCodeEnum.BALANCE_AND_GIFT_AND_WECHAT.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 先用余额
|
||||||
|
if (balance != null && balance.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedBalance = remaining.min(balance);
|
||||||
|
remaining = remaining.subtract(usedBalance);
|
||||||
|
purchaseRecordDO.setAccountBalanceSpent(usedBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增收支明细
|
||||||
|
// 减去用掉的得到剩下的
|
||||||
|
BigDecimal newAmounta = balance.subtract(usedBalance);
|
||||||
|
BigDecimal giftAmount = organAmountDO.getGiftAmount();
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.cashAmountChange(usedBalance)
|
||||||
|
.availableAmount(newAmounta.add(giftAmount))
|
||||||
|
.amount(newAmounta)
|
||||||
|
.giftAmount(giftAmount)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 剩下走第三方
|
||||||
|
PayOrderDO payOrderDO = null;
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
payOrderDO = goExternalPay(remaining, payChannelCodeEnum);
|
||||||
|
// 记录第三方支付支出
|
||||||
|
if (PayChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum)) {
|
||||||
|
purchaseRecordDO.setAlipaySpent(remaining);
|
||||||
|
} else {
|
||||||
|
purchaseRecordDO.setWechatSpent(remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(newAmounta);
|
||||||
|
organAmountDO.setGiftAmount(giftAmount);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, payOrderDO, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用赠送金余额+第三方
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param gift
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByGiftAndExternal(BigDecimal price, BigDecimal gift, PayChannelCodeEnum payChannelCodeEnum) {
|
||||||
|
BigDecimal remaining = price;
|
||||||
|
BigDecimal usedGift = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(payChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum) ? PayProductChannelCodeEnum.GIFT_AND_ALIPAY.getCode() : PayProductChannelCodeEnum.GIFT_AND_WECHAT.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
// 先用余额
|
||||||
|
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedGift = remaining.min(gift);
|
||||||
|
remaining = remaining.subtract(usedGift);
|
||||||
|
purchaseRecordDO.setGiftMoneySpent(usedGift);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增收支明细
|
||||||
|
// 减去用掉的得到剩下的
|
||||||
|
BigDecimal newGift = gift.subtract(usedGift);
|
||||||
|
BigDecimal amount = organAmountDO.getAmount();
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.giftAmountChange(usedGift)
|
||||||
|
.availableAmount(amount.add(newGift))
|
||||||
|
.amount(amount)
|
||||||
|
.giftAmount(newGift)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 剩下走第三方
|
||||||
|
PayOrderDO payOrderDO = null;
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
goExternalPay(remaining, payChannelCodeEnum);
|
||||||
|
// 记录第三方支付支出
|
||||||
|
if (PayChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum)) {
|
||||||
|
purchaseRecordDO.setAlipaySpent(remaining);
|
||||||
|
} else {
|
||||||
|
purchaseRecordDO.setWechatSpent(remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(amount);
|
||||||
|
organAmountDO.setGiftAmount(newGift);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, payOrderDO, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用现在余额+赠送金余额支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param gift
|
||||||
|
* @param balance
|
||||||
|
*/
|
||||||
|
private ProductProcessorRespVO payByBalanceAndGiftAndExternal(BigDecimal price, BigDecimal gift, BigDecimal balance, PayChannelCodeEnum payChannelCodeEnum) {
|
||||||
|
BigDecimal remaining = price;
|
||||||
|
BigDecimal usedGift = BigDecimal.ZERO;
|
||||||
|
BigDecimal usedBalance = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// 新增购买记录
|
||||||
|
PurchaseRecordDO purchaseRecordDO = PurchaseRecordDO.builder()
|
||||||
|
.id(IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId())
|
||||||
|
.organId(organId)
|
||||||
|
.productId(productsDO.getId())
|
||||||
|
.productName(productsDO.getProductName())
|
||||||
|
.productDetailsId(productsDetailDO.getId())
|
||||||
|
.purchaseDuration(productsDetailDO.getDuration())
|
||||||
|
.purchaseDurationUnit(productsDetailDO.getDurationUnit())
|
||||||
|
.giftDuration(productsDetailDO.getGiftDuration())
|
||||||
|
.giftDurationUnit(productsDetailDO.getGiftDurationUnit())
|
||||||
|
.startTime(LocalDateTime.now())
|
||||||
|
.paymentMethod(PayProductChannelCodeEnum.BALANCE_AND_GIFT.getCode())
|
||||||
|
.totalAmount(price)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 先用赠送金
|
||||||
|
if (gift != null && gift.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedGift = remaining.min(gift);
|
||||||
|
remaining = remaining.subtract(usedGift);
|
||||||
|
purchaseRecordDO.setGiftMoneySpent(usedGift);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再用余额
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0 && balance != null && balance.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
usedBalance = remaining.min(balance);
|
||||||
|
remaining = remaining.subtract(usedBalance);
|
||||||
|
purchaseRecordDO.setAccountBalanceSpent(usedBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增收支明细
|
||||||
|
// 减去用掉的得到剩下的
|
||||||
|
BigDecimal newAmounta = balance.subtract(usedBalance);
|
||||||
|
BigDecimal newGift = gift.subtract(usedGift);
|
||||||
|
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
|
||||||
|
.organId(organId)
|
||||||
|
.purchaseId(purchaseRecordDO.getId())
|
||||||
|
.tradeType(TradeTypeEnum.PRODUCT.getCode())
|
||||||
|
.incomeExpenseType(IncomeExpenseTypeEnum.EXPENSES.getType())
|
||||||
|
.cashAmountChange(usedBalance)
|
||||||
|
.giftAmountChange(usedGift)
|
||||||
|
.availableAmount(newAmounta.add(newGift))
|
||||||
|
.amount(newAmounta)
|
||||||
|
.giftAmount(newGift)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 剩下走第三方
|
||||||
|
PayOrderDO payOrderDO = null;
|
||||||
|
if (remaining.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
payOrderDO = goExternalPay(remaining, payChannelCodeEnum);
|
||||||
|
// 记录第三方支付支出
|
||||||
|
if (PayChannelCodeEnum.ALIPAY_PC.equals(payChannelCodeEnum)) {
|
||||||
|
purchaseRecordDO.setAlipaySpent(remaining);
|
||||||
|
} else {
|
||||||
|
purchaseRecordDO.setWechatSpent(remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新余额
|
||||||
|
organAmountDO.setAmount(newAmounta);
|
||||||
|
organAmountDO.setGiftAmount(newGift);
|
||||||
|
return new ProductProcessorRespVO(purchaseRecordDO, incomeExpenseDetailsDO, payOrderDO, organAmountDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部支付
|
||||||
|
*
|
||||||
|
* @param price
|
||||||
|
* @param payChannelCodeEnum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private PayOrderDO goExternalPay(BigDecimal price, PayChannelCodeEnum payChannelCodeEnum) {
|
||||||
|
PayOrderDO payOrderDO = new PayOrderDO();
|
||||||
|
|
||||||
|
Long payOrderId = IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId();
|
||||||
|
Long organId = SecurityFrameworkUtils.getUserOrganId();
|
||||||
|
|
||||||
|
payOrderDO.setId(payOrderId);
|
||||||
|
payOrderDO.setPayNo(String.format(PayConstants.PAY_ORDER_PREFIX_FORMAT, organId, payOrderId, DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN)));
|
||||||
|
payOrderDO.setStatus(PayOrderStatusEnum.WAITING);
|
||||||
|
payOrderDO.setExpireTime(LocalDateTime.now().plus(payConfig.getPayExpireTime()));
|
||||||
|
payOrderDO.setPrice(price);
|
||||||
|
payOrderDO.setSubject(productsDO.getProductName());
|
||||||
|
payOrderDO.setChannelCode(payChannelCodeEnum);
|
||||||
|
payOrderDO.setOrganId(organId);
|
||||||
|
return payOrderDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算结束时间
|
||||||
|
*
|
||||||
|
* @param startTime
|
||||||
|
* @param duration
|
||||||
|
* @param durationUnit
|
||||||
|
* @param giftDuration
|
||||||
|
* @param giftDurationUnit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static LocalDateTime calculateEndTime(LocalDateTime startTime, String duration, Integer durationUnit,
|
||||||
|
String giftDuration, Integer giftDurationUnit) {
|
||||||
|
|
||||||
|
// 加正常时间
|
||||||
|
if (StringUtils.isNotEmpty(duration) && durationUnit != null) {
|
||||||
|
startTime = addTime(startTime, Integer.parseInt(duration), durationUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加赠送时间
|
||||||
|
if (StringUtils.isNotEmpty(giftDuration) && giftDurationUnit != null) {
|
||||||
|
startTime = addTime(startTime, Integer.parseInt(giftDuration), giftDurationUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于时长和单位累加time
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* @param duration
|
||||||
|
* @param unit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static LocalDateTime addTime(LocalDateTime time, int duration, int unit) {
|
||||||
|
switch (DurationUnitEnum.fromStatus(unit)) {
|
||||||
|
case YEAR:
|
||||||
|
return time.plusYears(duration);
|
||||||
|
case MONTH:
|
||||||
|
return time.plusMonths(duration);
|
||||||
|
case DAY:
|
||||||
|
return time.plusDays(duration);
|
||||||
|
default:
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+59
-4
@@ -1,12 +1,31 @@
|
|||||||
package com.cf.imes.module.system.service.pay.factory.impl.wechat;
|
package com.cf.imes.module.system.service.pay.factory.impl.wechat;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||||
|
import com.cf.imes.framework.pay.config.ChenfengWechatPayConfig;
|
||||||
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||||
|
import com.cf.imes.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
|
||||||
|
import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
|
||||||
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
|
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
|
||||||
|
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
||||||
|
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
|
||||||
|
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
||||||
|
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||||
|
import com.github.binarywang.wxpay.service.WxPayService;
|
||||||
|
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static cn.hutool.core.date.DatePattern.PURE_DATETIME_PATTERN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信native支付处理器
|
* 微信native支付处理器
|
||||||
@@ -18,9 +37,32 @@ import java.util.Map;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class WechatNativePayHandler extends AbstractPayHandler {
|
public class WechatNativePayHandler extends AbstractPayHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ChenfengWechatPayConfig chenfengWechatPayConfig;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
|
public PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws WxPayException {
|
||||||
return null;
|
// 构建 WxPayUnifiedOrderRequest 对象
|
||||||
|
WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
|
||||||
|
.outTradeNo(reqDTO.getOutTradeNo())
|
||||||
|
.body(reqDTO.getSubject())
|
||||||
|
.detail(reqDTO.getBody())
|
||||||
|
.totalFee(reqDTO.getPrice()) // 单位分
|
||||||
|
.timeExpire(TemporalAccessorUtil.format(reqDTO.getExpireTime().atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN))
|
||||||
|
.spbillCreateIp(reqDTO.getUserIp())
|
||||||
|
.notifyUrl(reqDTO.getNotifyUrl())
|
||||||
|
.attach(JSON.toJSONString(reqDTO.getPassbackParams()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
WxPayService client = new WxPayServiceImpl();
|
||||||
|
client.setConfig(chenfengWechatPayConfig);
|
||||||
|
|
||||||
|
// 执行请求
|
||||||
|
WxPayAppOrderResult response = client.createOrder(request);
|
||||||
|
|
||||||
|
// 转换结果
|
||||||
|
return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), JsonUtils.toJsonString(response),
|
||||||
|
reqDTO.getOutTradeNo(), response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -29,7 +71,20 @@ public class WechatNativePayHandler extends AbstractPayHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
|
public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) throws WxPayException {
|
||||||
return null;
|
// 1. 解析回调
|
||||||
|
WxPayService client = new WxPayServiceImpl();
|
||||||
|
client.setConfig(chenfengWechatPayConfig);
|
||||||
|
WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body);
|
||||||
|
// 2. 构建结果
|
||||||
|
// V2 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂
|
||||||
|
Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ?
|
||||||
|
PayOrderStatusEnum.SUCCESS.getStatus() : PayOrderStatusEnum.FAIL.getStatus();
|
||||||
|
return PayOrderRespDTO.of(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()),
|
||||||
|
response.getOutTradeNo(), body);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LocalDateTime parseDateV2(String time) {
|
||||||
|
return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-63
@@ -1,63 +0,0 @@
|
|||||||
package com.cf.imes.module.system.util;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class SnowflakeIdWorker3rd {
|
|
||||||
/** 初始时间 (2024-01-01 毫秒数: 1704038400000L) */
|
|
||||||
private final long twepoch = 1704038400000L;
|
|
||||||
/** 序列号占位数 */
|
|
||||||
private final long sequenceBits = 12L;
|
|
||||||
/** 时间戳左移位数 */
|
|
||||||
private final long timestampLeftShift = 22L; // 12位序列号 + 10位预留
|
|
||||||
/** 序列号掩码 */
|
|
||||||
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
|
|
||||||
/** 当前序列号 */
|
|
||||||
private long sequence = 0L;
|
|
||||||
/** 上次生成ID的时间戳 */
|
|
||||||
private long lastTimestamp = -1L;
|
|
||||||
|
|
||||||
public synchronized long nextId() {
|
|
||||||
long timestamp = timeGen();
|
|
||||||
if (timestamp < lastTimestamp) {
|
|
||||||
throw new RuntimeException("时钟回拨,无法生成ID。回拨时间:" + (lastTimestamp - timestamp) + "ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同一毫秒内生成序列号
|
|
||||||
if (timestamp == lastTimestamp) {
|
|
||||||
sequence = (sequence + 1) & sequenceMask;
|
|
||||||
// 序列号溢出,等待下一毫秒
|
|
||||||
if (sequence == 0) {
|
|
||||||
timestamp = tilNextMillis(lastTimestamp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sequence = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTimestamp = timestamp;
|
|
||||||
// 组合时间戳和序列号生成ID
|
|
||||||
return ((timestamp - twepoch) << timestampLeftShift) | sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 等待至下一毫秒 */
|
|
||||||
private long tilNextMillis(long lastTimestamp) {
|
|
||||||
long timestamp = timeGen();
|
|
||||||
while (timestamp <= lastTimestamp) {
|
|
||||||
timestamp = timeGen();
|
|
||||||
}
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前毫秒时间 */
|
|
||||||
private long timeGen() {
|
|
||||||
return System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SnowflakeIdWorker3rd idWorker = new SnowflakeIdWorker3rd();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
System.out.println(idWorker.nextId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -291,6 +291,12 @@ chenfeng:
|
|||||||
privateKey: H/XEvo3RBcn9PFtuV6R94kMDyLkhAyVP0TrY6LNZPDKSpt6m47265Q5wZJzlcZ2FO1ChVaqd4SNQQuQiSkTwzS3dlHtJuZO4SDzSzwDfCQCgAbGkMNjJyMue9WOjtumxC19vDZVQvmQHP+iFis/psw5MMppp+GwtyVGm64kwhKAlUvbSOJWN38H3z0i67KdcRC07tdoD5NTh5vWQOljRK52ISHlxssaK8+oC9rTSsI6mvkNL1OH/MktfLfmWEfZTX8tuSIrLkWikU9NFfXjD+IWrkC7qRIxdDeWHwCHTU86KSkYteRkMaltLmvWXBYycieM18iRIf2QvT6/gymkT8qosvderqKS0wz5gCIq9LVEZVdYsNKcXAZvN56lVlbb3zsHIFCtZBTfwSHJ5xy3r4Xn3kor8QqeCMk+ACZoxTaORxJ/phPEltCgIEVhAXCMdRmpJKd11NsjAHAP0P633MOhl/i2fzeagJWhV1wk1S8N0m4hfvchn//JEjxsqU90S3fuQokvj7KnDfXUsu9RgOAySAyZbkuMM7q/s7ZPNd0y41WmBoK3gVesu3qKfNzeap9vRD/N8ccyiRG1HwhH3NJhJ8Uo158KNFlJydFsq1Lllm0MsokeJEwEQuVUX07RfM9sPbdFfluXLTP1Xi817lKO8duIqwTmHcesv9Zlb2DX9prMtuTWB/CokboGhXh1L1gAtPXMCIHcjNpz+ACIOhxdQEP5hW9zRWnhF6LMc9lReUPnkKj7Lx08FLTsX8O00gvzX7plR8UyrMJc7a7MMRjN98L1XBKDzHg3gonIJXdGJxJP1j0elyILjr6DUDB8H4fYVmndm9FcuCMTXx84poIK39BAey5PJPvFTm1l8l6vw3gXjajffLhgdqCqn60nwG20464FvZusdMzmx/7s5HPB5wGfCNQZ0J+Q5FctITR92juHTUe6BsBbo7ZlGkWBlJByGy0kw4m81jCFzQpymTmpWaxCi56ysHnMXRnbeMyPe7v/6pHvNqwMLOBJzKBZi72I3o0gEuBnxR87F4r1GAVljlmSthxYFqWe4Jt9zG+dnUrscWJ+/pvGaRz40exLl8ahywPNX63sm9uXqt96PAqosOB1Il9vwY31xa+OeSOp4gT5thKKbbUtTPQIu92vp82HdFCTLLwDYOa3NQPrvxZjWH8cR6sYM7D1AUizzHNc6WfiU1YutDOHQVev6U9RKqwsZKgj94ySa1bH+24CiglXojLyAQ1uU99Hkth3JwCX2hPpCyNHJ34mhsMoe0XZZRrpzmtxRBkhVHtyF44pVekCH/SU3qZkeNuk5ETk+13GpZ7vhbmE9dBpLR4LsiPEfGJHqNH8D624cEKbcXcAL4tWfYiBqQAHlqnnd3dLHLawaAbXGr6xM0/hXVT/Z9Cb1Yh//pPtGnuHPZVCKSzdL14NLDlhJ3IDDYcmDW8pjbCRXNsfi75eZgNJwju2A6+I7j3Ovl0ma8kHrA73SAy2e8ldx25t7kvuw3s/kcYLCuGo9d4Fq0RpTk3YzF7XlevoHxrfXjxf/tGoZCrttURFjaWVtNnOmo2He894V3mSpl3IuaPwvo2VrPPlSFQ3aNkK0/Et2Gmt7OWGRHWgzPKWH378zMxPMo5cYcktmKXvOBvGyrMrHbKEl1lMMM/cAZh6pMdtcqU5J3kCKUbickAkf10KgULzqenPku+7rFB34Uv0Emw5s+l42bW9pcia58FyY+3km6Fl3dkPe2nm7YRvWSfisCAyCi/CHqxHecgchCParCJ9EcGoMADQfzkfsJInIuOT5c8IQXYzwqpSpHMk9n5JjqcyfCNPWEO1/YQOYTExkeDp4SENYIf6TZxvPQCb5cOnYzZcct2YNSrPzKahmzoTwpYmTxxMYuunFlWmyineV/Y+1sGoQ/Lzk+M83uf3UCHG9Pbsp5gFj9t21U95Yukw4Qs45fG8bVPPYfU97K/DrWDd4tfroFUyResqAP2HsXKNd0k+59rpBzEg2TrJH0XlU9zBdU0Oe93HSC/0TggZrKtd717uQXKqo5hJ65lV0JqbZInl92qK2t6BqZE/sKj4hMdeHnAebxROfLOojLFtJB5se6Dn9XnG+sf/cExSMmJqgDIGsOyGt7aA1dV0tDbzgio2V6jjOE2U9kx4luHuaTd2aWJ0oIAuWo6v2U3kMcLH8z+KqtnWAgGS0mEgpr7iz27w=
|
privateKey: H/XEvo3RBcn9PFtuV6R94kMDyLkhAyVP0TrY6LNZPDKSpt6m47265Q5wZJzlcZ2FO1ChVaqd4SNQQuQiSkTwzS3dlHtJuZO4SDzSzwDfCQCgAbGkMNjJyMue9WOjtumxC19vDZVQvmQHP+iFis/psw5MMppp+GwtyVGm64kwhKAlUvbSOJWN38H3z0i67KdcRC07tdoD5NTh5vWQOljRK52ISHlxssaK8+oC9rTSsI6mvkNL1OH/MktfLfmWEfZTX8tuSIrLkWikU9NFfXjD+IWrkC7qRIxdDeWHwCHTU86KSkYteRkMaltLmvWXBYycieM18iRIf2QvT6/gymkT8qosvderqKS0wz5gCIq9LVEZVdYsNKcXAZvN56lVlbb3zsHIFCtZBTfwSHJ5xy3r4Xn3kor8QqeCMk+ACZoxTaORxJ/phPEltCgIEVhAXCMdRmpJKd11NsjAHAP0P633MOhl/i2fzeagJWhV1wk1S8N0m4hfvchn//JEjxsqU90S3fuQokvj7KnDfXUsu9RgOAySAyZbkuMM7q/s7ZPNd0y41WmBoK3gVesu3qKfNzeap9vRD/N8ccyiRG1HwhH3NJhJ8Uo158KNFlJydFsq1Lllm0MsokeJEwEQuVUX07RfM9sPbdFfluXLTP1Xi817lKO8duIqwTmHcesv9Zlb2DX9prMtuTWB/CokboGhXh1L1gAtPXMCIHcjNpz+ACIOhxdQEP5hW9zRWnhF6LMc9lReUPnkKj7Lx08FLTsX8O00gvzX7plR8UyrMJc7a7MMRjN98L1XBKDzHg3gonIJXdGJxJP1j0elyILjr6DUDB8H4fYVmndm9FcuCMTXx84poIK39BAey5PJPvFTm1l8l6vw3gXjajffLhgdqCqn60nwG20464FvZusdMzmx/7s5HPB5wGfCNQZ0J+Q5FctITR92juHTUe6BsBbo7ZlGkWBlJByGy0kw4m81jCFzQpymTmpWaxCi56ysHnMXRnbeMyPe7v/6pHvNqwMLOBJzKBZi72I3o0gEuBnxR87F4r1GAVljlmSthxYFqWe4Jt9zG+dnUrscWJ+/pvGaRz40exLl8ahywPNX63sm9uXqt96PAqosOB1Il9vwY31xa+OeSOp4gT5thKKbbUtTPQIu92vp82HdFCTLLwDYOa3NQPrvxZjWH8cR6sYM7D1AUizzHNc6WfiU1YutDOHQVev6U9RKqwsZKgj94ySa1bH+24CiglXojLyAQ1uU99Hkth3JwCX2hPpCyNHJ34mhsMoe0XZZRrpzmtxRBkhVHtyF44pVekCH/SU3qZkeNuk5ETk+13GpZ7vhbmE9dBpLR4LsiPEfGJHqNH8D624cEKbcXcAL4tWfYiBqQAHlqnnd3dLHLawaAbXGr6xM0/hXVT/Z9Cb1Yh//pPtGnuHPZVCKSzdL14NLDlhJ3IDDYcmDW8pjbCRXNsfi75eZgNJwju2A6+I7j3Ovl0ma8kHrA73SAy2e8ldx25t7kvuw3s/kcYLCuGo9d4Fq0RpTk3YzF7XlevoHxrfXjxf/tGoZCrttURFjaWVtNnOmo2He894V3mSpl3IuaPwvo2VrPPlSFQ3aNkK0/Et2Gmt7OWGRHWgzPKWH378zMxPMo5cYcktmKXvOBvGyrMrHbKEl1lMMM/cAZh6pMdtcqU5J3kCKUbickAkf10KgULzqenPku+7rFB34Uv0Emw5s+l42bW9pcia58FyY+3km6Fl3dkPe2nm7YRvWSfisCAyCi/CHqxHecgchCParCJ9EcGoMADQfzkfsJInIuOT5c8IQXYzwqpSpHMk9n5JjqcyfCNPWEO1/YQOYTExkeDp4SENYIf6TZxvPQCb5cOnYzZcct2YNSrPzKahmzoTwpYmTxxMYuunFlWmyineV/Y+1sGoQ/Lzk+M83uf3UCHG9Pbsp5gFj9t21U95Yukw4Qs45fG8bVPPYfU97K/DrWDd4tfroFUyResqAP2HsXKNd0k+59rpBzEg2TrJH0XlU9zBdU0Oe93HSC/0TggZrKtd717uQXKqo5hJ65lV0JqbZInl92qK2t6BqZE/sKj4hMdeHnAebxROfLOojLFtJB5se6Dn9XnG+sf/cExSMmJqgDIGsOyGt7aA1dV0tDbzgio2V6jjOE2U9kx4luHuaTd2aWJ0oIAuWo6v2U3kMcLH8z+KqtnWAgGS0mEgpr7iz27w=
|
||||||
alipayPublicKey: KbUGE7zsPBKWPx0/zMcAdLRldKrcgy2LRiOrqOBm7y4iPJLXTYtXFJT15p2JMQiyOM8mqiYQR0OEDwfrKxDgHXLtIut/e0EAk9bZwZoLrqVe0pN1huseRC38zEglbWil3yz+tZfHZuAaEq2EzvWJltX/tRKOzNBqAT9l+UvnqNedgCFB9MY2EErqJjbn/at3gYCkV2idt31ghF0z8SEQ5h9ztNYtmTvk8c8ipi0/hIjX8XryN6mlOvGQfyZ4rWrBWBuZ6iD/SyuThwxKmFYU4dhHbHVpBrva5nJWU43CP7RVaJm649nNJnce+Ppj2Tv8+ugSLe5poZWo2zmGe3Xn5WmN6OTZyRI1pnmn2/hGxtOMmTZJX7Gh0pI4v3wmU0gOd/gbRlqlvN+u12T92nyH8MQrHdA7UXuttAtolYUa/Rli/20qHX69QtOtvfZk8mNvDSj9dDvODseGcrFHm07jyfxpaIkQDeN75cQ3NwNgDQEW8urQszaU1IJ7hc+20tt0Z3td4+7MfiVPpGfVxsGE66gwLgpB8wsxEhyBTaBr7osMLqOv
|
alipayPublicKey: KbUGE7zsPBKWPx0/zMcAdLRldKrcgy2LRiOrqOBm7y4iPJLXTYtXFJT15p2JMQiyOM8mqiYQR0OEDwfrKxDgHXLtIut/e0EAk9bZwZoLrqVe0pN1huseRC38zEglbWil3yz+tZfHZuAaEq2EzvWJltX/tRKOzNBqAT9l+UvnqNedgCFB9MY2EErqJjbn/at3gYCkV2idt31ghF0z8SEQ5h9ztNYtmTvk8c8ipi0/hIjX8XryN6mlOvGQfyZ4rWrBWBuZ6iD/SyuThwxKmFYU4dhHbHVpBrva5nJWU43CP7RVaJm649nNJnce+Ppj2Tv8+ugSLe5poZWo2zmGe3Xn5WmN6OTZyRI1pnmn2/hGxtOMmTZJX7Gh0pI4v3wmU0gOd/gbRlqlvN+u12T92nyH8MQrHdA7UXuttAtolYUa/Rli/20qHX69QtOtvfZk8mNvDSj9dDvODseGcrFHm07jyfxpaIkQDeN75cQ3NwNgDQEW8urQszaU1IJ7hc+20tt0Z3td4+7MfiVPpGfVxsGE66gwLgpB8wsxEhyBTaBr7osMLqOv
|
||||||
notifyUrl: RIEeHCoPHaAryuVN6mEYskBSl+EPvhsxRpjIbuIE7f7jABVxm46bLc01WQUe4Fn9NPYyNTv0xCxM68iRrmFDjAUjQ/hkIVNG+yD/kNsjcYCWa2gtOQPrvWZzDA==
|
notifyUrl: RIEeHCoPHaAryuVN6mEYskBSl+EPvhsxRpjIbuIE7f7jABVxm46bLc01WQUe4Fn9NPYyNTv0xCxM68iRrmFDjAUjQ/hkIVNG+yD/kNsjcYCWa2gtOQPrvWZzDA==
|
||||||
|
# wechat:
|
||||||
|
# payBaseUrl: https://api.mch.weixin.qq.com/xdc/apiv2sandbox
|
||||||
|
# appId: wxd0b9c0b5d0b9c0b5
|
||||||
|
# mchId: 1725093395
|
||||||
|
# mchKey: Cf100261028910026102891002610289
|
||||||
|
|
||||||
|
|
||||||
justauth:
|
justauth:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ mybatis-plus:
|
|||||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||||
global-config:
|
global-config:
|
||||||
db-config:
|
db-config:
|
||||||
|
worker-id: 0
|
||||||
|
datacenter-id: 0
|
||||||
id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
|
||||||
# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
|
# id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
|
||||||
# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
# id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
|
||||||
|
|||||||
Reference in New Issue
Block a user