diff --git a/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderRespDTO.java b/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderRespDTO.java index 5338054be..3fbee25c5 100644 --- a/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderRespDTO.java +++ b/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderRespDTO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.Map; /** * 渠道支付订单 Response DTO @@ -75,6 +76,11 @@ public class PayOrderRespDTO { */ private String channelErrorMsg; + /** + * 发起支付给支付方后,异步回调原封不动回到调用方 + */ + private Map passbackParams; + /** * 创建【WAITING】状态的订单返回 */ @@ -122,6 +128,23 @@ public class PayOrderRespDTO { return respDTO; } + /** + * 创建指定状态的订单返回,适合支付渠道回调时 + */ + public static PayOrderRespDTO of(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, + String outTradeNo, Object rawData, Map passbackParams) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = status; + respDTO.channelOrderNo = channelOrderNo; + respDTO.channelUserId = channelUserId; + respDTO.successTime = successTime; + // 相对通用的字段 + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + respDTO.passbackParams = passbackParams; + return respDTO; + } + /** * 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时 */ diff --git a/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java b/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java index 00c9dd44c..c0606a7e0 100644 --- a/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java +++ b/cf-framework/cf-spring-boot-starter-biz-pay/src/main/java/com/cf/imes/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java @@ -85,6 +85,11 @@ public class PayOrderUnifiedReqDTO { */ private Map channelExtras; + /** + * 发起支付给支付方后,异步回调原封不动回到调用方 + */ + private Map passbackParams; + /** * 展示模式 * diff --git a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/constants/RedisKeyConstants.java b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/constants/RedisKeyConstants.java index 171adf40e..da25a288a 100644 --- a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/constants/RedisKeyConstants.java +++ b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/constants/RedisKeyConstants.java @@ -16,4 +16,10 @@ public class RedisKeyConstants { * 刷新权限 */ public static final String PERMISSION_REFRESH = "PERMISSION_REFRESH"; + + + /** + * + */ + public static final String PAY_NOTIFY_ORDER_LOCK_KEY = "pay_recharge_order:%s%s"; } diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index b80d160f5..4d853e604 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -411,7 +411,7 @@ public class ErrorCodeConstants { //=========== 资金管理 1-002-043-000 ============ - public static final ErrorCode ORGAN_AMOUNT_NO_EXIST = new ErrorCode(1_002_043_001, "当前组织无资金管理"); + public static final ErrorCode ORGAN_AMOUNT_NO_EXIST = new ErrorCode(1_002_043_001, "当前组织没有可用的资金记录,请联系客服"); public static final ErrorCode INVOICE_NO_EXIST = new ErrorCode(1_002_043_002, "当前发票记录有误,请重新查看"); public static final ErrorCode INVOICING_REJECT_REASON = new ErrorCode(1_002_043_003, "请填写拒绝开票原因"); public static final ErrorCode INVOICE_FILE_IS_NULL = new ErrorCode(1_002_043_004, "发票附件不存在,请重新上传"); @@ -433,6 +433,7 @@ public class ErrorCodeConstants { public static final ErrorCode ADVERTISEMENT_REPUBLISH_NO_TIME = new ErrorCode(1_002_043_021, "广告重新发布,应重新选择投放时间"); 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 ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR = new ErrorCode(1_002_043_024, "组织充值失败,请检查组织资金数据"); //=========== 支付相关 1-002-048-000 ============ public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道"); @@ -442,6 +443,9 @@ public class ErrorCodeConstants { public static final ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1_002_048_004, "支付订单不处于待支付"); public static final ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_002_048_005, "发起渠道支付异常,请联系客服"); public static final ErrorCode PAY_RECHARGE_ORDER_ORGANID_CHECK_ERROR = new ErrorCode(1_002_048_006, "充值目标组织和当前操作人组织不同,发起充值支付失败"); + 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_TRADETYPE_NOT_SUPPORT_ERROR = new ErrorCode(1_002_048_009, "不支持的支付回调tradeType:【{}】,请检查支付渠道"); //=========== 产品相关 1-002-045-000 ============ public static final ErrorCode PRODUCTS_NO_EXIST = new ErrorCode(1_002_045_001, "当前产品不存在"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/BalanceDetailsController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/BalanceDetailsController.java new file mode 100644 index 000000000..a970c8afd --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/BalanceDetailsController.java @@ -0,0 +1,63 @@ +package com.cf.imes.module.system.controller.admin.funds.balancedetails; + + +import com.cf.imes.framework.common.pojo.CommonResult; +import com.cf.imes.framework.common.pojo.PageParam; +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.common.util.object.BeanUtils; +import com.cf.imes.framework.excel.core.util.ExcelUtils; +import com.cf.imes.framework.operatelog.core.annotations.OperateLog; + +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsPageReqVO; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsRespVO; +import com.cf.imes.module.system.service.funds.incomeandexpense.IncomeExpenseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static com.cf.imes.framework.common.pojo.CommonResult.success; +import static com.cf.imes.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +/** + * @author 组织余额明细 + */ +@Tag(name = "管理后台 - 组织余额明细") +@RestController +@RequestMapping("/system/balance") +@Validated +public class BalanceDetailsController { + + + @Resource + private IncomeExpenseService incomeExpenseService; + + @GetMapping("") + @Operation(summary = "查询组织余额明细分页") + public CommonResult> getBalanceDetailsPage(@Valid BalanceDetailsPageReqVO pageReqVO) { + return success(incomeExpenseService.getBalanceDetailsPage(pageReqVO)); + } + + + + + @GetMapping("/export") + @Operation(summary = "组织余额明细导出") + @OperateLog(type = EXPORT) + public void balanceDetailsExport(@Valid BalanceDetailsPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = incomeExpenseService.getBalanceDetailsPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "余额明细表.xls", "数据", BalanceDetailsRespVO.class, + BeanUtils.toBean(list, BalanceDetailsRespVO.class)); + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsPageReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsPageReqVO.java new file mode 100644 index 000000000..5bd8881b9 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsPageReqVO.java @@ -0,0 +1,40 @@ +package com.cf.imes.module.system.controller.admin.funds.balancedetails.vo; + + +import com.cf.imes.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; + +import static com.cf.imes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + + +@Schema(description = "管理后台 - 组织余额明细分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +public class BalanceDetailsPageReqVO extends PageParam { + + + @Schema(description = "流水号") + private String businessNo; + + @Schema(description = "交易类型") + private Integer tradeType; + + @Schema(description = "收支类型") + private Integer incomeExpenseType; + + @Schema(description = "创建时间", example = "[2022-07-01 ,2022-07-01]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate[] createTime; + + @Schema(description = "组织ID") + private Long organId; + + +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsRespVO.java new file mode 100644 index 000000000..5ec738a66 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/balancedetails/vo/BalanceDetailsRespVO.java @@ -0,0 +1,82 @@ +package com.cf.imes.module.system.controller.admin.funds.balancedetails.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class BalanceDetailsRespVO { + + + @Schema(description = "流水号") + @ExcelProperty("流水号") + private String businessNo; + + + @Schema(description = "交易类型,0充值 1软件购买") + @ExcelProperty("交易类型") + private Integer tradeType; + + + @Schema(description = "收支类型,0收入 1支出") + private Integer incomeExpenseType; + + + @Schema(description = "入账现金") + @ExcelProperty("入账现金") + private BigDecimal entryAmount; + + + @Schema(description = "入账赠送金") + @ExcelProperty("入账赠送金") + private BigDecimal entryGiftAmount; + + + @Schema(description = "支出现金") + @ExcelProperty("支出现金") + private BigDecimal expensesAmount; + + + @Schema(description = "支出赠送金") + @ExcelProperty("支出赠送金") + private BigDecimal expensesGiftAmount; + + + @Schema(description = "可用金额") + @ExcelProperty("可用金额") + private BigDecimal availableAmount; + + + @Schema(description = "现金金额") + @ExcelProperty("现金金额") + private BigDecimal amount; + + + @Schema(description = "赠送金额") + @ExcelProperty("赠送金额") + private BigDecimal giftAmount; + + + @Schema(description = "交易时间") + @ExcelProperty("交易时间") + private LocalDateTime createTime; + + + @Schema(description = "操作人") + @ExcelProperty("操作人") + private String creator; + + + @Schema(description = "支出/入账现金金额") + private BigDecimal cashAmountChange; + + + + @Schema(description = "支出/入账赠送金金额") + private BigDecimal bonusAmountChange; + + +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganAmountRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganAmountRespVO.java index 5c3e7f87c..68bfcb788 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganAmountRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganAmountRespVO.java @@ -1,6 +1,5 @@ package com.cf.imes.module.system.controller.admin.funds.organamount.vo; - import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -9,12 +8,6 @@ import java.math.BigDecimal; @Schema(description = "管理后台 - 组织余额信息 Response VO") @Data public class OrganAmountRespVO { - - - @Schema(description = "可用总金额") - private BigDecimal availableAmount; - - @Schema(description = "现金余额") private BigDecimal amount; @@ -26,5 +19,7 @@ public class OrganAmountRespVO { @Schema(description = "可开票金额") private BigDecimal invoiceableAmount; + @Schema(description = "产品有效期") + private String productEfficientDate; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganRechargeAmountRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganRechargeAmountRespVO.java new file mode 100644 index 000000000..f6b9936c2 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/organamount/vo/OrganRechargeAmountRespVO.java @@ -0,0 +1,31 @@ +package com.cf.imes.module.system.controller.admin.funds.organamount.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author Gqr + * @since 2025/8/13 16:46 + */ +@Schema(description = "管理后台 - 组织充值后余额信息 Response VO") +@Data +@AllArgsConstructor +public class OrganRechargeAmountRespVO { + /** + * 可用余额 + */ + private BigDecimal availableAmount; + + /** + * 现金余额 + */ + private BigDecimal amount; + + /** + * 赠送金余额 + */ + private BigDecimal giftAmount; +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/pay/PayController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/pay/PayController.java index 277d18a1d..70be38d9f 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/pay/PayController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/pay/PayController.java @@ -2,10 +2,10 @@ package com.cf.imes.module.system.controller.admin.pay; import com.cf.imes.framework.common.pojo.CommonResult; 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.service.pay.PayOrderService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; @@ -44,15 +44,17 @@ public class PayController { return success(payOrderRespDTO); } - @PostMapping("/product") - @Operation(summary = "创建产品支付订单") - public CommonResult initiatePay(@RequestBody PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) { - payOrderService.productPay(payProductOrderUnifiedReqVO); - return success(null); - } +// @PostMapping("/product") +// @Operation(summary = "创建产品支付订单") +// public CommonResult initiatePay(@RequestBody PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) { +// payOrderService.productPay(payProductOrderUnifiedReqVO); +// return success(null); +// } @GetMapping("/order/{channelCode}/{outTradeNo}") @Operation(summary = "查询支付订单") + @Parameter(name = "outTradeNo", description = "支付流水号", required = true, example = "P1O1955") + @Parameter(name = "channelCode", description = "支付渠道", required = true, example = "0") public CommonResult queryPayOrder(@PathVariable("outTradeNo") String outTradeNo, @PathVariable("channelCode") int channelCode) { payOrderService.queryPayOrderStatus(outTradeNo, channelCode); return success(true); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/organamount/OrganAmountDO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/organamount/OrganAmountDO.java index 59a027109..1f4b1c830 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/organamount/OrganAmountDO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/organamount/OrganAmountDO.java @@ -9,8 +9,8 @@ import lombok.*; import java.math.BigDecimal; -@TableName("organ_amount") -@KeySequence("organ_amount_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("system_organization_amount") +@KeySequence("system_organization_amount_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @@ -62,5 +62,8 @@ public class OrganAmountDO extends BaseDO { */ private BigDecimal invoiceableAmount; - + /** + * 版本号 + */ + private int version; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/incomeandexpense/IncomeExpenseDetailsDO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/incomeandexpense/IncomeExpenseDetailsDO.java new file mode 100644 index 000000000..02bfda3f3 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/incomeandexpense/IncomeExpenseDetailsDO.java @@ -0,0 +1,118 @@ +package com.cf.imes.module.system.dal.dataobject.incomeandexpense; + +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; + +/** + * @author 收支明细表 + */ +@TableName("income_expense_details") +@KeySequence("income_expense_details_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IncomeExpenseDetailsDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + + + /** + * 流水号 + */ + private String businessNo; + + + /** + * 组织ID + */ + private Long organId; + + + /** + * 充值-赠送金规则表 + */ + private Long giftMoneyId; + + + /** + * 购买-购买记录id + */ + private Long purchaseId; + + + /** + * 交易类型 + */ + private Integer tradeType; + + + /** + * 收支类型 + */ + private Integer incomeExpenseType; + + + /** + * 支出/入账现金金额 + */ + private BigDecimal cashAmountChange; + + + /** + * 支出/入账赠送金金额 + */ + private BigDecimal bonusAmountChange; + + + /** + * 可用余额 + */ + private BigDecimal availableAmount; + + + + /** + * 现金金额 + */ + private BigDecimal amount; + + + /** + * 赠送金额 + */ + private BigDecimal giftAmount; + + + /** + * 货币类型 + */ + private Integer currency; + + + /** + * 货币单位 + */ + private String currencyUnit; + + + + + +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/incomeandexpense/IncomeExpenseDetailsMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/incomeandexpense/IncomeExpenseDetailsMapper.java new file mode 100644 index 000000000..a69bdb3a2 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/incomeandexpense/IncomeExpenseDetailsMapper.java @@ -0,0 +1,32 @@ +package com.cf.imes.module.system.dal.mysql.incomeandexpense; + + +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; +import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsPageReqVO; +import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 收支明细 Mapper + * + * @author Gqr + * @since 2025/8/13 11:41 + */ +@Mapper +public interface IncomeExpenseDetailsMapper extends BaseMapperX { + default PageResult selectDetailsPage(BalanceDetailsPageReqVO pageReqVO, List organIds) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(IncomeExpenseDetailsDO::getOrganId, pageReqVO.getOrganId()) + .inIfPresent(IncomeExpenseDetailsDO::getOrganId, organIds) + .eq(IncomeExpenseDetailsDO::getDeleted, false) + .likeIfPresent(IncomeExpenseDetailsDO::getBusinessNo, pageReqVO.getBusinessNo()) + .eqIfPresent(IncomeExpenseDetailsDO::getTradeType,pageReqVO.getTradeType()) + .eqIfPresent(IncomeExpenseDetailsDO::getIncomeExpenseType,pageReqVO.getIncomeExpenseType()) + .betweenIfPresent(IncomeExpenseDetailsDO::getCreateTime,pageReqVO.getCreateTime())); + + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/IncomeExpenseTypeEnum.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/IncomeExpenseTypeEnum.java new file mode 100644 index 000000000..9c4a7b134 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/IncomeExpenseTypeEnum.java @@ -0,0 +1,51 @@ +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 IncomeExpenseTypeEnum { + + /** + * 收入 + */ + INCOME(0, "收入"), + /** + * 支出 + */ + EXPENSES(1, "支出"); + + + + /** + * 类型 + */ + private final Integer type; + + /** + * 名称 + */ + private final String name; + + + + public static IncomeExpenseTypeEnum fromType(Integer type) { + if (type == null) { + return null; + } + for (IncomeExpenseTypeEnum value : values()) { + if (ObjectUtil.equal(value.getType(), type)) { + return value; + } + } + return null; + } + +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/PayConstants.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/PayConstants.java new file mode 100644 index 000000000..0656d674f --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/PayConstants.java @@ -0,0 +1,11 @@ +package com.cf.imes.module.system.enums.pay; + +/** + * 支付常量 + * @author Gqr + * @since 2025/8/12 17:49 + */ +public class PayConstants { + 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 +} \ No newline at end of file diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/TradeTypeEnum.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/TradeTypeEnum.java new file mode 100644 index 000000000..0134c7806 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/enums/pay/TradeTypeEnum.java @@ -0,0 +1,34 @@ +package com.cf.imes.module.system.enums.pay; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 交易类型枚举 + * @author Gqr + * @since 2025/8/12 17:45 + */ +@Getter +@AllArgsConstructor +public enum TradeTypeEnum { + /** + * 充值 + */ + RECHARGE(0), + + /** + * 产品购买 + */ + PRODUCT(1); + + private final Integer code; + + public static TradeTypeEnum fromCode(Integer code) { + for (TradeTypeEnum value : TradeTypeEnum.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseService.java new file mode 100644 index 000000000..e35761c77 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseService.java @@ -0,0 +1,29 @@ +package com.cf.imes.module.system.service.funds.incomeandexpense; + +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsPageReqVO; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsRespVO; +import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO; + +/** + * 收支明细接口 + * + * @author Gqr + * @since 2025/8/13 10:19 + */ +public interface IncomeExpenseService { + /** + * 创建收支明细 + * + * @param incomeExpenseDetailsDO + */ + void createDetail(IncomeExpenseDetailsDO incomeExpenseDetailsDO); + + /** + * 查询余额明细分页 + * + * @param pageReqVO + * @return + */ + PageResult getBalanceDetailsPage(BalanceDetailsPageReqVO pageReqVO); +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseServiceImpl.java new file mode 100644 index 000000000..26037bd92 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/incomeandexpense/IncomeExpenseServiceImpl.java @@ -0,0 +1,51 @@ +package com.cf.imes.module.system.service.funds.incomeandexpense; + +import cn.hutool.core.collection.CollUtil; +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.common.util.object.BeanUtils; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsPageReqVO; +import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsRespVO; +import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO; +import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper; +import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +/** + * 收支明细接口实现类 + * + * @author Gqr + * @since 2025/8/13 10:29 + */ +@Service +public class IncomeExpenseServiceImpl implements IncomeExpenseService { + @Resource + private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper; + + @Override + public void createDetail(IncomeExpenseDetailsDO incomeExpenseDetailsDO) { + incomeExpenseDetailsMapper.insert(incomeExpenseDetailsDO); + } + + @Override + public PageResult getBalanceDetailsPage(BalanceDetailsPageReqVO pageReqVO) { + PageResult pageResult = incomeExpenseDetailsMapper.selectDetailsPage(pageReqVO,null); + if(CollUtil.isEmpty(pageResult.getList())){ + return new PageResult<>(); + } + + PageResult result = BeanUtils.toBean(pageResult, BalanceDetailsRespVO.class); + + // 根据收支类型赋值对应的 支出/收入字段 + result.getList().forEach(f -> { + if (f.getIncomeExpenseType().equals(IncomeExpenseTypeEnum.INCOME.getType())) { + f.setEntryAmount(f.getCashAmountChange()); + f.setEntryGiftAmount(f.getBonusAmountChange()); + } else { + f.setExpensesAmount(f.getCashAmountChange()); + f.setExpensesGiftAmount(f.getBonusAmountChange()); + } + }); + return result; + } +} diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountService.java index 2127036b4..c8614c82d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountService.java @@ -3,12 +3,31 @@ package com.cf.imes.module.system.service.funds.organamount; 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.OrganRechargeAmountRespVO; +import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO; + +import java.math.BigDecimal; /** * @author 资金管理接口 */ public interface OrganAmountService { + /** + * 校验机构套餐 + * + * @param organId + */ + OrganAmountDO validOrganAmount(Long organId); + + /** + * 更新机构余额 + * + * @param organId + * @param amount 充值金额 + * @return + */ + OrganRechargeAmountRespVO recharge(Long organId, BigDecimal amount); OrganAmountRespVO getOrganAmount(Long organId); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountServiceImpl.java index 244c83a48..8ccd83361 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/organamount/OrganAmountServiceImpl.java @@ -1,11 +1,14 @@ package com.cf.imes.module.system.service.funds.organamount; -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.framework.common.util.Assert.AssertUtils; import com.cf.imes.framework.common.util.object.BeanUtils; 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.OrganAmountRespVO; +import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO; import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO; import com.cf.imes.module.system.dal.mysql.funds.organamount.OrganAmountMapper; import com.cf.imes.module.system.service.organ.OrganService; @@ -18,6 +21,7 @@ import java.math.BigDecimal; 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_RECHARGE_AMOUNT_UPDATE_ERROR; /** * @author 资金管理接口 实现类 @@ -38,27 +42,63 @@ public class OrganAmountServiceImpl implements OrganAmountService { private ExecutorFundsApi executorFundsApi; + @Override + public OrganAmountDO validOrganAmount(Long organId) { + OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper().eq(OrganAmountDO::getOrganId, organId)); + AssertUtils.notEmpty(organAmountDO, ORGAN_AMOUNT_NO_EXIST); + return organAmountDO; + } + @Override + public OrganRechargeAmountRespVO recharge(Long organId, BigDecimal price) { + OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper().eq(OrganAmountDO::getOrganId, organId)); + + int updated = organAmountMapper.update(new LambdaUpdateWrapper() + .eq(OrganAmountDO::getOrganId, organId) + .eq(OrganAmountDO::getVersion, organAmountDO.getVersion()) + .set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price)) + .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1)); + // 1. 首次更新失败,认为出现并发,再查一次再更新 + if (updated == 0) { + organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper().eq(OrganAmountDO::getOrganId, organId)); + updated = organAmountMapper.update(new LambdaUpdateWrapper() + .eq(OrganAmountDO::getOrganId, organId) + .eq(OrganAmountDO::getVersion, organAmountDO.getVersion()) + .set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price)) + .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1)); + // 2. 第二次更新失败,资金表可能不存在 + if (updated == 0) { + throw exception(ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR); + } else { + // 可用余额:现金+赠送金+支付价格 + BigDecimal availableAmount = organAmountDO.getAmount().add(price).add(organAmountDO.getGiftAmount()); + // 现金余额:现金+支付价格 + BigDecimal amount = organAmountDO.getAmount().add(price); + return new OrganRechargeAmountRespVO(availableAmount, amount, organAmountDO.getGiftAmount()); + } + } else { + // 可用余额:现金+赠送金+支付价格 + BigDecimal availableAmount = organAmountDO.getAmount().add(price).add(organAmountDO.getGiftAmount()); + // 现金余额:现金+支付价格 + BigDecimal amount = organAmountDO.getAmount().add(price); + return new OrganRechargeAmountRespVO(availableAmount, amount, organAmountDO.getGiftAmount()); + } + } @Override public OrganAmountRespVO getOrganAmount(Long organId) { organService.validOrgan(organId); - OrganAmountDO organAmountDO = validateOrganAmountExists(organId); + OrganAmountDO organAmountDO = validOrganAmount(organId); OrganAmountRespVO organAmountRespVO = BeanUtils.toBean(organAmountDO, OrganAmountRespVO.class); - organAmountRespVO.setAvailableAmount(organAmountRespVO.getAmount().add(organAmountRespVO.getGiftAmount())); - return organAmountRespVO; } - - - @Override public AllOrganAmountRespVO getOrganAmountAll() { @@ -76,21 +116,4 @@ public class OrganAmountServiceImpl implements OrganAmountService { } - - - - - private OrganAmountDO validateOrganAmountExists(Long organId) { - - OrganAmountDO organAmountDO = organAmountMapper.selectById(organId); - - if (ObjectUtil.isNull(organAmountDO)) { - throw exception(ORGAN_AMOUNT_NO_EXIST); - } - - return organAmountDO; - - } - - } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayOrderServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayOrderServiceImpl.java index afb535953..7eda3460c 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayOrderServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/PayOrderServiceImpl.java @@ -3,6 +3,7 @@ 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 cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; +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.json.JsonUtils; import com.cf.imes.framework.common.util.validation.ValidationUtils; @@ -22,10 +24,16 @@ import com.cf.imes.framework.common.exception.PayException; import com.cf.imes.framework.pay.core.enums.order.PayOrderStatusRespEnum; 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.pay.vo.PayProductOrderUnifiedReqVO; import com.cf.imes.module.system.controller.admin.pay.vo.PayRechargeOrderReqVO; import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO; +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.PayChannelCodeEnum; +import com.cf.imes.module.system.enums.pay.PayConstants; +import com.cf.imes.module.system.enums.pay.TradeTypeEnum; +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.products.ProductsDetailService; import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler; @@ -43,11 +51,14 @@ import jakarta.validation.Validator; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_CHANNEL_QUERY_NOT_EXIST; import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_NOTIFY_DATA_PARSE_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_NOT_EXIST; @@ -89,6 +100,9 @@ public class PayOrderServiceImpl implements PayOrderService { @Resource private OrganAmountService organAmountService; + @Resource + private IncomeExpenseService incomeExpenseService; + @Override public void productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) { // 主动校验一次入参 @@ -104,25 +118,34 @@ public class PayOrderServiceImpl implements PayOrderService { } @Override + @Transactional(rollbackFor = Exception.class) public PayOrderRespDTO rechargePay(PayRechargeOrderReqVO payRechargeOrderReqVO) { // 主动校验一次入参 ValidationUtils.validate(validator, payRechargeOrderReqVO); + Long organId = payRechargeOrderReqVO.getOrganId(); // 校验组织名称 - AssertUtils.notEquals(payRechargeOrderReqVO.getOrganId(), SecurityFrameworkUtils.getUserOrganId(), PAY_RECHARGE_ORDER_ORGANID_CHECK_ERROR); + AssertUtils.notEquals(organId, SecurityFrameworkUtils.getUserOrganId(), PAY_RECHARGE_ORDER_ORGANID_CHECK_ERROR); + + // 校验组织套餐 + organAmountService.validOrganAmount(organId); - Integer channelCode = payRechargeOrderReqVO.getChannelCode(); // 获取渠道方处理器 + Integer channelCode = payRechargeOrderReqVO.getChannelCode(); AbstractPayHandler payHandler = payHandlerFactory.getPayHandler(channelCode); // 创建支付订单 PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode); payOrderMapper.insert(payOrder); + // 拼接充值个性化参数 + Map passbackParams = new HashMap<>(); + passbackParams.put(PayConstants.PAY_PASSBACK_PARAMS_TRADE_TYPE_KEY, TradeTypeEnum.RECHARGE.getCode()); + // 发起渠道方支付 PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = null; try { - payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder); + payOrderUnifiedReqDTO = createPayOrderUnifiedReqDTO(payOrder, passbackParams); return payHandler.unifiedOrder(payOrderUnifiedReqDTO); } catch (Throwable e) { // 系统异常,则包装成 PayException 异常抛出 @@ -161,7 +184,7 @@ public class PayOrderServiceImpl implements PayOrderService { * @param payOrderDO * @return */ - private PayOrderUnifiedReqDTO createPayOrderUnifiedReqDTO(PayOrderDO payOrderDO) { + private PayOrderUnifiedReqDTO createPayOrderUnifiedReqDTO(PayOrderDO payOrderDO, Map passbackParams) { PayOrderUnifiedReqDTO payOrderUnifiedReqDTO = new PayOrderUnifiedReqDTO(); String subject = payOrderDO.getSubject(); @@ -171,6 +194,7 @@ public class PayOrderServiceImpl implements PayOrderService { payOrderUnifiedReqDTO.setPrice(payOrderDO.getPrice().intValue()); payOrderUnifiedReqDTO.setExpireTime(payOrderDO.getExpireTime()); payOrderUnifiedReqDTO.setNotifyUrl(String.format(alipayConfig.getNotifyUrl(), payOrderDO.getChannelCode().getCode())); + payOrderUnifiedReqDTO.setPassbackParams(passbackParams); return payOrderUnifiedReqDTO; } @@ -299,6 +323,50 @@ public class PayOrderServiceImpl implements PayOrderService { throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); } log.debug("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId()); + + // 3. 根据交易类型做对应回调处理 + Map 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: + notifyRechargeOrderSuccess(order, organId); + break; + case PRODUCT: + break; + default: + throw ServiceExceptionUtil.exception(PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR, passbackObj.toString()); + } + } + + /** + * 充值成功回调 + * @param payOrderDO + * @param organId + */ + private void notifyRechargeOrderSuccess(PayOrderDO payOrderDO, Long organId) { + // 支付订单的金额 + BigDecimal price = payOrderDO.getPrice(); + // 订单流水号 + String payNo = payOrderDO.getPayNo(); + + // 1.更新组织资金 + OrganRechargeAmountRespVO rechargeAmountRespVO = organAmountService.recharge(organId, price); + + // 2.新增收支明细 + IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder() + .organId(organId) + .businessNo(payNo) + .tradeType(TradeTypeEnum.RECHARGE.getCode()) + .incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getType()) + .cashAmountChange(price) + .availableAmount(rechargeAmountRespVO.getAvailableAmount()) + .amount(rechargeAmountRespVO.getAmount()) + .giftAmount(rechargeAmountRespVO.getGiftAmount()) + .build(); + incomeExpenseDetailsDO.setCreator(payOrderDO.getCreator()); + incomeExpenseDetailsDO.setUpdater(payOrderDO.getUpdater()); + incomeExpenseService.createDetail(incomeExpenseDetailsDO); } /** diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/factory/impl/alipay/AlipayPcPayHandler.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/factory/impl/alipay/AlipayPcPayHandler.java index 04dc6c622..04b8f4eaa 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/factory/impl/alipay/AlipayPcPayHandler.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/pay/factory/impl/alipay/AlipayPcPayHandler.java @@ -20,6 +20,7 @@ import com.cf.imes.framework.pay.config.ChenfengAlipayConfig; 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.enums.order.PayOrderStatusRespEnum; +import com.cf.imes.module.system.enums.pay.PayConstants; import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -61,12 +62,7 @@ public class AlipayPcPayHandler extends AbstractPayHandler { model.setTimeExpire(LocalDateTimeUtil.format(reqDTO.getExpireTime(), NORM_DATETIME_FORMATTER)); model.setProductCode(alipayConfig.getProductCode()); model.setQrPayMode(alipayConfig.getQrPayMode()); - - Map passbackMap = new HashMap<>(); - passbackMap.put("test1", "1"); - passbackMap.put("test2", "2"); - passbackMap.put("test3", outTradeNo); - model.setPassbackParams(JSON.toJSONString(passbackMap)); + model.setPassbackParams(JSON.toJSONString(reqDTO.getPassbackParams())); // 1.2 构建 AlipayTradePagePayRequest 请求 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); @@ -121,11 +117,15 @@ public class AlipayPcPayHandler extends AbstractPayHandler { Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); Integer status = parseStatus(bodyObj.get("trade_status")); + // 3.解析创建支付时候的个性化参数 + String passbackParamsStr = bodyObj.get(PayConstants.PAY_PASSBACK_PARAMS_KEY); + Map passbackParams = JSON.parseObject(passbackParamsStr, Map.class); + Assert.notNull(status, (Supplier) () -> { throw new IllegalArgumentException(CharSequenceUtil.format("body({}) 的 trade_status 不正确", body)); }); return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), - bodyObj.get("out_trade_no"), body); + bodyObj.get("out_trade_no"), body, passbackParams); } /** diff --git a/cf-module-system/cf-module-system-biz/src/main/resources/application-local.yaml b/cf-module-system/cf-module-system-biz/src/main/resources/application-local.yaml index 6c76178f9..c1d7b6a57 100644 --- a/cf-module-system/cf-module-system-biz/src/main/resources/application-local.yaml +++ b/cf-module-system/cf-module-system-biz/src/main/resources/application-local.yaml @@ -290,7 +290,7 @@ chenfeng: appId: 8wb0qYthTUqf9290UJfLejTcOA5CU1wiAhmpLbXmwDCCt+ZakcBPBK1a88E= privateKey: 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 alipayPublicKey: KbUGE7zsPBKWPx0/zMcAdLRldKrcgy2LRiOrqOBm7y4iPJLXTYtXFJT15p2JMQiyOM8mqiYQR0OEDwfrKxDgHXLtIut/e0EAk9bZwZoLrqVe0pN1huseRC38zEglbWil3yz+tZfHZuAaEq2EzvWJltX/tRKOzNBqAT9l+UvnqNedgCFB9MY2EErqJjbn/at3gYCkV2idt31ghF0z8SEQ5h9ztNYtmTvk8c8ipi0/hIjX8XryN6mlOvGQfyZ4rWrBWBuZ6iD/SyuThwxKmFYU4dhHbHVpBrva5nJWU43CP7RVaJm649nNJnce+Ppj2Tv8+ugSLe5poZWo2zmGe3Xn5WmN6OTZyRI1pnmn2/hGxtOMmTZJX7Gh0pI4v3wmU0gOd/gbRlqlvN+u12T92nyH8MQrHdA7UXuttAtolYUa/Rli/20qHX69QtOtvfZk8mNvDSj9dDvODseGcrFHm07jyfxpaIkQDeN75cQ3NwNgDQEW8urQszaU1IJ7hc+20tt0Z3td4+7MfiVPpGfVxsGE66gwLgpB8wsxEhyBTaBr7osMLqOv - notifyUrl: VvJ5DOVuGOBw39j7tyrvsEEtLSseVM8T3u9kqsWKago+iI5ao8JzoggmeSe+N9LrsYxutK4fkGpmr4jOGJ3JTQFZ7YBXLxf2oLIXOZH9O27EnDtm + notifyUrl: RIEeHCoPHaAryuVN6mEYskBSl+EPvhsxRpjIbuIE7f7jABVxm46bLc01WQUe4Fn9NPYyNTv0xCxM68iRrmFDjAUjQ/hkIVNG+yD/kNsjcYCWa2gtOQPrvWZzDA== justauth: enabled: true