分账计算使用了公共方法

This commit is contained in:
Jack 2025-10-01 01:03:52 +08:00
parent 57504c9458
commit 1d4b884215
5 changed files with 69 additions and 61 deletions

View File

@ -37,5 +37,8 @@ public class RedisConstant {
public static final String SF_Order_Proc_WillExpire_Key = ConstantRedis.Cache_NameSpace + "sf_order_proc_will_expire_key__";
public static final String Order_Pay_Retry_Count_Key = ConstantRedis.Cache_NameSpace + "order_pay_retry_count:";
// 您有新的订单来了
public static final String New_Order_Push_Flag_Key = ConstantRedis.Cache_NameSpace + "new:order:comimg:";
}

View File

@ -61,15 +61,15 @@ public class LklSeparateDTO {
// 测试基于可分账金额的分账算法正常情况
System.out.println("\n=== 基于可分账金额的分账算法测试(正常情况) ===");
LklSeparateDTO dto2 = new LklSeparateDTO();
dto2.setTotalSeparateAmount(1500); // 分账总额 1000分
dto2.setTotalSeparateAmount(900); // 分账总额 1000分
dto2.setShippingFee(500); // 配送费 100分
// dto2.setRefCanSeparateAmount(null);
dto2.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025
dto2.setMchRatio(new BigDecimal("0.95")); // 商家分账比例 0.857 (会产生小数)
dto2.setPlatRatio(new BigDecimal("0.06")); // 平台分账比例 0.01
dto2.setPlatRatio(new BigDecimal("0.01")); // 平台分账比例 0.01
// 不设置一级和二级代理商分账比例测试不参与分账的情况
dto2.setAgent1stRatio(new BigDecimal("0.11")); // 一级代理商分账比例 0.023 (会产生小数)
dto2.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例 0.031 (会产生小数)
// dto2.setAgent1stRatio(new BigDecimal("0.11")); // 一级代理商分账比例 0.023 (会产生小数)
// dto2.setAgent2ndRatio(new BigDecimal("0.04")); // 二级代理商分账比例 0.031 (会产生小数)
SharingResult result2 = dto2.sharingOnCanSeparateAmount();
System.out.println(result2);

View File

@ -19,6 +19,7 @@ import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@ -125,16 +126,6 @@ public class UniCloudPushServiceImpl implements UniCloudPushService {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON); // Content-Type: application/json
// headers.add("Accept", "*/*");
// headers.add("Host", "fc-mp-39e3d50a-2d2b-415a-9664-2e48974bcfbd.next.bspapp.com");
// headers.add("Connection", "keep-alive");
// headers.add("Authorization", "Basic ZWxhc3TiYzpQQjI1NkZFTjBPaDY0cFZV");
// headers.add("User-Agent", "Apifox/1.0.0 (https://apifox.com)");
// headers.add("Cookie", "aliyungf_tc=3a871d6048f74707aa0ac71c13f654c4d0fba0471c40625f4c120b6aca248dcf; acw_tc=ac11000117529360358682662e17bea869dfc6fb823bd2d372dbf9eca1c342");
// return headers;
}
/**
@ -150,21 +141,23 @@ public class UniCloudPushServiceImpl implements UniCloudPushService {
clientIds.size(), distinctClientIds.size());
}
// 新增生成消息唯一标识符
String messageId = UUID.randomUUID().toString().replace("-", "");
request.put("push_clientid", distinctClientIds)
.put("title", title)
.put("content", content);
.put("content", content)
.put("message_id", messageId); // 添加唯一消息ID
if (payload != null) {
request.put("payload", payload);
}
request.put("settings", new JSONObject().set("ttl", DEFAULT_TTL));
log.debug("[推送服务] 请求参数: {}", request);
return request;
}
/**
* 处理推送响应
*/

View File

