feat 分账接收方功能

This commit is contained in:
bootx
2024-10-07 21:49:30 +08:00
parent 21957cd100
commit 5c1587eb3f
63 changed files with 2120 additions and 189 deletions

View File

@@ -12,9 +12,9 @@ import lombok.Getter;
@AllArgsConstructor
public enum AllocOrderStatusEnum {
ALLOCATION_PROCESSING("allocation_processing", "分账处理中"),
ALLOCATION_END("allocation_end", "分账完成"),
ALLOCATION_FAILED("allocation_failed", "分账失败"),
ALLOC_PROCESSING("alloc_processing", "分账处理中"),
ALLOC_END("alloc_end", "分账完成"),
ALLOC_FAILED("alloc_failed", "分账失败"),
FINISH("finish", "完结"),
FINISH_FAILED("finish_failed", "完结失败"),
;

View File

@@ -4,7 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
/**
* 分账接收方类型
@@ -14,17 +13,14 @@ import java.util.List;
@Getter
@AllArgsConstructor
public enum AllocReceiverTypeEnum {
/** 个人 */
WX_PERSONAL("wx_personal", "个人"),
/** 商户 */
WX_MERCHANT("wx_merchant", "商户"),
/** userId 以2088开头的纯16位数字 */
ALI_USER_ID("ali_user_id", "用户ID"),
/** 商户号 */
MERCHANT_NO("merchant_no", "商户号"),
/** userId */
USER_ID("user_id", "用户ID"),
/** openId */
ALI_OPEN_ID("ali_open_id", "openId"),
OPEN_ID("open_id", "openId"),
/** 账号 */
ALI_LOGIN_NAME("ali_login_name", "账号");
LOGIN_NAME("login_name", "账号");
/** 编码 */
private final String code;
@@ -41,9 +37,4 @@ public enum AllocReceiverTypeEnum {
.orElseThrow(() -> new IllegalArgumentException("未找到对应的分账接收方类型"));
}
/** 微信支持类型 */
public static final List<AllocReceiverTypeEnum> WECHAT_LIST = List.of(WX_PERSONAL, WX_MERCHANT);
/** 支付宝支持类型 */
public static final List<AllocReceiverTypeEnum> ALI_LIST = List.of(ALI_OPEN_ID, ALI_USER_ID, ALI_LOGIN_NAME);
}

View File

