分账逻辑及逻辑接入及分账记录查询

This commit is contained in:
2025-02-18 10:18:07 +08:00
parent 25e6e6788d
commit 63df84fa7c
13 changed files with 302 additions and 172 deletions

View File

@ -3,9 +3,9 @@ package com.ycwl.basic.profitsharing.biz;
import com.ycwl.basic.profitsharing.entity.ProfitSharingConfig;
import com.ycwl.basic.profitsharing.entity.ProfitSharingRecord;
import com.ycwl.basic.profitsharing.entity.ProfitSharingUser;
import com.ycwl.basic.profitsharing.mapper.ProfitSharingConfigMapper;
import com.ycwl.basic.profitsharing.mapper.ProfitSharingRecordMapper;
import com.ycwl.basic.profitsharing.repository.ProfitSharingRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -14,7 +14,9 @@ import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Component
public class ProfitSharingBiz {
@Autowired
@ -28,21 +30,27 @@ public class ProfitSharingBiz {
if (config == null || config.getUsers() == null || config.getUsers().isEmpty()) {
return;
}
List<ProfitSharingRecord> records = new ArrayList<>();
BigDecimal totalPercentage = BigDecimal.ZERO;
for (ProfitSharingUser user : config.getUsers()) {
totalPercentage = totalPercentage.add(user.getRealRate());
}
if (totalPercentage.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new RuntimeException("分账比例总和超过100%");
}
BigDecimal myPercentage = BigDecimal.valueOf(100).subtract(totalPercentage);
for (ProfitSharingUser user : config.getUsers()) {
BigDecimal userAmount = amount.multiply(user.getRealRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
BigDecimal wxAmount = amount.multiply(user.getWxRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
BigDecimal manualAmount = userAmount.subtract(wxAmount);
List<ProfitSharingUser> alreadyProcessedUsers = new ArrayList<>();
// 先找出1,3的用户
config.getUsers().stream().filter(user -> user.getRateMode() == 1 || user.getRateMode() == 3).forEach(user -> {
if (alreadyProcessedUsers.contains(user)) {
return;
}
BigDecimal userAmount;
BigDecimal wxAmount;
BigDecimal manualAmount;
if (user.getRateMode() == 1) { // 比例抽成
userAmount = amount.multiply(user.getRealRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
wxAmount = amount.multiply(user.getWxRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
manualAmount = userAmount.subtract(wxAmount);
} else if (user.getRateMode() == 3) { // 固定抽成
userAmount = user.getRealRate();
wxAmount = user.getWxRate();
manualAmount = userAmount.subtract(wxAmount);
} else {
return;
}
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
@ -51,28 +59,146 @@ public class ProfitSharingBiz {
record.setAmount(userAmount);
record.setWxAmount(wxAmount);
record.setManualAmount(manualAmount);
record.setRateMode(user.getRateMode());
record.setWxRate(user.getWxRate());
record.setRealRate(user.getRealRate());
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
alreadyProcessedUsers.add(user);
});
final BigDecimal mode2RemainAmount = amount.subtract(records.stream().map(ProfitSharingRecord::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
// 找出2的用户
config.getUsers().stream().filter(user -> user.getRateMode() == 2).forEach(user -> {
if (alreadyProcessedUsers.contains(user)) {
return;
}
BigDecimal userAmount;
BigDecimal wxAmount;
BigDecimal manualAmount;
if (user.getRateMode() == 2) { // 扣除固定抽成后的动态比例
userAmount = mode2RemainAmount.multiply(user.getRealRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
wxAmount = mode2RemainAmount.multiply(user.getWxRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
manualAmount = userAmount.subtract(wxAmount);
} else {
return;
}
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
record.setUserId(user.getId());
record.setUserName(user.getName());
record.setAmount(userAmount);
record.setWxAmount(wxAmount);
record.setManualAmount(manualAmount);
record.setRateMode(user.getRateMode());
record.setWxRate(user.getWxRate());
record.setRealRate(user.getRealRate());
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
alreadyProcessedUsers.add(user);
});
final BigDecimal mode4RemainAmount = amount.subtract(records.stream().map(ProfitSharingRecord::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
// 找出4的用户
config.getUsers().stream().filter(user -> user.getRateMode() == 4).forEach(user -> {
if (alreadyProcessedUsers.contains(user)) {
return;
}
BigDecimal userAmount;
BigDecimal wxAmount;
BigDecimal manualAmount;
if (user.getRateMode() == 4) { // 扣除其他所有类型抽成后的动态比例
userAmount = mode4RemainAmount.multiply(user.getRealRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
wxAmount = mode4RemainAmount.multiply(user.getWxRate()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_DOWN);
manualAmount = userAmount.subtract(wxAmount);
} else {
return;
}
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
record.setUserId(user.getId());
record.setUserName(user.getName());
record.setAmount(userAmount);
record.setWxAmount(wxAmount);
record.setManualAmount(manualAmount);
record.setRateMode(user.getRateMode());
record.setWxRate(user.getWxRate());
record.setRealRate(user.getRealRate());
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
alreadyProcessedUsers.add(user);
});
final BigDecimal mode0RemainAmount = amount.subtract(records.stream().map(ProfitSharingRecord::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
// 找出0的用户
List<ProfitSharingUser> mode0User = config.getUsers().stream().filter(user -> user.getRateMode() == 0).collect(Collectors.toList());
mode0User.forEach(user -> {
if (alreadyProcessedUsers.contains(user)) {
return;
}
BigDecimal userAmount;
BigDecimal wxAmount;
BigDecimal manualAmount;
if (user.getRateMode() == 0) { // 剩余比例
userAmount = mode0RemainAmount.divide(BigDecimal.valueOf(mode0User.size()), 2, RoundingMode.HALF_DOWN);
wxAmount = mode0RemainAmount.divide(BigDecimal.valueOf(mode0User.size()), 2, RoundingMode.HALF_DOWN);
manualAmount = userAmount.subtract(wxAmount);
} else {
return;
}
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
record.setUserId(user.getId());
record.setUserName(user.getName());
record.setAmount(userAmount);
record.setWxAmount(wxAmount);
record.setManualAmount(manualAmount);
record.setRateMode(user.getRateMode());
record.setWxRate(user.getWxRate());
record.setRealRate(user.getRealRate());
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
alreadyProcessedUsers.add(user);
});
// 没有操作过的用户
config.getUsers().stream().filter(user -> !alreadyProcessedUsers.contains(user)).forEach(user -> {
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
record.setUserId(user.getId());
record.setUserName(user.getName());
record.setAmount(BigDecimal.ZERO);
record.setWxAmount(BigDecimal.ZERO);
record.setManualAmount(BigDecimal.ZERO);
record.setRateMode(user.getRateMode());
record.setWxRate(user.getWxRate());
record.setRealRate(user.getRealRate());
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
alreadyProcessedUsers.add(user);
});
final BigDecimal remainAmount = amount.subtract(records.stream().map(ProfitSharingRecord::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
if (remainAmount.compareTo(BigDecimal.ZERO) < 0) {
log.error("分账剩余金额不足!!! scenicId: {}, orderId: {}, amount: {}, config: {}", scenicId, orderId, amount, config);
return;
}
BigDecimal remainAmount = amount;
for (ProfitSharingRecord record : records) {
remainAmount = remainAmount.subtract(record.getAmount());
}
if (remainAmount.compareTo(BigDecimal.ZERO) > 0) {
ProfitSharingRecord record = new ProfitSharingRecord();
record.setScenicId(scenicId);
record.setOrderId(orderId);
record.setUserId(0L);
record.setUserName("自己");
record.setUserName("分账剩余");
record.setRateMode(-1);
record.setAmount(remainAmount);
record.setWxAmount(BigDecimal.ZERO);
record.setManualAmount(remainAmount);
record.setWxRate(BigDecimal.ZERO);
record.setRealRate(myPercentage);
record.setRealRate(BigDecimal.ZERO);
record.setOrderAmount(amount);
record.setCreateTime(new Date());
records.add(record);
@ -81,4 +207,7 @@ public class ProfitSharingBiz {
recordMapper.batchInsert(records);
}
public void revokeProfitSharing(Long scenicId, Long orderId) {
recordMapper.deleteByScenicIdAndOrderId(scenicId, orderId);
}
}

View File

@ -15,8 +15,10 @@ public class ProfitSharingRecord {
private BigDecimal amount;
private BigDecimal wxAmount;
private BigDecimal manualAmount;
private Integer rateMode; // 微信分账比例
private BigDecimal wxRate; // 微信分账比例
private BigDecimal realRate; // 实际分账比例
private BigDecimal orderAmount; // 订单金额
private Integer status;
private Date createTime;
}

View File

@ -15,6 +15,10 @@ public class ProfitSharingUser {
private Map<String, String> wxPayConfig;
private String name;
private String description;
/**
* 分账比例模式0剩余模式1固定比例2扣除固定抽成后的动态比例3固定抽成4扣除其他所有类型抽成后的动态比例
*/
private Integer rateMode;
/**
* 微信分账比例,单位为%
*/

View File

@ -1,15 +1,20 @@
package com.ycwl.basic.profitsharing.mapper;
import com.ycwl.basic.model.pc.profitsharing.resp.ProfitSharingRecordRespVO;
import com.ycwl.basic.profitsharing.entity.ProfitSharingRecord;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface ProfitSharingRecordMapper {
List<ProfitSharingRecordRespVO> findByScenicId(@Param("scenicId") Long scenicId);
void batchInsert(List<ProfitSharingRecord> records);
@Delete("DELETE FROM profit_sharing_record WHERE scenic_id = #{scenicId} AND order_id = #{orderId}")

View File

@ -7,15 +7,18 @@ import java.util.List;
@Mapper
public interface ProfitSharingUserMapper {
@Insert("INSERT INTO profit_sharing_user (config_id, wx_pay_type, wx_pay_config, name, description, wx_rate, real_rate) " +
"VALUES (#{configId}, #{wxPayType}, #{wxPayConfig}, #{name}, #{description}, #{wxRate}, #{realRate})")
@Insert("INSERT INTO profit_sharing_user (config_id, name, description, wx_rate, real_rate, rate_mode) " +
"VALUES (#{configId}, #{name}, #{description}, #{wxRate}, #{realRate}, #{rateMode})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insert(ProfitSharingUser user);
@Update("UPDATE profit_sharing_user SET config_id = #{configId}, wx_pay_type = #{wxPayType}, wx_pay_config = #{wxPayConfig}, " +
"name = #{name}, description = #{description}, wx_rate = #{wxRate}, real_rate = #{realRate} WHERE id = #{id}")
@Update("UPDATE profit_sharing_user SET config_id = #{configId}, " +
"name = #{name}, description = #{description}, wx_rate = #{wxRate}, real_rate = #{realRate}, rate_mode = #{rateMode} WHERE id = #{id}")
void update(ProfitSharingUser user);
@Update("UPDATE profit_sharing_user SET wx_pay_type = #{wxPayType}, wx_pay_config = #{wxPayConfig} WHERE id = #{id}")
void updateWxPayConfig(ProfitSharingUser user);
@Delete("DELETE FROM profit_sharing_user WHERE id = #{id}")
void deleteById(Long id);