refactor(transaction): 重构分账逻辑
- 移除了不必要的账户信息获取方法 - 优化了分账规则的获取和校验逻辑 - 重构了分账计算逻辑,支持按不同手续费承担方式进行分账 - 新增了分账结果异步回调通知地址配置
This commit is contained in:
parent
dd588457e0
commit
83b4744fbd
@ -31,7 +31,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
* @author zcc
|
||||
* @date 2022-12-01
|
||||
*/
|
||||
//@Tag(name ="订单接口列表")
|
||||
@RestController
|
||||
@RequestMapping("/oms/order")
|
||||
@Slf4j
|
||||
@ -69,7 +68,11 @@ public class OrderController extends BaseController {
|
||||
return R.ok(util.writeExcel(convert.toVO(list), "订单列表数据"));
|
||||
}
|
||||
|
||||
@Tag(name ="获取订单表详细信息")
|
||||
/**
|
||||
* 获取订单详细信息
|
||||
* @param id 订单id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public R<ManagerOrderDetailVO> getInfo(@PathVariable("id") Long id) {
|
||||
return R.ok(orderService.selectById(id));
|
||||
|
@ -40,8 +40,13 @@ public class EasypayConfig {
|
||||
private String merRsaPrivateKey;
|
||||
|
||||
/**
|
||||
* 易生异步回调通知地址
|
||||
* 支付结果异步回调通知地址
|
||||
*/
|
||||
private String backUrl;
|
||||
private String tradeBackUrl;
|
||||
|
||||
/**
|
||||
* 分账结果异步回调通知地址
|
||||
*/
|
||||
private String separateBackUrl;
|
||||
|
||||
}
|
||||
|
@ -2,23 +2,16 @@ package com.wzj.soopin.transaction.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.EasyPayRequest;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPaymentResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
|
||||
import com.wzj.soopin.transaction.service.IEasypayService;
|
||||
import com.wzj.soopin.transaction.service.impl.WxAuthService;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.rmi.ServerException;
|
||||
@ -61,6 +54,7 @@ public class TransEasypayController {
|
||||
*/
|
||||
@Log(title = "易生支付-发起支付", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/trade")
|
||||
@SaIgnore
|
||||
public R<EasypayPrePayVO> trade(@RequestBody PaymentBO paymentBO) throws ServerException {
|
||||
EasypayPrePayVO easypayPrePayVO = easypayService.payment(paymentBO);
|
||||
return R.ok(easypayPrePayVO);
|
||||
@ -73,9 +67,10 @@ public class TransEasypayController {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/paymentQuery/{orderId}")
|
||||
public R<EasypayPaymentResultVO> paymentQuery(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
EasypayPaymentResultVO easypayPaymentResultVO = easypayService.paymentQuery(orderId);
|
||||
return R.ok(easypayPaymentResultVO);
|
||||
@SaIgnore
|
||||
public R<EasypayTransResultVO> paymentQuery(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
EasypayTransResultVO easypayTransResultVO = easypayService.paymentQuery(orderId);
|
||||
return R.ok(easypayTransResultVO);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,8 +81,43 @@ public class TransEasypayController {
|
||||
*/
|
||||
@Log(title = "易生支付-实时退款", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/refund/{orderId}")
|
||||
public R<EasypayPrePayVO> refund(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
@SaIgnore
|
||||
public R refund(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
easypayService.refund(orderId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款结果
|
||||
*
|
||||
* @param orderId 订单id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/refundQuery/{orderId}")
|
||||
@SaIgnore
|
||||
public R<EasypayTransResultVO> refundQuery(@PathVariable("orderId") Long orderId) throws ServerException {
|
||||
EasypayTransResultVO easypayTransResultVO = easypayService.refundQuery(orderId);
|
||||
return R.ok(easypayTransResultVO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理易生分账结果通知回调 处理
|
||||
*
|
||||
* @param easyPayRequest
|
||||
* @return
|
||||
*/
|
||||
@SaIgnore
|
||||
@Log(title = "易生支付-分账结果通知回调", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/separate/callback")
|
||||
public Map separateCallback(@RequestBody EasyPayRequest easyPayRequest) {
|
||||
easypayService.handleSeparateCallback(easyPayRequest);
|
||||
HashMap<Object, Object> map = new HashMap<>();
|
||||
map.put("code", "000000");
|
||||
map.put("msg", "Success");
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package com.wzj.soopin.transaction.domain.bo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分账请求参数
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class SeparateApplyBO {
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Long payId;
|
||||
|
||||
/**
|
||||
* 支付完成时间
|
||||
*/
|
||||
private Date transDate;
|
||||
|
||||
/**
|
||||
* 分账订单总金额.单位分
|
||||
*/
|
||||
private Long transSumAmt;
|
||||
|
||||
/**
|
||||
* 分账订单总笔数
|
||||
*/
|
||||
private Long transSumCount;
|
||||
|
||||
/**
|
||||
* 分账总单流水号
|
||||
*/
|
||||
private String separateBatchTrace;
|
||||
|
||||
/**
|
||||
* 分账项
|
||||
*/
|
||||
private List<SeparateItemBO> separateItemBOList;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.wzj.soopin.transaction.domain.bo;
|
||||
|
||||
import com.wzj.soopin.transaction.enums.easypay.SepaStatus;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 分账项
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class SeparateItemBO {
|
||||
|
||||
|
||||
/**
|
||||
* 分账子单流水号
|
||||
*/
|
||||
private String separateTrade;
|
||||
|
||||
/**
|
||||
* 分账收款方商户号
|
||||
*/
|
||||
private String receiveMchtCode;
|
||||
|
||||
/**
|
||||
* 分账金额,单位分
|
||||
*/
|
||||
private Integer sepaTransAmount;
|
||||
|
||||
/**
|
||||
* 手续费对应本金(原交易订单)金额
|
||||
* 当前分账接收方拟承担的手续费本金金额,金额和比例2选1必填。
|
||||
* 当前收款方不承担,则送0;
|
||||
* 当前收款方全额承担,则送原订单金额;
|
||||
* 当前收款方仅承担自己接收金额的手续费,则送分账金额。。
|
||||
*/
|
||||
private Integer sepaFeeAmount;
|
||||
|
||||
|
||||
// =============== 分账结果参数 ==============
|
||||
|
||||
/**
|
||||
* 分账单状态
|
||||
*/
|
||||
private SepaStatus sepaStatus;
|
||||
|
||||
/**
|
||||
* 分账平台应结金额,单位分
|
||||
*/
|
||||
private Long sepaPlatStlmAmount;
|
||||
|
||||
/**
|
||||
* 分账实际结算金额,单位分
|
||||
*/
|
||||
private Long sepaStlmAmount;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -75,10 +75,6 @@ public class SeparateInfo {
|
||||
* 分账比例,分账金额和分账比例2选一必填,30代表30%,仅可上送整数
|
||||
*/
|
||||
private Long sepaRatio;
|
||||
/**
|
||||
* 分账金额,分账金额和分账比例2选一必填,单位分
|
||||
*/
|
||||
private Long sepaTransAmount;
|
||||
/**
|
||||
* 分账订单描述
|
||||
*/
|
||||
|
@ -1,8 +1,12 @@
|
||||
package com.wzj.soopin.transaction.domain.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class WxAuthResponse {
|
||||
private String openid;
|
||||
private String session_key;
|
||||
|
@ -85,9 +85,9 @@ public class DivideDetail extends BaseEntity {
|
||||
@ExcelProperty(value = "状态", order = 5)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "账户id")
|
||||
@ExcelProperty(value = "账户id", order = 6)
|
||||
private Long accountId;
|
||||
@Schema(description = "账户code")
|
||||
@ExcelProperty(value = "账户code", order = 6)
|
||||
private String accountCode;
|
||||
/**
|
||||
* 账户名称
|
||||
* */
|
||||
|
@ -4,6 +4,7 @@ package com.wzj.soopin.transaction.domain.po;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
@ -46,6 +47,13 @@ public class DivideRule extends BaseEntity {
|
||||
private Long regionId;
|
||||
|
||||
|
||||
/**
|
||||
* 手续费承担方式类型见 {@link DivideRuleFeeType}
|
||||
*/
|
||||
@Schema(description = "手续费承担方式")
|
||||
private Integer feeType;
|
||||
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
|
@ -83,11 +83,11 @@ public class PayOrder extends BaseAudit {
|
||||
private String unTrace;
|
||||
|
||||
/**
|
||||
* 是否支付完成
|
||||
* 交易状态 0->待支付,1->支付中,2->已支付,3->退款中,4->已退款
|
||||
*/
|
||||
@TableField(value = "trans_over")
|
||||
@Schema(description = "是否支付完成")
|
||||
private Boolean transOver;
|
||||
@TableField(value = "trans_state")
|
||||
@Schema(description = "交易状态 0->待支付,1->支付中,2->已支付,3->退款中,4->已退款")
|
||||
private Integer transState;
|
||||
|
||||
@TableField(value = "del_flag")
|
||||
private String delFlag;
|
||||
|
@ -74,9 +74,9 @@ public class DivideDetailVO extends BaseEntity {
|
||||
private Integer type;
|
||||
|
||||
|
||||
@Schema(description = "账户id")
|
||||
@ExcelProperty(value = "账户id", order = 6)
|
||||
private Long accountId;
|
||||
@Schema(description = "账户code")
|
||||
@ExcelProperty(value = "账户code", order = 6)
|
||||
private String accountCode;
|
||||
/**
|
||||
* 账户名称
|
||||
* */
|
||||
|
@ -2,6 +2,7 @@ package com.wzj.soopin.transaction.domain.vo;
|
||||
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
@ -56,6 +57,12 @@ public class DivideRuleVO extends BaseEntity {
|
||||
@Schema(description = "区域id")
|
||||
private Long regionId;
|
||||
|
||||
/**
|
||||
* 手续费承担方式类型见 {@link DivideRuleFeeType}
|
||||
*/
|
||||
@Schema(description = "手续费承担方式")
|
||||
private Integer feeType;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
|
@ -14,7 +14,7 @@ import java.math.BigDecimal;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EasypayPaymentResultVO {
|
||||
public class EasypayTransResultVO {
|
||||
|
||||
/**
|
||||
* 订单id
|
||||
@ -27,9 +27,9 @@ public class EasypayPaymentResultVO {
|
||||
public Long payId;
|
||||
|
||||
/**
|
||||
* 支付是否完成
|
||||
* 交易状态 0->待支付,1->已支付,2->退款中,3->已退款
|
||||
*/
|
||||
public boolean paymentComplete;
|
||||
public int transState;
|
||||
|
||||
/**
|
||||
* 订单总金额
|
@ -1,5 +1,13 @@
|
||||
package com.wzj.soopin.transaction.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 分账规则的商户类型
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DivideRuleDetailType {
|
||||
|
||||
|
||||
@ -15,25 +23,14 @@ public enum DivideRuleDetailType {
|
||||
* 代理
|
||||
*/
|
||||
PROXY(3, "代理"),
|
||||
/**
|
||||
* 达人
|
||||
*/
|
||||
REFERENCE(4, "达人"),;
|
||||
|
||||
REFERENCE(4, "推广"),;
|
||||
private final int value;
|
||||
|
||||
private int value;
|
||||
private String desc;
|
||||
|
||||
DivideRuleDetailType(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
private final String desc;
|
||||
|
||||
public static DivideRuleDetailType getEnum(int value) {
|
||||
for (DivideRuleDetailType type : DivideRuleDetailType.values()) {
|
||||
|
@ -1,33 +1,44 @@
|
||||
package com.wzj.soopin.transaction.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DivideRuleFeeType {
|
||||
/**
|
||||
* 按比例分配
|
||||
*/
|
||||
RATE(1, "按比例分配"),
|
||||
RATE(0, "按比例分配"),
|
||||
/**
|
||||
* 商家承担
|
||||
*/
|
||||
SELLER(2, "商家承担"),
|
||||
SELLER(1, "商家承担"),
|
||||
/**
|
||||
* 平台承担
|
||||
*/
|
||||
PLATFORM(3, "平台承担"),
|
||||
PLATFORM(2, "平台承担"),
|
||||
|
||||
/**
|
||||
* 平台代理承担
|
||||
*/
|
||||
PROXY(3, "代理承担"),
|
||||
|
||||
|
||||
PROXY(4, "平台代理承担");
|
||||
|
||||
|
||||
private String desc;
|
||||
/**
|
||||
* 平台代理承担
|
||||
*/
|
||||
REFERENCE(4, "达人承担");
|
||||
|
||||
private int value;
|
||||
|
||||
DivideRuleFeeType(int value, String desc) {
|
||||
this.value = value;
|
||||
this.desc = desc;
|
||||
private String desc;
|
||||
|
||||
public static DivideRuleFeeType getByValue(int value) {
|
||||
return Arrays.stream(values()).filter(e -> e.value == value).findFirst().orElseThrow(() -> new ServiceException("手续费分配方式" + value + "不存在"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.wzj.soopin.transaction.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付单交易状态
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TransState {
|
||||
|
||||
PENDING(0, "待支付"),
|
||||
|
||||
Payment(1, "支付中"),
|
||||
|
||||
PAID(2, "已支付"),
|
||||
|
||||
REFUND_PENDING(3, "退款中"),
|
||||
|
||||
REFUNDED(4, "已退款");
|
||||
|
||||
|
||||
private final int code;
|
||||
|
||||
private final String desc;
|
||||
|
||||
|
||||
}
|
@ -1,27 +1,42 @@
|
||||
package com.wzj.soopin.transaction.enums.easypay;
|
||||
|
||||
import java.io.IOException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* 分账单状态,(处理中、成功、失败、已退款)
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SepaStatus {
|
||||
PENDING, REFUNDED, SUCCESS;
|
||||
|
||||
public String toValue() {
|
||||
return switch (this) {
|
||||
case PENDING -> "PENDING";
|
||||
case REFUNDED -> "REFUNDED";
|
||||
case SUCCESS -> "SUCCESS";
|
||||
};
|
||||
}
|
||||
SUCCESS("SUCCESS", "成功"),
|
||||
FAIL("FAIL", "失败"),
|
||||
PENDING("PENDING", "处理中"),
|
||||
PROCESSING("PROCESSING", "处理中"),
|
||||
REFUNDED("REFUNDED", "已退款");
|
||||
|
||||
|
||||
/**
|
||||
* 状态code
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 状态描述
|
||||
*/
|
||||
private final String info;
|
||||
|
||||
public static SepaStatus getByValue(String value) {
|
||||
return Arrays.stream(SepaStatus.values())
|
||||
.filter(e -> StrUtil.equals(e.getValue(), value))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new ServiceException("分账状态不存在"));
|
||||
|
||||
public static SepaStatus forValue(String value) throws IOException {
|
||||
return switch (value) {
|
||||
case "PENDING" -> PENDING;
|
||||
case "REFUNDED" -> REFUNDED;
|
||||
case "SUCCESS" -> SUCCESS;
|
||||
default -> throw new IOException("Cannot deserialize SepaStatus");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.wzj.soopin.transaction.mapper;
|
||||
|
||||
import com.wzj.soopin.transaction.domain.po.DivideDetail;
|
||||
import com.wzj.soopin.transaction.domain.vo.DivideDetailVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
@ -9,6 +10,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
*
|
||||
* @author zcc
|
||||
*/
|
||||
@Mapper
|
||||
public interface DivideDetailMapper extends BaseMapperPlus<DivideDetail, DivideDetailVO> {
|
||||
|
||||
}
|
||||
|
@ -3,13 +3,20 @@ package com.wzj.soopin.transaction.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.wzj.soopin.transaction.domain.po.Divide;
|
||||
import com.wzj.soopin.transaction.domain.vo.DivideVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* 意见反馈Mapper接口
|
||||
*
|
||||
* @author zcc
|
||||
*/
|
||||
@Mapper
|
||||
public interface DivideMapper extends BaseMapper<Divide> {
|
||||
|
||||
DivideVO getVOById(Long divideId);
|
||||
|
||||
@Select("select * from trans_divide where order_id = #{orderId}")
|
||||
Divide selectByOrderId(@Param("orderId") Long orderId);
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ package com.wzj.soopin.transaction.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.wzj.soopin.transaction.domain.po.PayOrder;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@Mapper
|
||||
public interface PayOrderMapper extends BaseMapper<PayOrder> {
|
||||
|
@ -2,9 +2,10 @@ package com.wzj.soopin.transaction.service;
|
||||
|
||||
|
||||
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.EasyPayRequest;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPaymentResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -24,7 +25,7 @@ public interface IEasypayService {
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
EasypayPaymentResultVO paymentQuery(Long orderId) throws ServerException;
|
||||
EasypayTransResultVO paymentQuery(Long orderId) throws ServerException;
|
||||
|
||||
/**
|
||||
* 处理易生支付结果通知回调
|
||||
@ -38,6 +39,27 @@ public interface IEasypayService {
|
||||
*/
|
||||
void refund(Long orderId);
|
||||
|
||||
/**
|
||||
* 退款查询
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
EasypayTransResultVO refundQuery(Long orderId);
|
||||
|
||||
|
||||
/**
|
||||
* 发起分账
|
||||
* @param separateApplyBO
|
||||
* @return
|
||||
*/
|
||||
SeparateApplyBO separateApply(SeparateApplyBO separateApplyBO);
|
||||
|
||||
/**
|
||||
* 处理易生分账结果通知回调
|
||||
* @param easyPayRequest
|
||||
*/
|
||||
void handleSeparateCallback(EasyPayRequest easyPayRequest);
|
||||
|
||||
/**
|
||||
* 获取易生账户
|
||||
* @param memberId
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.wzj.soopin.transaction.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.wzj.soopin.transaction.convert.DivideRuleConvert;
|
||||
@ -104,15 +105,9 @@ public class DivideRuleServiceImpl extends ServiceImpl<DivideRuleMapper, DivideR
|
||||
List<DivideRule> divideRuleList = baseMapper.selectList(new QueryWrapper<DivideRule>().lambda()
|
||||
.eq(DivideRule::getType,orderType)
|
||||
.eq(DivideRule::getStatus,DivideRuleStatus.ON.getCode()));
|
||||
if (CollectionUtils.isEmpty(divideRuleList)) {
|
||||
return null;
|
||||
}
|
||||
if(divideRuleList.size()>1){
|
||||
throw new ServiceException("分账规则不唯一");
|
||||
}
|
||||
|
||||
Assert.notEmpty(divideRuleList, () -> new ServiceException("未找到品类的分账规则"));
|
||||
Assert.isTrue(divideRuleList.size() == 1, () -> new ServiceException("品类分账规则不唯一"));
|
||||
DivideRule divideRule = divideRuleList.get(0);
|
||||
|
||||
List<DivideRuleDetail> detailList = detailMapper.selectList(new QueryWrapper<DivideRuleDetail>().lambda()
|
||||
.eq(DivideRuleDetail::getRuleId, divideRule.getId()));
|
||||
DivideRuleVO vo = convert.toVO(divideRule);
|
||||
|
@ -1,30 +1,35 @@
|
||||
package com.wzj.soopin.transaction.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.wzj.soopin.member.domain.po.Member;
|
||||
import com.wzj.soopin.member.domain.po.MemberAccount;
|
||||
import com.wzj.soopin.member.service.IMemberAccountService;
|
||||
import com.wzj.soopin.member.service.IMemberService;
|
||||
import com.wzj.soopin.order.domain.entity.Order;
|
||||
import com.wzj.soopin.order.service.OrderItemService;
|
||||
import com.wzj.soopin.order.service.OrderService;
|
||||
import com.wzj.soopin.order.utils.StringUtils;
|
||||
import com.wzj.soopin.transaction.convert.DivideConvert;
|
||||
import com.wzj.soopin.transaction.convert.DivideDetailConvert;
|
||||
import com.wzj.soopin.transaction.domain.bo.DivideBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.SeparateItemBO;
|
||||
import com.wzj.soopin.transaction.domain.po.Divide;
|
||||
import com.wzj.soopin.transaction.domain.po.DivideDetail;
|
||||
import com.wzj.soopin.transaction.domain.po.PayOrder;
|
||||
import com.wzj.soopin.transaction.domain.vo.DivideRuleDetailVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.DivideVO;
|
||||
import com.wzj.soopin.transaction.enums.DivideRuleDetailType;
|
||||
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
|
||||
import com.wzj.soopin.transaction.enums.DivideStatus;
|
||||
import com.wzj.soopin.transaction.enums.TransState;
|
||||
import com.wzj.soopin.transaction.mapper.DivideDetailMapper;
|
||||
import com.wzj.soopin.transaction.mapper.DivideMapper;
|
||||
import com.wzj.soopin.transaction.service.IDivideRuleService;
|
||||
import com.wzj.soopin.transaction.service.IDivideService;
|
||||
import com.wzj.soopin.transaction.service.IEasypayService;
|
||||
import com.wzj.soopin.transaction.service.PayOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
@ -36,9 +41,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 分账服务实现类
|
||||
@ -56,23 +60,17 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
|
||||
|
||||
private final DivideConvert divideConvert;
|
||||
|
||||
|
||||
private final OrderService orderService;
|
||||
|
||||
private final PayOrderService payOrderService;
|
||||
|
||||
private final IDivideRuleService ruleService;
|
||||
|
||||
private final OrderItemService orderItemService;
|
||||
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
private final IEasypayService easypayService;
|
||||
|
||||
private final IMemberAccountService accountService;
|
||||
|
||||
private final ISysTenantService sysTenantService;
|
||||
|
||||
private final IMemberService memberService;
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -138,177 +136,270 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
|
||||
return baseMapper.selectOne(new QueryWrapper<Divide>().lambda().eq(Divide::getOrderSn, orderNo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单金额分账
|
||||
* 商家先从订单总金额中分走租户中配置的比例后,剩余的按分账规则分给平台和推广等账户
|
||||
*
|
||||
* @param orderId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean divide(Long orderId) {
|
||||
//获取订单信息
|
||||
Order order = orderService.getById(orderId);
|
||||
|
||||
if (order == null) {
|
||||
throw new ServiceException("订单不存在");
|
||||
}
|
||||
if (order.getStatus() != 3) { //订单状态为已完成
|
||||
throw new ServiceException("订单状态不正确");
|
||||
}
|
||||
Divide divide = this.getById(orderId);
|
||||
if (divide != null) {
|
||||
throw new ServiceException("已存在分账记录,无需再次分账");
|
||||
}
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
Assert.isTrue(order.getStatus() == 3, () -> new ServiceException("订单未支付"));
|
||||
PayOrder payOrder = payOrderService.getById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("支付单不存在"));
|
||||
Assert.isTrue(payOrder.getTransState() == TransState.PAID.getCode(), () -> new ServiceException("订单未支付"));
|
||||
Assert.isFalse(this.exists(Wrappers.lambdaQuery(Divide.class).eq(Divide::getOrderId, orderId)), () -> new ServiceException("已存在分账记录,无需再次分账"));
|
||||
//查找分账规则
|
||||
DivideRuleVO rule = ruleService.getVOByOrderType(order.getType());
|
||||
if (rule == null) {
|
||||
throw new ServiceException("未找到分账规则");
|
||||
}
|
||||
//开始分账
|
||||
Integer feeType = rule.getFeeType();
|
||||
DivideRuleFeeType divideRuleFeeType = DivideRuleFeeType.getByValue(feeType);
|
||||
List<DivideRuleDetailVO> details = rule.getDetails();
|
||||
checkRule(details, divideRuleFeeType);
|
||||
|
||||
//根据易生支付的合同查看手续费金额
|
||||
BigDecimal totalAmount = order.getTotalAmount();
|
||||
BigDecimal totalFee = new BigDecimal(0);
|
||||
String feeRate = configService.getConfigValue("transaction.divide.feeRate");
|
||||
if (StringUtils.isNotBlank(feeRate)) {
|
||||
totalFee = totalAmount.multiply(new BigDecimal(feeRate)).divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP);
|
||||
}
|
||||
BigDecimal actualMoney = totalAmount.subtract(totalFee);
|
||||
|
||||
//计算订单可分配金额,订单只考虑整单退,不考虑单独退,所以直接计算订单金额
|
||||
//先生成主表信息
|
||||
divide = Divide.builder()
|
||||
Divide divide = Divide.builder()
|
||||
.ruleId(rule.getId())
|
||||
.orderMoney(totalAmount)
|
||||
.fee(totalFee)
|
||||
.actualMoney(actualMoney)
|
||||
// .fee(totalFee)
|
||||
// .actualMoney(actualMoney)
|
||||
.orderSn(order.getOrderSn())
|
||||
.status(DivideStatus.PENDING.getCode())
|
||||
.build();
|
||||
super.save(divide);
|
||||
|
||||
//计算商户的手续费
|
||||
List<DivideDetail> detailList = new ArrayList<>();
|
||||
List<SeparateItemBO> separateItemBOList = new ArrayList<>();
|
||||
// 从租户信息得到商户的分账比例,先分给商户
|
||||
SysTenantVo tenant = sysTenantService.queryById(order.getTenantId());
|
||||
if (tenant == null) {
|
||||
throw new ServiceException("租户信息不存在");
|
||||
}
|
||||
BigDecimal sellerFee = new BigDecimal(0);
|
||||
BigDecimal platformFee = new BigDecimal(0);
|
||||
if (tenant.getBearFeeFlag() == 1) {
|
||||
//如果承担手续费,计算手续费
|
||||
sellerFee = totalFee;
|
||||
} else {
|
||||
platformFee = totalFee;
|
||||
}
|
||||
DivideDetail sellerDivideDetail = divideSeller(totalAmount, divide.getId(), tenant, divideRuleFeeType, detailList, separateItemBOList);
|
||||
detailList.add(sellerDivideDetail);
|
||||
// 商户分完后分给代理和达人,最后剩余都给平台
|
||||
rule.getDetails().stream()
|
||||
.filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue())
|
||||
.findFirst()
|
||||
.ifPresent(ruleDetailVO -> {
|
||||
DivideDetail proxyDivideDetail = divideProxy(totalAmount, ruleDetailVO, divide.getId(), order.getTenantId(),divideRuleFeeType, detailList, separateItemBOList);
|
||||
});
|
||||
rule.getDetails().stream()
|
||||
.filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue())
|
||||
.findFirst()
|
||||
.ifPresent(ruleDetailVO -> {
|
||||
DivideDetail divideReference = divideReference(totalAmount, ruleDetailVO, divide.getId(), order.getMemberId(),divideRuleFeeType, detailList, separateItemBOList);
|
||||
detailList.add(divideReference);
|
||||
});
|
||||
|
||||
//生成商户的分账明细
|
||||
BigDecimal sellerAmount = divideSeller(actualMoney, sellerFee, divide.getId(), tenant);
|
||||
|
||||
|
||||
BigDecimal platformAmount = actualMoney.subtract(sellerAmount);
|
||||
BigDecimal finalAmount = new BigDecimal(0);
|
||||
//按规则进行分账
|
||||
//先分代理 然后达人 最后的剩余都给平台
|
||||
DivideRuleDetailVO divideRuleDetail = rule.getDetails().stream().filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue()).findFirst().orElse(null);
|
||||
|
||||
if ((divideRuleDetail != null)) {
|
||||
finalAmount = platformAmount.subtract(divideproxy(platformAmount, divideRuleDetail, divide.getId(), order.getTenantId()));
|
||||
}
|
||||
divideRuleDetail = rule.getDetails().stream().filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue()).findFirst().orElse(null);
|
||||
|
||||
if ((divideRuleDetail != null)) {
|
||||
finalAmount = finalAmount.subtract(divideDarren(platformAmount, divideRuleDetail, divide.getId(), order.getMemberId()));
|
||||
}
|
||||
dividePlatform(finalAmount, platformFee, divideRuleDetail, divide.getId(), tenant.getBearFeeFlag() == 1);
|
||||
rule.getDetails().stream()
|
||||
.filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue())
|
||||
.findFirst()
|
||||
.ifPresent(ruleDetailVO -> {
|
||||
DivideDetail dividePlatform = dividePlatform(totalAmount, ruleDetailVO, divide.getId(),divideRuleFeeType, detailList, separateItemBOList);
|
||||
detailList.add(dividePlatform);
|
||||
});
|
||||
|
||||
//同步订单状态
|
||||
syncOrderStatus(order);
|
||||
|
||||
//同步易生支付
|
||||
syncYisheng(null);
|
||||
// 调用易生支付实时分账
|
||||
SeparateApplyBO separateApplyBO = SeparateApplyBO.builder()
|
||||
.orderId(order.getId())
|
||||
.payId(order.getPayId())
|
||||
.transDate(payOrder.getEndTransDate())
|
||||
.transSumAmt(payOrder.getTransAmount())
|
||||
.transSumCount((long) separateItemBOList.size())
|
||||
.separateBatchTrace(String.valueOf(divide.getId()))
|
||||
.separateItemBOList(separateItemBOList)
|
||||
.build();
|
||||
easypayService.separateApply(separateApplyBO);
|
||||
return true;
|
||||
}
|
||||
|
||||
private BigDecimal divideSeller(BigDecimal actualMoney, BigDecimal sellerFee, Long divideId, SysTenantVo tenant) {
|
||||
//获取商户的账户信息
|
||||
Map<String, String> account = getSellerAccount(tenant.getId());
|
||||
if (account == null) {
|
||||
log.error("商户信息不存在,不参与分账");
|
||||
/**
|
||||
* 校验分账规则详情和规则中的手续费承担类型是否一致
|
||||
*
|
||||
* @param details
|
||||
* @param divideRuleFeeType
|
||||
*/
|
||||
private void checkRule(List<DivideRuleDetailVO> details, DivideRuleFeeType divideRuleFeeType) {
|
||||
if (DivideRuleFeeType.SELLER == divideRuleFeeType) {
|
||||
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.SELLER.getValue()).count();
|
||||
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置商户承担手续费,但未配置商户分账规则详情"));
|
||||
}
|
||||
if (DivideRuleFeeType.PLATFORM == divideRuleFeeType) {
|
||||
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue()).count();
|
||||
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置平台承担手续费,但未配置平台分账规则详情"));
|
||||
}
|
||||
if (DivideRuleFeeType.PROXY == divideRuleFeeType) {
|
||||
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue()).count();
|
||||
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置代理承担手续费,但未配置代理分账规则详情"));
|
||||
}
|
||||
if (DivideRuleFeeType.REFERENCE == divideRuleFeeType) {
|
||||
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue()).count();
|
||||
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置达人承担手续费,但未配置达人分账规则详情"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户分账
|
||||
*
|
||||
* @param totalAmount 总金额
|
||||
* @param divideId 分账总表id
|
||||
* @param divideRuleFeeType
|
||||
* @param tenant 商户所属租户
|
||||
* @param detailList
|
||||
* @param separateItemBOList
|
||||
* @return
|
||||
*/
|
||||
private DivideDetail divideSeller(BigDecimal totalAmount, Long divideId, SysTenantVo tenant,
|
||||
DivideRuleFeeType divideRuleFeeType, List<DivideDetail> detailList,
|
||||
List<SeparateItemBO> separateItemBOList) {
|
||||
//获取商户的账户信息
|
||||
String mchtCode = getMchtCode(tenant.getId());
|
||||
//计算商户的分账金额
|
||||
BigDecimal divideRate = tenant.getDivideRate();
|
||||
Integer bearFeeFlag = tenant.getBearFeeFlag();
|
||||
|
||||
//计算商户的分账金额
|
||||
BigDecimal sellerAmount = actualMoney.multiply(divideRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
|
||||
BigDecimal sellerAmount = totalAmount.multiply(divideRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
//生成商户的分账明细
|
||||
DivideDetail sellerDetail = DivideDetail.builder()
|
||||
.divideId(divideId)
|
||||
.accountCode(mchtCode)
|
||||
.money(sellerAmount)
|
||||
.fee(sellerFee)
|
||||
.feePercent(bearFeeFlag == 1 ? new BigDecimal(100) : new BigDecimal(0))
|
||||
.moneyPercent(divideRate)
|
||||
.type(DivideRuleDetailType.SELLER.getValue()).build();
|
||||
|
||||
detailMapper.insert(sellerDetail);
|
||||
|
||||
return sellerAmount;
|
||||
detailList.add(sellerDetail);
|
||||
Integer sepaFeeAmount = 0;
|
||||
if (divideRuleFeeType == DivideRuleFeeType.SELLER) {
|
||||
sepaFeeAmount = totalAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
} else if (divideRuleFeeType == DivideRuleFeeType.RATE) {
|
||||
sepaFeeAmount = sellerAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
}
|
||||
separateItemBOList.add(SeparateItemBO.builder()
|
||||
.separateTrade(String.valueOf(sellerDetail.getId()))
|
||||
.receiveMchtCode(mchtCode)
|
||||
.sepaTransAmount(sellerAmount.multiply(BigDecimal.valueOf(100)).intValue())
|
||||
.sepaFeeAmount(sepaFeeAmount)
|
||||
.build());
|
||||
return sellerDetail;
|
||||
}
|
||||
|
||||
private BigDecimal divideproxy(BigDecimal platformMoney, DivideRuleDetailVO rule, Long divideId, Long tenantId) {
|
||||
/**
|
||||
* 代理商分账
|
||||
*
|
||||
* @param totalAmount 总金额
|
||||
* @param rule 代理商的分账规则详情
|
||||
* @param divideId 分账总表id
|
||||
* @param tenantId 代理商所属租户id
|
||||
* @param divideRuleFeeType
|
||||
* @param detailList
|
||||
* @param separateItemBOList
|
||||
* @return
|
||||
*/
|
||||
private DivideDetail divideProxy(BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, Long tenantId, DivideRuleFeeType divideRuleFeeType, List<DivideDetail> detailList, List<SeparateItemBO> separateItemBOList) {
|
||||
//获取代理人的账户信息
|
||||
Map<String, String> account = getProxyAccount(tenantId);
|
||||
if (account == null) {
|
||||
log.error("代理人信息不存在,不参与分账");
|
||||
return new BigDecimal(0);
|
||||
}
|
||||
String mchtCode = getMchtCode(tenantId);
|
||||
//计算代理人的分账金额
|
||||
BigDecimal proxyAmount = platformMoney.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
BigDecimal proxyAmount = totalAmount.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
DivideDetail proxyDetail = DivideDetail.builder()
|
||||
.divideId(divideId)
|
||||
.accountCode(mchtCode)
|
||||
.money(proxyAmount)
|
||||
.fee(new BigDecimal(0))
|
||||
.feePercent(new BigDecimal(0))
|
||||
.moneyPercent(rule.getMoneyPercent())
|
||||
.type(DivideRuleDetailType.PROXY.getValue())
|
||||
.build();
|
||||
detailMapper.insert(proxyDetail);
|
||||
return proxyAmount;
|
||||
detailList.add(proxyDetail);
|
||||
Integer sepaFeeAmount = 0;
|
||||
if (divideRuleFeeType == DivideRuleFeeType.PROXY) {
|
||||
sepaFeeAmount = totalAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
} else if (divideRuleFeeType == DivideRuleFeeType.RATE) {
|
||||
sepaFeeAmount = proxyAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
}
|
||||
separateItemBOList.add(SeparateItemBO.builder()
|
||||
.separateTrade(String.valueOf(proxyDetail.getId()))
|
||||
.receiveMchtCode(mchtCode)
|
||||
.sepaTransAmount(proxyAmount.multiply(BigDecimal.valueOf(100)).intValue())
|
||||
.sepaFeeAmount(sepaFeeAmount)
|
||||
.build());
|
||||
return proxyDetail;
|
||||
}
|
||||
|
||||
private BigDecimal divideDarren(BigDecimal platformMoney, DivideRuleDetailVO rule, Long divideId, Long tenantId) {
|
||||
/**
|
||||
* 达人分账
|
||||
*
|
||||
* @param totalAmount
|
||||
* @param rule
|
||||
* @param divideId
|
||||
* @param tenantId
|
||||
* @param divideRuleFeeType
|
||||
* @param detailList
|
||||
* @param separateItemBOList
|
||||
* @return
|
||||
*/
|
||||
private DivideDetail divideReference(BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, Long tenantId, DivideRuleFeeType divideRuleFeeType, List<DivideDetail> detailList, List<SeparateItemBO> separateItemBOList) {
|
||||
//获取达人的账户信息
|
||||
Map<String, String> account = getReferenceAccount(tenantId);
|
||||
if (account == null) {
|
||||
log.error("达人信息不存在,不参与分账");
|
||||
return new BigDecimal(0);
|
||||
}
|
||||
String mchtCode = getMchtCode(tenantId);
|
||||
//计算达人的分账金额
|
||||
BigDecimal proxyAmount = platformMoney.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
DivideDetail proxyDetail = DivideDetail.builder()
|
||||
BigDecimal proxyAmount = totalAmount.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
DivideDetail referenceDetail = DivideDetail.builder()
|
||||
.divideId(divideId)
|
||||
.accountCode(mchtCode)
|
||||
.money(proxyAmount)
|
||||
.fee(new BigDecimal(0))
|
||||
.feePercent(new BigDecimal(0))
|
||||
.moneyPercent(rule.getMoneyPercent())
|
||||
.type(DivideRuleDetailType.REFERENCE.getValue())
|
||||
.build();
|
||||
detailMapper.insert(proxyDetail);
|
||||
return proxyAmount;
|
||||
detailMapper.insert(referenceDetail);
|
||||
detailList.add(referenceDetail);
|
||||
Integer sepaFeeAmount = 0;
|
||||
if (divideRuleFeeType == DivideRuleFeeType.REFERENCE) {
|
||||
sepaFeeAmount = totalAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
} else if (divideRuleFeeType == DivideRuleFeeType.RATE) {
|
||||
sepaFeeAmount = proxyAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
}
|
||||
separateItemBOList.add(SeparateItemBO.builder()
|
||||
.separateTrade(String.valueOf(referenceDetail.getId()))
|
||||
.receiveMchtCode(mchtCode)
|
||||
.sepaTransAmount(proxyAmount.multiply(BigDecimal.valueOf(100)).intValue())
|
||||
.sepaFeeAmount(sepaFeeAmount)
|
||||
.build());
|
||||
return referenceDetail;
|
||||
}
|
||||
|
||||
private void dividePlatform(BigDecimal platformMoney, BigDecimal fee, DivideRuleDetailVO rule, Long divideId, boolean feeFlag) {
|
||||
private DivideDetail dividePlatform(BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, DivideRuleFeeType divideRuleFeeType, List<DivideDetail> detailList, List<SeparateItemBO> separateItemBOList) {
|
||||
//获取平台的账户信息
|
||||
Map<String, String> account = getPlatformAccount();
|
||||
if (account == null) {
|
||||
log.error("平台信息不存在,不参与分账");
|
||||
}
|
||||
String mchtCode = getMchtCode(1L);
|
||||
//计算平台的分账金额
|
||||
BigDecimal proxyAmount = platformMoney.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
DivideDetail proxyDetail = DivideDetail.builder()
|
||||
BigDecimal platformAmount = totalAmount.multiply(rule.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
||||
DivideDetail platformDetail = DivideDetail.builder()
|
||||
.divideId(divideId)
|
||||
.money(proxyAmount)
|
||||
.fee(fee)
|
||||
.feePercent(feeFlag ? new BigDecimal(100) : new BigDecimal(0))
|
||||
.accountCode(mchtCode)
|
||||
.money(platformAmount)
|
||||
.moneyPercent(rule.getMoneyPercent())
|
||||
.type(DivideRuleDetailType.REFERENCE.getValue())
|
||||
.type(DivideRuleDetailType.PLATFORM.getValue())
|
||||
.build();
|
||||
detailMapper.insert(proxyDetail);
|
||||
detailMapper.insert(platformDetail);
|
||||
detailList.add(platformDetail);
|
||||
Integer sepaFeeAmount = 0;
|
||||
if (divideRuleFeeType == DivideRuleFeeType.PLATFORM) {
|
||||
sepaFeeAmount = totalAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
} else if (divideRuleFeeType == DivideRuleFeeType.RATE) {
|
||||
sepaFeeAmount = platformAmount.multiply(BigDecimal.valueOf(100)).intValue();
|
||||
}
|
||||
separateItemBOList.add(SeparateItemBO.builder()
|
||||
.separateTrade(String.valueOf(platformDetail.getId()))
|
||||
.receiveMchtCode(mchtCode)
|
||||
.sepaTransAmount(platformAmount.multiply(BigDecimal.valueOf(100)).intValue())
|
||||
.sepaFeeAmount(sepaFeeAmount)
|
||||
.build());
|
||||
return platformDetail;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -327,84 +418,22 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> getPlatformAccount() {
|
||||
return new HashMap<>() {{
|
||||
put("account", "123456");
|
||||
put("name", "平台");
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取达人的账户信息
|
||||
* 获取平台或商家或推广或达人在易生侧的商户号
|
||||
*
|
||||
* @param memberId
|
||||
* @param tenantId
|
||||
* @return
|
||||
*/
|
||||
private Map<String, String> getReferenceAccount(Long memberId) {
|
||||
Member member = memberService.getById(memberId);
|
||||
if (member == null) {
|
||||
return null;
|
||||
}
|
||||
//推广人
|
||||
Long inviteUserId = member.getSpreadUid();
|
||||
if (inviteUserId == null) {
|
||||
return null;
|
||||
}
|
||||
MemberAccount account = accountService.getMemberAccount(inviteUserId);
|
||||
if (account == null) {
|
||||
return null;
|
||||
}
|
||||
return new HashMap<>() {{
|
||||
put("accountId", account.getId() + "");
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代理的账户信息
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
private Map<String, String> getProxyAccount(Long memberId) {
|
||||
if (memberId != null) {
|
||||
return null;
|
||||
}
|
||||
MemberAccount account = accountService.getMemberAccount(memberId);
|
||||
|
||||
if (account == null) {
|
||||
return null;
|
||||
}
|
||||
return new HashMap<>() {{
|
||||
put("accountId", account.getId() + "");
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商家的账户信息
|
||||
*
|
||||
* @param sellerId
|
||||
* @return
|
||||
*/
|
||||
private Map<String, String> getSellerAccount(Long sellerId) {
|
||||
|
||||
SysTenantVo tenant = sysTenantService.queryById(sellerId);
|
||||
if (tenant != null) {
|
||||
return null;
|
||||
}
|
||||
MemberAccount account = accountService.getMemberAccount(tenant.getId());
|
||||
|
||||
// if (account == null)
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
return new HashMap<>() {{
|
||||
put("accountId", account.getId() + "");
|
||||
}};
|
||||
private String getMchtCode(Long tenantId) {
|
||||
SysTenantVo tenant = sysTenantService.queryById(tenantId);
|
||||
Assert.notNull(tenant, () -> new ServiceException("商户信息异常"));
|
||||
// todo 需要从租户信息中获得商家在易生侧的商户号
|
||||
String mchtCode = "";
|
||||
Assert.notBlank(mchtCode, () -> new ServiceException("未维护商户在易生侧的商户号信息"));
|
||||
return mchtCode;
|
||||
}
|
||||
|
||||
private void syncOrderStatus(Order order) {
|
||||
}
|
||||
|
||||
private void syncYisheng(List<DivideDetail> divideDetails) {
|
||||
}
|
||||
}
|
||||
|
@ -18,17 +18,21 @@ import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.tencentcloudapi.dlc.v20210125.models.Asset;
|
||||
import com.wzj.soopin.order.domain.entity.Order;
|
||||
import com.wzj.soopin.order.emum.OrderStatusEnum;
|
||||
import com.wzj.soopin.order.mapper.OrderMapper;
|
||||
import com.wzj.soopin.transaction.config.EasypayConfig;
|
||||
import com.wzj.soopin.transaction.config.WechatMiniProgramConfig;
|
||||
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.*;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundApplyReqBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundReqOrderInfo;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.resp.RefundApplyRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateApplyReqBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateReqOrderInfo;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateApplyRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespOrderInfo;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.req.*;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsApiRespBody;
|
||||
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsapiRespOrderInfo;
|
||||
@ -39,34 +43,30 @@ import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryR
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.domain.po.PayOrder;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPaymentResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO;
|
||||
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
|
||||
import com.wzj.soopin.transaction.enums.TransState;
|
||||
import com.wzj.soopin.transaction.enums.easypay.DelaySettleFlag;
|
||||
import com.wzj.soopin.transaction.enums.easypay.PatnerSettleFlag;
|
||||
import com.wzj.soopin.transaction.enums.easypay.PayType;
|
||||
import com.wzj.soopin.transaction.enums.easypay.SplitSettleFlag;
|
||||
import com.wzj.soopin.transaction.mapper.DivideDetailMapper;
|
||||
import com.wzj.soopin.transaction.mapper.DivideMapper;
|
||||
import com.wzj.soopin.transaction.mapper.PayOrderMapper;
|
||||
import com.wzj.soopin.transaction.service.IDivideService;
|
||||
import com.wzj.soopin.transaction.service.IEasypayService;
|
||||
import com.wzj.soopin.transaction.service.PayOrderService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.enums.FormatsType;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.DateUtils;
|
||||
import org.dromara.common.core.utils.ServletUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.rmi.ServerException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
|
||||
import static com.wzj.soopin.transaction.constans.EasypayConstants.*;
|
||||
|
||||
@ -80,18 +80,17 @@ import static com.wzj.soopin.transaction.constans.EasypayConstants.*;
|
||||
@Slf4j
|
||||
public class EasypayServiceImpl implements IEasypayService {
|
||||
|
||||
private EasypayConfig easypayConfig;
|
||||
private final EasypayConfig easypayConfig;
|
||||
|
||||
private WechatMiniProgramConfig wechatMiniProgramConfig;
|
||||
private final WechatMiniProgramConfig wechatMiniProgramConfig;
|
||||
|
||||
private WxAuthService wxAuthService;
|
||||
private final WxAuthService wxAuthService;
|
||||
|
||||
private final OrderMapper orderMapper;
|
||||
|
||||
private final DivideMapper divideMapper;
|
||||
|
||||
private final PayOrderMapper payOrderMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 生成易生接口请求头参数
|
||||
*
|
||||
@ -231,7 +230,12 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
payOrder.setPayType(paymentBO.getPayType().getValue());
|
||||
payOrder.setStartTransDate(new Date());
|
||||
payOrder.setEasypayTrace(respOrderInfo.getOutTrace());
|
||||
payOrder.setTransState(TransState.Payment.getCode());
|
||||
payOrderMapper.updateById(payOrder);
|
||||
//关联订单的最新支付单
|
||||
orderMapper.updateById(Order.builder().id(payOrder.getOrderId()).payId(payOrder.getId()).build());
|
||||
// 产生待分账记录
|
||||
generateDivideRecord(payOrder);
|
||||
// 生成返回前端的预支付信息
|
||||
return generatePrePayVO(paymentBO.getPayType(), jsApiRespBody);
|
||||
} else {
|
||||
@ -248,6 +252,14 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成待分账记录
|
||||
* @param payOrder
|
||||
*/
|
||||
private void generateDivideRecord(PayOrder payOrder) {
|
||||
//TODO 待完善
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付类型校验请求参数是否完整
|
||||
*
|
||||
@ -255,9 +267,12 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
*/
|
||||
private void checkPaymentParamByPayType(PaymentBO paymentBO) throws ServerException {
|
||||
switch (paymentBO.getPayType()) {
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP -> Assert.notBlank(paymentBO.getBuyerId(), () -> new ServiceException("支付宝支付缺少必要参数:buyerId"));
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> Assert.notBlank(paymentBO.getWxLoginCode(), () -> new ServiceException("微信支付缺少必要参数:微信登录授权code"));
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI -> Assert.isTrue(StrUtil.isAllNotBlank(paymentBO.getTransType(), paymentBO.getUserAuthCode(),
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP ->
|
||||
Assert.notBlank(paymentBO.getBuyerId(), () -> new ServiceException("支付宝支付缺少必要参数:buyerId"));
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP ->
|
||||
Assert.notBlank(paymentBO.getWxLoginCode(), () -> new ServiceException("微信支付缺少必要参数:微信登录授权code"));
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI ->
|
||||
Assert.isTrue(StrUtil.isAllNotBlank(paymentBO.getTransType(), paymentBO.getUserAuthCode(),
|
||||
paymentBO.getUserId(), paymentBO.getAreaInfo(), paymentBO.getPaymentValidTime(),
|
||||
paymentBO.getQrCode(), paymentBO.getQrCodeType()), () -> new ServiceException("银联支付缺少必要参数"));
|
||||
default -> throw new ServerException("不支持的支付方式");
|
||||
@ -272,13 +287,14 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
*/
|
||||
private void setPayInfo(JsApiReqBody apiReqBody, PaymentBO paymentBO) throws ServerException {
|
||||
switch (paymentBO.getPayType()) {
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP -> apiReqBody.setAliBizParam(AliBizParam.builder().buyerId(paymentBO.getBuyerId()).build());
|
||||
case ALI_PAY_JSAPI, ALI_PAY_MINI_APP ->
|
||||
apiReqBody.setAliBizParam(AliBizParam.builder().buyerId(paymentBO.getBuyerId()).build());
|
||||
case WE_CHAT_JSAPI, WE_CHAT_MINI_APP -> {
|
||||
WxAuthResponse wxAuthResponse = wxAuthService.getOpenIdByMiniProgramCode(paymentBO.getWxLoginCode());
|
||||
Assert.isTrue(StrUtil.equals(wxAuthResponse.getErrcode(), "0"), () -> new ServiceException("微信小程序登录异常"));
|
||||
apiReqBody.setWxBizParam(WxBizParam.builder().subAppid(wechatMiniProgramConfig.getAppId()).subOpenId(wxAuthResponse.getOpenid()).build());
|
||||
}
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI -> apiReqBody.setQrBizParam(BeanUtil.copyProperties(paymentBO, QrBizParam.class));
|
||||
case UNION_PAY_JSAPI, UNION_PAY_Js_MINI ->
|
||||
apiReqBody.setQrBizParam(BeanUtil.copyProperties(paymentBO, QrBizParam.class));
|
||||
default -> throw new ServerException("不支持的支付方式");
|
||||
}
|
||||
PayInfo payInfo = PayInfo.builder()
|
||||
@ -297,27 +313,27 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
Order order = orderMapper.selectById(paymentBO.getOrderId());
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
Assert.isTrue(Objects.equals(order.getStatus(), OrderStatusEnum.UNPAID.getValue()), () -> new ServiceException("订单已支付"));
|
||||
PayOrder payOrder;
|
||||
// 订单首次支付,创建支付订单记录
|
||||
if(order.getPayId() == null){
|
||||
payOrder = PayOrder.builder()
|
||||
.orderId(order.getId())
|
||||
.transAmount(apiReqBody.getReqOrderInfo().getTransAmount())
|
||||
.startTransDate(new Date())
|
||||
.transOver(false)
|
||||
.build();
|
||||
payOrderMapper.insert(payOrder);
|
||||
orderMapper.updateById(Order.builder().id(order.getId()).payId(payOrder.getId()).build());
|
||||
}else {
|
||||
payOrder = payOrderMapper.selectById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单异常"));
|
||||
}
|
||||
// 订单中的金额单位为元,需转换为分
|
||||
long transAmount = order.getTotalAmount().multiply(BigDecimal.valueOf(100)).longValue();
|
||||
PayOrder payOrder;
|
||||
// 订单已拉起过支付,支付中或已支付状态不可再次支付
|
||||
if (order.getPayId() != null) {
|
||||
payOrder = payOrderMapper.selectById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单异常"));
|
||||
Assert.isTrue(Objects.equals(payOrder.getTransState(), TransState.PENDING.getCode()), () -> new ServiceException("订单支付中或已支付"));
|
||||
}
|
||||
payOrder = PayOrder.builder()
|
||||
.orderId(order.getId())
|
||||
.transAmount(transAmount)
|
||||
.startTransDate(new Date())
|
||||
.transState(TransState.PENDING.getCode())
|
||||
.payType(paymentBO.getPayType().getValue())
|
||||
.build();
|
||||
payOrderMapper.insert(payOrder);
|
||||
JsapiReqOrderInfo jsapiReqOrderInfo = JsapiReqOrderInfo.builder()
|
||||
.orgTrace(String.valueOf(payOrder.getId()))
|
||||
.transAmount(transAmount)
|
||||
.backUrl(easypayConfig.getBackUrl())
|
||||
.backUrl(easypayConfig.getTradeBackUrl())
|
||||
.timeout(String.valueOf(TRACE_TIMEOUT))
|
||||
.orderSub("无终街支付订单")
|
||||
.orderDes("无终街支付订单:" + order.getMerchantNote())
|
||||
@ -357,23 +373,22 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
|
||||
/**
|
||||
* 查询支付结果
|
||||
*
|
||||
* @param orderId
|
||||
* @return
|
||||
* @throws ServerException
|
||||
*/
|
||||
@Override
|
||||
public EasypayPaymentResultVO paymentQuery(Long orderId) throws ServerException {
|
||||
public EasypayTransResultVO paymentQuery(Long orderId) throws ServerException {
|
||||
Order order = orderMapper.selectById(orderId);
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
PayOrder payOrder = payOrderMapper.selectOne(Wrappers.lambdaQuery(PayOrder.class)
|
||||
.eq(PayOrder::getOrderId, orderId)
|
||||
.last("limit 1"));
|
||||
PayOrder payOrder = payOrderMapper.selectById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单不存在"));
|
||||
EasypayPaymentResultVO paymentResultVO = EasypayPaymentResultVO.builder()
|
||||
EasypayTransResultVO paymentResultVO = EasypayTransResultVO.builder()
|
||||
.orderId(order.getId())
|
||||
.payId(order.getPayId())
|
||||
.totalAmount(order.getTotalAmount())
|
||||
.paymentComplete(false)
|
||||
.transState(TransState.PENDING.getCode())
|
||||
.build();
|
||||
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
|
||||
TradeQueryReqBody queryReqBody = TradeQueryReqBody.builder()
|
||||
@ -415,10 +430,10 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
.easypayTrace(respOrderInfo.getOutTrace())
|
||||
.pcTrace(respOrderInfo.getPcTrace())
|
||||
.unTrace(respOrderInfo.getUnTrace())
|
||||
.transOver(true)
|
||||
.transState(TransState.PAID.getCode())
|
||||
.build();
|
||||
payOrderMapper.updateById(payOrderUpdate);
|
||||
paymentResultVO.setPaymentComplete(true);
|
||||
paymentResultVO.setTransState(TransState.PAID.getCode());
|
||||
}
|
||||
} else {
|
||||
log.error("查询支付结果失败:{}", respStateInfo.getRespDesc());
|
||||
@ -434,6 +449,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handleTradeCallback(EasyPayRequest easyPayRequest) {
|
||||
log.debug("易生支付结果通知回调:{}", JSONObject.toJSONString(easyPayRequest));
|
||||
verify(easyPayRequest.getReqHeader(), easyPayRequest.getReqBody(), easyPayRequest.getReqSign());
|
||||
TradeQueryRespBody tradeQueryRespBody = BeanUtil.toBean(easyPayRequest.getReqBody(), TradeQueryRespBody.class);
|
||||
RespStateInfo respStateInfo = tradeQueryRespBody.getRespStateInfo();
|
||||
@ -452,7 +468,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
.easypayTrace(respOrderInfo.getOutTrace())
|
||||
.pcTrace(respOrderInfo.getPcTrace())
|
||||
.unTrace(respOrderInfo.getUnTrace())
|
||||
.transOver(true)
|
||||
.transState(TransState.PAID.getCode())
|
||||
.build());
|
||||
// 更新订单信息
|
||||
orderMapper.updateById(Order.builder()
|
||||
@ -474,11 +490,18 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void refund(Long orderId) {
|
||||
Order order = orderMapper.selectById(orderId);
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
PayOrder payOrder = payOrderMapper.selectOne(Wrappers.lambdaQuery(PayOrder.class).eq(PayOrder::getOrderId, orderId).last("limit 1"));
|
||||
PayOrder payOrder = payOrderMapper.selectById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单不存在"));
|
||||
Assert.isTrue(payOrder.getTransState() == TransState.PAID.getCode(), () -> new ServiceException("订单未支付,不可发起退款"));
|
||||
// 更新支付订单状态为退款中
|
||||
payOrderMapper.updateById(PayOrder.builder()
|
||||
.id(payOrder.getId())
|
||||
.transState(TransState.REFUND_PENDING.getCode())
|
||||
.build());
|
||||
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
|
||||
RefundApplyReqBody refundApplyReqBody = RefundApplyReqBody.builder()
|
||||
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
|
||||
@ -486,7 +509,7 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
.reqOrderInfo(RefundReqOrderInfo.builder()
|
||||
.orgTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString())
|
||||
.oriOrgTrace(String.valueOf(order.getPayId()))
|
||||
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD,payOrder.getStartTransDate()))
|
||||
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, payOrder.getEndTransDate()))
|
||||
.refundAmount(payOrder.getTransAmount())
|
||||
.build())
|
||||
.build();
|
||||
@ -504,7 +527,157 @@ public class EasypayServiceImpl implements IEasypayService {
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("调用易实时退款接口响应:{}", body);
|
||||
RefundApplyRespBody refundApplyRespBody = JSONObject.parseObject(body, RefundApplyRespBody.class);
|
||||
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
|
||||
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
|
||||
verify(easyPayResponse.getRspHeader(), easyPayResponse.getRspBody(), easyPayResponse.getRspSign());
|
||||
RefundApplyRespBody refundApplyRespBody = JSON.parseObject(JSONObject.toJSONString(easyPayResponse.getRspBody()), RefundApplyRespBody.class);
|
||||
RespStateInfo respStateInfo = refundApplyRespBody.getRespStateInfo();
|
||||
if (StrUtil.equals(RSP_BODY_RESP_OK, respStateInfo.getRespCode())) {
|
||||
if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK)) {
|
||||
// 更新支付单退款状态
|
||||
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.REFUNDED.getCode()).build());
|
||||
}
|
||||
} else {
|
||||
log.error("易生退款失败:{}", respStateInfo.getRespDesc());
|
||||
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.PAID.getCode()).build());
|
||||
throw new ServiceException("易生退款失败:" + respStateInfo.getRespDesc());
|
||||
}
|
||||
} else {
|
||||
log.error("易生退款通讯失败:{}", easyPayResponse.getRspHeader().getRspInfo());
|
||||
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.PAID.getCode()).build());
|
||||
throw new ServiceException("易生退款通讯失败:" + easyPayResponse.getRspHeader().getRspInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EasypayTransResultVO refundQuery(Long orderId) {
|
||||
Order order = orderMapper.selectById(orderId);
|
||||
Assert.notNull(order, () -> new ServiceException("订单不存在"));
|
||||
PayOrder payOrder = payOrderMapper.selectById(order.getPayId());
|
||||
Assert.notNull(payOrder, () -> new ServiceException("订单不存在"));
|
||||
EasypayTransResultVO easypayTransResultVO = EasypayTransResultVO.builder()
|
||||
.orderId(order.getId())
|
||||
.payId(payOrder.getId())
|
||||
.totalAmount(order.getTotalAmount())
|
||||
.transState(payOrder.getTransState())
|
||||
.build();
|
||||
if (payOrder.getTransState() == TransState.REFUNDED.getCode()) {
|
||||
return easypayTransResultVO;
|
||||
}
|
||||
Assert.isTrue(payOrder.getTransState() == TransState.PAID.getCode() || payOrder.getTransState() == TransState.REFUND_PENDING.getCode(), () -> new ServiceException("订单未支付"));
|
||||
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
|
||||
RefundApplyReqBody refundApplyReqBody = RefundApplyReqBody.builder()
|
||||
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
|
||||
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
|
||||
.reqOrderInfo(RefundReqOrderInfo.builder()
|
||||
.orgTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString())
|
||||
.oriOrgTrace(String.valueOf(order.getPayId()))
|
||||
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, payOrder.getEndTransDate()))
|
||||
.refundAmount(payOrder.getTransAmount())
|
||||
.build())
|
||||
.build();
|
||||
String reqSign = getSignStr(reqHeader, refundApplyReqBody);
|
||||
EasyPayRequest easyRequest = EasyPayRequest.builder()
|
||||
.reqHeader(reqHeader)
|
||||
.reqBody(refundApplyReqBody)
|
||||
.reqSign(reqSign)
|
||||
.build();
|
||||
log.debug("调用易生实时退款接口请求:{}", JSONObject.toJSONString(easyRequest));
|
||||
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/refund/query").toString();
|
||||
String body = HttpRequest.post(url)
|
||||
.timeout(3000)
|
||||
.body(JSON.toJSONString(easyRequest))
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("调用易实时退款接口响应:{}", body);
|
||||
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
|
||||
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
|
||||
verify(easyPayResponse.getRspHeader(), easyPayResponse.getRspBody(), easyPayResponse.getRspSign());
|
||||
RefundApplyRespBody refundApplyRespBody = JSON.parseObject(JSONObject.toJSONString(easyPayResponse.getRspBody()), RefundApplyRespBody.class);
|
||||
RespStateInfo respStateInfo = refundApplyRespBody.getRespStateInfo();
|
||||
if (StrUtil.equals(RSP_BODY_RESP_OK, respStateInfo.getRespCode())) {
|
||||
if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK)) {
|
||||
easypayTransResultVO.setTransState(TransState.REFUNDED.getCode());
|
||||
// 更新支付单退款状态
|
||||
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.REFUNDED.getCode()).build());
|
||||
}
|
||||
} else {
|
||||
log.error("查询支付结果失败:{}", respStateInfo.getRespDesc());
|
||||
throw new ServiceException("查询支付结果失败:" + respStateInfo.getRespDesc());
|
||||
}
|
||||
} else {
|
||||
log.error("查询支付结果通讯失败:{}", easyPayResponse.getRspHeader().getRspInfo());
|
||||
throw new ServiceException("查询支付结果通讯失败:" + easyPayResponse.getRspHeader().getRspInfo());
|
||||
}
|
||||
return easypayTransResultVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeparateApplyBO separateApply(SeparateApplyBO separateApplyBO) {
|
||||
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
|
||||
List<SeparateInfo.SeparateOrderDetailList> separateOrderDetailListList = separateApplyBO.getSeparateItemBOList().stream().map(item -> BeanUtil.copyProperties(item, SeparateInfo.SeparateOrderDetailList.class)).toList();
|
||||
SeparateApplyReqBody separateApplyReqBody = SeparateApplyReqBody.builder()
|
||||
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
|
||||
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
|
||||
.reqOrderInfo(SeparateReqOrderInfo.builder()
|
||||
.backUrl(easypayConfig.getSeparateBackUrl())
|
||||
.oriOrgTrace(String.valueOf(separateApplyBO.getPayId()))
|
||||
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, separateApplyBO.getTransDate()))
|
||||
.separateBatchTrace(separateApplyBO.getSeparateBatchTrace())
|
||||
.transSumAmt(separateApplyBO.getTransSumAmt())
|
||||
.transSumCount(separateApplyBO.getSeparateItemBOList().size())
|
||||
.separateOrderDetailList(separateOrderDetailListList)
|
||||
.build())
|
||||
.build();
|
||||
String reqSign = getSignStr(reqHeader, separateApplyReqBody);
|
||||
EasyPayRequest easyRequest = EasyPayRequest.builder()
|
||||
.reqHeader(reqHeader)
|
||||
.reqBody(separateApplyReqBody)
|
||||
.reqSign(reqSign)
|
||||
.build();
|
||||
log.debug("调用易生请求分账接口请求:{}", JSONObject.toJSONString(easyRequest));
|
||||
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/separate/orderApply").toString();
|
||||
String body = HttpRequest.post(url)
|
||||
.timeout(3000)
|
||||
.body(JSON.toJSONString(easyRequest))
|
||||
.execute()
|
||||
.body();
|
||||
log.debug("调用易生请求分账接口响应:{}", body);
|
||||
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
|
||||
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
|
||||
verify(easyPayResponse.getRspHeader(), easyPayResponse.getRspBody(), easyPayResponse.getRspSign());
|
||||
SeparateApplyRespBody separateApplyRespBody = JSON.parseObject(JSONObject.toJSONString(easyPayResponse.getRspBody()), SeparateApplyRespBody.class);
|
||||
RespStateInfo respStateInfo = separateApplyRespBody.getRespStateInfo();
|
||||
if (StrUtil.equals(RSP_BODY_RESP_OK, respStateInfo.getRespCode())) {
|
||||
if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK)) {
|
||||
// 更新分账状态
|
||||
SeparateRespOrderInfo respOrderInfo = separateApplyRespBody.getRespOrderInfo();
|
||||
handleSeparateInfo(separateApplyBO, respOrderInfo);
|
||||
}
|
||||
} else {
|
||||
log.error("请求分账失败:{}", respStateInfo.getRespDesc());
|
||||
throw new ServiceException("请求分账失败:" + respStateInfo.getRespDesc());
|
||||
}
|
||||
} else {
|
||||
log.error("易生请求分账通讯失败:{}", easyPayResponse.getRspHeader().getRspInfo());
|
||||
throw new ServiceException("易生请求分账通讯失败:" + easyPayResponse.getRspHeader().getRspInfo());
|
||||
}
|
||||
return separateApplyBO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSeparateCallback(EasyPayRequest easyPayRequest) {
|
||||
// TODO 处理回调分账结果信息,更新分账详情表
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理分账结果信息,更新分账详情表
|
||||
* @param respOrderInfo
|
||||
*/
|
||||
private SeparateApplyBO handleSeparateInfo(SeparateApplyBO separateApplyBO, SeparateRespOrderInfo respOrderInfo) {
|
||||
//TODO 处理分账结果信息,更新分账详情表
|
||||
return separateApplyBO;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.wzj.soopin.transaction.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.wzj.soopin.transaction.domain.po.PayOrder;
|
||||
import com.wzj.soopin.transaction.mapper.PayOrderMapper;
|
||||
|
@ -1,10 +1,15 @@
|
||||
package com.wzj.soopin.transaction.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
|
||||
import com.wzj.soopin.transaction.config.WechatMiniProgramConfig;
|
||||
import com.wzj.soopin.transaction.wechat.WechatPayConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@ -55,10 +60,10 @@ public class WxAuthService {
|
||||
.append(code)
|
||||
.append("&grant_type=authorization_code")
|
||||
.toString();
|
||||
WxAuthResponse response = restTemplate.getForObject(url, WxAuthResponse.class);
|
||||
if (response == null || response.getOpenid() == null) {
|
||||
throw new RuntimeException("Failed to get openid from WeChat");
|
||||
}
|
||||
String body = HttpRequest.get(url).timeout(3000).execute().body();
|
||||
Assert.notBlank(body, () -> new ServiceException("微信小程序登录异常"));
|
||||
WxAuthResponse response = JSONObject.parseObject(body, WxAuthResponse.class);
|
||||
Assert.notBlank(response.getOpenid(), () -> new ServiceException("微信小程序登录异常:" + response.getErrmsg()));
|
||||
return response;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user