@@ -14,6 +14,8 @@ import lombok.Getter;
public enum PayAllocStatusEnum {
WAITING("waiting", "待分账"),
ALLOCATION("allocation", "已分账"),
/** 部分通道不支持分账 */
IGNORE("ignore", "忽略分账"),
;
private final String code;

View File

@@ -0,0 +1,123 @@
package org.dromara.daxpay.service.controller.allocation;
import cn.bootx.platform.core.rest.Res;
import cn.bootx.platform.core.rest.param.PageParam;
import cn.bootx.platform.core.rest.result.PageResult;
import cn.bootx.platform.core.rest.result.Result;
import cn.bootx.platform.core.util.ValidationUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupBindParam;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupParam;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupQuery;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupUnbindParam;
import org.dromara.daxpay.service.result.allocation.AllocGroupReceiverResult;
import org.dromara.daxpay.service.result.allocation.AllocGroupResult;
import org.dromara.daxpay.service.service.allocation.AllocGroupService;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 分账组
* @author xxm
* @since 2024/4/2
*/
@Tag(name = "分账组")
@RestController
@RequestMapping("/allocation/group")
@RequiredArgsConstructor
public class AllocGroupController {
private final AllocGroupService allocGroupService;
@Operation(summary = "分页")
@GetMapping("/page")
public Result<PageResult<AllocGroupResult>> page(PageParam pageParam, AllocGroupQuery query){
return Res.ok(allocGroupService.page(pageParam,query));
}
@Operation(summary = "查询详情")
@GetMapping("/findById")
public Result<AllocGroupResult> findById(Long id){
return Res.ok(allocGroupService.findById(id));
}
@Operation(summary = "编码是否存在")
@GetMapping("/existsByGroupNo")
public Result<Boolean> existsByGroupNo(String groupNo, String appId){
return Res.ok(allocGroupService.existsByGroupNo(groupNo, appId));
}
@Operation(summary = "查询分账接收方信息")
@GetMapping("/findReceiversByGroups")
public Result<List<AllocGroupReceiverResult>> findReceiversByGroups(Long groupId){
return Res.ok(allocGroupService.findReceiversByGroups(groupId));
}
@Operation(summary = "创建")
@PostMapping("/create")
public Result<Void> create(@RequestBody AllocGroupParam param){
allocGroupService.create(param);
return Res.ok();
}
@Operation(summary = "修改")
@PostMapping("/update")
public Result<Void> update(@RequestBody AllocGroupParam param){
allocGroupService.update(param);
return Res.ok();
}
@Operation(summary = "删除")
@PostMapping("/delete")
public Result<Void> delete(Long id){
allocGroupService.delete(id);
return Res.ok();
}
@Operation(summary = "批量绑定接收者")
@PostMapping("/bindReceivers")
public Result<Void> bindReceivers(@RequestBody AllocGroupBindParam param){
ValidationUtil.validateParam(param);
allocGroupService.bindReceivers(param);
return Res.ok();
}
@Operation(summary = "批量取消绑定接收者")
@PostMapping("/unbindReceivers")
public Result<Void> unbindReceivers(@RequestBody AllocGroupUnbindParam param){
allocGroupService.unbindReceivers(param);
return Res.ok();
}
@Operation(summary = "取消绑定接收者")
@PostMapping("/unbindReceiver")
public Result<Void> unbindReceiver(Long receiverId){
allocGroupService.unbindReceiver(receiverId);
return Res.ok();
}
@Operation(summary = "修改分账比例")
@PostMapping("/updateRate")
public Result<Void> updateRate(Long receiverId, BigDecimal rate){
allocGroupService.updateRate(receiverId,rate);
return Res.ok();
}
@Operation(summary = "设置默认分账组")
@PostMapping("/setDefault")
public Result<Void> setDefault(Long id){
allocGroupService.setUpDefault(id);
return Res.ok();
}
@Operation(summary = "清除默认分账组")
@PostMapping("/clearDefault")
public Result<Void> clearDefault(Long id){
allocGroupService.clearDefault(id);
return Res.ok();
}
}

View File

@@ -0,0 +1,80 @@
package org.dromara.daxpay.service.controller.allocation;
import cn.bootx.platform.core.rest.Res;
import cn.bootx.platform.core.rest.dto.LabelValue;
import cn.bootx.platform.core.rest.param.PageParam;
import cn.bootx.platform.core.rest.result.PageResult;
import cn.bootx.platform.core.rest.result.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverAddParam;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverQuery;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverRemoveParam;
import org.dromara.daxpay.service.result.allocation.AllocReceiverResult;
import org.dromara.daxpay.service.service.allocation.AllocReceiverService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 分账接收方控制器
* @author xxm
* @since 2024/3/28
*/
@Validated
@Tag(name = "分账接收方控制器")
@RestController
@RequestMapping("/allocation/receiver")
@RequiredArgsConstructor
public class AllocReceiverController {
private final AllocReceiverService receiverService;
@Operation(summary = "分页")
@GetMapping("/page")
public Result<PageResult<AllocReceiverResult>> page(PageParam pageParam, AllocReceiverQuery query){
return Res.ok(receiverService.page(pageParam, query));
}
@Operation(summary = "查询详情")
@GetMapping("/findById")
public Result<AllocReceiverResult> findById(Long id){
return Res.ok(receiverService.findById(id));
}
@Operation(summary = "编码是否存在")
@GetMapping("/existsByReceiverNo")
public Result<Boolean> existsByReceiverNo(@NotBlank(message = "接收者编号必填") String receiverNo,@NotBlank(message = "商户应用ID必填") String appId){
return Res.ok(receiverService.existsByReceiverNo(receiverNo, appId));
}
@Operation(summary = "添加")
@PostMapping("/add")
public Result<Void> add(@RequestBody @Validated AllocReceiverAddParam param){
receiverService.addAndSync(param);
return Res.ok();
}
@Operation(summary = "删除")
@PostMapping("/delete")
public Result<Void> delete(@RequestBody @Validated AllocReceiverRemoveParam param){
receiverService.removeAndSync(param);
return Res.ok();
}
@Operation(summary = "可分账的通道列表")
@GetMapping("/findChannels")
public Result<List<LabelValue>> findChannels(){
return Res.ok(receiverService.findChannels());
}
@Operation(summary = "根据通道获取分账接收方类型")
@GetMapping("/findReceiverTypeByChannel")
public Result<List<LabelValue>> findReceiverTypeByChannel(String channel){
return Res.ok(receiverService.findReceiverTypeByChannel(channel));
}
}

View File

@@ -0,0 +1,21 @@
package org.dromara.daxpay.service.convert.allocation;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroup;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupParam;
import org.dromara.daxpay.service.result.allocation.AllocGroupResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author xxm
* @since 2024/4/1
*/
@Mapper
public interface AllocGroupConvert {
AllocGroupConvert CONVERT = Mappers.getMapper(AllocGroupConvert.class);
AllocGroupResult convert(AllocGroup in);
AllocGroup convert(AllocGroupParam in);
}

View File

@@ -0,0 +1,21 @@
package org.dromara.daxpay.service.convert.allocation;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroupReceiver;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupReceiverParam;
import org.dromara.daxpay.service.result.allocation.AllocGroupReceiverResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author xxm
* @since 2024/4/1
*/
@Mapper
public interface AllocGroupReceiverConvert {
AllocGroupReceiverConvert CONVERT = Mappers.getMapper(AllocGroupReceiverConvert.class);
AllocGroupReceiverResult convert(AllocGroupReceiver in);
AllocGroupReceiver convert(AllocGroupReceiverParam in);
}

View File

@@ -0,0 +1,21 @@
package org.dromara.daxpay.service.convert.allocation;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverAddParam;
import org.dromara.daxpay.service.result.allocation.AllocReceiverResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
*
* @author xxm
* @since 2024/3/28
*/
@Mapper
public interface AllocReceiverConvert {
AllocReceiverConvert CONVERT = Mappers.getMapper(AllocReceiverConvert.class);
AllocReceiver convert(AllocReceiverAddParam in);
AllocReceiverResult toResult(AllocReceiver in);
}

View File

@@ -0,0 +1,77 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.query.generator.QueryGenerator;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.core.rest.param.PageParam;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroup;
import org.dromara.daxpay.service.param.allocation.group.AllocGroupQuery;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class AllocGroupManager extends BaseManager<AllocGroupMapper, AllocGroup> {
/**
* 分页
*/
public Page<AllocGroup> page(PageParam pageParam, AllocGroupQuery query) {
Page<AllocGroup> mpPage = MpUtil.getMpPage(pageParam, AllocGroup.class);
QueryWrapper<AllocGroup> generator = QueryGenerator.generator(query);
return page(mpPage,generator);
}
/**
* 根据分账组编号查询
*/
public Optional<AllocGroup> findByGroupNo(String groupNo, String appId) {
return this.lambdaQuery()
.eq(AllocGroup::getGroupNo,groupNo)
.eq(AllocGroup::getAppId,appId)
.oneOpt();
}
/**
* 清除默认分账组
*/
public void clearDefault(String channel, String appId) {
lambdaUpdate()
.set(AllocGroup::isDefaultGroup,false)
.eq(AllocGroup::getChannel,channel)
.eq(AllocGroup::getAppId,appId)
.update();
}
/**
* 获取默认分账组
*/
public Optional<AllocGroup> findDefaultGroup(String channel, String appId) {
return this.lambdaQuery()
.eq(AllocGroup::getChannel,channel)
.eq(AllocGroup::isDefaultGroup,true)
.eq(AllocGroup::getAppId,appId)
.oneOpt();
}
/**
* 分账组编号是否存在
*/
public boolean existedByGroupNo(String groupNo, String appId) {
return this.lambdaQuery()
.eq(AllocGroup::getGroupNo,groupNo)
.eq(AllocGroup::getAppId,appId)
.exists();
}
}

View File

@@ -0,0 +1,14 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroup;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Mapper
public interface AllocGroupMapper extends MPJBaseMapper<AllocGroup> {
}

View File

@@ -0,0 +1,47 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroupReceiver;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class AllocGroupReceiverManager extends BaseManager<AllocGroupReceiverMapper, AllocGroupReceiver> {
/**
* 判断接收者是否已经被使用
*/
public boolean isUsed(Long receiverId){
return existedByField(AllocGroupReceiver::getReceiverId, receiverId);
}
/**
* 根据分组ID进行查询
*/
public List<AllocGroupReceiver> findByGroupId(Long groupId){
return findAllByField(AllocGroupReceiver::getGroupId, groupId);
}
/**
* 根据分组ID进行批量删除
*/
public void deleteByGroupId(Long groupId){
deleteByField(AllocGroupReceiver::getGroupId, groupId);
}
/**
* 判断是否存在分账接收者
*/
}

View File

@@ -0,0 +1,14 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroupReceiver;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Mapper
public interface AllocGroupReceiverMapper extends MPJBaseMapper<AllocGroupReceiver> {
}

View File

@@ -0,0 +1,78 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.common.mybatisplus.query.generator.QueryGenerator;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.core.rest.param.PageParam;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverQuery;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 分账接收方
* @author xxm
* @since 2024/10/6
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class AllocReceiverManager extends BaseManager<AllocReceiverMapper, AllocReceiver> {
/**
* 分页
*/
public Page<AllocReceiver> page(PageParam pageParam, AllocReceiverQuery param){
Page<AllocReceiver> mpPage = MpUtil.getMpPage(pageParam, AllocReceiver.class);
QueryWrapper<AllocReceiver> generator = QueryGenerator.generator(param);
return this.page(mpPage, generator);
}
/**
* 根据接收方编号查询
*/
public Optional<AllocReceiver> findByReceiverNo(String receiverNo, String appId) {
return lambdaQuery()
.eq(AllocReceiver::getReceiverNo, receiverNo)
.eq(MchAppBaseEntity::getAppId, appId)
.oneOpt();
}
/**
* 根据分账方编号查询列表
*/
public List<AllocReceiver> findAllByReceiverNos(List<String> receiverNos, String appId) {
return lambdaQuery()
.eq(AllocReceiver::getReceiverNo, receiverNos)
.eq(MchAppBaseEntity::getAppId, appId)
.list();
}
/**
* 根据所属通道查询
*/
public List<AllocReceiver> findAllByChannel(String channel, String appId) {
return lambdaQuery()
.eq(AllocReceiver::getChannel, channel)
.eq(MchAppBaseEntity::getAppId, appId)
.list();
}
/**
* 判断是否存在
*/
public boolean existedByReceiverNo(String receiverNo, String appId) {
return lambdaQuery()
.eq(AllocReceiver::getReceiverNo, receiverNo)
.eq(MchAppBaseEntity::getAppId, appId)
.exists();
}
}

View File

@@ -0,0 +1,14 @@
package org.dromara.daxpay.service.dao.allocation.receiver;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Mapper
public interface AllocReceiverMapper extends MPJBaseMapper<AllocReceiver> {
}

View File

@@ -0,0 +1,18 @@
package org.dromara.daxpay.service.dao.config;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.service.entity.config.AllocConfig;
import org.springframework.stereotype.Repository;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class AllocConfigManger extends BaseManager<AllocConfigMapper, AllocConfig> {
}

View File

@@ -0,0 +1,14 @@
package org.dromara.daxpay.service.dao.config;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.daxpay.service.entity.config.AllocConfig;
/**
*
* @author xxm
* @since 2024/10/6
*/
@Mapper
public interface AllocConfigMapper extends MPJBaseMapper<AllocConfig> {
}

View File

@@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
@@ -21,6 +22,15 @@ import java.util.Optional;
@RequiredArgsConstructor
public class ChannelCashierConfigManage extends BaseManager<ChannelCashierConfigMapper, ChannelCashierConfig> {
/**
* 根据AppId查询列表
*/
public List<ChannelCashierConfig> findAllByAppId(String appId) {
return this.lambdaQuery()
.eq(ChannelCashierConfig::getAppId, appId)
.list();
}
/**
* 判断类型是否存在
*/

View File

@@ -13,7 +13,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -54,7 +53,7 @@ public class AllocOrderManager extends BaseManager<AllocOrderMapper, AllocOrder>
* 查询待同步的分账单
*/
public List<AllocOrder> findSyncOrder(){
List<String> statusList = List.of(AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode(), AllocOrderStatusEnum.ALLOCATION_END.getCode());
List<String> statusList = List.of(AllocOrderStatusEnum.ALLOC_PROCESSING.getCode(), AllocOrderStatusEnum.ALLOC_END.getCode());
return lambdaQuery()
.in(AllocOrder::getStatus, statusList)
.list();

View File

@@ -1,11 +1,15 @@
package org.dromara.daxpay.service.entity.allocation.receiver;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import cn.bootx.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import org.dromara.daxpay.service.convert.allocation.AllocGroupConvert;
import org.dromara.daxpay.service.result.allocation.AllocGroupResult;
import java.math.BigDecimal;
@@ -17,7 +21,8 @@ import java.math.BigDecimal;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class AllocGroup extends MchAppBaseEntity {
@TableName("pay_alloc_group")
public class AllocGroup extends MchAppBaseEntity implements ToResult<AllocGroupResult> {
/** 分账组编码 */
private String groupNo;
@@ -37,4 +42,9 @@ public class AllocGroup extends MchAppBaseEntity {
/** 备注 */
private String remark;
@Override
public AllocGroupResult toResult() {
return AllocGroupConvert.CONVERT.convert(this);
}
}

View File

@@ -1,9 +1,13 @@
package org.dromara.daxpay.service.entity.allocation.receiver;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import cn.bootx.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import org.dromara.daxpay.service.convert.allocation.AllocGroupReceiverConvert;
import org.dromara.daxpay.service.result.allocation.AllocGroupReceiverResult;
import java.math.BigDecimal;
@@ -15,7 +19,8 @@ import java.math.BigDecimal;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class AllocGroupReceiver extends MchAppBaseEntity {
@TableName("pay_alloc_group_receiver")
public class AllocGroupReceiver extends MchAppBaseEntity implements ToResult<AllocGroupReceiverResult> {
/** 分账组ID */
private Long groupId;
@@ -25,4 +30,9 @@ public class AllocGroupReceiver extends MchAppBaseEntity {
/** 分账比例(百分之多少) */
private BigDecimal rate;
@Override
public AllocGroupReceiverResult toResult() {
return AllocGroupReceiverConvert.CONVERT.convert(this);
}
}

View File

@@ -1,5 +1,7 @@
package org.dromara.daxpay.service.entity.allocation.receiver;
import cn.bootx.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.TableName;
import org.dromara.daxpay.core.enums.AllocReceiverTypeEnum;
import org.dromara.daxpay.core.enums.AllocRelationTypeEnum;
import org.dromara.daxpay.core.enums.ChannelEnum;
@@ -9,6 +11,8 @@ import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.service.convert.allocation.AllocReceiverConvert;
import org.dromara.daxpay.service.result.allocation.AllocReceiverResult;
/**
* 分账接收方
@@ -18,7 +22,8 @@ import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class AllocReceiver extends MchAppBaseEntity {
@TableName("pay_alloc_receiver")
public class AllocReceiver extends MchAppBaseEntity implements ToResult<AllocReceiverResult> {
/** 分账接收方编号, 需要保证唯一 */
private String receiverNo;
@@ -51,4 +56,9 @@ public class AllocReceiver extends MchAppBaseEntity {
/** 关系名称 */
private String relationName;
@Override
public AllocReceiverResult toResult() {
return AllocReceiverConvert.CONVERT.toResult(this);
}
}

View File

@@ -0,0 +1,33 @@
package org.dromara.daxpay.service.entity.config;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import java.math.BigDecimal;
/**
* 分账配置
* @author xxm
* @since 2024/10/6
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@TableName("pay_alloc_config")
public class AllocConfig extends MchAppBaseEntity {
/** 是否自动分账 */
private Boolean autoAlloc;
/** 开启分账最低额 */
private Boolean enableAllocLimit;
/** 大于多少开启分账 */
private BigDecimal minAmount;
/** 分账时机类型 立即/定期/延时 */
private String allocTimeType;
}

View File

@@ -1,6 +1,10 @@
package org.dromara.daxpay.service.entity.config;
import cn.bootx.platform.common.mybatisplus.function.ToResult;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.core.enums.CashierTypeEnum;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.core.enums.PayMethodEnum;
@@ -8,11 +12,6 @@ import org.dromara.daxpay.service.common.entity.MchAppBaseEntity;
import org.dromara.daxpay.service.convert.config.ChannelCashierConfigConvert;
import org.dromara.daxpay.service.param.config.ChannelCashierConfigParam;
import org.dromara.daxpay.service.result.config.ChannelCashierConfigResult;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 通道收银台配置
@@ -55,7 +54,6 @@ public class ChannelCashierConfig extends MchAppBaseEntity implements ToResult<C
private Boolean autoAllocation;
/** 备注 */
@Schema(description = "备注")
private String remark;
public static ChannelCashierConfig init(ChannelCashierConfigParam param){

View File

@@ -31,8 +31,8 @@ public class AllocOrderDetail extends MchAppBaseEntity {
/** 分账接收方编号 */
private String receiverNo;
/** 分账比例 */
private Integer rate;
/** 分账比例(百分之多少) */
private BigDecimal rate;
/** 分账金额 */
private BigDecimal amount;

View File

@@ -0,0 +1,30 @@
package org.dromara.daxpay.service.param.allocation.group;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 分账组绑定参数
* @author xxm
* @since 2024/4/1
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账组绑定参数")
public class AllocGroupBindParam {
@NotNull(message = "分账组ID不可为空")
@Schema(description = "分账组ID")
private Long groupId;
@Valid
@NotEmpty(message = "分账接收方不可为空")
@Schema(description = "分账接收方集合")
private List<AllocGroupReceiverParam> receivers;
}

View File

@@ -0,0 +1,34 @@
package org.dromara.daxpay.service.param.allocation.group;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 分账组参数
* @author xxm
* @since 2024/4/1
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账组参数")
public class AllocGroupParam {
@Schema(description = "主键")
private Long id;
@Schema(description = "分账组编号")
private String groupNo;
@Schema(description = "分组名称")
private String name;
@Schema(description = "通道")
private String channel;
@Schema(description = "备注")
private String remark;
@Schema(description = "商户应用ID")
private String appId;
}

View File

@@ -0,0 +1,34 @@
package org.dromara.daxpay.service.param.allocation.group;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.service.common.param.MchAppQuery;
/**
* 分账组参数
* @author xxm
* @since 2024/4/1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "分账组参数")
public class AllocGroupQuery extends MchAppQuery {
@Schema(description = "分账组编号")
private String groupNo;
@Schema(description = "分组名称")
private String name;
@Schema(description = "通道")
private String channel;
@Schema(description = "备注")
private String remark;
@Schema(description = "商户应用ID")
private String appId;
}

View File

@@ -0,0 +1,35 @@
package org.dromara.daxpay.service.param.allocation.group;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.Min;
import java.math.BigDecimal;
/**
* 分账组接收者参数
* @author xxm
* @since 2024/4/1
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账组接收者参数")
public class AllocGroupReceiverParam {
@NotNull(message = "接收者ID不可为空")
@Schema(description = "接收者ID")
private Long receiverId;
@Schema(description = "分账比例(百分之多少)")
@NotNull(message = "分账比例不可为空")
@Min(value = 0,message = "分账比例不可为负数")
@DecimalMax(value = "100",message = "分账比例不可大于100%")
@DecimalMin(value = "0.01", message = "分账比例不可小于0.01%")
@Digits(integer = 3, fraction = 2, message = "分账比例最多只允许两位小数")
private BigDecimal rate;
}

View File

@@ -0,0 +1,28 @@
package org.dromara.daxpay.service.param.allocation.group;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 分账组接收者解除绑定
* @author xxm
* @since 2024/4/1
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账组取消接收者绑定")
public class AllocGroupUnbindParam {
@NotNull(message = "分账组ID不可为空")
@Schema(description = "分账组ID")
private Long groupId;
@NotBlank(message = "分账接收方不可为空")
@Schema(description = "分账接收方集合")
List<Long> receiverIds;
}

View File

@@ -0,0 +1,75 @@
package org.dromara.daxpay.service.param.allocation.receiver;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.daxpay.core.enums.AllocReceiverTypeEnum;
import org.dromara.daxpay.core.enums.AllocRelationTypeEnum;
import org.dromara.daxpay.core.enums.ChannelEnum;
import javax.validation.constraints.Size;
/**
* 分账接收者添加参数
* @author xxm
* @since 2024/5/20
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账接收者添加参数")
public class AllocReceiverAddParam{
@Schema(description = "接收者编号, 需要保证唯一")
@NotBlank(message = "接收者编号必填")
@Size(max = 32, message = "接收者编号不可超过32位")
private String receiverNo;
/**
* 所属通道
* @see ChannelEnum
*/
@Schema(description = "所属通道")
@NotBlank(message = "所属通道必填")
@Size(max = 20, message = "所属通道不可超过20位")
private String channel;
/**
* 分账接收方类型 根据不同类型的通道进行传输
* @see AllocReceiverTypeEnum
*/
@Schema(description = "分账接收方类型")
@NotBlank(message = "分账接收方类型必填")
@Size(max = 20, message = "分账接收方类型不可超过20位")
private String receiverType;
/** 接收方账号 */
@Schema(description = "接收方账号")
@NotBlank(message = "接收方账号必填")
@Size(max = 100, message = "接收方账号不可超过100位")
private String receiverAccount;
/** 接收方姓名 */
@Schema(description = "接收方姓名")
@Size(max = 100, message = "接收方姓名不可超过50位")
private String receiverName;
/**
* 分账关系类型
* @see AllocRelationTypeEnum
*/
@Schema(description = "分账关系类型")
@NotBlank(message = "分账关系类型必填")
@Size(max = 20, message = "分账关系类型不可超过20位")
private String relationType;
/** 关系名称 关系类型为自定义是填写 */
@Schema(description = "关系名称")
@Size(max = 50, message = "关系名称不可超过50位")
private String relationName;
@Schema(description = "商户应用ID")
@NotBlank(message = "商户应用ID必填")
@Size(max = 32, message = "商户应用ID不可超过32位")
private String appId;
}

View File

@@ -0,0 +1,50 @@
package org.dromara.daxpay.service.param.allocation.receiver;
import cn.bootx.platform.core.annotation.QueryParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.dromara.daxpay.core.enums.AllocRelationTypeEnum;
import org.dromara.daxpay.service.common.param.MchAppQuery;
/**
* 分账接收方查询条件
* @author xxm
* @since 2024/4/1
*/
@Getter
@Setter
public class AllocReceiverQuery extends MchAppQuery {
@QueryParam(type = QueryParam.CompareTypeEnum.LIKE)
@Schema(description = "接收方编号")
private String receiverNo;
/**
* @see org.dromara.daxpay.core.enums.ChannelEnum
*/
@Schema(description = "所属通道")
private String channel;
/**
* 分账接收方类型 个人/商户
*/
@Schema(description = "分账接收方类型")
private String receiverType;
@QueryParam(type = QueryParam.CompareTypeEnum.LIKE)
@Schema(description = "接收方账号")
private String receiverAccount;
/** 接收方姓名 */
@QueryParam(type = QueryParam.CompareTypeEnum.LIKE)
@Schema(description = "接收方姓名")
private String receiverName;
/**
* 分账关系类型
* @see AllocRelationTypeEnum
*/
@Schema(description = "分账关系类型")
private String relationType;
}

View File

@@ -0,0 +1,29 @@
package org.dromara.daxpay.service.param.allocation.receiver;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.Size;
/**
* 分账接收者删除参数
* @author xxm
* @since 2024/5/20
*/
@Data
@Accessors(chain = true)
@Schema(title = "分账接收者删除参数")
public class AllocReceiverRemoveParam {
@Schema(description = "接收者编号")
@NotBlank(message = "接收者编号必填")
@Size(max = 32, message = "接收者编号不可超过32位")
private String receiverNo;
@Schema(description = "商户应用ID")
@NotBlank(message = "商户应用ID必填")
@Size(max = 32, message = "商户应用ID不可超过32位")
private String appId;
}

View File

@@ -15,7 +15,7 @@ import lombok.experimental.Accessors;
@QueryParam(type = QueryParam.CompareTypeEnum.LIKE)
@Accessors(chain = true)
@Schema(title = "商户应用查询参数")
public class MchAppQuery {
public final class MchAppQuery {
/** 应用名称 */
@Schema(description = "应用号")

View File

@@ -0,0 +1,58 @@
package org.dromara.daxpay.service.result.allocation;
import cn.bootx.platform.common.jackson.sensitive.SensitiveInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.core.enums.AllocRelationTypeEnum;
import org.dromara.daxpay.core.result.MchAppResult;
import java.math.BigDecimal;
/**
* 分账组接收方信息
* @author xxm
* @since 2024/4/1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "分账组接收方信息")
public class AllocGroupReceiverResult extends MchAppResult {
@Schema(description = "接收方ID")
private Long receiverId;
@Schema(description = "接收方编号")
private String receiverNo;
@Schema(description = "分账比例(百分之多少)")
private BigDecimal rate;
/**
* 分账接收方类型
* @see org.dromara.daxpay.core.enums.AllocReceiverTypeEnum
*/
@Schema(description = "分账接收方类型")
private String receiverType;
@Schema(description = "接收方账号")
@SensitiveInfo
private String receiverAccount;
/** 接收方姓名 */
@Schema(description = "接收方姓名")
@SensitiveInfo(SensitiveInfo.SensitiveType.CHINESE_NAME)
private String receiverName;
/**
* 分账关系类型
* @see AllocRelationTypeEnum
*/
@Schema(description = "分账关系类型")
private String relationType;
@Schema(description = "关系名称")
private String relationName;
}

View File

@@ -0,0 +1,39 @@
package org.dromara.daxpay.service.result.allocation;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.core.result.MchAppResult;
import java.math.BigDecimal;
/**
* 分账组
* @author xxm
* @since 2024/4/1
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "分账组")
public class AllocGroupResult extends MchAppResult {
@Schema(description = "分账组编号")
private String groupNo;
@Schema(description = "名称")
private String name;
@Schema(description = "通道")
private String channel;
@Schema(description = "默认分账组")
private Boolean defaultGroup;
@Schema(description = "分账比例(百分之多少)")
private BigDecimal totalRate;
@Schema(description = "备注")
private String remark;
}

View File

@@ -0,0 +1,60 @@
package org.dromara.daxpay.service.result.allocation;
import cn.bootx.platform.common.jackson.sensitive.SensitiveInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.core.result.MchAppResult;
/**
* 分账接收方
* @author xxm
* @since 2024/3/28
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Schema(title = "分账接收方")
public class AllocReceiverResult extends MchAppResult {
@Schema(description = "账号别名")
private String name;
@Schema(description = "接收方编号")
private String receiverNo;
/**
* @see ChannelEnum
*/
@Schema(description = "所属通道")
private String channel;
/**
* 分账接收方类型 个人/商户
* @see org.dromara.daxpay.core.enums.AllocReceiverTypeEnum
*/
@Schema(description = "分账接收方类型")
private String receiverType;
@Schema(description = "接收方账号")
@SensitiveInfo
private String receiverAccount;
/** 接收方姓名 */
@Schema(description = "接收方姓名")
@SensitiveInfo(SensitiveInfo.SensitiveType.CHINESE_NAME)
private String receiverName;
/**
* 分账关系类型
* @see org.dromara.daxpay.core.enums.AllocRelationTypeEnum
*/
@Schema(description = "分账关系类型")
private String relationType;
@Schema(description = "关系名称")
private String relationName;
}

View File

@@ -20,7 +20,7 @@ import java.math.BigDecimal;
@Data
@Accessors(chain = true)
@Schema(title = "商户应用")
public class MchAppResult extends BaseResult {
public final class MchAppResult extends BaseResult {
/** 应用号 */
@Schema(description = "应用号")

View File

@@ -0,0 +1,247 @@
package org.dromara.daxpay.service.service.allocation;
import cn.bootx.platform.common.mybatisplus.function.CollectorsFunction;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.core.exception.BizException;
import cn.bootx.platform.core.exception.DataNotExistException;
import cn.bootx.platform.core.rest.param.PageParam;
import cn.bootx.platform.core.rest.result.PageResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.service.convert.allocation.AllocGroupConvert;
import org.dromara.daxpay.service.dao.allocation.receiver.AllocGroupManager;
import org.dromara.daxpay.service.dao.allocation.receiver.AllocGroupReceiverManager;
import org.dromara.daxpay.service.dao.allocation.receiver.AllocReceiverManager;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroup;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocGroupReceiver;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
import org.dromara.daxpay.service.param.allocation.group.*;
import org.dromara.daxpay.service.result.allocation.AllocGroupReceiverResult;
import org.dromara.daxpay.service.result.allocation.AllocGroupResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 分账组服务
* @author xxm
* @since 2024/4/1
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AllocGroupService {
private final AllocGroupManager groupManager;
private final AllocGroupReceiverManager groupReceiverManager;
private final AllocReceiverManager receiverManager;
/**
* 分页
*/
public PageResult<AllocGroupResult> page(PageParam pageParam, AllocGroupQuery query){
return MpUtil.toPageResult(groupManager.page(pageParam, query));
}
/**
* 查询详情
*/
public AllocGroupResult findById(Long id){
return groupManager.findById(id).map(AllocGroup::toResult).orElseThrow(()->new DataNotExistException("分账组不存在"));
}
/**
* 查询分账接收方
*/
public List<AllocGroupReceiverResult> findReceiversByGroups(Long groupId){
List<AllocGroupReceiver> groupReceivers = groupReceiverManager.findByGroupId(groupId);
List<Long> receiverIds = groupReceivers.stream()
.map(AllocGroupReceiver::getReceiverId)
.collect(Collectors.toList());
// 查询关联接收方信息
Map<Long, AllocReceiver> receiverMap = receiverManager.findAllByIds(receiverIds)
.stream()
.collect(Collectors.toMap(AllocReceiver::getId, Function.identity(), CollectorsFunction::retainLatest));
// 组装信息
return groupReceivers.stream()
.map(o -> {
AllocReceiver receiver = receiverMap.get(o.getReceiverId());
AllocGroupReceiverResult result = new AllocGroupReceiverResult()
.setReceiverId(receiver.getId())
.setReceiverNo(receiver.getReceiverNo())
.setReceiverAccount(receiver.getReceiverAccount())
.setReceiverName(receiver.getReceiverName())
.setRate(o.getRate())
.setReceiverType(receiver.getReceiverType())
.setRelationName(receiver.getRelationName())
.setRelationType(receiver.getRelationType());
result.setId(o.getId());
return result;
})
.collect(Collectors.toList());
}
/**
* 创建分账组
*/
public void create(AllocGroupParam param){
AllocGroup group = AllocGroupConvert.CONVERT.convert(param);
group.setTotalRate(BigDecimal.ZERO);
groupManager.save(group);
}
/**
* 设置默认分账组
*/
@Transactional(rollbackFor = Exception.class)
public void setUpDefault(Long id){
// 分账组
AllocGroup group = groupManager.findById(id).orElseThrow(() -> new DataNotExistException("未找到分账组"));
groupManager.clearDefault(group.getChannel(), group.getAppId());
group.setDefaultGroup(true);
groupManager.updateById(group);
}
/**
* 清除默认分账组
*/
@Transactional(rollbackFor = Exception.class)
public void clearDefault(Long id){
AllocGroup group = groupManager.findById(id).orElseThrow(() -> new DataNotExistException("未找到分账组"));
group.setDefaultGroup(false);
groupManager.updateById(group);
}
/**
* 更新分账组
*/
public void update(AllocGroupParam param){
AllocGroup group = groupManager.findById(param.getId()).orElseThrow(() -> new DataNotExistException("未找到分账组"));
BeanUtil.copyProperties(param,group, CopyOptions.create().ignoreNullValue());
group.setTotalRate(null);
groupManager.updateById(group);
}
/**
* 删除分账组
*/
@Transactional(rollbackFor = Exception.class)
public void delete(Long id){
groupManager.deleteById(id);
groupReceiverManager.deleteByGroupId(id);
}
/**
* 绑定分账接收方
*/
@Transactional(rollbackFor = Exception.class)
public void bindReceivers(AllocGroupBindParam param) {
// 分账组
AllocGroup group = groupManager.findById(param.getGroupId()).orElseThrow(() -> new DataNotExistException("未找到分账组"));
// 查询接收方
List<AllocGroupReceiverParam> receiverParams = param.getReceivers();
List<Long> receiverIds = receiverParams.stream()
.map(AllocGroupReceiverParam::getReceiverId)
.collect(Collectors.toList());
List<AllocReceiver> receivers = receiverManager.findAllByIds(receiverIds);
if (receivers.size() != receiverIds.size()){
throw new DataNotExistException("传入的分账接收房数量与查询到的不一致");
}
// 接收方只能为一个支付通道
long count = receivers.stream()
.map(AllocReceiver::getChannel)
.distinct()
.count();
if (count > 1){
throw new BizException("接收方只能为一个支付通道");
}
// 检查接收方和传入的通道是否是不一致
if (!Objects.equals(group.getChannel(), receivers.getFirst().getChannel())){
throw new BizException("接收方和传入的通道不一致");
}
// 保存分账接收者
List<AllocGroupReceiver> groupReceivers = receivers.stream()
.map(receiver -> new AllocGroupReceiver().setGroupId(group.getId())
.setReceiverId(receiver.getId())
.setRate(receiverParams.get(receivers.indexOf(receiver))
.getRate()))
.collect(Collectors.toList());
groupReceiverManager.saveAll(groupReceivers);
// 计算分账比例
var sum = receiverParams.stream()
.map(AllocGroupReceiverParam::getRate)
.reduce(BigDecimal.ZERO, BigDecimal::add);
group.setTotalRate(group.getTotalRate().add(sum));
groupManager.updateById(group);
}
/**
* 批量删除分账接收方
*/
@Transactional(rollbackFor = Exception.class)
public void unbindReceivers(AllocGroupUnbindParam param){
// 分账组
AllocGroup group = groupManager.findById(param.getGroupId())
.orElseThrow(() -> new DataNotExistException("未找到分账组"));
// 删除接收方
List<AllocGroupReceiver> receivers = groupReceiverManager.findAllByIds(param.getReceiverIds());
if (receivers.size() != param.getReceiverIds().size()){
throw new DataNotExistException("传入的分账接收房数量与查询到的不一致");
}
groupReceiverManager.deleteByIds(param.getReceiverIds());
// 计算分账比例
var sum = receivers.stream()
.map(AllocGroupReceiver::getRate)
.reduce(BigDecimal.ZERO, BigDecimal::add);
group.setTotalRate(group.getTotalRate().subtract(sum));
groupManager.updateById(group);
}
/**
* 删除单个分账接收方
*/
@Transactional
public void unbindReceiver(Long receiverId){
AllocGroupReceiver groupReceiver = groupReceiverManager.findById(receiverId)
.orElseThrow(() -> new DataNotExistException("未找到分账接收方"));
AllocGroup group = groupManager.findById(groupReceiver.getGroupId())
.orElseThrow(() -> new DataNotExistException("未找到分账组"));
// 更新分账比例
group.setTotalRate(group.getTotalRate().subtract(groupReceiver.getRate()));
// 更新接收比例
groupReceiverManager.deleteById(receiverId);
groupManager.updateById(group);
}
/**
* 修改分账比例
*/
@Transactional(rollbackFor = Exception.class)
public void updateRate(Long receiverId, BigDecimal rate){
AllocGroupReceiver groupReceiver = groupReceiverManager.findById(receiverId)
.orElseThrow(() -> new DataNotExistException("未找到分账接收方"));
AllocGroup group = groupManager.findById(groupReceiver.getGroupId())
.orElseThrow(() -> new DataNotExistException("未找到分账组"));
// 更新分账比例
group.setTotalRate(group.getTotalRate().subtract(groupReceiver.getRate()).add(rate));
// 更新接收比例
groupReceiver.setRate(rate);
groupReceiverManager.updateById(groupReceiver);
groupManager.updateById(group);
}
/**
* 判断分账组编号是否存在
*/
public boolean existsByGroupNo(String groupNo, String appId) {
return groupManager.existedByGroupNo(groupNo, appId);
}
}

View File

@@ -0,0 +1,161 @@
package org.dromara.daxpay.service.service.allocation;
import cn.bootx.platform.baseapi.service.dict.DictionaryItemService;
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
import cn.bootx.platform.core.exception.DataNotExistException;
import cn.bootx.platform.core.exception.ValidationFailedException;
import cn.bootx.platform.core.rest.dto.LabelValue;
import cn.bootx.platform.core.rest.param.PageParam;
import cn.bootx.platform.core.rest.result.PageResult;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.core.exception.DataErrorException;
import org.dromara.daxpay.core.exception.OperationFailException;
import org.dromara.daxpay.core.exception.OperationProcessingException;
import org.dromara.daxpay.service.convert.allocation.AllocReceiverConvert;
import org.dromara.daxpay.service.dao.allocation.receiver.AllocGroupReceiverManager;
import org.dromara.daxpay.service.dao.allocation.receiver.AllocReceiverManager;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverAddParam;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverQuery;
import org.dromara.daxpay.service.param.allocation.receiver.AllocReceiverRemoveParam;
import org.dromara.daxpay.service.result.allocation.AllocReceiverResult;
import org.dromara.daxpay.service.strategy.AbsAllocReceiverStrategy;
import org.dromara.daxpay.service.strategy.PaymentStrategy;
import org.dromara.daxpay.service.util.PaymentStrategyFactory;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* 分账接收方服务类
* @author xxm
* @since 2024/3/27
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AllocReceiverService {
private final AllocGroupReceiverManager groupReceiverManager;
private final AllocReceiverManager allocReceiverManager;
private final LockTemplate lockTemplate;
private final DictionaryItemService dictionaryItemService;
/**
* 分页
*/
public PageResult<AllocReceiverResult> page(PageParam pageParam, AllocReceiverQuery query) {
return MpUtil.toPageResult(allocReceiverManager.page(pageParam, query));
}
/**
* 查询详情
*/
public AllocReceiverResult findById(Long id) {
return allocReceiverManager.findById(id)
.map(AllocReceiver::toResult)
.orElseThrow(() -> new DataNotExistException("分账接收方不存在"));
}
/**
* 编码是否存在
*/
public boolean existsByReceiverNo(String receiverNo, String appId) {
return allocReceiverManager.existedByReceiverNo(receiverNo, appId);
}
/**
* 添加分账接收方并同步到三方支付系统中
*/
public void addAndSync(AllocReceiverAddParam param) {
// 判断是否已经添加
LockInfo lock = lockTemplate.lock("payment:receiver:" + param.getReceiverNo(), 10000, 200);
if (Objects.isNull(lock)) {
throw new OperationProcessingException("分账方处理中,请勿重复操作");
}
try {
Optional<AllocReceiver> receiverOptional = allocReceiverManager.findByReceiverNo(param.getReceiverNo(),param.getAppId());
if (receiverOptional.isPresent()) {
throw new OperationFailException("该接收方已存在");
}
AllocReceiver receiver = AllocReceiverConvert.CONVERT.convert(param);
// 获取策略
AbsAllocReceiverStrategy receiverStrategy = PaymentStrategyFactory.create(param.getChannel(), AbsAllocReceiverStrategy.class);
// 校验
receiverStrategy.setAllocReceiver(receiver);
if (!receiverStrategy.validation()) {
throw new ValidationFailedException("接收方信息校验失败");
}
// 先添加到三方支付系统中, 然后保存到本地
receiverStrategy.doBeforeHandler();
receiverStrategy.bind();
allocReceiverManager.save(receiver);
} finally {
lockTemplate.releaseLock(lock);
}
}
/**
* 分账方删除
*/
public void removeAndSync(AllocReceiverRemoveParam param) {
// 判断是否存在
AllocReceiver receiver = allocReceiverManager.findByReceiverNo(param.getReceiverNo(), param.getAppId())
.orElseThrow(() -> new DataErrorException("该接收方不存在"));
if (groupReceiverManager.isUsed(receiver.getId())) {
throw new OperationFailException("该接收方已被使用,无法被删除");
}
// 获取策略
var receiverStrategy = PaymentStrategyFactory.create(receiver.getChannel(), AbsAllocReceiverStrategy.class);
LockInfo lock = lockTemplate.lock("payment:receiver:" + param.getReceiverNo(), 10000, 200);
if (Objects.isNull(lock)) {
throw new OperationProcessingException("分账方处理中,请勿重复操作");
}
try {
receiverStrategy.setAllocReceiver(receiver);
// 校验
receiverStrategy.validation();
// 预处理
receiverStrategy.doBeforeHandler();
// 取消绑定
receiverStrategy.unbind();
allocReceiverManager.deleteById(receiver.getId());
} finally {
lockTemplate.releaseLock(lock);
}
}
/**
* 可分账的通道列表
*/
public List<LabelValue> findChannels() {
// 先查询策略, 然后查询通道并进行过滤
List<String> channelCodes = SpringUtil.getBeansOfType(AbsAllocReceiverStrategy.class)
.values()
.stream()
.map(PaymentStrategy::getChannel)
.toList();
return dictionaryItemService.findEnableByDictCode("channel").stream()
.filter(item -> channelCodes.contains(item.getCode()))
.map(item -> new LabelValue(item.getName(), item.getCode()))
.toList();
}
/**
* 根据通道获取分账接收方类型
*/
public List<LabelValue> findReceiverTypeByChannel(String channel) {
var receiverStrategy = PaymentStrategyFactory.create(channel, AbsAllocReceiverStrategy.class);
return receiverStrategy.getSupportReceiverTypes().stream()
.map(o-> new LabelValue(o.getName(), o.getCode()))
.toList();
}
}

View File

@@ -27,17 +27,17 @@ import java.util.List;
@Service
@RequiredArgsConstructor
public class ChannelCashierConfigService {
private final ChannelCashierConfigManage cashierConfigManage;
private final MchAppManager mchAppManager;
private final ChannelCashierConfigManage cashierConfigManage;
private final PlatformConfigService platformConfigService;
/**
* 分页
* 列表
*/
public List<ChannelCashierConfigResult> findByAppId(String appId) {
return MpUtil.toListResult(cashierConfigManage.findAll());
return MpUtil.toListResult(cashierConfigManage.findAllByAppId(appId));
}
/**

View File

@@ -0,0 +1,50 @@
package org.dromara.daxpay.service.strategy;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.core.enums.AllocReceiverTypeEnum;
import org.dromara.daxpay.service.entity.allocation.receiver.AllocReceiver;
import java.util.List;
/**
* 分账抽象策略
* @author xxm
* @since 2024/4/1
*/
@Slf4j
@Getter
@Setter
public abstract class AbsAllocReceiverStrategy implements PaymentStrategy{
private AllocReceiver allocReceiver;
/**
* 支持的接收者类型
*/
public abstract List<AllocReceiverTypeEnum> getSupportReceiverTypes();
/**
* 操作前校验
*/
public boolean validation() {
return true;
}
/**
* 操作前处理, 校验和初始化支付配置
*/
public void doBeforeHandler() {
}
/**
* 添加到三方支付系统中
*/
public abstract void bind();
/**
* 从三方支付系统中删除
*/
public abstract void unbind();
}

View File

@@ -27,4 +27,6 @@ public class PaymentStrategyFactory {
.findFirst()
.orElseThrow(() -> new UnsupportedAbilityException("不支持的能力"));
}
}