@ -2471,16 +2471,16 @@ public class LakalaApiServiceImpl implements LakalaApiService {
return Pair.of(true, "订单已分账,请勿重复操作");
}
// 5. 检查可分账余额
Integer canSeparateAmt = null;
// 5. 从拉卡拉平台检查可分账余额
Integer refCanSeparateAmt = null;
Pair<String, String> mchCanSplitAmt = queryMchCanSplitAmt(lklMerchantNo, receiveLogNo, shopOrderLkl.getLkl_log_date());
if (mchCanSplitAmt != null) {
log.info("[分账操作] 查询拉卡拉可分账余额接口:lklMerchantNo={} logDate={} receiveLogNo={}",
lklMerchantNo, shopOrderLkl.getLkl_log_date(), receiveLogNo);
log.info("[分账操作] 查询拉卡拉可分账余额接口:lklMerchantNo={} logDate={} receiveLogNo={} 结果:{}",
lklMerchantNo, shopOrderLkl.getLkl_log_date(), receiveLogNo, mchCanSplitAmt);
// 可分账金额
canSeparateAmt = Convert.toInt(mchCanSplitAmt.getSecond());
if (canSeparateAmt == null || canSeparateAmt <= 0) {
refCanSeparateAmt = Convert.toInt(mchCanSplitAmt.getSecond());
if (CheckUtil.isEmpty(refCanSeparateAmt)) {
log.warn("[分账操作] lklMerchantNo={} receiveTradeNo={} receiveLogNo={} 拉卡拉可分账金额无值或0系统将自动计算可分账金额",
lklMerchantNo, receiveTradeNo, receiveLogNo);
}
@ -2493,7 +2493,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
BigDecimal mchSplitRatioRaw = shopOrderLkl.getSplit_ratio();
if (mchSplitRatioRaw == null ||
mchSplitRatioRaw.compareTo(BigDecimal.ZERO) <= 0 ||
mchSplitRatioRaw.compareTo(new BigDecimal(100)) > 0) {
mchSplitRatioRaw.compareTo(new BigDecimal(100)) >= 0) {
log.error("[分账操作] 店铺[{}]商家分账比例[{}]不在(0-100]范围内,无法分账",
shopOrderLkl.getStore_id(), mchSplitRatioRaw);
return Pair.of(false, "商家分账比例有误");
@ -2505,60 +2505,55 @@ public class LakalaApiServiceImpl implements LakalaApiService {
// 获取分账平台接收方信息
LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo);
if (platformReceiver == null) {
log.error("[分账操作] 店铺[{}]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id());
log.error("[分账操作] 商户号{} 未绑定平台方接收账户,跳过分账", merchantNo);
return Pair.of(false, "平台方未绑定账户");
}
// 获取代理商分账信息
BigDecimal platformSplitRatio = BigDecimal.valueOf(0.01);
BigDecimal distributorSplitRatio = BigDecimal.ZERO;
List<LklLedgerMerReceiverBind> distributorReceivers = lklLedgerMerReceiverBindService.selectDistributorByMerCupNo(merchantNo);
if (CollUtil.isNotEmpty(distributorReceivers)) {
distributorSplitRatio = BigDecimal.valueOf(1).subtract(platformSplitRatio).subtract(mchSplitRatio);
distributorSplitRatio = BigDecimal.valueOf(1).subtract(mchSplitRatio).subtract(platformSplitRatio);
log.debug("[分账操作] 检测到代理商存在,调整分账比例: 代理商比例={}, 平台比例={}", distributorSplitRatio, platformSplitRatio);
} else {
platformSplitRatio = BigDecimal.valueOf(1).subtract(mchSplitRatio);
distributorSplitRatio = null;
}
// 内部配送费
Integer shoppingFeeInner = CheckUtil.isEmpty(shopOrderLkl.getShopping_fee_inner()) ? 0 : shopOrderLkl.getShopping_fee_inner();
BigDecimal wxFeeRatio = StrUtil.isEmpty(wxFee) ? BigDecimal.valueOf(0.0025) : new BigDecimal(wxFee).divide(BigDecimal.valueOf(100));
// 构建分账参数对象
LklSeparateDTO lklSeparateDTO = new LklSeparateDTO();
lklSeparateDTO.setTotalSeparateAmount(shopOrderLkl.getTotal_amt());
lklSeparateDTO.setShippingFee(shoppingFeeInner);
lklSeparateDTO.setLklRatio(wxFeeRatio); // 拉卡拉给的微信分账比例 0.0025 千分之2.5
lklSeparateDTO.setMchRatio(mchSplitRatio);
lklSeparateDTO.setPlatRatio(platformSplitRatio);
// 计算拉卡拉手续费商家分账金额平台和代理商的分账金额
Pair<Boolean, LklSeparateDTO> calcResult = calculateAndEvaluateSharingParams(
CommonConstant.SeparateCalcMode_CanSeparateAmt,
shopOrderLkl.getTotal_amt(),
shoppingFeeInner,
mchSplitRatio,
platformSplitRatio,
null, distributorSplitRatio, refCanSeparateAmt);
if (distributorSplitRatio.compareTo(BigDecimal.ZERO) > 0) { // 二级代理商参与分账
lklSeparateDTO.setAgent2ndRatio(distributorSplitRatio);
}
lklSeparateDTO.setRefCanSeparateAmount(canSeparateAmt); // 拉卡拉实时返回的可分账金额
// 分账方式根据可分账金额分账
LklSeparateDTO.SharingResult canSeparateAmtResult = lklSeparateDTO.sharingOnCanSeparateAmount();
if (!canSeparateAmtResult.isSuccess()) {
log.error("[分账操作] 分账参数评估,结果无法分账 {}", lklSeparateDTO);
return Pair.of(false, "分账参数评估,结果无法分账");
if (calcResult == null || !calcResult.getFirst() || calcResult.getSecond() == null) {
log.error("[分账操作] 分账参数评估,结果无法分账");
return Pair.of(false, "分账数据评估,结果无法分账");
}
LklSeparateDTO lklSeparateDTO = calcResult.getSecond();
log.debug("[分账操作] 分账参数计算结果:{}", lklSeparateDTO);
// 更新分账计算结果
shopOrderLkl.setSeparate_remark(lklSeparateDTO.toString()); // 写入分账具体情况
if (CheckUtil.isEmpty(canSeparateAmt)) {
if (CheckUtil.isEmpty(refCanSeparateAmt)) {
shopOrderLkl.setSplit_amt(lklSeparateDTO.getCanSeparateAmount());
canSeparateAmt = lklSeparateDTO.getCanSeparateAmount();
refCanSeparateAmt = lklSeparateDTO.getCanSeparateAmount();
} else {
shopOrderLkl.setSplit_amt_ref(canSeparateAmt);
shopOrderLkl.setSplit_amt_ref(refCanSeparateAmt);
}
shopOrderLklService.safeUpdate(shopOrderLkl);
// 分账金额校验
if (canSeparateAmt <= 0) {
if (CheckUtil.isEmpty(refCanSeparateAmt)) {
String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱跳过分账",
shopOrderLkl.getStore_id(), orderId, canSeparateAmt);
shopOrderLkl.getStore_id(), orderId, refCanSeparateAmt);
log.error(errorMsg);
if (existingSeparateRecord != null) {
lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg);
@ -2574,7 +2569,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
Integer agentAmount = lklSeparateDTO.getAgent2ndAmount();
log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 可分金额={}分, 商家比例={}, 商家分得={}分, 平台比例={}, 平台分得={}分, 代理商比例={}, 代理商分得={}分",
orderId, merchantNo, shopOrderLkl.getTotal_amt(), canSeparateAmt, mchSplitRatio, merchantAmount,
orderId, merchantNo, shopOrderLkl.getTotal_amt(), refCanSeparateAmt, mchSplitRatio, merchantAmount,
platformSplitRatio, platformAmount, distributorSplitRatio, agentAmount);
// 构建分账接收方分账参数
@ -2598,11 +2593,14 @@ public class LakalaApiServiceImpl implements LakalaApiService {
// 二级代理商县级分账参数
if (agentAmount != null && agentAmount > 0 && CollUtil.isNotEmpty(distributorReceivers)) {
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
receiver.setRecvNo(distributorReceivers.get(0).getReceiver_no());
receiver.setSeparateValue(agentAmount.toString());
recvDatas.add(receiver);
log.debug("[分账操作] 添加代理商接收方: receiverNo={}, amount={}", distributorReceivers.get(0).getReceiver_no(), agentAmount);
LklLedgerMerReceiverBind distributorReceiver = distributorReceivers.get(0);
if (distributorReceiver != null && StrUtil.isNotBlank(distributorReceiver.getReceiver_no())) {
V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas();
receiver.setRecvNo(distributorReceiver.getReceiver_no());
receiver.setSeparateValue(agentAmount.toString());
recvDatas.add(receiver);
log.debug("[分账操作] 添加代理商接收方: receiverNo={}, amount={}", distributorReceiver.getReceiver_no(), agentAmount);
}
}
// 初始化拉卡拉SDK
@ -2615,7 +2613,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
separateRequest.setOutSeparateNo(shopOrderLkl.getOut_separate_no());
separateRequest.setLogNo(shopOrderLkl.getLkl_receive_log_no()); // 使用确认收货流水号作为分账流水号
separateRequest.setLogDate(shopOrderLkl.getLkl_log_date());
separateRequest.setTotalAmt(canSeparateAmt.toString());
separateRequest.setTotalAmt(refCanSeparateAmt.toString());
separateRequest.setLklOrgNo(orgCode);
separateRequest.setCalType("0"); // 0- 按照指定金额1- 按照指定比例默认 0
separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify");
@ -2650,6 +2648,9 @@ public class LakalaApiServiceImpl implements LakalaApiService {
(respJson != null ? respJson.getStr("msg") : "未知错误"));
}
// 只有在分账请求成功发送后才更新分账备注
shopOrderLklService.safeUpdate(shopOrderLkl);
// 保存分账记录
JSONObject respData = respJson.getJSONObject("resp_data");
LklOrderSeparate separateRecord = new LklOrderSeparate();
@ -2665,7 +2666,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas()));
separateRecord.setStatus(respData.getStr("status"));
separateRecord.setTotal_amt(separateRequest.getTotalAmt());
separateRecord.setActual_separate_amt(Convert.toStr(canSeparateAmt));
separateRecord.setActual_separate_amt(Convert.toStr(refCanSeparateAmt));
separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTO.getLklAmount()));
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {

View File

@ -172,6 +172,13 @@ public class OrderPayedListener {
// 处理异常不抛出以免影响到主流程
try {
// 检查是否已发送过推送消息幂等性检查
String pushFlagKey = RedisConstant.New_Order_Push_Flag_Key + orderId;
if (redisService.get(pushFlagKey) != null) {
logger.info("[订单支付监听] 推送消息已发送,跳过重复推送. 订单ID: {}", orderId);
continue;
}
// 同城配送或普通快递都发送 unipush 推送您有一个新的订单请查收
String orderType = orderInfoOld.getDelivery_type_id() == StateCode.DELIVERY_TYPE_SAME_CITY ? "同城" : "";
String title = String.format("您有一笔新的%s订单请注意查收。", orderType);
@ -189,9 +196,13 @@ public class OrderPayedListener {
mchOrderExpireSeconds = shopOrderBaseService.sameCityOrderExpireSeconds(1500L);
redisService.set(RedisConstant.SF_Order_Proc_Expire_Key + String.format("%d&%s", orderInfoOld.getStore_id(), orderId), orderId, mchOrderExpireSeconds);
// 记录推送已发送状态避免重复推送
redisService.set(pushFlagKey, "1", 24 * 3600); // 24小时过期
} catch (Exception e) {
log.error("[订单支付监听] 发送推送消息失败. 订单ID: {}", orderId, e);
}
}
}
}