分账功能

This commit is contained in:
zengtao01
2024-07-19 09:42:18 +08:00
parent 2f8a2ae032
commit de023eb5e3
50 changed files with 2227 additions and 8 deletions

View File

@ -89,4 +89,13 @@ public interface ErrorCodeConstants {
ErrorCode DEMO_TRANSFER_NOT_FOUND = new ErrorCode(1_007_901_001, "示例转账单不存在");
ErrorCode DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR = new ErrorCode(1_007_901_002, "转账失败,转账单编号不匹配");
ErrorCode DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "转账失败,转账单金额不匹配");
ErrorCode DIVIDE_NOT_EXISTS = new ErrorCode(1_007_902_001, "分账单不存在");
ErrorCode DIVIDE_COMPANY_NOT_EXISTS = new ErrorCode(1_007_903_001, "分账公司不存在");
ErrorCode DIVIDE_INFO_NOT_EXISTS = new ErrorCode(1_007_904_001, "分账明细不存在");
}

View File

@ -26,12 +26,12 @@ public class PayAppBaseVO {
@Schema(description = "备注", example = "我是一个测试应用")
private String remark;
@Schema(description = "支付结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay-callback")
@Schema(description = "支付结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:8895/pay-callback")
@NotNull(message = "支付结果的回调地址不能为空")
@URL(message = "支付结果的回调地址必须为 URL 格式")
private String orderNotifyUrl;
@Schema(description = "退款结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/refund-callback")
@Schema(description = "退款结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:8895/refund-callback")
@NotNull(message = "退款结果的回调地址不能为空")
@URL(message = "退款结果的回调地址必须为 URL 格式")
private String refundNotifyUrl;

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.pay.controller.admin.divide;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.*;
import cn.iocoder.yudao.module.pay.dal.dataobject.divide.DivideDO;
import cn.iocoder.yudao.module.pay.service.divide.DivideService;
@Tag(name = "管理后台 - 分账单")
@RestController
@RequestMapping("/pay/divide")
@Validated
public class DivideController {
@Resource
private DivideService divideService;
@PostMapping("/create")
@Operation(summary = "创建分账单")
@PreAuthorize("@ss.hasPermission('pay:divide:create')")
public CommonResult<Long> createDivide(@Valid @RequestBody DivideSaveReqVO createReqVO) {
return success(divideService.createDivide(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新分账单")
@PreAuthorize("@ss.hasPermission('pay:divide:update')")
public CommonResult<Boolean> updateDivide(@Valid @RequestBody DivideSaveReqVO updateReqVO) {
divideService.updateDivide(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除分账单")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('pay:divide:delete')")
public CommonResult<Boolean> deleteDivide(@RequestParam("id") Long id) {
divideService.deleteDivide(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得分账单")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('pay:divide:query')")
public CommonResult<DivideRespVO> getDivide(@RequestParam("id") Long id) {
DivideDO divide = divideService.getDivide(id);
return success(BeanUtils.toBean(divide, DivideRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得分账单分页")
@PreAuthorize("@ss.hasPermission('pay:divide:query')")
public CommonResult<PageResult<DivideRespVO>> getDividePage(@Valid DividePageReqVO pageReqVO) {
PageResult<DivideDO> pageResult = divideService.getDividePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DivideRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出分账单 Excel")
@PreAuthorize("@ss.hasPermission('pay:divide:export')")
@OperateLog(type = EXPORT)
public void exportDivideExcel(@Valid DividePageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DivideDO> list = divideService.getDividePage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "分账单.xls", "数据", DivideRespVO.class,
BeanUtils.toBean(list, DivideRespVO.class));
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.pay.controller.admin.divide.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 分账单分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DividePageReqVO extends PageParam {
@Schema(description = "渠道编号", example = "11564")
private Long channelId;
@Schema(description = "渠道编码")
private String channelCode;
@Schema(description = "总金额,单位:分", example = "30938")
private Integer totalPrice;
@Schema(description = "分账状态", example = "1")
private String status;
@Schema(description = "商户分账单号")
private String no;
@Schema(description = "渠道订单号")
private String channelOrderNo;
@Schema(description = "微信分账单号", example = "3065")
private String orderId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.pay.controller.admin.divide.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 分账单 Response VO")
@Data
@ExcelIgnoreUnannotated
public class DivideRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "8729")
@ExcelProperty("主键")
private Long id;
@Schema(description = "渠道编号", example = "11564")
@ExcelProperty("渠道编号")
private Long channelId;
@Schema(description = "渠道编码")
@ExcelProperty("渠道编码")
private String channelCode;
@Schema(description = "总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "30938")
@ExcelProperty("总金额,单位:分")
private Integer totalPrice;
@Schema(description = "分账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("分账状态")
private String status;
@Schema(description = "商户分账单号")
@ExcelProperty("商户分账单号")
private String no;
@Schema(description = "渠道订单号")
@ExcelProperty("渠道订单号")
private String channelOrderNo;
@Schema(description = "微信分账单号", example = "3065")
@ExcelProperty("微信分账单号")
private String orderId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.pay.controller.admin.divide.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 分账单新增/修改 Request VO")
@Data
public class DivideSaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "8729")
private Long id;
@Schema(description = "渠道编号", example = "11564")
private Long channelId;
@Schema(description = "渠道编码")
private String channelCode;
@Schema(description = "总金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "30938")
@NotNull(message = "总金额,单位:分不能为空")
private Integer totalPrice;
@Schema(description = "分账状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "分账状态不能为空")
private String status;
@Schema(description = "商户分账单号")
private String no;
@Schema(description = "渠道订单号")
private String channelOrderNo;
@Schema(description = "微信分账单号", example = "3065")
private String orderId;
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.pay.controller.admin.dividecompany;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.*;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import cn.iocoder.yudao.module.pay.service.dividecompany.DivideCompanyService;
@Tag(name = "管理后台 - 分账公司")
@RestController
@RequestMapping("/pay/divide-company")
@Validated
public class DivideCompanyController {
@Resource
private DivideCompanyService divideCompanyService;
@PostMapping("/create")
@Operation(summary = "创建分账公司")
@PreAuthorize("@ss.hasPermission('pay:divide-company:create')")
public CommonResult<Long> createDivideCompany(@Valid @RequestBody DivideCompanySaveReqVO createReqVO) {
return success(divideCompanyService.createDivideCompany(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新分账公司")
@PreAuthorize("@ss.hasPermission('pay:divide-company:update')")
public CommonResult<Boolean> updateDivideCompany(@Valid @RequestBody DivideCompanySaveReqVO updateReqVO) {
divideCompanyService.updateDivideCompany(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除分账公司")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('pay:divide-company:delete')")
public CommonResult<Boolean> deleteDivideCompany(@RequestParam("id") Long id) {
divideCompanyService.deleteDivideCompany(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得分账公司")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('pay:divide-company:query')")
public CommonResult<DivideCompanyRespVO> getDivideCompany(@RequestParam("id") Long id) {
DivideCompanyDO divideCompany = divideCompanyService.getDivideCompany(id);
return success(BeanUtils.toBean(divideCompany, DivideCompanyRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得分账公司分页")
@PreAuthorize("@ss.hasPermission('pay:divide-company:query')")
public CommonResult<PageResult<DivideCompanyRespVO>> getDivideCompanyPage(@Valid DivideCompanyPageReqVO pageReqVO) {
PageResult<DivideCompanyDO> pageResult = divideCompanyService.getDivideCompanyPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DivideCompanyRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出分账公司 Excel")
@PreAuthorize("@ss.hasPermission('pay:divide-company:export')")
@OperateLog(type = EXPORT)
public void exportDivideCompanyExcel(@Valid DivideCompanyPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DivideCompanyDO> list = divideCompanyService.getDivideCompanyPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "分账公司.xls", "数据", DivideCompanyRespVO.class,
BeanUtils.toBean(list, DivideCompanyRespVO.class));
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 分账公司分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DivideCompanyPageReqVO extends PageParam {
@Schema(description = "分账个人接收方姓名", example = "赵六")
private String name;
@Schema(description = "分账接收方类型", example = "1")
private String type;
@Schema(description = "分账接收方账号", example = "2045")
private String account;
@Schema(description = "分账比例0-0.3")
private String proportion;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 分账公司 Response VO")
@Data
@ExcelIgnoreUnannotated
public class DivideCompanyRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "19877")
@ExcelProperty("主键")
private Long id;
@Schema(description = "分账个人接收方姓名", example = "赵六")
@ExcelProperty("分账个人接收方姓名")
private String name;
@Schema(description = "分账接收方类型", example = "1")
@ExcelProperty("分账接收方类型")
private String type;
@Schema(description = "分账接收方账号", example = "2045")
@ExcelProperty("分账接收方账号")
private String account;
@Schema(description = "分账比例0-0.3")
@ExcelProperty("分账比例0-0.3")
private String proportion;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 分账公司新增/修改 Request VO")
@Data
public class DivideCompanySaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "19877")
private Long id;
@Schema(description = "分账个人接收方姓名", example = "赵六")
private String name;
@Schema(description = "分账接收方类型", example = "1")
private String type;
@Schema(description = "分账接收方账号", example = "2045")
private String account;
@Schema(description = "分账比例0-0.3")
private String proportion;
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.pay.controller.admin.divideinfo;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.*;
import cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo.DivideInfoDO;
import cn.iocoder.yudao.module.pay.service.divideinfo.DivideInfoService;
@Tag(name = "管理后台 - 分账明细")
@RestController
@RequestMapping("/pay/divide-info")
@Validated
public class DivideInfoController {
@Resource
private DivideInfoService divideInfoService;
@PostMapping("/create")
@Operation(summary = "创建分账明细")
@PreAuthorize("@ss.hasPermission('pay:divide-info:create')")
public CommonResult<Long> createDivideInfo(@Valid @RequestBody DivideInfoSaveReqVO createReqVO) {
return success(divideInfoService.createDivideInfo(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新分账明细")
@PreAuthorize("@ss.hasPermission('pay:divide-info:update')")
public CommonResult<Boolean> updateDivideInfo(@Valid @RequestBody DivideInfoSaveReqVO updateReqVO) {
divideInfoService.updateDivideInfo(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除分账明细")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('pay:divide-info:delete')")
public CommonResult<Boolean> deleteDivideInfo(@RequestParam("id") Long id) {
divideInfoService.deleteDivideInfo(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得分账明细")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('pay:divide-info:query')")
public CommonResult<DivideInfoRespVO> getDivideInfo(@RequestParam("id") Long id) {
DivideInfoDO divideInfo = divideInfoService.getDivideInfo(id);
return success(BeanUtils.toBean(divideInfo, DivideInfoRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得分账明细分页")
@PreAuthorize("@ss.hasPermission('pay:divide-info:query')")
public CommonResult<PageResult<DivideInfoRespVO>> getDivideInfoPage(@Valid DivideInfoPageReqVO pageReqVO) {
PageResult<DivideInfoDO> pageResult = divideInfoService.getDivideInfoPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, DivideInfoRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出分账明细 Excel")
@PreAuthorize("@ss.hasPermission('pay:divide-info:export')")
@OperateLog(type = EXPORT)
public void exportDivideInfoExcel(@Valid DivideInfoPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<DivideInfoDO> list = divideInfoService.getDivideInfoPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "分账明细.xls", "数据", DivideInfoRespVO.class,
BeanUtils.toBean(list, DivideInfoRespVO.class));
}
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 分账明细分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DivideInfoPageReqVO extends PageParam {
@Schema(description = "微信订单号", example = "21654")
private String transactionId;
@Schema(description = "商户分账单号")
private String outOrderNo;
@Schema(description = "分账个人接收方姓名", example = "李四")
private String name;
@Schema(description = "分账接收方类型", example = "1")
private String type;
@Schema(description = "分账接收方账号", example = "30507")
private String account;
@Schema(description = "分账金额")
private Integer amount;
@Schema(description = "估算金额")
private Integer computeAmount;
@Schema(description = "描述", example = "你猜")
private String description;
@Schema(description = "分账结果")
private String result;
@Schema(description = "分账失败原因", example = "不对")
private String failReason;
@Schema(description = "分账明细单号", example = "14997")
private String detailId;
@Schema(description = "分账创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private String[] dCreateTime;
@Schema(description = "分账完成时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private String[] dFinishTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 分账明细 Response VO")
@Data
@ExcelIgnoreUnannotated
public class DivideInfoRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "30177")
@ExcelProperty("主键")
private Long id;
@Schema(description = "微信订单号", example = "21654")
@ExcelProperty("微信订单号")
private String transactionId;
@Schema(description = "商户分账单号")
@ExcelProperty("商户分账单号")
private String outOrderNo;
@Schema(description = "分账个人接收方姓名", example = "李四")
@ExcelProperty("分账个人接收方姓名")
private String name;
@Schema(description = "分账接收方类型", example = "1")
@ExcelProperty("分账接收方类型")
private String type;
@Schema(description = "分账接收方账号", example = "30507")
@ExcelProperty("分账接收方账号")
private String account;
@Schema(description = "分账金额")
@ExcelProperty("分账金额")
private Integer amount;
@Schema(description = "估算金额")
@ExcelProperty("估算金额")
private Integer computeAmount;
@Schema(description = "描述", example = "你猜")
@ExcelProperty("描述")
private String description;
@Schema(description = "分账结果")
@ExcelProperty("分账结果")
private String result;
@Schema(description = "分账失败原因", example = "不对")
@ExcelProperty("分账失败原因")
private String failReason;
@Schema(description = "分账明细单号", example = "14997")
@ExcelProperty("分账明细单号")
private String detailId;
@Schema(description = "分账创建时间")
@ExcelProperty("分账创建时间")
private String dCreateTime;
@Schema(description = "分账完成时间")
@ExcelProperty("分账完成时间")
private String dFinishTime;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 分账明细新增/修改 Request VO")
@Data
public class DivideInfoSaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "30177")
private Long id;
@Schema(description = "微信订单号", example = "21654")
private String transactionId;
@Schema(description = "商户分账单号")
private String outOrderNo;
@Schema(description = "分账个人接收方姓名", example = "李四")
private String name;
@Schema(description = "分账接收方类型", example = "1")
private String type;
@Schema(description = "分账接收方账号", example = "30507")
private String account;
@Schema(description = "分账金额")
private Integer amount;
@Schema(description = "估算金额")
private Integer computeAmount;
@Schema(description = "描述", example = "你猜")
private String description;
@Schema(description = "分账结果")
private String result;
@Schema(description = "分账失败原因", example = "不对")
private String failReason;
@Schema(description = "分账明细单号", example = "14997")
private String detailId;
@Schema(description = "分账创建时间")
private String dCreateTime;
@Schema(description = "分账完成时间")
private String dFinishTime;
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.divide;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 分账单 DO
*
* @author 管理员
*/
@TableName("pay_divide")
@KeySequence("pay_divide_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DivideDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 渠道编号
*/
private Long channelId;
/**
* 渠道编码
*/
private String channelCode;
/**
* 总金额,单位:分
*/
private Integer totalPrice;
/**
* 分账状态
*/
private String status;
/**
* 商户分账单号
*/
private String no;
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 微信分账单号
*/
private String orderId;
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 分账公司 DO
*
* @author 管理员
*/
@TableName("pay_divide_company")
@KeySequence("pay_divide_company_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DivideCompanyDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 分账个人接收方姓名
*/
private String name;
/**
* 分账接收方类型
*/
private String type;
/**
* 分账接收方账号
*/
private String account;
/**
* 分账比例0-0.3
*/
private String proportion;
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 分账明细 DO
*
* @author 管理员
*/
@TableName("pay_divide_info")
@KeySequence("pay_divide_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DivideInfoDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 微信订单号
*/
private String transactionId;
/**
* 商户分账单号
*/
private String outOrderNo;
/**
* 分账个人接收方姓名
*/
private String name;
/**
* 分账接收方类型
*/
private String type;
/**
* 分账接收方账号
*/
private String account;
/**
* 分账金额
*/
private Integer amount;
/**
* 估算金额
*/
private Integer computeAmount;
/**
* 描述
*/
private String description;
/**
* 分账结果
*/
private String result;
/**
* 分账失败原因
*/
private String failReason;
/**
* 分账明细单号
*/
private String detailId;
/**
* 分账创建时间
*/
private String dCreateTime;
/**
* 分账完成时间
*/
private String dFinishTime;
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.pay.dal.mysql.divide;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.pay.dal.dataobject.divide.DivideDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.*;
/**
* 分账单 Mapper
*
* @author 管理员
*/
@Mapper
public interface DivideMapper extends BaseMapperX<DivideDO> {
default PageResult<DivideDO> selectPage(DividePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DivideDO>()
.eqIfPresent(DivideDO::getChannelId, reqVO.getChannelId())
.eqIfPresent(DivideDO::getChannelCode, reqVO.getChannelCode())
.eqIfPresent(DivideDO::getTotalPrice, reqVO.getTotalPrice())
.eqIfPresent(DivideDO::getStatus, reqVO.getStatus())
.eqIfPresent(DivideDO::getNo, reqVO.getNo())
.eqIfPresent(DivideDO::getChannelOrderNo, reqVO.getChannelOrderNo())
.eqIfPresent(DivideDO::getOrderId, reqVO.getOrderId())
.betweenIfPresent(DivideDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DivideDO::getId));
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.pay.dal.mysql.dividecompany;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.*;
/**
* 分账公司 Mapper
*
* @author 管理员
*/
@Mapper
public interface DivideCompanyMapper extends BaseMapperX<DivideCompanyDO> {
default PageResult<DivideCompanyDO> selectPage(DivideCompanyPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DivideCompanyDO>()
.likeIfPresent(DivideCompanyDO::getName, reqVO.getName())
.eqIfPresent(DivideCompanyDO::getType, reqVO.getType())
.eqIfPresent(DivideCompanyDO::getAccount, reqVO.getAccount())
.eqIfPresent(DivideCompanyDO::getProportion, reqVO.getProportion())
.betweenIfPresent(DivideCompanyDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DivideCompanyDO::getId));
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.pay.dal.mysql.divideinfo;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo.DivideInfoDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.*;
/**
* 分账明细 Mapper
*
* @author 管理员
*/
@Mapper
public interface DivideInfoMapper extends BaseMapperX<DivideInfoDO> {
default PageResult<DivideInfoDO> selectPage(DivideInfoPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DivideInfoDO>()
.eqIfPresent(DivideInfoDO::getTransactionId, reqVO.getTransactionId())
.eqIfPresent(DivideInfoDO::getOutOrderNo, reqVO.getOutOrderNo())
.likeIfPresent(DivideInfoDO::getName, reqVO.getName())
.eqIfPresent(DivideInfoDO::getType, reqVO.getType())
.eqIfPresent(DivideInfoDO::getAccount, reqVO.getAccount())
.eqIfPresent(DivideInfoDO::getAmount, reqVO.getAmount())
.eqIfPresent(DivideInfoDO::getComputeAmount, reqVO.getComputeAmount())
.eqIfPresent(DivideInfoDO::getDescription, reqVO.getDescription())
.eqIfPresent(DivideInfoDO::getResult, reqVO.getResult())
.eqIfPresent(DivideInfoDO::getFailReason, reqVO.getFailReason())
.eqIfPresent(DivideInfoDO::getDetailId, reqVO.getDetailId())
.betweenIfPresent(DivideInfoDO::getDCreateTime, reqVO.getDCreateTime())
.betweenIfPresent(DivideInfoDO::getDFinishTime, reqVO.getDFinishTime())
.betweenIfPresent(DivideInfoDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DivideInfoDO::getId));
}
}

View File

@ -4,6 +4,8 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@ -187,4 +189,19 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
throw new UnsupportedOperationException("待实现");
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.pay.job.divide;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.pay.service.divide.DivideService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 支付通知 Job
* 通过不断扫描待通知的 PayNotifyTaskDO 记录,回调业务线的回调接口
*
* @author 芋道源码
*/
@Component
@Slf4j
public class PayDivideFreezeJob implements JobHandler {
@Resource
private DivideService divideService;
@Override
@TenantJob
public String execute(String param) throws Exception {
int divideFreeze = divideService.getDivideFreeze();
return String.format("执行分账解冻剩余资金 %s 个", divideFreeze);
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.pay.job.divide;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.pay.service.divide.DivideService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 支付通知 Job
* 通过不断扫描待通知的 PayNotifyTaskDO 记录,回调业务线的回调接口
*
* @author 芋道源码
*/
@Component
@Slf4j
public class PayDivideJob implements JobHandler {
@Resource
private DivideService divideService;
@Override
@TenantJob
public String execute(String param) throws Exception {
int divideCount = divideService.startDivide();
return String.format("执行分账 %s 个", divideCount);
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.pay.job.divide;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.pay.service.divide.DivideService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 支付通知 Job
* 通过不断扫描待通知的 PayNotifyTaskDO 记录,回调业务线的回调接口
*
* @author 芋道源码
*/
@Component
@Slf4j
public class PayDivideResultJob implements JobHandler {
@Resource
private DivideService divideService;
@Override
@TenantJob
public String execute(String param) throws Exception {
int divideResult = divideService.getDivideResult();
return String.format("执行分账结果 %s 个", divideResult);
}
}

View File

@ -0,0 +1,69 @@
package cn.iocoder.yudao.module.pay.service.divide;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.DividePageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.DivideSaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.divide.DivideDO;
import javax.validation.Valid;
/**
* 分账单 Service 接口
*
* @author 管理员
*/
public interface DivideService {
/**
* 创建分账单
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createDivide(@Valid DivideSaveReqVO createReqVO);
/**
* 更新分账单
*
* @param updateReqVO 更新信息
*/
void updateDivide(@Valid DivideSaveReqVO updateReqVO);
/**
* 删除分账单
*
* @param id 编号
*/
void deleteDivide(Long id);
/**
* 获得分账单
*
* @param id 编号
* @return 分账单
*/
DivideDO getDivide(Long id);
/**
* 获得分账单分页
*
* @param pageReqVO 分页查询
* @return 分账单分页
*/
PageResult<DivideDO> getDividePage(DividePageReqVO pageReqVO);
/**
* 开始分账
*/
int startDivide();
/**
* 同步分账结果
*/
int getDivideResult();
/**
* 解冻剩余资金
*/
int getDivideFreeze();
}

View File

@ -0,0 +1,234 @@
package cn.iocoder.yudao.module.pay.service.divide;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.enums.divide.PayDivideStatusRespEnum;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.DividePageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.DivideSaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.divide.DivideDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo.DivideInfoDO;
import cn.iocoder.yudao.module.pay.dal.mysql.divide.DivideMapper;
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
import cn.iocoder.yudao.module.pay.service.dividecompany.DivideCompanyService;
import cn.iocoder.yudao.module.pay.service.divideinfo.DivideInfoService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.DIVIDE_NOT_EXISTS;
/**
* 分账单 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class DivideServiceImpl implements DivideService {
@Resource
private DivideMapper divideMapper;
@Resource
private DivideInfoService divideInfoService;
@Resource
private DivideCompanyService divideCompanyService;
@Resource
private PayChannelService channelService;
@Override
public Long createDivide(DivideSaveReqVO createReqVO) {
// 插入
DivideDO divide = BeanUtils.toBean(createReqVO, DivideDO.class);
divideMapper.insert(divide);
// 返回
return divide.getId();
}
@Override
public void updateDivide(DivideSaveReqVO updateReqVO) {
// 校验存在
validateDivideExists(updateReqVO.getId());
// 更新
DivideDO updateObj = BeanUtils.toBean(updateReqVO, DivideDO.class);
divideMapper.updateById(updateObj);
}
@Override
public void deleteDivide(Long id) {
// 校验存在
validateDivideExists(id);
// 删除
divideMapper.deleteById(id);
}
private void validateDivideExists(Long id) {
if (divideMapper.selectById(id) == null) {
throw exception(DIVIDE_NOT_EXISTS);
}
}
@Override
public DivideDO getDivide(Long id) {
return divideMapper.selectById(id);
}
@Override
public PageResult<DivideDO> getDividePage(DividePageReqVO pageReqVO) {
return divideMapper.selectPage(pageReqVO);
}
public List<ProfitSharingV3Request.Receiver> createDivideInfo(DivideDO divideDO) {
List<ProfitSharingV3Request.Receiver> receivers = new ArrayList<>();
List<DivideCompanyDO> companyList = divideCompanyService.getList();
List<DivideInfoDO> infoDOList = new ArrayList<>();
for (DivideCompanyDO divideCompanyDO : companyList) {
DivideInfoDO divideInfoDO = new DivideInfoDO();
int money = (int) Math.ceil(divideDO.getTotalPrice() * Double.valueOf(divideCompanyDO.getProportion()));
divideInfoDO.setTransactionId(divideDO.getChannelOrderNo())
.setOutOrderNo(divideDO.getNo())
.setName(divideCompanyDO.getName())
.setType(divideCompanyDO.getType())
.setAccount(divideCompanyDO.getAccount())
.setAmount(money)
.setComputeAmount(money)
.setDescription("" + divideCompanyDO.getName() + "分账");
infoDOList.add(divideInfoDO);
ProfitSharingV3Request.Receiver receiver = new ProfitSharingV3Request.Receiver();
BeanUtil.copyProperties(divideInfoDO, receiver);
receivers.add(receiver);
}
divideInfoService.insertList(infoDOList);
return receivers;
}
@Override
public int startDivide() {
List<DivideDO> divideDOS = divideMapper.selectList(Wrappers.<DivideDO>lambdaQuery()
.eq(DivideDO::getStatus, PayDivideStatusRespEnum.WAITING.getStatus()));
if(CollectionUtil.isEmpty(divideDOS)){
return 0;
}
int counter = 0;
for (DivideDO divideDO : divideDOS) {
PayClient client = channelService.getPayClient(divideDO.getChannelId());
PayDivideUnifiedDto payDivideUnifiedDto = new PayDivideUnifiedDto();
payDivideUnifiedDto.setTransactionId(divideDO.getChannelOrderNo())
.setOutOrderNo(divideDO.getNo())
.setUnfreezeUnsplit(false)
.setReceivers(createDivideInfo(divideDO));
PayDivideRespDto payDivideRespDto = client.unifiedDivide(payDivideUnifiedDto);
divideDO.setStatus(PayDivideStatusRespEnum.PROGRESS.getStatus());
divideDO.setOrderId(payDivideRespDto.getOrderId());
// 每执行250次休息一分钟
if (++counter % 250 == 0) {
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
}
divideMapper.updateBatch(divideDOS);
return divideDOS.size();
}
@Override
public int getDivideResult() {
List<DivideDO> divideDOS = divideMapper.selectList(Wrappers.<DivideDO>lambdaQuery()
.eq(DivideDO::getStatus, PayDivideStatusRespEnum.PROGRESS.getStatus()));
if(CollectionUtil.isEmpty(divideDOS)){
return 0;
}
for (DivideDO divideDO : divideDOS) {
PayClient client = channelService.getPayClient(divideDO.getChannelId());
PayDivideUnifiedDto payDivideUnifiedDto = new PayDivideUnifiedDto();
payDivideUnifiedDto.setTransactionId(divideDO.getChannelOrderNo())
.setOutOrderNo(divideDO.getNo());
PayDivideRespDto payDivideRespDto = client.unifiedDivideResult(payDivideUnifiedDto);
updateDivideInfo(payDivideRespDto.getReceivers(),divideDO.getNo());
divideDO.setStatus(PayDivideStatusRespEnum.COMPLETE.getStatus());
}
divideMapper.updateBatch(divideDOS);
return divideDOS.size();
}
void updateDivideInfo(List<ProfitSharingV3Result.Receiver> receivers,String outOrderNo){
List<DivideInfoDO> list = new ArrayList<>();
for (ProfitSharingV3Result.Receiver receiver:receivers){
DivideInfoDO divideInfo = divideInfoService.getDivideInfo(outOrderNo, receiver.getAccount());
divideInfo.setResult(receiver.getResult())
.setFailReason(receiver.getFailReason())
.setDetailId(receiver.getDetailId())
.setDCreateTime(receiver.getCreateTime())
.setDFinishTime(receiver.getFinishTime());
list.add(divideInfo);
}
divideInfoService.updateList(list);
}
@Override
public int getDivideFreeze() {
List<DivideDO> divideDOS = divideMapper.selectList(Wrappers.<DivideDO>lambdaQuery()
.eq(DivideDO::getStatus, PayDivideStatusRespEnum.COMPLETE.getStatus()));
if(CollectionUtil.isEmpty(divideDOS)){
return 0;
}
for (DivideDO divideDO : divideDOS) {
PayClient client = channelService.getPayClient(divideDO.getChannelId());
PayDivideUnifiedDto payDivideUnifiedDto = new PayDivideUnifiedDto();
if(checkSuccess(divideDO.getNo())){
payDivideUnifiedDto.setTransactionId(divideDO.getChannelOrderNo())
.setOutOrderNo(divideDO.getNo());
client.unifiedDivideFreeze(payDivideUnifiedDto);
divideDO.setStatus(PayDivideStatusRespEnum.FINISH.getStatus());
}
}
divideMapper.updateBatch(divideDOS);
return divideDOS.size();
}
boolean checkSuccess(String outOrderNo){
List<DivideInfoDO> divideList = divideInfoService.getDivideList(outOrderNo);
for (DivideInfoDO divideInfoDO:divideList){
if(!"SUCCESS".equals(divideInfoDO.getResult())){
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,58 @@
package cn.iocoder.yudao.module.pay.service.dividecompany;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.DivideCompanyPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.DivideCompanySaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import javax.validation.Valid;
import java.util.List;
/**
* 分账公司 Service 接口
*
* @author 管理员
*/
public interface DivideCompanyService {
/**
* 创建分账公司
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createDivideCompany(@Valid DivideCompanySaveReqVO createReqVO);
/**
* 更新分账公司
*
* @param updateReqVO 更新信息
*/
void updateDivideCompany(@Valid DivideCompanySaveReqVO updateReqVO);
/**
* 删除分账公司
*
* @param id 编号
*/
void deleteDivideCompany(Long id);
/**
* 获得分账公司
*
* @param id 编号
* @return 分账公司
*/
DivideCompanyDO getDivideCompany(Long id);
/**
* 获得分账公司分页
*
* @param pageReqVO 分页查询
* @return 分账公司分页
*/
PageResult<DivideCompanyDO> getDivideCompanyPage(DivideCompanyPageReqVO pageReqVO);
List<DivideCompanyDO> getList();
}

View File

@ -0,0 +1,77 @@
package cn.iocoder.yudao.module.pay.service.dividecompany;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.DivideCompanyPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.dividecompany.vo.DivideCompanySaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import cn.iocoder.yudao.module.pay.dal.mysql.dividecompany.DivideCompanyMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.DIVIDE_COMPANY_NOT_EXISTS;
/**
* 分账公司 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class DivideCompanyServiceImpl implements DivideCompanyService {
@Resource
private DivideCompanyMapper divideCompanyMapper;
@Override
public Long createDivideCompany(DivideCompanySaveReqVO createReqVO) {
// 插入
DivideCompanyDO divideCompany = BeanUtils.toBean(createReqVO, DivideCompanyDO.class);
divideCompanyMapper.insert(divideCompany);
// 返回
return divideCompany.getId();
}
@Override
public void updateDivideCompany(DivideCompanySaveReqVO updateReqVO) {
// 校验存在
validateDivideCompanyExists(updateReqVO.getId());
// 更新
DivideCompanyDO updateObj = BeanUtils.toBean(updateReqVO, DivideCompanyDO.class);
divideCompanyMapper.updateById(updateObj);
}
@Override
public void deleteDivideCompany(Long id) {
// 校验存在
validateDivideCompanyExists(id);
// 删除
divideCompanyMapper.deleteById(id);
}
private void validateDivideCompanyExists(Long id) {
if (divideCompanyMapper.selectById(id) == null) {
throw exception(DIVIDE_COMPANY_NOT_EXISTS);
}
}
@Override
public DivideCompanyDO getDivideCompany(Long id) {
return divideCompanyMapper.selectById(id);
}
@Override
public PageResult<DivideCompanyDO> getDivideCompanyPage(DivideCompanyPageReqVO pageReqVO) {
return divideCompanyMapper.selectPage(pageReqVO);
}
@Override
public List<DivideCompanyDO> getList() {
return divideCompanyMapper.selectList();
}
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.pay.service.divideinfo;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.DivideInfoPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.DivideInfoSaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo.DivideInfoDO;
import javax.validation.Valid;
import java.util.List;
/**
* 分账明细 Service 接口
*
* @author 管理员
*/
public interface DivideInfoService {
/**
* 创建分账明细
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createDivideInfo(@Valid DivideInfoSaveReqVO createReqVO);
/**
* 更新分账明细
*
* @param updateReqVO 更新信息
*/
void updateDivideInfo(@Valid DivideInfoSaveReqVO updateReqVO);
/**
* 删除分账明细
*
* @param id 编号
*/
void deleteDivideInfo(Long id);
/**
* 获得分账明细
*
* @param id 编号
* @return 分账明细
*/
DivideInfoDO getDivideInfo(Long id);
/**
* 获得分账明细分页
*
* @param pageReqVO 分页查询
* @return 分账明细分页
*/
PageResult<DivideInfoDO> getDivideInfoPage(DivideInfoPageReqVO pageReqVO);
void insertList(List<DivideInfoDO> list);
DivideInfoDO getDivideInfo(String outOrderNo,String account);
List<DivideInfoDO> getDivideList(String outOrderNo);
void updateList(List<DivideInfoDO> list);
}

View File

@ -0,0 +1,96 @@
package cn.iocoder.yudao.module.pay.service.divideinfo;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.DivideInfoPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.divideinfo.vo.DivideInfoSaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.divideinfo.DivideInfoDO;
import cn.iocoder.yudao.module.pay.dal.mysql.divideinfo.DivideInfoMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.DIVIDE_INFO_NOT_EXISTS;
/**
* 分账明细 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class DivideInfoServiceImpl implements DivideInfoService {
@Resource
private DivideInfoMapper divideInfoMapper;
@Override
public Long createDivideInfo(DivideInfoSaveReqVO createReqVO) {
// 插入
DivideInfoDO divideInfo = BeanUtils.toBean(createReqVO, DivideInfoDO.class);
divideInfoMapper.insert(divideInfo);
// 返回
return divideInfo.getId();
}
@Override
public void updateDivideInfo(DivideInfoSaveReqVO updateReqVO) {
// 校验存在
validateDivideInfoExists(updateReqVO.getId());
// 更新
DivideInfoDO updateObj = BeanUtils.toBean(updateReqVO, DivideInfoDO.class);
divideInfoMapper.updateById(updateObj);
}
@Override
public void deleteDivideInfo(Long id) {
// 校验存在
validateDivideInfoExists(id);
// 删除
divideInfoMapper.deleteById(id);
}
private void validateDivideInfoExists(Long id) {
if (divideInfoMapper.selectById(id) == null) {
throw exception(DIVIDE_INFO_NOT_EXISTS);
}
}
@Override
public DivideInfoDO getDivideInfo(Long id) {
return divideInfoMapper.selectById(id);
}
@Override
public PageResult<DivideInfoDO> getDivideInfoPage(DivideInfoPageReqVO pageReqVO) {
return divideInfoMapper.selectPage(pageReqVO);
}
@Override
public void insertList(List<DivideInfoDO> list) {
divideInfoMapper.insertBatch(list);
}
@Override
public DivideInfoDO getDivideInfo(String outOrderNo, String account) {
DivideInfoDO divideInfoDO = divideInfoMapper.selectOne(Wrappers.<DivideInfoDO>lambdaQuery()
.eq(DivideInfoDO::getAccount, account)
.eq(DivideInfoDO::getOutOrderNo, outOrderNo).last("limit 1"));
return divideInfoDO;
}
@Override
public void updateList(List<DivideInfoDO> list) {
divideInfoMapper.updateBatch(list);
}
@Override
public List<DivideInfoDO> getDivideList(String outOrderNo) {
return divideInfoMapper.selectList(Wrappers.<DivideInfoDO>lambdaQuery()
.eq(DivideInfoDO::getOutOrderNo, outOrderNo));
}
}

View File

@ -10,9 +10,11 @@ import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.divide.PayDivideStatusRespEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.controller.admin.divide.vo.DivideSaveReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
@ -30,6 +32,7 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
import cn.iocoder.yudao.module.pay.service.divide.DivideService;
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
@ -75,6 +78,9 @@ public class PayOrderServiceImpl implements PayOrderService {
@Resource
private PayNotifyService notifyService;
@Resource
private DivideService divideService;
@Override
public PayOrderDO getOrder(Long id) {
return orderMapper.selectById(id);
@ -292,6 +298,17 @@ public class PayOrderServiceImpl implements PayOrderService {
orderExtension.getOrderId());
}
private void addDivide(PayChannelDO channel, PayOrderDO payOrderDO) {
DivideSaveReqVO divideSaveReqVO = new DivideSaveReqVO();
String no = noRedisDAO.generate(payProperties.getOrderNoPrefix());
divideSaveReqVO.setChannelId(channel.getId())
.setChannelCode(channel.getCode())
.setTotalPrice(payOrderDO.getPrice())
.setNo(no).setStatus(PayDivideStatusRespEnum.WAITING.getStatus())
.setChannelOrderNo(payOrderDO.getChannelOrderNo());
divideService.createDivide(divideSaveReqVO);
}
/**
* 更新 PayOrderExtensionDO 支付成功
*
@ -359,6 +376,10 @@ public class PayOrderServiceImpl implements PayOrderService {
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
}
log.info("[updateOrderExtensionSuccess][order({}) 更新为已支付]", order.getId());
//3.添加分账
order.setChannelOrderNo(notify.getChannelOrderNo());
addDivide(channel,order);
return false;
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@ -95,4 +97,32 @@ public interface PayClient {
* @return 转账信息
*/
PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type);
/**
* 发起分账
*
* @param reqDTO 分账参数
* @return 分账
*/
PayDivideRespDto unifiedDivide(PayDivideUnifiedDto reqDTO);
/**
* 分账结果查询
*
* @param reqDTO 分账参数
* @return 分账
*/
PayDivideRespDto unifiedDivideResult(PayDivideUnifiedDto reqDTO);
/**
* 解冻分账剩余资金
*
* @param reqDTO 分账参数
* @return 分账
*/
PayDivideRespDto unifiedDivideFreeze(PayDivideUnifiedDto reqDTO);
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.divide;
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import lombok.Data;
import java.util.List;
/**
* @author zt
* @description <description class purpose>
* @since 2024/7/17
*/
@Data
public class PayDivideRespDto {
private String subMchId;
private String transactionId;
private String outOrderNo;
private String orderId;
private String state;
private List<ProfitSharingV3Result.Receiver> receivers;
/**
* 调用渠道的错误码
*
* 注意:这里返回的是业务异常,而是不系统异常。
* 如果是系统异常,则会抛出 {@link PayException}
*/
private String channelErrorCode;
/**
* 调用渠道报错时,错误信息
*/
private String channelErrorMsg;
/**
* 原始的异步通知结果
*/
private Object rawData;
/**
* 创建【FAILURE】状态的退款返回
*/
public static PayDivideRespDto failureOf(String channelErrorCode, String channelErrorMsg,
String transactionId, Object rawData) {
PayDivideRespDto respDTO = new PayDivideRespDto();
//respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus();
respDTO.channelErrorCode = channelErrorCode;
respDTO.channelErrorMsg = channelErrorMsg;
// 相对通用的字段
respDTO.transactionId = transactionId;
respDTO.rawData = rawData;
return respDTO;
}
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.divide;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request;
import lombok.Data;
import java.util.List;
/**
* @author zt
* @description <description class purpose>
* @since 2024/7/17
*/
@Data
public class PayDivideUnifiedDto {
/**
* 应用ID
*/
private String appid;
/**
* 微信订单号
*/
private String transactionId;
/**
* 商户分账单号
*/
private String outOrderNo;
/**
* 是否解冻剩余未分资金
*/
private boolean unfreezeUnsplit;
/**
* 分账接收方列表
*/
private List<ProfitSharingV3Request.Receiver> receivers;
}

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@ -238,6 +240,8 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type)
throws Throwable;
// ========== 各种工具方法 ==========
private PayException buildPayException(Throwable ex) {
@ -247,4 +251,66 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
throw new PayException(ex);
}
@Override
public PayDivideRespDto unifiedDivide(PayDivideUnifiedDto reqDTO) {
ValidationUtils.validate(reqDTO);
// 执行统一下单
PayDivideRespDto resp;
try {
resp = doUnifiedDivide(reqDTO);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
// 系统异常,则包装成 PayException 异常抛出
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
getId(), toJsonString(reqDTO), ex);
throw buildPayException(ex);
}
return resp;
}
protected abstract PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO)
throws Throwable;
@Override
public PayDivideRespDto unifiedDivideResult(PayDivideUnifiedDto reqDTO) {
ValidationUtils.validate(reqDTO);
// 执行统一下单
PayDivideRespDto resp;
try {
resp = doUnifiedDivideResult(reqDTO);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
// 系统异常,则包装成 PayException 异常抛出
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
getId(), toJsonString(reqDTO), ex);
throw buildPayException(ex);
}
return resp;
}
protected abstract PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO)
throws Throwable;
@Override
public PayDivideRespDto unifiedDivideFreeze(PayDivideUnifiedDto reqDTO) {
ValidationUtils.validate(reqDTO);
// 执行统一下单
PayDivideRespDto resp;
try {
resp = dounifiedDivideFreeze(reqDTO);
} catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可
throw ex;
} catch (Throwable ex) {
// 系统异常,则包装成 PayException 异常抛出
log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]",
getId(), toJsonString(reqDTO), ex);
throw buildPayException(ex);
}
return resp;
}
protected abstract PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO)
throws Throwable;
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -56,4 +58,19 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
reqDTO.getOutTradeNo(), response);
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -82,4 +84,19 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, "",
reqDTO.getOutTradeNo(), response);
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -66,4 +68,19 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
reqDTO.getOutTradeNo(), response);
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -63,4 +65,19 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(),
reqDTO.getOutTradeNo(), response);
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -56,4 +58,19 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
reqDTO.getOutTradeNo(), response);
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.mock;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@ -77,4 +79,19 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
throw new UnsupportedOperationException("待实现");
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
return null;
}
}

View File

@ -8,6 +8,8 @@ import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideRespDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
@ -21,8 +23,24 @@ import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingUnfreezeV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingUnfreezeV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
@ -481,4 +499,115 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
return e.getReturnMsg();
}
@Override
protected PayDivideRespDto doUnifiedDivide(PayDivideUnifiedDto reqDTO) throws Throwable {
try {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doUnifiedDivideV2(reqDTO);
case WxPayClientConfig.API_VERSION_V3:
return doUnifiedDivideV3(reqDTO);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
} catch (WxPayException e) {
String errorCode = getErrorCode(e);
String errorMessage = getErrorMessage(e);
return PayDivideRespDto.failureOf(errorCode, errorMessage,
reqDTO.getTransactionId(), e.getXmlString());
}
}
@Override
protected PayDivideRespDto doUnifiedDivideResult(PayDivideUnifiedDto reqDTO) throws Throwable {
try {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doUnifiedDivideResultV2(reqDTO);
case WxPayClientConfig.API_VERSION_V3:
return doUnifiedDivideResultV3(reqDTO);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
} catch (WxPayException e) {
String errorCode = getErrorCode(e);
String errorMessage = getErrorMessage(e);
return PayDivideRespDto.failureOf(errorCode, errorMessage,
reqDTO.getTransactionId(), e.getXmlString());
}
}
private PayDivideRespDto doUnifiedDivideV2(PayDivideUnifiedDto reqDTO) throws Throwable {
throw new UnsupportedOperationException("待实现");
}
private PayDivideRespDto doUnifiedDivideV3(PayDivideUnifiedDto reqDTO) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
ProfitSharingV3Request request = new ProfitSharingV3Request();
request.setAppid(config.getAppId());
request.setTransactionId(reqDTO.getTransactionId());
request.setUnfreezeUnsplit(reqDTO.isUnfreezeUnsplit());
request.setOutOrderNo(reqDTO.getOutOrderNo());
request.setReceivers(reqDTO.getReceivers());
// 2.1 执行请求
ProfitSharingV3Result response = client.getProfitSharingService().profitSharingV3(request);
PayDivideRespDto payDivideRespDto = new PayDivideRespDto();
BeanUtil.copyProperties(response,payDivideRespDto);
payDivideRespDto.setReceivers(response.getReceivers());
return payDivideRespDto;
}
private PayDivideRespDto doUnifiedDivideResultV2(PayDivideUnifiedDto reqDTO) throws Throwable {
throw new UnsupportedOperationException("待实现");
}
private PayDivideRespDto doUnifiedDivideResultV3(PayDivideUnifiedDto reqDTO) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
//ProfitSharingQueryV3Request request = new ProfitSharingQueryV3Request();
//request.setTransactionId(reqDTO.getTransactionId());
//request.setOutOrderNo(reqDTO.getOutOrderNo());
// 2.1 执行请求
ProfitSharingV3Result response = client.getProfitSharingService().profitSharingQueryV3(reqDTO.getOutOrderNo(),reqDTO.getTransactionId());
PayDivideRespDto payDivideRespDto = new PayDivideRespDto();
BeanUtil.copyProperties(response,payDivideRespDto);
payDivideRespDto.setReceivers(response.getReceivers());
return payDivideRespDto;
}
@Override
protected PayDivideRespDto dounifiedDivideFreeze(PayDivideUnifiedDto reqDTO) throws Throwable {
try {
switch (config.getApiVersion()) {
case API_VERSION_V2:
return doUnifiedDivideFreezeV2(reqDTO);
case WxPayClientConfig.API_VERSION_V3:
return doUnifiedDivideFreezeV3(reqDTO);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
} catch (WxPayException e) {
String errorCode = getErrorCode(e);
String errorMessage = getErrorMessage(e);
return PayDivideRespDto.failureOf(errorCode, errorMessage,
reqDTO.getTransactionId(), e.getXmlString());
}
}
private PayDivideRespDto doUnifiedDivideFreezeV2(PayDivideUnifiedDto reqDTO) throws Throwable {
throw new UnsupportedOperationException("待实现");
}
private PayDivideRespDto doUnifiedDivideFreezeV3(PayDivideUnifiedDto reqDTO) throws Throwable {
// 1. 构建 WxPayRefundRequest 请求
ProfitSharingUnfreezeV3Request request = new ProfitSharingUnfreezeV3Request();
request.setTransactionId(reqDTO.getTransactionId());
request.setOutOrderNo(reqDTO.getOutOrderNo());
request.setDescription("解冻全部剩余资金");
// 2.1 执行请求
ProfitSharingUnfreezeV3Result response = client.getProfitSharingService().profitSharingUnfreeze(request);
PayDivideRespDto payDivideRespDto = new PayDivideRespDto();
BeanUtil.copyProperties(response,payDivideRespDto);
return payDivideRespDto;
}
}

View File

@ -59,6 +59,8 @@ public class WxPubPayClient extends AbstractWxPayClient {
// 构建 WxPayUnifiedOrderRequest 对象
WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO)
.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO)));
//添加分账
request.setSettleInfo(new WxPayUnifiedOrderV3Request.SettleInfo().setProfitSharing(true));
// 执行请求
WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request);

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.pay.core.enums.divide;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 渠道的退款状态枚举
*
* @author jason
*/
@Getter
@AllArgsConstructor
public enum PayDivideStatusRespEnum {
WAITING("0", "等待分账"),
PROGRESS("10", "分账进行中"),
COMPLETE("20", "分账完成"),
FINISH("30", "分账结束"),
;
private final String status;
private final String name;
}