Compare commits
26 Commits
1a841f3f85
...
c7ab97f948
| Author | SHA1 | Date | |
|---|---|---|---|
| c7ab97f948 | |||
| 3e7c7f8cd9 | |||
| c1b872c8a2 | |||
| 8b2a127ce3 | |||
| 4ff33b938d | |||
| 1d4b884215 | |||
| 57504c9458 | |||
| afaca094f5 | |||
| 62d76b3a67 | |||
| ce85d72cee | |||
| 2a4dfe2b24 | |||
| c438e4b3b9 | |||
| 7fdd03b23e | |||
| f2a07771b2 | |||
| 8eb1e4f59f | |||
| 8687a295c0 | |||
| 129ba5b394 | |||
| 62b5d71b3b | |||
| f9f7fc1688 | |||
| 22cfe81958 | |||
| c7c951638c | |||
| 77fdb27275 | |||
| 43f88175cd | |||
| 1d72343004 | |||
| f16efdd8b9 | |||
| 9f62bf8ddd |
@ -110,4 +110,9 @@ public class CommonConstant {
|
||||
//秒杀活动订阅消息模板id
|
||||
public static final String BIND_SUB_TMPL_SKILL = "kiDj_hSF_ASwD-Dlgxnypi6IJBQZ12a-hEpd3zZ-Uxc";
|
||||
|
||||
//分账计算方式:1-按总金额;2-按可分账金额;
|
||||
public static final int SeparateCalcMode_TotalAmt = 1;
|
||||
public static final int SeparateCalcMode_CanSeparateAmt = 2;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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:";
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.suisung.mall.common.exception;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.api.ResultCode;
|
||||
import io.seata.rm.datasource.exec.LockWaitTimeoutException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@ -91,13 +92,14 @@ public class GlobalExceptionHandler {
|
||||
/**
|
||||
* 处理系统级异常(数据库异常/通用异常)
|
||||
*/
|
||||
@ExceptionHandler({SQLException.class, DataAccessException.class, Exception.class})
|
||||
@ExceptionHandler({SQLException.class, DataAccessException.class, LockWaitTimeoutException.class, Exception.class})
|
||||
public CommonResult handleSystemException(HttpServletRequest req, Exception e) {
|
||||
logError(req, e.getMessage(), e);
|
||||
|
||||
if (e instanceof SQLException || e instanceof DataAccessException) {
|
||||
return CommonResult.failed("系统数据异常,请联系管理员!");
|
||||
}
|
||||
|
||||
return CommonResult.failed("系统内部异常,请联系管理员!");
|
||||
}
|
||||
|
||||
|
||||
@ -92,6 +92,9 @@ public class ShopOrderData implements Serializable {
|
||||
@ApiModelProperty(value = "实际运费金额-卖家可修改")
|
||||
private BigDecimal order_shipping_fee;
|
||||
|
||||
@ApiModelProperty(value = "平台内部运费金额")
|
||||
private BigDecimal order_shipping_fee_inner;
|
||||
|
||||
@ApiModelProperty(value = "总计分账金额(从拉卡拉上分账,分给平台和代理商费用),单位:元")
|
||||
private BigDecimal total_separate_value;
|
||||
|
||||
|
||||
@ -72,6 +72,8 @@ public class MchOrderInfoDTO implements Serializable {
|
||||
private Integer delivery_type_id;
|
||||
@ApiModelProperty(value = "订单运费")
|
||||
private BigDecimal order_shipping_fee;
|
||||
@ApiModelProperty(value = "平台内部配送费")
|
||||
private BigDecimal order_shipping_fee_inner;
|
||||
@ApiModelProperty(value = "平台费")
|
||||
private BigDecimal platform_fee;
|
||||
@ApiModelProperty(value = "店铺统一设置的打包费")
|
||||
|
||||
@ -61,15 +61,15 @@ public class LklSeparateDTO {
|
||||
// 测试基于可分账金额的分账算法(正常情况)
|
||||
System.out.println("\n=== 基于可分账金额的分账算法测试(正常情况) ===");
|
||||
LklSeparateDTO dto2 = new LklSeparateDTO();
|
||||
dto2.setTotalSeparateAmount(1); // 分账总额 1000分
|
||||
dto2.setShippingFee(0); // 配送费 100分
|
||||
dto2.setTotalSeparateAmount(1000); // 分账总额 1000分
|
||||
dto2.setShippingFee(500); // 配送费 100分
|
||||
// dto2.setRefCanSeparateAmount(null);
|
||||
dto2.setLklRatio(new BigDecimal("0.0025")); // 拉卡拉分账比例 0.0025
|
||||
dto2.setMchRatio(new BigDecimal("0.94")); // 商家分账比例 0.857 (会产生小数)
|
||||
dto2.setPlatRatio(new BigDecimal("0.01")); // 平台分账比例 0.01
|
||||
dto2.setMchRatio(new BigDecimal("0.95")); // 商家分账比例 0.857 (会产生小数)
|
||||
dto2.setPlatRatio(new BigDecimal("0.05")); // 平台分账比例 0.01
|
||||
// 不设置一级和二级代理商分账比例,测试不参与分账的情况
|
||||
// dto2.setAgent1stRatio(new BigDecimal("0.01")); // 一级代理商分账比例 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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理推送响应
|
||||
*/
|
||||
|
||||
@ -188,28 +188,80 @@ public class CheckUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验数据的某个字段是否为指定值
|
||||
*
|
||||
* @param value 指定值的字段值
|
||||
* @param data 需要对比的数据Map
|
||||
* @param key 字段名
|
||||
* @return boolean 字段值等于指定值返回true,否则返回false
|
||||
*/
|
||||
public static boolean checkDataRights(Integer value, Map data, String key) {
|
||||
if (CollUtil.isEmpty(data)) return false;
|
||||
// 检查数据是否为空或key是否为空
|
||||
if (CollUtil.isEmpty(data) || StrUtil.isBlank(key)) {
|
||||
log.debug("数据为空或key为空, data: {}, key: {}", data, key);
|
||||
return false;
|
||||
}
|
||||
// 从数据中获取指定key的值并转换为Integer类型
|
||||
Integer _value = Convert.toInt(data.get(key));
|
||||
return ObjectUtil.equal(_value, value);
|
||||
// 比较获取的值与指定值是否相等
|
||||
boolean result = ObjectUtil.equal(_value, value);
|
||||
log.info("校验数据权限, key: {}, 值: {}==数据值: {} ? 结果: {}", key, value, _value, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验数据对象的某个字段是否为指定值
|
||||
*
|
||||
* @param value 指定值的字段值
|
||||
* @param data 需要对比的数据对象
|
||||
* @param idMapper 获取数据对象ID的函数
|
||||
* @param <T> 数据对象类型
|
||||
* @return boolean 字段值等于指定值返回true,否则返回false
|
||||
*/
|
||||
public static <T> boolean checkDataRights(Integer value, T data, Function<T, Integer> idMapper) {
|
||||
if (ObjectUtil.isEmpty(data)) return false;
|
||||
// 检查数据对象或映射函数是否为空
|
||||
if (ObjectUtil.isEmpty(data) || ObjectUtil.isEmpty(idMapper)) {
|
||||
log.debug("数据对象或映射函数为空, data: {}, idMapper: {}", data, idMapper);
|
||||
return false;
|
||||
}
|
||||
// 通过映射函数获取数据对象的值
|
||||
Object _value = idMapper.apply(data);
|
||||
return ObjectUtil.equal(_value, value);
|
||||
// 比较获取的值与指定值是否相等
|
||||
boolean result = ObjectUtil.equal(_value, value);
|
||||
log.debug("校验单个对象数据权限, 值: {}, 数据值: {}, 结果: {}", value, _value, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验数据列表中每个对象的某个字段是否为指定值
|
||||
*
|
||||
* @param value 指定值的字段值
|
||||
* @param data 需要对比的数据列表
|
||||
* @param idMapper 获取数据对象ID的函数
|
||||
* @param <T> 数据对象类型
|
||||
* @return boolean 所有对象字段值都等于指定值返回true,否则返回false
|
||||
*/
|
||||
public static <T> boolean checkDataRights(Integer value, List<T> data, Function<T, Integer> idMapper) {
|
||||
if (CollUtil.isEmpty(data)) return false;
|
||||
// 检查数据列表或映射函数是否为空
|
||||
if (CollUtil.isEmpty(data) || ObjectUtil.isEmpty(idMapper)) {
|
||||
log.debug("数据列表或映射函数为空, 数据大小: {}, 映射函数: {}",
|
||||
data != null ? data.size() : 0, idMapper);
|
||||
return false;
|
||||
}
|
||||
// 遍历数据列表中的每个对象
|
||||
for (T datum : data) {
|
||||
// 递归校验每个对象,如果有任何一个不匹配则返回false
|
||||
if (!checkDataRights(value, datum, idMapper)) {
|
||||
log.debug("列表数据权限校验失败,失败项: {}", datum);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
log.debug("列表数据权限校验成功, 数据大小: {}, 值: {}", data.size(), value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static String addslashes(String str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.suisung.mall.pay.controller.admin;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.modules.order.ShopOrderReturn;
|
||||
@ -17,6 +18,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -56,6 +58,8 @@ public class PayController {
|
||||
private PayPlantformResourceService payPlantformResourceService;
|
||||
@Autowired
|
||||
private PayUserPayService payUserPayService;
|
||||
@Autowired
|
||||
private LakalaPayService lakalaPayService;
|
||||
|
||||
@ApiOperation(value = "根据user_id 删除门店顾客关系数据", notes = "根据user_id 删除门店顾客关系数据")
|
||||
@RequestMapping(value = "/deleteUserChainByUid", method = RequestMethod.POST)
|
||||
@ -410,8 +414,22 @@ public class PayController {
|
||||
@ApiOperation(value = "批量保存", notes = "用户资源表")
|
||||
@RequestMapping(value = "/saveBatchPayUserResources", method = {RequestMethod.POST})
|
||||
public ThirdApiRes saveBatchPayUserResources(@RequestBody List<PayUserResource> payUserResourceList) {
|
||||
return payUserPayService.saveBatchPayUserResources(payUserResourceList);
|
||||
return payUserPayService.saveBatchPayUserResources(payUserResourceList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款通知
|
||||
*/
|
||||
@ApiOperation(value = "【测试】平台强制到拉卡拉退款", notes = "平台强制到拉卡拉退款")
|
||||
@RequestMapping(value = "/lkl/refund", method = {RequestMethod.POST})
|
||||
public CommonResult refundFromLakala(HttpServletRequest request, @RequestBody JSONArray returnJsonArray) {
|
||||
Pair<Boolean, String> pair = lakalaPayService.innerLklRefundForDemo(request, returnJsonArray);
|
||||
if (pair.getFirst()) {
|
||||
return CommonResult.success(pair.getSecond());
|
||||
}
|
||||
return CommonResult.failed(pair.getSecond());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -8,9 +8,12 @@
|
||||
|
||||
package com.suisung.mall.pay.service;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface LakalaPayService {
|
||||
|
||||
Boolean initLKLSDK();
|
||||
@ -70,6 +73,28 @@ public interface LakalaPayService {
|
||||
*/
|
||||
Pair<Boolean, String> innerLklRefund(Integer storeId, String outTradeNo, String originTradeNo, String refundAmount, String refundReason, String lklMerchantNo, String lklTermNo);
|
||||
|
||||
|
||||
/**
|
||||
* 执行内部拉卡拉交易退款(测试)
|
||||
* 参考地址:https://o.lakala.com/#/home/document/detail?id=113
|
||||
* 参数示例
|
||||
* [
|
||||
* {
|
||||
* "sub_trade_no": "20251009110113130266250070712668",
|
||||
* "merchant_no": "822584059990FYP",
|
||||
* "amount": "500",
|
||||
* "settle_type": "0",
|
||||
* "sub_log_no": "66250070712668",
|
||||
* "out_sub_trade_no": "DF_DD_20251009_2",
|
||||
* "term_no": "N5811590"
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* @param returnJsonArray 退款信息数组
|
||||
* @return Pair<Boolean, String>,包含退款是否成功以及消息
|
||||
*/
|
||||
Pair<Boolean, String> innerLklRefundForDemo(HttpServletRequest request, JSONArray returnJsonArray);
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=90
|
||||
|
||||
@ -22,6 +22,7 @@ import com.lkl.laop.sdk.request.V2MmsOpenApiUploadFileRequest;
|
||||
import com.lkl.laop.sdk.request.V3LabsRelationRefundRequest;
|
||||
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
|
||||
import com.suisung.mall.common.constant.CommonConstant;
|
||||
import com.suisung.mall.common.domain.UserDto;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.common.feignService.ShopService;
|
||||
import com.suisung.mall.common.modules.store.ShopStoreBase;
|
||||
@ -44,6 +45,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.suisung.mall.common.utils.ContextUtil.getCurrentUser;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -574,6 +577,10 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
|
||||
// TODO 重要的逻辑,获取是否已经分账?已分账:分账退回;查商家账户余额够不够退回?够就执行退回
|
||||
|
||||
if (StrUtil.isBlank(refundReason)) {
|
||||
refundReason = "商家与买方协商退款";
|
||||
}
|
||||
|
||||
// 5. 构造退款请求并发送
|
||||
V3LabsRelationRefundRequest refundRequest = new V3LabsRelationRefundRequest();
|
||||
refundRequest.setOutTradeNo(outTradeNo);
|
||||
@ -630,6 +637,138 @@ public class LakalaPayServiceImpl implements LakalaPayService {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行内部拉卡拉交易退款
|
||||
* 参考地址:https://o.lakala.com/#/home/document/detail?id=113
|
||||
* 参数示例
|
||||
* [
|
||||
* {
|
||||
* "sub_trade_no": "20251009110113130266250070712668",
|
||||
* "merchant_no": "822584059990FYP",
|
||||
* "amount": "500",
|
||||
* "settle_type": "0",
|
||||
* "sub_log_no": "66250070712668",
|
||||
* "out_sub_trade_no": "DF_DD_20251009_2",
|
||||
* "term_no": "N5811590"
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* @param returnJsonArray 退款信息数组
|
||||
* @return Pair<Boolean, String>,包含退款是否成功以及消息
|
||||
*/
|
||||
@Override
|
||||
public Pair<Boolean, String> innerLklRefundForDemo(HttpServletRequest request, JSONArray returnJsonArray) {
|
||||
try {
|
||||
log.info("[拉卡拉退款Demo] 开始执行拉卡拉内部退款,退款订单数: {}",
|
||||
returnJsonArray != null ? returnJsonArray.size() : 0);
|
||||
|
||||
UserDto userDto = getCurrentUser();
|
||||
if (userDto == null || !userDto.isAdmin()) {
|
||||
log.error("[拉卡拉退款Demo] 非管理员用户尝试执行退款, userId={}",
|
||||
userDto != null ? userDto.getId() : "unknown");
|
||||
return Pair.of(false, I18nUtil._("非管理员用户尝试执行拉卡拉内部退款,请勿非法操作!"));
|
||||
}
|
||||
|
||||
if (returnJsonArray == null || returnJsonArray.isEmpty()) {
|
||||
log.error("[拉卡拉退款Demo] 退款信息为空");
|
||||
return Pair.of(false, I18nUtil._("退款信息为空,退款失败!"));
|
||||
}
|
||||
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
log.error("[拉卡拉退款Demo] 无法获取请求上下文");
|
||||
return Pair.of(false, I18nUtil._("系统异常,无法获取请求信息!"));
|
||||
}
|
||||
|
||||
String requestIp = IpKit.getRealIp(request);
|
||||
if (StrUtil.isBlank(requestIp)) {
|
||||
requestIp = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
String refundReason = "系统触发退款";
|
||||
int successCount = 0;
|
||||
int totalCount = returnJsonArray.size();
|
||||
|
||||
// 初始化拉卡拉SDK
|
||||
initLKLSDK();
|
||||
|
||||
for (int i = 0; i < returnJsonArray.size(); i++) {
|
||||
JSONObject returnJsonObject = returnJsonArray.getJSONObject(i);
|
||||
|
||||
// 参数提取
|
||||
String outTradeNo = returnJsonObject.getStr("out_sub_trade_no");
|
||||
String originTradeNo = returnJsonObject.getStr("sub_trade_no");
|
||||
String refundAmount = returnJsonObject.getStr("amount");
|
||||
String lklMerchantNo = returnJsonObject.getStr("merchant_no");
|
||||
String lklTermNo = returnJsonObject.getStr("term_no");
|
||||
|
||||
// 参数校验
|
||||
if (StrUtil.hasBlank(outTradeNo, originTradeNo, refundAmount, lklMerchantNo, lklTermNo)) {
|
||||
log.warn("[拉卡拉退款Demo] 第{}笔退款参数不完整, 跳过处理", i + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 金额格式校验
|
||||
if (!refundAmount.matches("\\d+") || Integer.parseInt(refundAmount) <= 0) {
|
||||
log.warn("[拉卡拉退款Demo] 第{}笔退款金额格式不正确: {}, 跳过处理", i + 1, refundAmount);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 构造退款请求
|
||||
V3LabsRelationRefundRequest refundRequest = new V3LabsRelationRefundRequest();
|
||||
refundRequest.setOutTradeNo(outTradeNo);
|
||||
refundRequest.setOriginTradeNo(originTradeNo);
|
||||
refundRequest.setMerchantNo(lklMerchantNo);
|
||||
refundRequest.setTermNo(lklTermNo);
|
||||
refundRequest.setRefundAmount(refundAmount);
|
||||
refundRequest.setRefundReason(refundReason);
|
||||
refundRequest.setLocationInfo(new V3LabsTradeLocationInfo(requestIp, null, ""));
|
||||
|
||||
// 发送请求
|
||||
String responseString = LKLSDK.httpPost(refundRequest);
|
||||
|
||||
// 处理响应
|
||||
if (StrUtil.isBlank(responseString)) {
|
||||
log.error("[拉卡拉退款Demo] 第{}笔退款无响应, outTradeNo={}", i + 1, outTradeNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject lakalaResponseJson = JSONUtil.parseObj(responseString);
|
||||
if (lakalaResponseJson == null) {
|
||||
log.error("[拉卡拉退款Demo] 第{}笔退款响应解析失败, outTradeNo={}", i + 1, outTradeNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
String responseCode = lakalaResponseJson.getStr("code");
|
||||
if (StrUtil.isBlank(responseCode)) {
|
||||
log.error("[拉卡拉退款Demo] 第{}笔退款响应码为空, outTradeNo={}", i + 1, outTradeNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!"BBS00000".equals(responseCode)) {
|
||||
String errorMessage = lakalaResponseJson.getStr("msg", "未知错误");
|
||||
log.error("[拉卡拉退款Demo] 第{}笔退款失败, 响应码: {}, 错误信息: {}, outTradeNo={}",
|
||||
i + 1, responseCode, errorMessage, outTradeNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
successCount++;
|
||||
log.info("[拉卡拉退款Demo] 第{}笔退款成功, outTradeNo={}", i + 1, outTradeNo);
|
||||
}
|
||||
|
||||
log.info("[拉卡拉退款Demo] 退款处理完成,总笔数: {}, 成功笔数: {}", totalCount, successCount);
|
||||
return Pair.of(true, I18nUtil._("退款成功!") + successCount + "笔/" + totalCount + "笔");
|
||||
|
||||
} catch (SDKException e) {
|
||||
log.error("[拉卡拉退款Demo] SDK异常", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款SDK异常,退款失败!") + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("[拉卡拉退款Demo] 未知异常", e);
|
||||
return Pair.of(false, I18nUtil._("拉卡拉退款发生未知异常,退款失败!") + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* 参考:https://o.lakala.com/#/home/document/detail?id=90
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -27,7 +27,7 @@ public class UpdateOrderSeparateJob extends QuartzJobBean {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer processedCount = lakalaApiService.fixedUnSuccessSeparateStatusJob();
|
||||
Integer processedCount = lakalaApiService.fixUnSuccessSeparateStatusJob();
|
||||
|
||||
logger.info("[分账状态修复定时任务] 执行完成,共处理 {} 条记录", processedCount);
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -49,7 +49,7 @@ public class LakalaAdminController extends BaseControllerImpl {
|
||||
}
|
||||
|
||||
// 执行业务逻辑
|
||||
Boolean success = lakalaPayService.ewalletWithDrawD1(paramsJSON.getStr("mercId"), paramsJSON.getStr("merOrderNo"), paramsJSON.getStr("drawAmt"), paramsJSON.getStr("remark"), paramsJSON.getStr("summary"));
|
||||
Boolean success = lakalaPayService.ewalletWithDrawD1(paramsJSON.getStr("mercId"), paramsJSON.getStr("merOrderNo"), paramsJSON.getStr("drawAmt"), paramsJSON.getStr("summary"));
|
||||
if (success) {
|
||||
return CommonResult.success("账户D1提现提交成功");
|
||||
}
|
||||
|
||||
@ -11,9 +11,11 @@ package com.suisung.mall.shop.lakala.service;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.modules.store.ShopMchEntry;
|
||||
import com.suisung.mall.common.pojo.dto.LklSeparateDTO;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 拉卡拉业务接口
|
||||
@ -299,7 +301,7 @@ public interface LakalaApiService {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Integer fixedUnSuccessSeparateStatusJob();
|
||||
Integer fixUnSuccessSeparateStatusJob();
|
||||
|
||||
/**
|
||||
* 检测修复补全商户的商户分账业务信息及分账接收方绑定关系(分账业务申请异步通知的补偿机制)
|
||||
@ -337,10 +339,9 @@ public interface LakalaApiService {
|
||||
* @param mercId 822商户号或receiveNo
|
||||
* @param merOrderNo 商户订单号
|
||||
* @param drawAmt 提现金额(分)
|
||||
* @param remark
|
||||
* @param summary
|
||||
*/
|
||||
Boolean ewalletWithDrawD1(String mercId, String merOrderNo, String drawAmt, String remark, String summary);
|
||||
Boolean ewalletWithDrawD1(String mercId, String merOrderNo, String drawAmt, String summary);
|
||||
|
||||
/**
|
||||
* 拉卡拉账户D1提现结果通知
|
||||
@ -351,4 +352,26 @@ public interface LakalaApiService {
|
||||
*/
|
||||
JSONObject ewalletWithDrawNotify(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* 商户分账参数计算及评估
|
||||
*
|
||||
* @param splitMode 分账模式:1-总金额为基准分账,2-可分账金额基准分账,必填参数
|
||||
* @param orderPayAmount 订单支付总金额(单位:分)必填参数
|
||||
* @param shippingFeeInner 平台内部配送费(单位:分)必填参数
|
||||
* @param mchSplitRatioRaw 商户分账比例值(分子值,如10表示10%)必填参数
|
||||
* @param platSplitRatio 平台分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param agent1stRatio 一级分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param agent2ndRatio 二级分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param refCanSeparateAmt 参考可分金额(单位:分) 可选参数
|
||||
* @return Pair<Boolean, LklSeparateDTO> 分账参数评估结果,第一个元素表示是否成功,第二个元素为分账参数对象
|
||||
*/
|
||||
Pair<Boolean, LklSeparateDTO> calculateAndEvaluateSharingParams(int splitMode,
|
||||
Integer orderPayAmount,
|
||||
Integer shippingFeeInner,
|
||||
BigDecimal mchSplitRatioRaw,
|
||||
BigDecimal platSplitRatio,
|
||||
BigDecimal agent1stRatio,
|
||||
BigDecimal agent2ndRatio,
|
||||
Integer refCanSeparateAmt);
|
||||
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ import com.suisung.mall.shop.lakala.utils.LakalaUtil;
|
||||
import com.suisung.mall.shop.message.service.PushMessageService;
|
||||
import com.suisung.mall.shop.message.service.ShopMessageTemplateService;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderBaseService;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderInfoService;
|
||||
import com.suisung.mall.shop.order.service.ShopOrderLklService;
|
||||
import com.suisung.mall.shop.page.service.OssService;
|
||||
import com.suisung.mall.shop.store.service.ShopMchEntryService;
|
||||
@ -153,6 +154,10 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
@Resource
|
||||
private ShopOrderBaseService shopOrderBaseService;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private ShopOrderInfoService shopOrderInfoService;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private PushMessageService pushMessageService;
|
||||
@ -772,7 +777,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
|
||||
/**
|
||||
* 发货类交易确认收货通知处理
|
||||
* 发货类交易确认收货通知处理, 微信通知拉卡拉,拉卡拉通知我们系统,已经完成确认收货
|
||||
* <p>
|
||||
* 参考文档:https://o.lakala.com/#/home/document/detail?id=1003
|
||||
* </p>
|
||||
@ -2466,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);
|
||||
}
|
||||
@ -2488,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, "商家分账比例有误");
|
||||
@ -2500,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);
|
||||
@ -2569,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);
|
||||
|
||||
// 构建分账接收方分账参数
|
||||
@ -2593,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
|
||||
@ -2610,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");
|
||||
@ -2645,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();
|
||||
@ -2660,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)) {
|
||||
@ -2693,13 +2699,14 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
* 参考文档:https://o.lakala.com/#/home/document/detail?id=393
|
||||
* </p>
|
||||
*
|
||||
* @param request
|
||||
* @param request HTTP请求对象,包含拉卡拉分账结果通知的参数
|
||||
* @param merchantNoParam 分账方商户号,非空表示是事后补偿
|
||||
* @param separateNoParam 分账指令流水号,非空表示是事后补偿
|
||||
* <ul>
|
||||
* <li>成功: {"code": "SUCCESS", "message": "操作成功"}</li>
|
||||
* <li>失败: {"code": "FAIL", "message": "错误信息"}</li>
|
||||
* </ul>
|
||||
* @return 处理结果JSON对象
|
||||
* <ul>
|
||||
* <li>成功: {"code": "SUCCESS", "message": "操作成功"}</li>
|
||||
* <li>失败: {"code": "FAIL", "message": "错误信息"}</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public JSONObject sacsSeparateNotify(HttpServletRequest request, String merchantNoParam, String separateNoParam) {
|
||||
@ -2708,7 +2715,8 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
JSONObject paramsJson = null;
|
||||
if (!StrUtil.hasBlank(merchantNoParam, separateNoParam)) {
|
||||
channel = "(补偿)";
|
||||
log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调 merchantNoParam={},separateNoParam={}" + channel, merchantNoParam, separateNoParam);
|
||||
log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调{},merchantNoParam={},separateNoParam={}",
|
||||
channel, merchantNoParam, separateNoParam);
|
||||
paramsJson = sacsQuery(merchantNoParam, separateNoParam);
|
||||
} else {
|
||||
log.info("[拉卡拉分账通知] 开始处理拉卡拉分账结果通知异步回调");
|
||||
@ -2742,15 +2750,15 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
String status = paramsJson.getStr("status");
|
||||
String finalStatus = paramsJson.getStr("final_status");
|
||||
|
||||
// 必要参数
|
||||
// 必要参数校验
|
||||
List<String> missingParams = new ArrayList<>();
|
||||
if (StrUtil.isBlank(outSeparateNo)) missingParams.add("outSeparateNo");
|
||||
if (StrUtil.isBlank(separateNo)) missingParams.add("separateNo");
|
||||
if (StrUtil.isBlank(status)) missingParams.add("status");
|
||||
|
||||
if (!missingParams.isEmpty()) {
|
||||
String errorMsg = "分账通知缺少必要参数" + channel + String.join(", ", missingParams);
|
||||
log.error("[拉卡拉分账通知] {} {},参数详情: {}", channel, errorMsg, paramsJson);
|
||||
String errorMsg = "分账通知缺少必要参数" + channel + ": " + String.join(", ", missingParams);
|
||||
log.error("[拉卡拉分账通知] {},参数详情: {}", errorMsg, paramsJson);
|
||||
return JSONUtil.createObj()
|
||||
.put("code", "FAIL")
|
||||
.put("message", errorMsg);
|
||||
@ -2761,7 +2769,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
if (lklOrderSeparateExist == null) {
|
||||
String errorMsg = "未找到对应的分账记录" + channel;
|
||||
log.error("[拉卡拉分账通知] {},外部分账单号={},分账单号={},参数详情: {}",
|
||||
errorMsg, outSeparateNo, separateNoParam, paramsJson);
|
||||
errorMsg, outSeparateNo, separateNo, paramsJson);
|
||||
return JSONUtil.createObj()
|
||||
.put("code", "FAIL")
|
||||
.put("message", errorMsg);
|
||||
@ -2779,8 +2787,8 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
}
|
||||
|
||||
// 6. 记录关键参数信息,便于问题排查
|
||||
log.info("[拉卡拉分账通知] 接收到分账通知,分账单号={},外部分账单号={},状态={},最终状态={}" + channel,
|
||||
separateNo, outSeparateNo, status, finalStatus);
|
||||
log.info("[拉卡拉分账通知] 接收到分账通知{},分账单号={},外部分账单号={},状态={},最终状态={}",
|
||||
channel, separateNo, outSeparateNo, status, finalStatus);
|
||||
|
||||
// 7. 构建分账记录对象 - 准备更新数据库的分账记录
|
||||
LklOrderSeparate lklOrderSeparate = new LklOrderSeparate();
|
||||
@ -2819,14 +2827,34 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
// 更改分账状态:分账成功
|
||||
shopOrderLklService.updateSeparateStatusByReceiveLogNo(logNo, CommonConstant.Sta_Separate_Success, "");
|
||||
|
||||
// 本次分账成功后,给商户和接收方 D1提现到银行卡
|
||||
if (CollUtil.isNotEmpty(detailDatas)) {
|
||||
int idx = 1;
|
||||
for (JSONObject detailData : detailDatas.jsonIter()) {
|
||||
if (detailData == null || detailData.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String recvNo = Convert.toStr(detailData.get("recv_no"), "");
|
||||
String amt = Convert.toStr(detailData.get("amt"), "");
|
||||
if (StrUtil.isNotBlank(recvNo) && StrUtil.isNotBlank(amt)) {
|
||||
String outSeparateNoTemp = String.format("%s_%d", outSeparateNo, idx);
|
||||
Boolean drawSuccess = ewalletWithDrawD1(recvNo, outSeparateNoTemp, amt, JSONUtil.toJsonStr(detailDatas));
|
||||
log.info("[拉卡拉分账通知] 账户D1提现{},商户号={},分账单号={},金额={}分",
|
||||
Boolean.TRUE.equals(drawSuccess) ? "成功" : "失败", recvNo, outSeparateNoTemp, amt);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9. 记录处理成功日志
|
||||
log.info("[拉卡拉分账通知] 分账通知处理成功, separateNo={}, status={}" + channel, separateNo, status);
|
||||
log.info("[拉卡拉分账通知] 分账通知处理成功{},separateNo={},status={}", channel, separateNo, status);
|
||||
return JSONUtil.createObj()
|
||||
.put("code", "SUCCESS")
|
||||
.put("message", "操作成功");
|
||||
} catch (Exception e) {
|
||||
// 10. 异常处理
|
||||
String errorMsg = String.format("分账通知数据处理异常: %s" + channel, e.getMessage());
|
||||
String errorMsg = String.format("分账通知数据处理异常: %s%s", e.getMessage(), channel);
|
||||
log.error("[拉卡拉分账通知] {}", errorMsg, e);
|
||||
return JSONUtil.createObj()
|
||||
.put("code", "FAIL")
|
||||
@ -2920,15 +2948,15 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
* @return 成功处理的记录数量
|
||||
*/
|
||||
@Override
|
||||
public Integer fixedUnSuccessSeparateStatusJob() {
|
||||
public Integer fixUnSuccessSeparateStatusJob() {
|
||||
log.info("[分账状态修复任务] 开始执行未成功分账记录的状态修复任务");
|
||||
|
||||
// 获取3天前分账状态未成功的记录
|
||||
// 获取2天前分账状态未成功的记录
|
||||
Date now = new Date();
|
||||
Date threeDaysAgo = DateUtils.addHours(now, -72);
|
||||
Date threeDaysAgo = DateUtils.addHours(now, -48);
|
||||
|
||||
// 分页参数
|
||||
int pageSize = 100;
|
||||
int pageSize = 200;
|
||||
int currentPage = 1;
|
||||
int totalSuccessCount = 0;
|
||||
int totalProcessed = 0;
|
||||
@ -3384,12 +3412,11 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
* @param mercId 822商户号或receiveNo
|
||||
* @param merOrderNo 商户订单号
|
||||
* @param drawAmt 提现金额(分)
|
||||
* @param remark 备注信息
|
||||
* @param summary 摘要信息
|
||||
* @return 操作结果,成功返回true,失败返回false
|
||||
*/
|
||||
@Override
|
||||
public Boolean ewalletWithDrawD1(String mercId, String merOrderNo, String drawAmt, String remark, String summary) {
|
||||
public Boolean ewalletWithDrawD1(String mercId, String merOrderNo, String drawAmt, String summary) {
|
||||
// 1. 参数校验
|
||||
if (StrUtil.hasBlank(mercId, merOrderNo, drawAmt)) {
|
||||
log.warn("[D1提现申请] D1提现参数校验失败,关键参数为空: mercId={}, merOrderNo={}, drawAmt={}",
|
||||
@ -3399,8 +3426,10 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
|
||||
// 账号类型(01:收款账户,04:分账接收方账户)
|
||||
String payType = "04";
|
||||
String payTypeStr = "接收方账户04";
|
||||
if (StrUtil.startWith(mercId, "822")) {
|
||||
payType = "01";
|
||||
payTypeStr = "收款账户01";
|
||||
}
|
||||
|
||||
try {
|
||||
@ -3411,10 +3440,7 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if (StrUtil.isBlank(remark)) {
|
||||
remark = String.format("商户订单:%s 账号类型:%s 分账后立即提现", merOrderNo, payType);
|
||||
}
|
||||
String remark = String.format("订单:%s %s 分账后立即提现", merOrderNo, payTypeStr);
|
||||
|
||||
log.info("[D1提现申请] 开始处理D1提现,商户号={},订单号={},提现金额={}分", mercId, merOrderNo, drawAmt);
|
||||
|
||||
@ -3587,4 +3613,111 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 商户分账参数计算及评估
|
||||
*
|
||||
* @param splitMode 分账模式:1-总金额为基准分账,2-可分账金额基准分账,必填参数
|
||||
* @param orderPayAmount 订单支付总金额(单位:分)必填参数
|
||||
* @param shippingFeeInner 平台内部配送费(单位:分)必填参数
|
||||
* @param mchSplitRatioRaw 商户分账比例值(分子值,如10表示10%)必填参数
|
||||
* @param platSplitRatio 平台分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param agent1stRatio 一级分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param agent2ndRatio 二级分账比例(百分比值,如0.01表示1%)可选参数
|
||||
* @param refCanSeparateAmt 参考可分金额(单位:分) 可选参数
|
||||
* @return Pair<Boolean, LklSeparateDTO> 分账参数评估结果,第一个元素表示是否成功,第二个元素为分账参数对象
|
||||
*/
|
||||
@Override
|
||||
public Pair<Boolean, LklSeparateDTO> calculateAndEvaluateSharingParams(int splitMode,
|
||||
Integer orderPayAmount,
|
||||
Integer shippingFeeInner,
|
||||
BigDecimal mchSplitRatioRaw,
|
||||
BigDecimal platSplitRatio,
|
||||
BigDecimal agent1stRatio,
|
||||
BigDecimal agent2ndRatio,
|
||||
Integer refCanSeparateAmt) {
|
||||
log.debug("[分账参数计算] 开始计算分账参数: splitMode={}, orderPayAmount={}, shippingFeeInner={}, " +
|
||||
"mchSplitRatioRaw={}, platSplitRatio={}, agent1stRatio={}, agent2ndRatio={}, refCanSeparateAmt={}",
|
||||
splitMode, orderPayAmount, shippingFeeInner, mchSplitRatioRaw, platSplitRatio,
|
||||
agent1stRatio, agent2ndRatio, refCanSeparateAmt);
|
||||
|
||||
// 参数校验
|
||||
if (orderPayAmount == null || orderPayAmount <= 0) {
|
||||
log.warn("[分账参数计算] 订单支付金额参数无效: orderPayAmount={}", orderPayAmount);
|
||||
return Pair.of(false, null);
|
||||
}
|
||||
|
||||
if (mchSplitRatioRaw == null || mchSplitRatioRaw.compareTo(BigDecimal.ZERO) <= 0 || mchSplitRatioRaw.compareTo(BigDecimal.valueOf(100)) > 0) {
|
||||
log.warn("[分账参数计算] 商户分账比例参数无效: mchSplitRatioRaw={}", mchSplitRatioRaw);
|
||||
return Pair.of(false, null);
|
||||
}
|
||||
|
||||
if (splitMode != 1 && splitMode != 2) {
|
||||
log.warn("[分账参数计算] 分账模式参数错误: splitMode={}", splitMode);
|
||||
return Pair.of(false, null);
|
||||
}
|
||||
|
||||
// 计算商家分账比例(转换为小数)
|
||||
BigDecimal mchSplitRatio = mchSplitRatioRaw.divide(new BigDecimal(100));
|
||||
log.debug("[分账参数计算] 商家分账比例转换: {} -> {}", mchSplitRatioRaw, mchSplitRatio);
|
||||
|
||||
// 平台分账比例处理
|
||||
BigDecimal platformSplitRatio = platSplitRatio;
|
||||
if (platformSplitRatio == null || platformSplitRatio.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
platformSplitRatio = BigDecimal.valueOf(0.01); // 默认平台分账1%
|
||||
log.debug("[分账参数计算] 使用默认平台分账比例: {}", platformSplitRatio);
|
||||
}
|
||||
|
||||
// 内部配送费处理
|
||||
Integer actualShippingFeeInner = CheckUtil.isEmpty(shippingFeeInner) ? 0 : shippingFeeInner;
|
||||
BigDecimal wxFeeRatio = StrUtil.isEmpty(wxFee) ? BigDecimal.valueOf(0.0025) : new BigDecimal(wxFee).divide(BigDecimal.valueOf(100));
|
||||
log.debug("[分账参数计算] 配送费: {}, 拉卡拉费率: {}", actualShippingFeeInner, wxFeeRatio);
|
||||
|
||||
// 构建分账参数对象
|
||||
LklSeparateDTO lklSeparateDTO = new LklSeparateDTO();
|
||||
lklSeparateDTO.setTotalSeparateAmount(orderPayAmount);
|
||||
lklSeparateDTO.setShippingFee(actualShippingFeeInner);
|
||||
lklSeparateDTO.setLklRatio(wxFeeRatio); // 拉卡拉给的微信分账比例 0.0025 千分之2.5
|
||||
lklSeparateDTO.setMchRatio(mchSplitRatio);
|
||||
lklSeparateDTO.setPlatRatio(platformSplitRatio);
|
||||
|
||||
// 设置代理商分账比例
|
||||
if (agent1stRatio != null && agent1stRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
lklSeparateDTO.setAgent1stRatio(agent1stRatio);
|
||||
log.debug("[分账参数计算] 设置一级代理商分账比例: {}", agent1stRatio);
|
||||
}
|
||||
|
||||
if (agent2ndRatio != null && agent2ndRatio.compareTo(BigDecimal.ZERO) > 0) {
|
||||
lklSeparateDTO.setAgent2ndRatio(agent2ndRatio);
|
||||
log.debug("[分账参数计算] 设置二级代理商分账比例: {}", agent2ndRatio);
|
||||
}
|
||||
|
||||
// 设置参考可分账金额
|
||||
if (refCanSeparateAmt != null && refCanSeparateAmt > 0) {
|
||||
lklSeparateDTO.setRefCanSeparateAmount(refCanSeparateAmt);
|
||||
log.debug("[分账参数计算] 设置参考可分账金额: {}", refCanSeparateAmt);
|
||||
}
|
||||
|
||||
// 根据分账模式执行不同的分账计算
|
||||
LklSeparateDTO.SharingResult canSeparateAmtResult;
|
||||
if (splitMode == 1) {
|
||||
// 总金额为基准分账
|
||||
log.debug("[分账参数计算] 使用总金额为基准分账模式");
|
||||
canSeparateAmtResult = lklSeparateDTO.sharingOnTotalAmount();
|
||||
} else {
|
||||
// 可分金额基准分账
|
||||
log.debug("[分账参数计算] 使用可分账金额基准分账模式");
|
||||
canSeparateAmtResult = lklSeparateDTO.sharingOnCanSeparateAmount();
|
||||
}
|
||||
|
||||
if (!canSeparateAmtResult.isSuccess()) {
|
||||
log.warn("[分账参数计算] 分账参数评估失败: {}", canSeparateAmtResult.getErrorMessage());
|
||||
return Pair.of(false, lklSeparateDTO);
|
||||
}
|
||||
|
||||
log.info("[分账参数计算] 分账参数计算评估成功, result={}", lklSeparateDTO);
|
||||
return Pair.of(true, lklSeparateDTO);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -80,6 +80,8 @@ import static com.suisung.mall.common.utils.I18nUtil._;
|
||||
@Slf4j
|
||||
public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageTemplateMapper, ShopMessageTemplate> implements ShopMessageTemplateService {
|
||||
|
||||
// 批处理阈值
|
||||
private static final int BATCH_SIZE = 30;
|
||||
@Autowired
|
||||
ShopStoreBaseService shopStoreBaseService;
|
||||
@Autowired
|
||||
@ -90,19 +92,13 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
private SnsService snsService;
|
||||
@Autowired
|
||||
private GeTuiUtil geTuiUtil;
|
||||
|
||||
@Autowired
|
||||
private CloundService cloundService;
|
||||
|
||||
@Autowired
|
||||
private ShopWechatTplmsgService shopWechatTplmsgService;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
// 批处理阈值
|
||||
private static final int BATCH_SIZE = 30;
|
||||
|
||||
public String dealMessageTemplate(String message_content, Map args) {
|
||||
StringSubstitutor sub = new StringSubstitutor(args);
|
||||
|
||||
@ -658,16 +654,22 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
/**
|
||||
* 异步批量发送阿里云短信
|
||||
*
|
||||
* @param mobiles
|
||||
* @param tmplCode
|
||||
* @param tmplParams
|
||||
* @return
|
||||
* @param mobiles 手机号列表
|
||||
* @param tmplCode 模板代码
|
||||
* @param tmplParams 模板参数
|
||||
* @return 成功发送的数量
|
||||
*/
|
||||
@Async
|
||||
@Override
|
||||
public Integer aliyunSmsSend(List<String> mobiles, String tmplCode, Map<String, Object> tmplParams) {
|
||||
// 过滤重复手机号,避免重复发送短信
|
||||
List<String> uniqueMobiles = mobiles.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int successCnt = 0;
|
||||
for (String mobile : mobiles) {
|
||||
for (String mobile : uniqueMobiles) {
|
||||
if (aliyunSmsSend(mobile, tmplCode, tmplParams)) {
|
||||
successCnt++;
|
||||
}
|
||||
@ -676,22 +678,23 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
return successCnt;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CommonResult sendToXcxUserMessage(Integer user_id) {
|
||||
Map bind_row = accountService.getBind(user_id, BindCode.MOBILE);
|
||||
if(bind_row == null){
|
||||
if (bind_row == null) {
|
||||
return CommonResult.failed("账号不存在");
|
||||
}
|
||||
if(bind_row.get("bind_openid")==null){
|
||||
if (bind_row.get("bind_openid") == null) {
|
||||
log.info("微信id不存在");
|
||||
return CommonResult.failed("微信id不存在");
|
||||
}
|
||||
String open_id = (String) bind_row.get("bind_openid");
|
||||
Map args=new HashMap();
|
||||
Map args = new HashMap();
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
String activeProfile = activeProfiles[0];
|
||||
//微信小程序订阅消息
|
||||
args.put("evn",activeProfile);
|
||||
args.put("evn", activeProfile);
|
||||
//String open_id = Convert.toStr(user_setting.get("bind_openid"));
|
||||
//从bind表中读取用户公众号openid
|
||||
if (StrUtil.isNotEmpty(open_id)) {
|
||||
@ -700,10 +703,10 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
QueryWrapper<ShopWechatTplmsg> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("tplmsg_id", 1022);//todo 后期改为动态
|
||||
ShopWechatTplmsg wechatTplmsg = shopWechatTplmsgService.getOne(queryWrapper);
|
||||
ShopStoreBase shopStoreBase= shopStoreBaseService.get(wechatTplmsg.getStore_id());
|
||||
ShopStoreBase shopStoreBase = shopStoreBaseService.get(wechatTplmsg.getStore_id());
|
||||
args.put("storeName", shopStoreBase.getStore_name());
|
||||
if (wechatTplmsg != null) {
|
||||
Map timeArgs=getActiveTime();
|
||||
Map timeArgs = getActiveTime();
|
||||
args.putAll(timeArgs);
|
||||
String wechatTplData = getXcxWechatTplData(open_id, wechatTplmsg, args);
|
||||
log.info(wechatTplData);
|
||||
@ -720,10 +723,10 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
return CommonResult.success();
|
||||
}
|
||||
|
||||
private Map getActiveTime(){
|
||||
Map args = new HashMap();
|
||||
private Map getActiveTime() {
|
||||
Map args = new HashMap();
|
||||
// 获取当前时间
|
||||
LocalDateTime now = LocalDateTime.of(LocalDate.now(), LocalTime.of(9,0,0));
|
||||
LocalDateTime now = LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0, 0));
|
||||
// 加上13小时30分钟
|
||||
LocalDateTime futureTime = now.plusHours(13).minusMinutes(30);
|
||||
// 格式化输出
|
||||
@ -738,7 +741,7 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
@Override
|
||||
public void sendToXcxAllUserMessage() {
|
||||
long allBindCount = accountService.getAllBindCount(CommonConstant.BIND_SUB_TMPL_SKILL);
|
||||
if(allBindCount==0){
|
||||
if (allBindCount == 0) {
|
||||
return;
|
||||
}
|
||||
String accessToken = accountService.getXcxAccessToken(true);
|
||||
@ -746,25 +749,25 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
QueryWrapper<ShopWechatTplmsg> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("tplmsg_id", 1022);//todo 后期改为动态
|
||||
ShopWechatTplmsg wechatTplmsg = shopWechatTplmsgService.getOne(queryWrapper);
|
||||
ShopStoreBase shopStoreBase= shopStoreBaseService.get(wechatTplmsg.getStore_id());
|
||||
Map args=new HashMap();
|
||||
ShopStoreBase shopStoreBase = shopStoreBaseService.get(wechatTplmsg.getStore_id());
|
||||
Map args = new HashMap();
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
String activeProfile = activeProfiles[0];
|
||||
args.put("storeName", shopStoreBase.getStore_name());
|
||||
args.put("evn",activeProfile);
|
||||
Map timeArgs=getActiveTime();
|
||||
args.put("evn", activeProfile);
|
||||
Map timeArgs = getActiveTime();
|
||||
args.putAll(timeArgs);
|
||||
int total= (int) allBindCount;
|
||||
Integer pages= CommonUtil.getPagesCount(total,BATCH_SIZE);
|
||||
int total = (int) allBindCount;
|
||||
Integer pages = CommonUtil.getPagesCount(total, BATCH_SIZE);
|
||||
ExecutorService executor = Executors.newFixedThreadPool(6);
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
for (int i=1;i<=pages;i++){
|
||||
List<AccountUserBindConnect> finalList=accountService.getAllBindPage(CommonConstant.BIND_SUB_TMPL_SKILL,i,BATCH_SIZE);
|
||||
for (int i = 1; i <= pages; i++) {
|
||||
List<AccountUserBindConnect> finalList = accountService.getAllBindPage(CommonConstant.BIND_SUB_TMPL_SKILL, i, BATCH_SIZE);
|
||||
int finalI = i;
|
||||
futures.add(executor.submit(() -> {
|
||||
finalList.forEach(accountUserBindConnect -> {
|
||||
String open_id=accountUserBindConnect.getBind_openid();
|
||||
if(StrUtil.isNotEmpty(open_id)){
|
||||
String open_id = accountUserBindConnect.getBind_openid();
|
||||
if (StrUtil.isNotEmpty(open_id)) {
|
||||
String wechatTplData = getXcxWechatTplData(open_id, wechatTplmsg, args);
|
||||
String result = WxHttpUtil.request(WxHttpUtil.MethodType.POST, WxHttpUtil.WxType.XCX, accessToken, url, null, wechatTplData);
|
||||
JSONObject resultJson = JSONUtil.parseObj(result);
|
||||
@ -775,7 +778,7 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
}
|
||||
}
|
||||
});
|
||||
return "完成推送批次:"+ finalI;
|
||||
return "完成推送批次:" + finalI;
|
||||
}));
|
||||
}
|
||||
// 等待所有任务完成
|
||||
@ -804,11 +807,11 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
wxXcxMsgPushVo.setTemplate_id(wechatTplmsg.getTplmsg_tpl_id());
|
||||
wxXcxMsgPushVo.setPage(wechatTplmsg.getLink_url());
|
||||
|
||||
String evn=Convert.toStr(args.get("evn"));
|
||||
String storeName=Convert.toStr(args.get("storeName"));
|
||||
String miniprogram_state="trial";//默认为体验版
|
||||
if(evn.equals("prod")){
|
||||
miniprogram_state="formal";
|
||||
String evn = Convert.toStr(args.get("evn"));
|
||||
String storeName = Convert.toStr(args.get("storeName"));
|
||||
String miniprogram_state = "trial";//默认为体验版
|
||||
if (evn.equals("prod")) {
|
||||
miniprogram_state = "formal";
|
||||
}
|
||||
wxXcxMsgPushVo.setMiniprogram_state(miniprogram_state);
|
||||
wxXcxMsgPushVo.setLang("zh_CN");
|
||||
@ -829,8 +832,8 @@ public class ShopMessageTemplateServiceImpl extends BaseServiceImpl<ShopMessageT
|
||||
|
||||
amount4.setValue("0.01");
|
||||
BaseValue.setAmount4(amount4);
|
||||
String formattedNow=Convert.toStr(args.get("formattedNow"));
|
||||
String formattedFuture=Convert.toStr(args.get("formattedFuture"));
|
||||
String formattedNow = Convert.toStr(args.get("formattedNow"));
|
||||
String formattedFuture = Convert.toStr(args.get("formattedFuture"));
|
||||
|
||||
time6.setValue(formattedNow);
|
||||
BaseValue.setTime6(time6);
|
||||
|
||||
@ -86,6 +86,9 @@ public class ShopOrderReturnController extends BaseControllerImpl {
|
||||
ShopOrderReturn shopOrderReturn = new ShopOrderReturn();
|
||||
shopOrderReturn.setReturn_id(return_id);
|
||||
shopOrderReturn.setReturn_flag(return_flag);
|
||||
if (StrUtil.isBlank(return_store_message)) {
|
||||
return_store_message = I18nUtil._("同意");
|
||||
}
|
||||
shopOrderReturn.setReturn_store_message(return_store_message);
|
||||
return CommonResult.success(shopOrderReturnService.processReviewList(shopOrderReturn, receiving_address));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,4 +81,12 @@ public interface ShopOrderInfoService extends IBaseService<ShopOrderInfo> {
|
||||
*/
|
||||
CommonResult orderPickingCompleted(String storeId, String orderId);
|
||||
|
||||
/**
|
||||
* 确认收货之后更改订单的收货状态
|
||||
*
|
||||
* @param orderId 订单ID
|
||||
* @return Boolean 更新是否成功
|
||||
*/
|
||||
Boolean updateOrderReceived(String orderId);
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.modules.order.ShopOrderLkl;
|
||||
import com.suisung.mall.core.web.service.IBaseService;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public interface ShopOrderLklService extends IBaseService<ShopOrderLkl> {
|
||||
@ -113,4 +114,22 @@ public interface ShopOrderLklService extends IBaseService<ShopOrderLkl> {
|
||||
* @return
|
||||
*/
|
||||
Boolean safeUpdate(ShopOrderLkl record);
|
||||
|
||||
/**
|
||||
* 获取平台内部订单配送费
|
||||
*
|
||||
* @param storeId 店铺Id
|
||||
* @param orderId 订单编号
|
||||
* @return
|
||||
*/
|
||||
Integer getOrderShippingFeeInner(Integer storeId, String orderId);
|
||||
|
||||
/**
|
||||
* 获取平台内部订单配送费
|
||||
*
|
||||
* @param storeId 店铺Id
|
||||
* @param orderId 订单编号
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getOrderShippingFeeInnerToDecimal(Integer storeId, String orderId);
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ import com.suisung.mall.common.modules.product.ShopProductItem;
|
||||
import com.suisung.mall.common.modules.product.ShopProductValidPeriod;
|
||||
import com.suisung.mall.common.modules.store.*;
|
||||
import com.suisung.mall.common.modules.user.*;
|
||||
import com.suisung.mall.common.pojo.dto.LklSeparateDTO;
|
||||
import com.suisung.mall.common.pojo.dto.StandardAddressDTO;
|
||||
import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO;
|
||||
import com.suisung.mall.common.pojo.req.*;
|
||||
@ -2374,10 +2375,10 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
shopOrderInfo.setOrder_is_shipped(StateCode.ORDER_SHIPPED_STATE_YES);
|
||||
queryWrapper.eq("order_state_id", order_state_id).in("order_is_shipped", Arrays.asList(StateCode.ORDER_SHIPPED_STATE_NO, StateCode.ORDER_SHIPPED_STATE_PART)).eq("order_is_received", 0);
|
||||
break;
|
||||
case StateCode.ORDER_STATE_SHIPPED: // 待收获确认
|
||||
shopOrderInfo.setOrder_is_received(CommonConstant.Enable);
|
||||
shopOrderInfo.setOrder_settlement_time(time);
|
||||
shopOrderInfo.setOrder_qs_time(time);
|
||||
case StateCode.ORDER_STATE_SHIPPED: // 待收货确认(已发货)
|
||||
shopOrderInfo.setOrder_is_received(CommonConstant.Enable); // 已收货
|
||||
shopOrderInfo.setOrder_settlement_time(time); // 结单时间
|
||||
shopOrderInfo.setOrder_qs_time(time); // 签收时间
|
||||
queryWrapper.eq("order_state_id", order_state_id).eq("order_is_received", CommonConstant.Disable);
|
||||
break;
|
||||
default:
|
||||
@ -3228,6 +3229,8 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
|
||||
// 获取所有店铺管理员的手机号
|
||||
shopKeeperMobiles.add(mobile);
|
||||
// 增加谢总的手机号
|
||||
shopKeeperMobiles.add("17777525395");
|
||||
|
||||
// 老流程(之前获取用户id不正确,现在更正) 2024-12-10 update 获取所有店铺管理员的 user_id
|
||||
MsgTO sellerMsgTo = new MsgTO(userId, store_id, message_id, args);
|
||||
@ -3239,8 +3242,8 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
Map<String, Object> tmplArgs = new HashMap<>(2);
|
||||
tmplArgs.put("order_id", order_id);
|
||||
tmplArgs.put("order_payment_amount", order_payment_amount);
|
||||
// 所有店铺管理员的发送邮件, 提醒商家:您有一笔新的订单 ${order_id},请及时处理。
|
||||
shopMessageTemplateService.aliyunSmsSend(shopKeeperMobiles, "SMS_476810378", tmplArgs);//SMS_475836097
|
||||
// 所有店铺管理员的发送邮件, 提醒商家:您有一笔新的订单 ${order_id},请及时处理。
|
||||
shopMessageTemplateService.aliyunSmsSend(shopKeeperMobiles, "SMS_476810378", tmplArgs);
|
||||
}
|
||||
|
||||
// 付款成功,对通知推广员进行提醒
|
||||
@ -4220,7 +4223,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
if (!shopProductItemService.edit(shopProductItem)) {
|
||||
throw new ApiException(String.format(I18nUtil._("释放: %s 冻结库存失败!"), order_item_row.getItem_id()));
|
||||
}
|
||||
log.debug("释放库存Item_src_id:{},数量:{}",shopProductItem.getItem_src_id(),order_item_quantity);
|
||||
log.debug("释放库存Item_src_id:{},数量:{}", shopProductItem.getItem_src_id(), order_item_quantity);
|
||||
// RMK 第三方数据同步相关:redis 给这个商品加上对应的库存
|
||||
Map<String, Integer> stockDeltaMap = new HashMap<>();
|
||||
stockDeltaMap.put(shopProductItem.getItem_src_id()+"_"+order_item_row.getOrder_id(), order_item_quantity);
|
||||
@ -5025,6 +5028,9 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
String order_id = order_row.getOrder_id();
|
||||
Integer store_id = order_row.getStore_id();
|
||||
|
||||
// 更改订单收货状态为:已确认收货,如果状态已是,不更改
|
||||
shopOrderInfoService.updateOrderReceived(order_id);
|
||||
|
||||
ShopOrderData order_data_row = shopOrderDataService.get(order_id);
|
||||
if (order_data_row == null) {
|
||||
log.warn("[确认收货] 无法获取订单数据: orderId={}", order_id);
|
||||
@ -6551,6 +6557,8 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
info_row.setStore_id((Integer) base_row.get("store_id")); // 卖家店铺编号
|
||||
info_row.setSubsite_id(subsite_id); // 所属分站
|
||||
|
||||
|
||||
info_row.setBuyer_user_id((Integer) base_row.get("buyer_user_id")); // 买家编号
|
||||
info_row.setKind_id(kind_id); // 订单种类(ENUM): 1201-实物 ; 1202-虚拟
|
||||
info_row.setOrder_lock_status(0); // 锁定状态(BOOL):0-是正常;1-锁定
|
||||
@ -6572,7 +6580,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
info_row.setOrder_is_paid(StateCode.ORDER_PAID_STATE_NO); // 付款状态(BOOL):0-未付款;6-付款待审核;7-部分付款;1-已付款
|
||||
info_row.setOrder_is_out(StateCode.ORDER_PICKING_STATE_NO);
|
||||
info_row.setOrder_is_shipped(StateCode.ORDER_SHIPPED_STATE_NO);
|
||||
info_row.setOrder_is_received(0); // 收货状态(BOOL):0-未收货;1-已收货
|
||||
info_row.setOrder_is_received(CommonConstant.Disable); // 收货状态(BOOL):0-未收货;1-已收货
|
||||
info_row.setChain_id(ObjectUtil.equal(base_store_id, chain_store_id) ? chain_id : 0);
|
||||
info_row.setDelivery_type_id(delivery_type_id); // 配送方式
|
||||
info_row.setOrder_is_offline(order_is_offline); // 线下订单
|
||||
@ -7234,7 +7242,7 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
}
|
||||
|
||||
// RMK 第三方数据同步相关:redis 给这个商品减去上对应的库存
|
||||
log.debug("减库存Item_src_id:{},数量:{}",item_src_id,cart_quantity);
|
||||
log.debug("减库存Item_src_id:{},数量:{}", item_src_id, cart_quantity);
|
||||
Map<String, Integer> stockDeltaMap = new HashMap<>();
|
||||
stockDeltaMap.put(item_src_id+"_"+order_id, -cart_quantity);
|
||||
syncThirdDataService.incrProductStockToRedis(stockDeltaMap);
|
||||
@ -7657,14 +7665,51 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
|
||||
// 店铺统一设置的打包费
|
||||
data_row.setPacking_fee(packingFee);
|
||||
|
||||
// 平台最低配送费,单位(分)
|
||||
Integer innerMinDeliverFee = accountBaseConfigService.getInnerMinDeliveryFee();
|
||||
|
||||
// 平台最低配送费,单位(元)
|
||||
BigDecimal shoppingFeeInner = Convert.toBigDecimal(innerMinDeliverFee).divide(BigDecimal.valueOf(100));
|
||||
data_row.setOrder_shipping_fee_inner(shoppingFeeInner);
|
||||
|
||||
// 从 base_row 中获取应付款 order_payment_amount,计算平台和代理商的总计分账金额
|
||||
BigDecimal split_amount_from = NumberUtil.sub(order_payment_amount, _freight, packingFee);
|
||||
// BigDecimal split_amount_from = NumberUtil.sub(order_payment_amount, _freight, packingFee);
|
||||
// BigDecimal platform_fee = calculatePlatformAndAgentShareAmount(Convert.toInt(base_row.get("store_id")), split_amount_from);
|
||||
|
||||
BigDecimal storeSplitRatio = shopStoreBaseService.getStoreSplitRatio(store_id, false);
|
||||
|
||||
// 计算平台和代理商的分账金额
|
||||
Pair<Boolean, LklSeparateDTO> calcResult = lakalaApiService.calculateAndEvaluateSharingParams(
|
||||
CommonConstant.SeparateCalcMode_CanSeparateAmt,
|
||||
Convert.toInt(order_payment_amount.multiply(BigDecimal.valueOf(100))),
|
||||
innerMinDeliverFee,
|
||||
storeSplitRatio,
|
||||
BigDecimal.valueOf(0.01),
|
||||
null, null, null);
|
||||
|
||||
// 计算平台费
|
||||
BigDecimal platform_fee = calculatePlatformAndAgentShareAmount(Convert.toInt(base_row.get("store_id")), split_amount_from);
|
||||
data_row.setTotal_separate_value(platform_fee); // 从拉卡拉分账,给平台和代理商的总计分账金额
|
||||
data_row.setPlatform_fee(platform_fee);
|
||||
if (calcResult != null && calcResult.getFirst() && calcResult.getSecond() != null) {
|
||||
try {
|
||||
LklSeparateDTO lklSeparateDTO = calcResult.getSecond();
|
||||
// 确保分账金额不为负数
|
||||
BigDecimal totalSeparateAmount = BigDecimal.valueOf(lklSeparateDTO.getCanSeparateAmount())
|
||||
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
BigDecimal platformFee = BigDecimal.valueOf(lklSeparateDTO.getPlatAmount() + lklSeparateDTO.getAgent1stAmount() + lklSeparateDTO.getAgent2ndAmount())
|
||||
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
|
||||
// 防止负值
|
||||
data_row.setTotal_separate_value(totalSeparateAmount.max(BigDecimal.ZERO));
|
||||
data_row.setPlatform_fee(platformFee.max(BigDecimal.ZERO));
|
||||
} catch (Exception e) {
|
||||
log.warn("分账金额计算异常,使用默认值: {}", e.getMessage());
|
||||
data_row.setTotal_separate_value(BigDecimal.ZERO);
|
||||
data_row.setPlatform_fee(BigDecimal.ZERO);
|
||||
}
|
||||
} else {
|
||||
log.warn("拉卡拉分账参数计算失败,使用默认值");
|
||||
data_row.setTotal_separate_value(BigDecimal.ZERO);
|
||||
data_row.setPlatform_fee(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
Integer voucher_id = (Integer) order_voucher_row.get("voucher_id");
|
||||
String voucher_code = (String) order_voucher_row.get("voucher_code");
|
||||
|
||||
@ -479,6 +479,41 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
|
||||
return CommonResult.success(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认收货之后更改订单的收货状态
|
||||
*
|
||||
* @param orderId 订单ID
|
||||
* @return Boolean 更新是否成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateOrderReceived(String orderId) {
|
||||
// 参数校验
|
||||
if (orderId == null) {
|
||||
logger.warn("[确认收货] 参数校验失败:订单ID为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
UpdateWrapper<ShopOrderInfo> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("order_id", orderId)
|
||||
.ne("order_is_received", CommonConstant.Enable);
|
||||
updateWrapper.set("order_is_received", CommonConstant.Enable)
|
||||
.set("order_deal_time", System.currentTimeMillis());
|
||||
|
||||
boolean result = update(updateWrapper);
|
||||
if (result) {
|
||||
logger.info("[确认收货] 订单收货状态更新成功, orderId={}", orderId);
|
||||
} else {
|
||||
logger.warn("[确认收货] 订单收货状态更新失败, orderId={}", orderId);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logger.error("[确认收货] 订单收货状态更新异常, orderId={}", orderId, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// todo 优化多次远程查询
|
||||
private Map dashboardPlantform() {
|
||||
List<Integer> order_state = Arrays.asList(
|
||||
|
||||
@ -28,7 +28,6 @@ import com.suisung.mall.shop.order.service.ShopOrderItemService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -228,28 +227,24 @@ public class ShopOrderItemServiceImpl extends BaseServiceImpl<ShopOrderItemMappe
|
||||
|
||||
@Override
|
||||
public List<ShopStoreOrderProductPrintVO> selectOrderItemPrintInfo(String orderId) {
|
||||
// 输入验证
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Map> mList = shopOrderItemMapper.selectOrderItemPrintInfo(orderId);
|
||||
if (CollUtil.isEmpty(mList)) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
DecimalFormat df2 = new DecimalFormat("#.##");
|
||||
List<ShopStoreOrderProductPrintVO> retList = new ArrayList<>();
|
||||
for (Map map : mList) {
|
||||
return mList.stream().map(map -> {
|
||||
ShopStoreOrderProductPrintVO vo = new ShopStoreOrderProductPrintVO();
|
||||
vo.setProduct_sn((String) map.get("product_sn"));
|
||||
vo.setItem_name((String) map.get("item_name"));
|
||||
vo.setProduct_sn(Convert.toStr(map.get("product_sn")));
|
||||
vo.setItem_name(Convert.toStr(map.get("item_name")));
|
||||
vo.setOrder_item_amount(Convert.toBigDecimal(map.get("order_item_amount")));
|
||||
vo.setOrder_item_quantity((Integer) map.get("order_item_quantity"));
|
||||
|
||||
retList.add(vo);
|
||||
}
|
||||
|
||||
return retList;
|
||||
vo.setOrder_item_quantity(Convert.toInt(map.get("order_item_quantity")));
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -33,8 +33,10 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -596,4 +598,64 @@ public class ShopOrderLklServiceImpl extends BaseServiceImpl<ShopOrderLklMapper,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平台内部订单运费
|
||||
*
|
||||
* @param storeId 店铺Id
|
||||
* @param orderId 订单编号
|
||||
* @return 平台内部订单运费,单位:分
|
||||
*/
|
||||
@Override
|
||||
public Integer getOrderShippingFeeInner(Integer storeId, String orderId) {
|
||||
// 参数校验
|
||||
if (storeId == null || StringUtils.isBlank(orderId)) {
|
||||
log.warn("[获取平台内部订单运费] 参数校验失败:storeId或orderId为空, storeId={}, orderId={}", storeId, orderId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
QueryWrapper<ShopOrderLkl> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select("shopping_fee_inner");
|
||||
queryWrapper.eq("store_id", storeId);
|
||||
queryWrapper.eq("order_id", orderId);
|
||||
|
||||
ShopOrderLkl shopOrderLkl = findOne(queryWrapper);
|
||||
Integer fee = Optional.ofNullable(shopOrderLkl)
|
||||
.map(ShopOrderLkl::getShopping_fee_inner)
|
||||
.orElse(0);
|
||||
|
||||
log.debug("[获取平台内部订单运费] 查询成功, storeId={}, orderId={}, fee={}", storeId, orderId, fee);
|
||||
return fee;
|
||||
} catch (Exception e) {
|
||||
log.error("[获取平台内部订单运费] 系统异常, storeId={}, orderId={}", storeId, orderId, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getOrderShippingFeeInnerToDecimal(Integer storeId, String orderId) {
|
||||
// 参数校验
|
||||
if (storeId == null || StringUtils.isBlank(orderId)) {
|
||||
log.warn("[获取平台内部订单运费(Decimal)] 参数校验失败:storeId或orderId为空, storeId={}, orderId={}", storeId, orderId);
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用已有的方法获取运费(单位:分)
|
||||
Integer feeInCents = getOrderShippingFeeInner(storeId, orderId);
|
||||
|
||||
// 转换为元为单位的BigDecimal
|
||||
BigDecimal feeInYuan = new BigDecimal(feeInCents).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
|
||||
log.debug("[获取平台内部订单运费(Decimal)] 查询成功, storeId={}, orderId={}, feeInCents={}, feeInYuan={}",
|
||||
storeId, orderId, feeInCents, feeInYuan);
|
||||
return feeInYuan;
|
||||
} catch (Exception e) {
|
||||
log.error("[获取平台内部订单运费(Decimal)] 系统异常, storeId={}, orderId={}", storeId, orderId, e);
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -58,10 +58,7 @@ import com.suisung.mall.shop.sfexpress.service.SFExpressApiService;
|
||||
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
|
||||
import com.suisung.mall.shop.store.service.ShopStoreConfigService;
|
||||
import com.suisung.mall.shop.store.service.ShopStoreShippingAddressService;
|
||||
import io.seata.core.context.RootContext;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import io.seata.tm.api.GlobalTransactionContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -196,6 +193,10 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
@Autowired
|
||||
private LklOrderSeparateService lklOrderSeparateService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopOrderLklService shopOrderLklService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private SFExpressApiService sfExpressApiService;
|
||||
@ -964,7 +965,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
* @param shopOrderId 商城订单ID
|
||||
* @return Boolean 处理结果,true表示成功,false表示失败
|
||||
*/
|
||||
@GlobalTransactional
|
||||
@Transactional
|
||||
@Override
|
||||
public Boolean sfExpressExpiredForceRefund(String shopOrderId) {
|
||||
logger.info("[顺丰超时自动退款] 开始处理订单: shopOrderId={}", shopOrderId);
|
||||
@ -972,7 +973,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
try {
|
||||
String remark = "同城配送异常自动退款!";
|
||||
|
||||
// 先整单退货申请
|
||||
// 对已存在部分退款的订单,进行剩余商品的全部退款
|
||||
CommonResult commonResult = addRemainingItems(shopOrderId, true, remark);
|
||||
commonResult.checkFenResult();
|
||||
logger.debug("[顺丰超时自动退款] 整单退货申请创建成功: shopOrderId={}", shopOrderId);
|
||||
@ -991,7 +992,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
shopOrderReturn.setReturn_store_message(remark);
|
||||
logger.debug("[顺丰超时自动退款] 退货单信息设置完成: returnId={}", shopOrderReturn.getReturn_id());
|
||||
|
||||
// 退货审核(商家同意退款,仅仅退款,因为商品还没有配送出去)
|
||||
// 退货审核
|
||||
Boolean result = processReviewList(shopOrderReturn, 0);
|
||||
if (result) {
|
||||
logger.info("[顺丰超时自动退款] 处理完成: shopOrderId={}", shopOrderId);
|
||||
@ -1001,14 +1002,9 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
// 如果本地异常,直接本地事务回滚,如果是分布式异常,则本地事务回滚
|
||||
logger.error("[顺丰超时自动退款] 处理过程中发生异常: shopOrderId={}", shopOrderId, e);
|
||||
// 手动触发Seata事务回滚
|
||||
try {
|
||||
GlobalTransactionContext.reload(RootContext.getXID()).rollback();
|
||||
} catch (TransactionException transactionException) {
|
||||
logger.error("[顺丰超时自动退款] Seata事务回滚异常: shopOrderId={}", shopOrderId, transactionException);
|
||||
}
|
||||
throw e;
|
||||
throw new ApiException(I18nUtil._("顺丰退货审核处理失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1282,6 +1278,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
if (!edit(shopOrderReturn)) {
|
||||
throw new ApiException(I18nUtil._("修改订单信息失败!"));
|
||||
}
|
||||
|
||||
if (!processReviewList(return_ids, orderReturns, StateCode.RETURN_PROCESS_CHECK, StateCode.RETURN_PROCESS_FINISH)) {
|
||||
throw new ApiException(I18nUtil._("审核失败!"));
|
||||
}
|
||||
@ -1376,6 +1373,9 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
*/
|
||||
@Override
|
||||
public boolean processReviewList(List<String> return_ids, List<ShopOrderReturn> return_rows, Integer return_curr_state_id, Integer return_next_state_id) {
|
||||
logger.info("退款审核 processReviewList 参数:return_ids {},return_rows {},return_curr_state_id {},return_next_state_id {}",
|
||||
return_ids, return_rows, return_curr_state_id, return_next_state_id);
|
||||
|
||||
if (CollUtil.isEmpty(return_ids)) {
|
||||
throw new ApiException(I18nUtil._("请选择需要审核的退单!"));
|
||||
}
|
||||
@ -1419,6 +1419,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("退款审核 processReviewList 符合审核条件的退单:{}", review_ids);
|
||||
if (CollUtil.isEmpty(review_ids)) {
|
||||
throw new ApiException(I18nUtil._("无符合审核条件的退单!"));
|
||||
}
|
||||
@ -1534,7 +1535,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
Integer return_is_shipping_fee = return_row.getReturn_is_shipping_fee();
|
||||
|
||||
// 处理非退运费单的情况
|
||||
if (CheckUtil.isEmpty(return_is_shipping_fee) || return_is_shipping_fee != 1) {
|
||||
if (CheckUtil.isEmpty(return_is_shipping_fee) || !CommonConstant.Enable.equals(return_is_shipping_fee)) {
|
||||
// 所有单品退款额度
|
||||
QueryWrapper<ShopOrderItem> orderItemQueryWrapper = new QueryWrapper<>();
|
||||
orderItemQueryWrapper.eq("order_id", order_id);
|
||||
@ -1593,7 +1594,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
// 当前订单状态
|
||||
Integer order_state_id = info_row.getOrder_state_id();
|
||||
|
||||
// 没有发货没有完成订单之前,允许取消订单和退运费
|
||||
// 没有发货没有完成订单之前,允许取消订单和退运费(这个存在争议)
|
||||
List<Integer> forbiddenStates = Arrays.asList(
|
||||
StateCode.ORDER_STATE_SHIPPED,
|
||||
StateCode.ORDER_STATE_RECEIVED,
|
||||
@ -1603,7 +1604,6 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
// shopOrderBaseService.cancel(order_id, info_row, false);
|
||||
logger.info("处理运费和打包费事宜:{}", order_id);
|
||||
|
||||
// 未发货,退运费 - 判断运费是否存在
|
||||
ShopOrderData order_data_row = shopOrderDataService.get(order_id);
|
||||
|
||||
// 如果有打包费,最后的退款订单的退款金额加上 打包费
|
||||
@ -1611,18 +1611,18 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
order_data_row.getPacking_fee() != null &&
|
||||
order_data_row.getPacking_fee().compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 退款金额+打包费
|
||||
BigDecimal order_refund_amount_add_fee = NumberUtil.add(
|
||||
BigDecimal orderRefundAmountAddFee = NumberUtil.add(
|
||||
order_data_row.getOrder_refund_amount(),
|
||||
order_data_row.getPacking_fee());
|
||||
// 最后一个退款订单如果有打包费,加上打包费
|
||||
return_row.setReturn_refund_amount(order_refund_amount_add_fee);
|
||||
logger.debug("已添加打包费到退款金额,订单ID: {}", order_id);
|
||||
return_row.setReturn_refund_amount(orderRefundAmountAddFee);
|
||||
logger.debug("最后一个商品,已添加打包费到退款金额,订单ID: {}", order_id);
|
||||
}
|
||||
|
||||
// 有运费的订单
|
||||
// 有运费的,重新生成一个运费退单
|
||||
if (order_data_row != null &&
|
||||
order_data_row.getOrder_shipping_fee() != null &&
|
||||
order_data_row.getOrder_shipping_fee().compareTo(BigDecimal.ZERO) > 0) {
|
||||
order_data_row.getOrder_shipping_fee_inner() != null &&
|
||||
order_data_row.getOrder_shipping_fee_inner().compareTo(BigDecimal.ZERO) > 0) {
|
||||
// 运费大于0的, 执行退运费操作, 有两种方案,1、生成退运费售后服务单; 2、直接执行退款
|
||||
// 1、生成独立退运费售后服务单,需注意运费是退给运费代理商的,需要获取代理商的交易单号
|
||||
|
||||
@ -1630,8 +1630,15 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
|
||||
Integer buyer_user_id = info_row.getBuyer_user_id();
|
||||
Integer storeId = info_row.getStore_id();
|
||||
// 订单运费
|
||||
BigDecimal order_shipping_fee = order_data_row.getOrder_shipping_fee();
|
||||
|
||||
// 平台内部订单运费
|
||||
BigDecimal orderShippingFeeInner = order_data_row.getOrder_shipping_fee_inner();
|
||||
if (orderShippingFeeInner == null || orderShippingFeeInner.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
orderShippingFeeInner = shopOrderLklService.getOrderShippingFeeInnerToDecimal(storeId, order_id);
|
||||
}
|
||||
|
||||
return_order_shipping_fee_row.setReturn_refund_amount(orderShippingFeeInner); // 平台内部配送费退款金额
|
||||
|
||||
BigDecimal order_points_fee = ObjectUtil.defaultIfNull(order_data_row.getOrder_points_fee(), BigDecimal.ZERO);
|
||||
BigDecimal order_refund_agree_points = ObjectUtil.defaultIfNull(order_data_row.getOrder_refund_agree_points(), BigDecimal.ZERO);
|
||||
BigDecimal return_refund_point = NumberUtil.round(NumberUtil.sub(order_points_fee, order_refund_agree_points), 2);
|
||||
@ -1640,12 +1647,12 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
return_order_shipping_fee_row.setBuyer_user_id(buyer_user_id);
|
||||
return_order_shipping_fee_row.setReturn_is_shipping_fee(1); //退货类型(BOOL): 0-退款单;1-退运费单
|
||||
return_order_shipping_fee_row.setReturn_reason_id(0);
|
||||
return_order_shipping_fee_row.setReturn_buyer_message(I18nUtil._("退运费"));
|
||||
return_order_shipping_fee_row.setReturn_buyer_message(I18nUtil._("订单(配送费)退款"));
|
||||
return_order_shipping_fee_row.setStore_id(storeId);
|
||||
return_order_shipping_fee_row.setReturn_refund_amount(order_shipping_fee);
|
||||
return_order_shipping_fee_row.setReturn_refund_point(NumberUtil.min(return_refund_point, order_shipping_fee));
|
||||
return_order_shipping_fee_row.setReturn_refund_point(NumberUtil.min(return_refund_point, orderShippingFeeInner));
|
||||
return_order_shipping_fee_row.setReturn_add_time(now); // 添加时间
|
||||
return_order_shipping_fee_row.setReturn_tel("");
|
||||
|
||||
// 店铺审核操作员
|
||||
Integer storeUserId = user != null ? user.getId() : 0;
|
||||
return_order_shipping_fee_row.setReturn_store_user_id(storeUserId);
|
||||
@ -1654,10 +1661,10 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
|
||||
// update 2025-07-24
|
||||
return_order_shipping_fee_row.setReturn_flag(0); // 退货标识(BOOL): 0-正常退货;1-退货换货
|
||||
return_order_shipping_fee_row.setReturn_store_message(I18nUtil._("退运费"));
|
||||
return_order_shipping_fee_row.setReturn_store_message(I18nUtil._("订单(配送费)退款"));
|
||||
return_order_shipping_fee_row.setReturn_finish_time(now);
|
||||
return_order_shipping_fee_row.setReturn_state_id(StateCode.RETURN_PROCESS_FINISH);
|
||||
return_order_shipping_fee_row.setReturn_is_paid(0);// 退款完成
|
||||
return_order_shipping_fee_row.setReturn_is_paid(1);// 退款完成
|
||||
return_order_shipping_fee_row.setReturn_channel_code("lakala");
|
||||
return_order_shipping_fee_row.setPayment_channel_id(1416);
|
||||
|
||||
@ -1672,27 +1679,12 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
|
||||
// 运费独立加一条退单记录
|
||||
if (!add(return_order_shipping_fee_row)) {
|
||||
logger.error("生成退运费订单失败!订单ID: {}", order_id);
|
||||
logger.error("配送费退款订单生成失败!订单ID: {}", order_id);
|
||||
// 1、生成退运费售后服务单;
|
||||
throw new ApiException(I18nUtil._("生成退运费订单失败!"));
|
||||
throw new ApiException(I18nUtil._("配送费退款订单生成失败!"));
|
||||
}
|
||||
logger.info("成功生成退运费订单,退单号: {}", return_id);
|
||||
logger.info("配送费退款订单生成成功,退单号: {}", return_id);
|
||||
|
||||
// 重要:加上单条运费退货单
|
||||
// return_rows.add(return_order_shipping_fee_row);
|
||||
|
||||
// // 修正退款总额 为 加上运费
|
||||
// ShopOrderData orderData = shopOrderDataService.get(order_id);
|
||||
// BigDecimal order_refund_amount = orderData.getOrder_refund_amount();
|
||||
// // 退款金额+运费
|
||||
// BigDecimal order_refund_amount_add_fee = NumberUtil.add(order_refund_amount, order_shipping_fee);
|
||||
// orderData.setOrder_refund_amount(order_refund_amount_add_fee);
|
||||
// if (!shopOrderDataService.edit(orderData)) {
|
||||
// throw new ApiException(I18nUtil._("修改订单退款总额(加运费)失败!"));
|
||||
// }
|
||||
//
|
||||
// // 最后一个退款订单如果有运费,加上运费
|
||||
// return_row.setReturn_refund_amount(order_refund_amount_add_fee);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1738,10 +1730,17 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
}
|
||||
|
||||
// 重要:执行退款操作
|
||||
if (!payService.doRefund(returnOrder)) {
|
||||
logger.error("执行退款操作失败!退单列表: {}", return_ids);
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
try {
|
||||
if (!payService.doRefund(returnOrder)) {
|
||||
logger.error("执行退款操作失败!退单列表: {}", return_ids);
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("执行退款操作异常!退单列表: {}", return_ids, e);
|
||||
// 根据业务需要决定是抛出异常触发回滚,还是其他处理方式
|
||||
throw new ApiException("退款服务调用异常: " + e.getMessage());
|
||||
}
|
||||
|
||||
logger.info("退款操作执行成功,退单列表: {}", return_ids);
|
||||
|
||||
// 更新退货单的退款完成状态和完成时间
|
||||
@ -1755,7 +1754,6 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
logger.error("更新退货单退款状态失败!退货单列表: {}", return_ids);
|
||||
throw new ApiException(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2290,6 +2288,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
* @param remark 退单备注
|
||||
* @return CommonResult 退款申请结果
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
public CommonResult addRemainingItems(String orderId, Boolean isSystemOpt, String remark) {
|
||||
logger.info("开始处理订单剩余商品退款申请,订单ID: {}", orderId);
|
||||
@ -2597,7 +2596,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
|
||||
List<ShopOrderItem> orderItems = shopOrderItemService.find(new QueryWrapper<ShopOrderItem>().eq("order_id", orderId));
|
||||
if (CollectionUtil.isEmpty(orderItems)) return CommonResult.failed("无可退货商品");
|
||||
|
||||
|
||||
// === 3. 检查退货单 ===
|
||||
ShopOrderReturn refundOrder = findOne(new QueryWrapper<ShopOrderReturn>()
|
||||
.eq("order_id", orderId)
|
||||
@ -2616,7 +2615,6 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
// 订单商品总金额
|
||||
BigDecimal orderGoodsAmount = orderItems.stream().map(ShopOrderItem::getOrder_item_amount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
|
||||
if (StrUtil.isNotBlank(requestParams.getStr("order_return_vo"))) {
|
||||
orderReturnInputVo = JSONUtil.toBean(requestParams.getStr("order_return_vo"), OrderReturnInputVo.class);
|
||||
// 如果orderReturnInputVo中的order_id为空或与上层参数不一致,则使用上层参数中的order_id
|
||||
@ -2696,7 +2694,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
|
||||
logger.info("商家退款订单:{}", JSONUtil.toJsonStr(refundOrder));
|
||||
|
||||
if (!processReviewList(refundOrder, 0)) {
|
||||
return CommonResult.failed("处理失败");
|
||||
throw new ApiException("退款审核失败!");
|
||||
}
|
||||
|
||||
// === 7. 特殊场景:同城配送订单取消 ===
|
||||
|
||||
@ -263,7 +263,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
//汽配 18:珠宝 20:披萨 21:中餐 22:水产 27:专人直送 32:中端饮品 33:便利店 34:面包糕点 35:火锅 36:证照 40:烧烤小龙虾 41:外部落地配 47:烟酒
|
||||
//行 48:成人用品 99:其他
|
||||
// 经营类型: 快餐,百货,生鲜,高端饮品,蛋糕,鲜花,数码,服装,披萨,水产,中端饮品,便利店,面包糕点,烟酒,其他
|
||||
params.put("shop_product_types", "1,3,6,8,13,14,15,16,20,22,32,33,34,47,99");
|
||||
params.put("shop_product_types", "33"); //"1,3,6,8,13,14,15,16,20,22,32,33,34,47,99"
|
||||
params.put("shop_type", 1); // 店铺类型: 1-普通型 2-平台型
|
||||
params.put("shop_address", shopAddress); // 店铺地址
|
||||
params.put("longitude", longitude); // 经度
|
||||
@ -1014,7 +1014,8 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
orderStatus = StateCode.ORDER_STATE_RECEIVED; //已签收
|
||||
|
||||
// 通知微信用户确认收货(同城配送不能调用微信的确认收货)
|
||||
// wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());
|
||||
wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());
|
||||
|
||||
// 不要提前 订单确认收货,等微信拉卡拉确认通知
|
||||
// try {
|
||||
// shopOrderBaseService.receive(shopOrderId, null);
|
||||
@ -1112,7 +1113,7 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
|
||||
// wxOrderShippingService.notifyConfirmReceive(shopStoreSfOrder.getShop_order_id());
|
||||
|
||||
// 订单确认收货
|
||||
// shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
// shopOrderBaseService.receive(shopStoreSfOrder.getShop_order_id(), null);
|
||||
|
||||
String orderId = shopStoreSfOrder.getShop_order_id();
|
||||
|
||||
|
||||
@ -137,5 +137,11 @@ public class ShopStorePrinterController {
|
||||
return shopStorePrinterService.tryPrint(printer_id);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "向厂家删除一个打票机", notes = "向厂家删除一个打票机")
|
||||
@RequestMapping(value = "/delete/from/feie", method = {RequestMethod.POST})
|
||||
public CommonResult deleteFeiePrinter(@RequestParam(name = "sn_list", required = true) String snList) {
|
||||
return shopStorePrinterService.deleteFeiePrinter(snList);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -94,5 +94,13 @@ public interface ShopStorePrinterService extends IBaseService<ShopStorePrinter>
|
||||
* @param printerId 打印机Id
|
||||
**/
|
||||
CommonResult tryPrint(Long printerId);
|
||||
|
||||
/**
|
||||
* 从飞鹅厂家删除飞鹅打印机
|
||||
*
|
||||
* @param snList 打印机编号,多台打印机请用减号“-”连接起来。如:316500010-316500011-316500012
|
||||
* @return
|
||||
*/
|
||||
CommonResult deleteFeiePrinter(String snList);
|
||||
}
|
||||
|
||||
|
||||
@ -786,11 +786,11 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
}
|
||||
|
||||
if (CheckUtil.isNotEmpty(store_category_id)) {
|
||||
queryWrapper.eq("store_category_id",store_category_id);
|
||||
queryWrapper.eq("store_category_id", store_category_id);
|
||||
params.put("store_category_id", store_category_id);
|
||||
}
|
||||
if(CheckUtil.isNotEmpty(store_2nd_category_id)){
|
||||
queryWrapper.eq("store_2nd_category_id",store_2nd_category_id);
|
||||
if (CheckUtil.isNotEmpty(store_2nd_category_id)) {
|
||||
queryWrapper.eq("store_2nd_category_id", store_2nd_category_id);
|
||||
}
|
||||
|
||||
|
||||
@ -3201,9 +3201,15 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
// 设置店铺基础信息(添加null检查)
|
||||
shopStoreBase.setUser_id(userId);
|
||||
shopStoreBase.setStore_name(shopMchEntry.getStore_name());
|
||||
shopStoreBase.setStore_category_id(shopMchEntry.getBiz_category());
|
||||
shopStoreBase.setStore_2nd_category_id(
|
||||
shopMchEntry.getBiz_second_category() != null ? shopMchEntry.getBiz_second_category() : 0);
|
||||
|
||||
// 店铺二级分类
|
||||
if (CheckUtil.isEmpty(shopStoreBase.getStore_category_id())) {
|
||||
shopStoreBase.setStore_category_id(shopMchEntry.getBiz_category());
|
||||
}
|
||||
if (CheckUtil.isEmpty(shopStoreBase.getStore_2nd_category_id())) {
|
||||
shopStoreBase.setStore_2nd_category_id(
|
||||
CheckUtil.isNotEmpty(shopMchEntry.getBiz_second_category()) ? shopMchEntry.getBiz_second_category() : 0);
|
||||
}
|
||||
|
||||
// 计算分账比例
|
||||
BigDecimal splitRatio = shopMchEntryService.getMchEntryRatioOrDefault(
|
||||
@ -3211,8 +3217,13 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
shopMchEntry.getBiz_second_category(),
|
||||
shopMchEntry.getSplit_ratio(),
|
||||
new BigDecimal(94));
|
||||
shopStoreBase.setSplit_ratio(splitRatio);
|
||||
shopStoreBase.setPacking_fee(BigDecimal.ZERO);
|
||||
|
||||
if (CheckUtil.isEmpty(shopStoreBase.getSplit_ratio())) {
|
||||
shopStoreBase.setSplit_ratio(splitRatio);
|
||||
}
|
||||
if (CheckUtil.isEmpty(shopStoreBase.getPacking_fee())) {
|
||||
shopStoreBase.setPacking_fee(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
// 处理图片信息
|
||||
String storeFacadeImage = shopMchEntry.getFront_facade_image();
|
||||
@ -3224,12 +3235,12 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
|
||||
|
||||
// 处理地址信息(添加null检查)
|
||||
String storeDistrict = shopMchEntry.getStore_district();
|
||||
if (storeDistrict != null) {
|
||||
if (StrUtil.isNotBlank(storeDistrict)) {
|
||||
shopStoreBase.setStore_district_id(storeDistrict);
|
||||
}
|
||||
|
||||
String storeArea = shopMchEntry.getStore_area();
|
||||
if (storeArea != null) {
|
||||
if (StrUtil.isNotBlank(storeArea)) {
|
||||
shopStoreBase.setStore_area(storeArea);
|
||||
}
|
||||
|
||||
|
||||
@ -131,6 +131,9 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
return CommonResult.success(null, "打票机已添加,请勿重复操作");
|
||||
}
|
||||
|
||||
// 从厂家删除其他店使用该打印机的记录
|
||||
feieUtil.delPrinter(record.getPrinter_sn());
|
||||
|
||||
if (add(record)) {
|
||||
return CommonResult.success(null, "添加成功");
|
||||
}
|
||||
@ -138,27 +141,36 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
return CommonResult.failed("添加失败!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新店铺打印机信息
|
||||
*
|
||||
* @param record 打印机信息
|
||||
* @return 更新结果
|
||||
*/
|
||||
@Override
|
||||
public CommonResult updateShopStorePrinter(ShopStorePrinter record) {
|
||||
|
||||
// 判断有没有权限
|
||||
UserDto user = getCurrentUser();
|
||||
if (user == null || !user.isStore()) {
|
||||
logger.warn("用户无权限操作更新打印机,用户ID: {}", user != null ? user.getId() : "null");
|
||||
return CommonResult.failed("无权限操作!");
|
||||
}
|
||||
|
||||
Integer userId = user.getId() == null ? 0 : user.getId();
|
||||
|
||||
if (record == null || record.getPrinter_id() <= 0) {
|
||||
logger.warn("更新打印机失败,记录不存在或ID无效,打印机ID: {}", record != null ? record.getPrinter_id() : "null");
|
||||
return CommonResult.failed("记录不存在!");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(record.getPrinter_sn()) || StrUtil.isBlank(record.getPrinter_key()) || StrUtil.isBlank(record.getPrinter_name())) {
|
||||
logger.warn("更新打印机失败,缺少必要参数,打印机ID: {}", record.getPrinter_id());
|
||||
return CommonResult.failed("缺少必要参数!");
|
||||
}
|
||||
|
||||
ShopStorePrinter existRecord = getById(record.getPrinter_id());
|
||||
if (existRecord == null) {
|
||||
logger.warn("更新打印机失败,打票机不存在,打印机ID: {}", record.getPrinter_id());
|
||||
return CommonResult.failed("打票机不存在!");
|
||||
}
|
||||
|
||||
@ -171,6 +183,8 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
updateWrapper.set("region_id", record.getRegion_id());
|
||||
updateWrapper.set("paper_with", record.getPaper_with());
|
||||
updateWrapper.set("website_url", record.getWebsite_url());
|
||||
|
||||
// 根据原记录状态设置更新后的状态
|
||||
if (existRecord.getStatus() == null || !CommonConstant.Enable.equals(existRecord.getStatus())) {
|
||||
updateWrapper.set("status", CommonConstant.Disable2);
|
||||
} else {
|
||||
@ -181,40 +195,53 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
updateWrapper.set("updated_by", userId);
|
||||
|
||||
String msg = "修改成功";
|
||||
|
||||
// 检查是否更改了打印机SN
|
||||
if (!existRecord.getPrinter_sn().equals(record.getPrinter_sn())) {
|
||||
logger.info("检测到打印机SN变更,原SN: {}, 新SN: {}", existRecord.getPrinter_sn(), record.getPrinter_sn());
|
||||
|
||||
// 更改了 sn,并且 sn 从未添加过(打票机不在门店内的)
|
||||
QueryWrapper<ShopStorePrinter> queryWrapper2 = new QueryWrapper<>();
|
||||
queryWrapper2.eq("store_id", record.getStore_id());
|
||||
queryWrapper2.eq("printer_sn", record.getPrinter_sn());
|
||||
ShopStorePrinter existRecord2 = getOne(queryWrapper2);
|
||||
ShopStorePrinter existRecord2 = findOne(queryWrapper2);
|
||||
if (existRecord2 == null || existRecord2.getPrinter_id() <= 0) {
|
||||
|
||||
// 打印机从未加入到厂家到情况,往厂商添加打印机
|
||||
// 格式:"922441475#r6ZXPvHH#核销柜台";
|
||||
Pair<Boolean, String> retPair = feieUtil.addPrinter(String.format("%s#%s#%s", record.getPrinter_sn(), record.getPrinter_key(), record.getPrinter_name()));
|
||||
String printerInfo = String.format("%s#%s#%s", record.getPrinter_sn(), record.getPrinter_key(), record.getPrinter_name());
|
||||
logger.info("向厂家添加新打印机: {}", printerInfo);
|
||||
Pair<Boolean, String> retPair = feieUtil.addPrinter(printerInfo);
|
||||
|
||||
if (retPair.getFirst()) {
|
||||
logger.info("向厂家添加打印机成功,SN: {}", record.getPrinter_sn());
|
||||
updateWrapper.set("flag", CommonConstant.Enable);
|
||||
updateWrapper.set("status", CommonConstant.Enable);
|
||||
} else {
|
||||
logger.warn("向厂家添加打印机失败,SN: {}, 错误信息: {}", record.getPrinter_sn(), retPair.getSecond());
|
||||
msg = msg + ",但打印机绑定未成功,请检查打印机编号和密钥是否填写正确。";
|
||||
updateWrapper.set("flag", CommonConstant.Disable2);
|
||||
updateWrapper.set("status", CommonConstant.Disable2);
|
||||
}
|
||||
|
||||
// 解绑之前的打印机
|
||||
logger.info("解绑原打印机,SN: {}", existRecord.getPrinter_sn());
|
||||
feieUtil.delPrinter(existRecord.getPrinter_sn());
|
||||
} else {
|
||||
// 打印机编号已被使用
|
||||
logger.warn("打印机已添加,请勿重复操作,SN: {}", record.getPrinter_sn());
|
||||
return CommonResult.success(null, "打票机已添加,请勿重复操作");
|
||||
}
|
||||
}
|
||||
|
||||
boolean success = update(updateWrapper);
|
||||
if (success) {
|
||||
logger.info("更新打印机信息成功,打印机ID: {}", record.getPrinter_id());
|
||||
return CommonResult.success(null, msg);
|
||||
}
|
||||
|
||||
logger.error("更新打印机信息失败,打印机ID: {}", record.getPrinter_id());
|
||||
return CommonResult.failed("修改失败!");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -232,7 +259,6 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
return CommonResult.failed("打票机不存在,无法操作!");
|
||||
}
|
||||
|
||||
|
||||
if (CommonConstant.Enable.equals(status)) {
|
||||
// 向厂家新增打印机
|
||||
// 格式:"922441475#r6ZXPvHH#核销柜台";
|
||||
@ -243,9 +269,9 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
} else {
|
||||
status = CommonConstant.Disable2;
|
||||
// 向厂家解绑打印机
|
||||
boolean success = feieUtil.delPrinter(record.getPrinter_sn());
|
||||
if (!success) {
|
||||
return CommonResult.failed("打印机解绑定未成功,操作失败。");
|
||||
Pair<Boolean, String> retPair = feieUtil.delPrinter(record.getPrinter_sn());
|
||||
if (!retPair.getFirst()) {
|
||||
return CommonResult.failed(retPair.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +412,6 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
return find(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 测试打印
|
||||
**/
|
||||
@ -442,5 +467,30 @@ public class ShopStorePrinterServiceImpl extends BaseServiceImpl<ShopStorePrinte
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从飞鹅厂家删除飞鹅打印机
|
||||
*
|
||||
* @param snList 打印机编号,多台打印机请用减号"-"连接起来。如:316500010-316500011-316500012
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
public CommonResult deleteFeiePrinter(String snList) {
|
||||
// 参数校验
|
||||
if (StrUtil.isBlank(snList)) {
|
||||
logger.warn("删除飞鹅打印机失败:打印机编号列表为空");
|
||||
return CommonResult.failed("打印机编号不能为空");
|
||||
}
|
||||
|
||||
logger.info("开始从厂家删除飞鹅打印机,打印机编号: {}", snList);
|
||||
|
||||
Pair<Boolean, String> retPair = feieUtil.delPrinter(snList);
|
||||
if (!retPair.getFirst()) {
|
||||
logger.error("从厂家删除飞鹅打印机失败,打印机编号: {}", snList);
|
||||
return CommonResult.failed(retPair.getSecond());
|
||||
}
|
||||
logger.info("从厂家删除飞鹅打印机成功,打印机编号: {}", snList);
|
||||
return CommonResult.success("从厂家删除飞鹅打印机成功");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -410,6 +410,7 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl<S
|
||||
transportBase.setStore_longitude(storeBase.getStore_longitude());
|
||||
transportBase.setStore_latitude(storeBase.getStore_latitude());
|
||||
transportBase.setStore_address(storeBase.getStore_address());
|
||||
transportBase.setBusiness_type(33); // 默认经营分类:顺丰同城的便利店
|
||||
|
||||
// 保存或更新基础配送信息
|
||||
Pair<Long, String> saveOrUpdateResult = saveOrUpdateShopStoreSameCityTransportBase(transportBase);
|
||||
|
||||
@ -120,18 +120,18 @@ public class FeieUtil {
|
||||
* @param snList 打印机编号,多台打印机请用减号“-”连接起来。如:316500010-316500011-316500012
|
||||
* @return
|
||||
*/
|
||||
public boolean delPrinter(String snList) {
|
||||
public Pair<Boolean, String> delPrinter(String snList) {
|
||||
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
|
||||
nvps.add(new BasicNameValuePair("snlist", snList));
|
||||
|
||||
FeiePrinterApiRes reps = sendHttpPost("Open_printerDelList", nvps);
|
||||
logger.info("飞鹅删除打印机返回数据:{}", reps);
|
||||
if (reps != null && reps.getRet().equals(0)) {
|
||||
return true;
|
||||
return Pair.of(true, "打印机删除成功!");
|
||||
}
|
||||
|
||||
logger.error("飞鹅删除打印机操作失败:{}", reps.getMsg());
|
||||
return false;
|
||||
return Pair.of(true, "打印机删除失败:" + reps.getMsg());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -8,10 +8,20 @@
|
||||
|
||||
package com.suisung.mall.shop.wechat.controller;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.suisung.mall.common.api.CommonResult;
|
||||
import com.suisung.mall.common.exception.ApiException;
|
||||
import com.suisung.mall.shop.wechat.service.WxOrderShippingService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.data.util.Pair;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 小程序发货信息管理服务 前端控制器
|
||||
*/
|
||||
@ -19,4 +29,17 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping("/admin/shop/order-shipping")
|
||||
public class WxOrderShippingController {
|
||||
|
||||
@Resource
|
||||
private WxOrderShippingService wxOrderShippingService;
|
||||
|
||||
@ApiOperation(value = "配置订单详情路径", notes = "配置订单详情路径")
|
||||
@RequestMapping(value = "/updateOrderDetailPath", method = RequestMethod.POST)
|
||||
public CommonResult updateOrderDetailPath(@RequestBody JSONObject params) {
|
||||
Pair<Boolean, String> result = wxOrderShippingService.updateOrderDetailPath(params.getStr("path"));
|
||||
if (!result.getFirst()) {
|
||||
throw new ApiException(result.getSecond());
|
||||
}
|
||||
return CommonResult.success(result.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,4 +30,26 @@ public interface WxOrderShippingService {
|
||||
* @return 返回确认收货结果,包含成功状态和错误消息
|
||||
*/
|
||||
Pair<Boolean, String> notifyConfirmReceive(String orderId);
|
||||
|
||||
|
||||
/**
|
||||
* 配置订单详情路径
|
||||
* 参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
*/
|
||||
/**
|
||||
* 更新订单详情路径
|
||||
* 参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
*
|
||||
* @param path 包括参数名=${商品订单号}
|
||||
* @return
|
||||
*/
|
||||
Pair<Boolean, String> updateOrderDetailPath(String path);
|
||||
|
||||
/**
|
||||
* 消息跳转路径设置接口
|
||||
*
|
||||
* @param orderId 订单号
|
||||
* @return
|
||||
*/
|
||||
Pair<Boolean, String> setMsgJumpPath(String orderId);
|
||||
}
|
||||
|
||||
@ -33,22 +33,24 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 对接微信订单管理相关接口
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WxOrderShippingServiceImpl implements WxOrderShippingService {
|
||||
|
||||
private final String ORDER_DETAIL_PATH = "member/order/detail";
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private WxUtil wxUtil;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopOrderBaseService shopOrderBaseService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopStoreSfOrderService shopStoreSfOrderService;
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private ShopOrderLogisticsService shopOrderLogisticsService;
|
||||
@ -159,6 +161,9 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
|
||||
return Pair.of(false, "发货信息录入失败: " + errorMsg);
|
||||
}
|
||||
|
||||
// 跳转链接设置
|
||||
setMsgJumpPath(orderId);
|
||||
|
||||
log.info("发货信息录入成功, 订单ID: {}", orderId);
|
||||
return Pair.of(true, "发货信息录入成功");
|
||||
|
||||
@ -230,6 +235,9 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
|
||||
return Pair.of(false, "通知微信用户确认收货失败: " + errorMsg);
|
||||
}
|
||||
|
||||
// 跳转链接设置
|
||||
setMsgJumpPath(orderId);
|
||||
|
||||
log.info("通知微信用户确认收货成功, 订单ID: {}", orderId);
|
||||
return Pair.of(true, "通知微信用户确认收货成功");
|
||||
|
||||
@ -241,4 +249,138 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
|
||||
return Pair.of(false, "通知微信确认收货失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置订单详情路径
|
||||
* 参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
*
|
||||
* @param path 订单详情页面路径
|
||||
* @return 配置结果,包含成功状态和错误消息
|
||||
*/
|
||||
@Override
|
||||
public Pair<Boolean, String> updateOrderDetailPath(String path) {
|
||||
log.debug("开始配置订单详情路径,路径: {}", path);
|
||||
if (StrUtil.isBlank(path)) {
|
||||
path = String.format("%s?on=${商品订单号}", ORDER_DETAIL_PATH);
|
||||
log.warn("订单详情路径为空,默认:{}", path);
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取微信访问令牌
|
||||
String accessToken = wxUtil.getAccessToken();
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
log.error("获取AccessToken失败");
|
||||
return Pair.of(false, "获取AccessToken失败");
|
||||
}
|
||||
|
||||
if (!StrUtil.contains(path, "?")) {
|
||||
path = String.format("%s?on=${商品订单号}", path);
|
||||
}
|
||||
|
||||
// 构造请求参数
|
||||
JSONObject paramsJSON = new JSONObject()
|
||||
.set("path", path);
|
||||
|
||||
// 构造请求URL
|
||||
String postUrl = "https://api.weixin.qq.com/wxa/sec/order/update_order_detail_path?access_token=" + accessToken;
|
||||
log.debug("配置订单详情路径请求: {} \n {}", postUrl, paramsJSON);
|
||||
|
||||
// 发送请求到微信API
|
||||
JSONObject respObj = RestTemplateHttpUtil.sendPost(
|
||||
postUrl,
|
||||
null, paramsJSON, JSONObject.class
|
||||
);
|
||||
|
||||
// 处理响应结果
|
||||
if (respObj == null) {
|
||||
log.error("配置订单详情路径失败,返回结果为空");
|
||||
return Pair.of(false, "配置订单详情路径失败,返回结果为空");
|
||||
}
|
||||
|
||||
int errCode = respObj.getInt("errcode", -1);
|
||||
if (errCode != 0) {
|
||||
String errorMsg = respObj.getStr("errmsg", "未知错误");
|
||||
log.error("配置订单详情路径失败,错误码: {}, 错误信息: {}", errCode, errorMsg);
|
||||
return Pair.of(false, "配置订单详情路径失败: " + errorMsg);
|
||||
}
|
||||
|
||||
log.info("配置订单详情路径成功,路径: {}", path);
|
||||
return Pair.of(true, path);
|
||||
|
||||
} catch (HttpClientErrorException e) {
|
||||
log.error("HTTP请求错误,状态码: {}, 错误信息: {}", e.getStatusCode(), e.getMessage(), e);
|
||||
return Pair.of(false, "HTTP请求错误: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("配置订单详情路径失败,错误信息: {}", e.getMessage(), e);
|
||||
return Pair.of(false, "配置订单详情路径失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息跳转路径设置接口
|
||||
* 参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html
|
||||
* 用于设置微信订单消息中的跳转路径,用户点击消息时可跳转到指定页面
|
||||
*
|
||||
* @param orderId 订单号
|
||||
* @return 设置结果,包含成功状态和跳转路径
|
||||
*/
|
||||
@Override
|
||||
public Pair<Boolean, String> setMsgJumpPath(String orderId) {
|
||||
log.debug("开始设置消息跳转路径,订单ID: {}", orderId);
|
||||
|
||||
if (StrUtil.isBlank(orderId)) {
|
||||
log.warn("订单号不能为空");
|
||||
return Pair.of(false, "订单号不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取微信访问令牌
|
||||
String accessToken = wxUtil.getAccessToken();
|
||||
if (StrUtil.isBlank(accessToken)) {
|
||||
log.error("获取AccessToken失败,订单ID: {}", orderId);
|
||||
return Pair.of(false, "获取AccessToken失败");
|
||||
}
|
||||
|
||||
// 构造跳转路径
|
||||
String path = String.format("%s?on=%s", ORDER_DETAIL_PATH, orderId);
|
||||
log.debug("构造消息跳转路径: {}", path);
|
||||
|
||||
// 构造请求参数
|
||||
JSONObject paramsJSON = new JSONObject()
|
||||
.set("path", path);
|
||||
|
||||
// 构造请求URL
|
||||
String postUrl = "https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path?access_token=" + accessToken;
|
||||
log.debug("消息跳转路径设置请求: {} \n {}", postUrl, paramsJSON);
|
||||
|
||||
// 发送请求到微信API
|
||||
JSONObject respObj = RestTemplateHttpUtil.sendPost(
|
||||
postUrl,
|
||||
null, paramsJSON, JSONObject.class
|
||||
);
|
||||
|
||||
// 处理响应结果
|
||||
if (respObj == null) {
|
||||
log.error("消息跳转路径设置失败,订单ID: {}, 返回结果为空", orderId);
|
||||
return Pair.of(false, "消息跳转路径设置失败,返回结果为空");
|
||||
}
|
||||
|
||||
int errCode = respObj.getInt("errcode", -1);
|
||||
if (errCode != 0) {
|
||||
String errorMsg = respObj.getStr("errmsg", "未知错误");
|
||||
log.error("消息跳转路径设置失败,订单ID: {}, 错误码: {}, 错误信息: {}", orderId, errCode, errorMsg);
|
||||
return Pair.of(false, "消息跳转路径设置失败: " + errorMsg);
|
||||
}
|
||||
|
||||
log.info("消息跳转路径设置成功,订单ID: {}, 路径: {}", orderId, path);
|
||||
return Pair.of(true, path);
|
||||
|
||||
} catch (HttpClientErrorException e) {
|
||||
log.error("HTTP请求错误,订单ID: {}, 状态码: {}, 错误信息: {}", orderId, e.getStatusCode(), e.getMessage(), e);
|
||||
return Pair.of(false, "HTTP请求错误: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("消息跳转路径设置失败,订单ID: {}, 错误信息: {}", orderId, e.getMessage(), e);
|
||||
return Pair.of(false, "消息跳转路径设置失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,18 +58,24 @@ public class WxUtil {
|
||||
params.put("secret", xcx_app_secret);
|
||||
params.put("grant_type", "client_credential");
|
||||
|
||||
JSONObject resultObj = new JSONObject();
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", params);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response);
|
||||
|
||||
// 修正:使用 jsonObject 而不是 resultObj 来检查错误信息
|
||||
Object errmsg = jsonObject.get("errmsg");
|
||||
if (ObjectUtil.isNotEmpty(errmsg)) {
|
||||
String errmsgStr = Convert.toStr(resultObj.get("errmsg"));
|
||||
if (!errmsgStr.equals("0")) {
|
||||
String errmsgStr = Convert.toStr(errmsg);
|
||||
if (!"0".equals(errmsgStr)) {
|
||||
throw new ApiException(I18nUtil._("获取access_token失败"));
|
||||
}
|
||||
}
|
||||
Integer expiresIn = Convert.toInt(jsonObject.get("expires_in"), 0);
|
||||
|
||||
// 优化:expiresIn 逻辑更清晰
|
||||
Long expiresIn = Convert.toLong(jsonObject.get("expires_in"), 7200L) - 60L;
|
||||
if (expiresIn <= 0L) {
|
||||
expiresIn = 7140L;
|
||||
}
|
||||
redisService.set(StateCode.WX_XCX_ACCESSTOKEN, Convert.toStr(jsonObject.get("access_token")), expiresIn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ sf-express:
|
||||
# dev_id: 1715091463
|
||||
# appid: 1715091463
|
||||
# appkey: 47466ae69c530f831395e1bc405639fb
|
||||
enable: 2
|
||||
enable: 1
|
||||
#拉卡拉进件配置
|
||||
lakala:
|
||||
#服务地址
|
||||
|
||||
@ -575,6 +575,7 @@
|
||||
<result property="order_product_amount" column="order_product_amount"/>
|
||||
<result property="order_payment_amount" column="order_payment_amount"/>
|
||||
<result property="order_shipping_fee" column="order_shipping_fee"/>
|
||||
<result property="order_shipping_fee_inner" column="order_shipping_fee_inner"/>
|
||||
<result property="packing_fee" column="packing_fee"/>
|
||||
<!--总计优惠金额 order_discount_amount + order_voucher_price + order_points_fee + order_adjust_fee-->
|
||||
<result property="total_discount_amount" column="total_discount_amount"/>
|
||||
@ -780,11 +781,12 @@
|
||||
AS is_new_buyer,
|
||||
oi.payment_time,
|
||||
od.order_shipping_fee,
|
||||
IFNULL(od.order_shipping_fee_inner, 0) as order_shipping_fee_inner,
|
||||
<!--总计优惠金额 order_discount_amount + order_voucher_price + order_points_fee + order_adjust_fee-->
|
||||
(od.order_discount_amount + od.voucher_price + od.order_points_fee + od.order_adjust_fee) as
|
||||
total_discount_amount,
|
||||
<!--预计收入:订单原价金额-总计优惠金额-配送费-平台费 + 打包费-->
|
||||
(ob.order_product_amount-od.order_discount_amount-od.voucher_price-od.order_points_fee-od.order_adjust_fee-od.platform_fee-od.order_shipping_fee+od.packing_fee)
|
||||
(ob.order_product_amount-od.order_discount_amount-od.voucher_price-od.order_points_fee-od.order_adjust_fee-od.platform_fee-order_shipping_fee_inner+od.packing_fee)
|
||||
as order_income_amount,
|
||||
od.platform_fee,
|
||||
od.packing_fee,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
, order_desc, order_delay_time, delivery_type_id, delivery_time_id, delivery_time, delivery_time_rang,
|
||||
delivery_time_h, delivery_time_i, delivery_istimer, invoice_type_id, invoice_company_code, order_invoice_title,
|
||||
order_message, order_item_amount, order_discount_amount, order_adjust_fee, order_points_fee,
|
||||
order_shipping_fee_amount, order_shipping_fee, platform_fee, packing_fee, voucher_id, voucher_number, voucher_price, redpacket_id,
|
||||
order_shipping_fee_amount, order_shipping_fee,order_shipping_fee_inner, platform_fee, packing_fee, voucher_id, voucher_number, voucher_price, redpacket_id,
|
||||
redpacket_number, redpacket_price, order_redpacket_price, order_resource_ext1, order_resource_ext2,
|
||||
order_resource_ext3, trade_payment_money, trade_payment_recharge_card, trade_payment_credit,
|
||||
order_refund_status, order_refund_amount, order_refund_agree_amount, order_return_status, order_return_num,
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.suisung.mall.shop.order.mapper.ShopOrderItemMapper">
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">order_item_id
|
||||
<sql id="Base_Column_List">
|
||||
order_item_id
|
||||
, order_id, buyer_id, store_id, product_id, item_id,
|
||||
item_name, category_id, spec_id, spec_info, item_unit_price, item_unit_points, item_unit_sp,
|
||||
order_item_unit_price,
|
||||
@ -38,24 +39,47 @@
|
||||
INNER JOIN
|
||||
shop_product_index ON shop_order_item.product_id = shop_product_index.product_id
|
||||
<where>
|
||||
<if test="map.store_id!=null">shop_order_info.store_id=#{map.store_id}</if>
|
||||
<if test="map.item_name!=null">and shop_order_item.item_name like concat('%', #{map.item_name}, '%')</if>
|
||||
<if test="map.product_name!=null">and shop_product_index.product_name like concat('%', #{map.product_name},
|
||||
<if test="map.store_id!=null">
|
||||
shop_order_info.store_id=#{map.store_id}
|
||||
</if>
|
||||
<if test="map.item_name!=null">
|
||||
and shop_order_item.item_name like concat('%', #{map.item_name}, '%')
|
||||
</if>
|
||||
<if test="map.product_name!=null">
|
||||
and shop_product_index.product_name like concat('%', #{map.product_name},
|
||||
'%')
|
||||
</if>
|
||||
<if test="map.category_id!=null">and shop_order_item.category_id=#{map.category_id}</if>
|
||||
<if test="map.product_id!=null">and shop_order_item.product_id=#{map.product_id}</if>
|
||||
<if test="map.order_st_time!=null">and shop_order_info.order_time >=#{map.order_st_time}</if>
|
||||
<if test="map.order_ed_time">and shop_order_info.order_time <=#{map.order_ed_time}</if>
|
||||
<if test="map.da_province_id!=null">and shop_order_delivery_address.da_province_id =#{map.da_province_id}
|
||||
<if test="map.category_id!=null">
|
||||
and shop_order_item.category_id=#{map.category_id}
|
||||
</if>
|
||||
<if test="map.da_city_id!=null">and shop_order_delivery_address.da_city_id =#{map.da_city_id}</if>
|
||||
<if test="map.da_county_id!=null">and shop_order_delivery_address.da_county_id =#{map.da_county_id}</if>
|
||||
<if test="map.da_address!=null">and shop_order_delivery_address.da_address like concat('%',
|
||||
<if test="map.product_id!=null">
|
||||
and shop_order_item.product_id=#{map.product_id}
|
||||
</if>
|
||||
<if test="map.order_st_time!=null">
|
||||
and shop_order_info.order_time >=#{map.order_st_time}
|
||||
</if>
|
||||
<if test="map.order_ed_time">
|
||||
and shop_order_info.order_time <=#{map.order_ed_time}
|
||||
</if>
|
||||
<if test="map.da_province_id!=null">
|
||||
and shop_order_delivery_address.da_province_id =#{map.da_province_id}
|
||||
</if>
|
||||
<if test="map.da_city_id!=null">
|
||||
and shop_order_delivery_address.da_city_id =#{map.da_city_id}
|
||||
</if>
|
||||
<if test="map.da_county_id!=null">
|
||||
and shop_order_delivery_address.da_county_id =#{map.da_county_id}
|
||||
</if>
|
||||
<if test="map.da_address!=null">
|
||||
and shop_order_delivery_address.da_address like concat('%',
|
||||
#{map.da_address}, '%')
|
||||
</if>
|
||||
<if test="map.order_is_paid!=null">and shop_order_info.order_is_paid =#{map.order_is_paid}</if>
|
||||
<if test="map.subsite_id!=null">and shop_order_info.subsite_id =#{map.subsite_id}</if>
|
||||
<if test="map.order_is_paid!=null">
|
||||
and shop_order_info.order_is_paid =#{map.order_is_paid}
|
||||
</if>
|
||||
<if test="map.subsite_id!=null">
|
||||
and shop_order_info.subsite_id =#{map.subsite_id}
|
||||
</if>
|
||||
</where>
|
||||
GROUP BY
|
||||
shop_order_item.item_id
|
||||
@ -68,29 +92,72 @@
|
||||
left join shop_order_delivery_address a ON a.order_id = o.order_id
|
||||
left join shop_product_base b ON m.product_id = b.product_id
|
||||
<where>
|
||||
<if test="params.store_id!=null">m.store_id=#{params.store_id}</if>
|
||||
<if test="params.order_id!=null">and m.order_id=#{params.order_id}</if>
|
||||
<if test="params.item_id!=null">and m.item_id=#{params.item_id}</if>
|
||||
<if test="params.order_is_paid!=null">and o.order_is_paid=#{params.order_is_paid}</if>
|
||||
<if test="params.order_st_time!=null">and o.order_time >=#{params.order_st_time}</if>
|
||||
<if test="params.order_ed_time">and o.order_time <=#{params.order_ed_time}</if>
|
||||
<if test="params.query_order_st_time!=null">and o.order_time >=#{params.query_order_st_time}</if>
|
||||
<if test="params.query_order_ed_time!=null">and o.order_time <=#{params.query_order_ed_time}</if>
|
||||
<if test="params.category_id!=null">and m.category_id=#{params.category_id}</if>
|
||||
<if test="params.product_name!=null">and b.product_name like concat('%', #{params.product_name}, '%')</if>
|
||||
<if test="params.product_id!=null">and m.product_id=#{params.product_id}</if>
|
||||
<if test="params.da_province_id!=null">and a.da_province_id =#{params.da_province_id}</if>
|
||||
<if test="params.da_city_id!=null">and a.da_city_id =#{params.da_city_id}</if>
|
||||
<if test="params.da_county_id!=null">and a.da_county_id =#{params.da_county_id}</if>
|
||||
<if test="params.da_address!=null">and a.da_address like concat('%', #{params.da_address}, '%')</if>
|
||||
<if test="params.store_id!=null">
|
||||
m.store_id=#{params.store_id}
|
||||
</if>
|
||||
<if test="params.order_id!=null">
|
||||
and m.order_id=#{params.order_id}
|
||||
</if>
|
||||
<if test="params.item_id!=null">
|
||||
and m.item_id=#{params.item_id}
|
||||
</if>
|
||||
<if test="params.order_is_paid!=null">
|
||||
and o.order_is_paid=#{params.order_is_paid}
|
||||
</if>
|
||||
<if test="params.order_st_time!=null">
|
||||
and o.order_time >=#{params.order_st_time}
|
||||
</if>
|
||||
<if test="params.order_ed_time">
|
||||
and o.order_time <=#{params.order_ed_time}
|
||||
</if>
|
||||
<if test="params.query_order_st_time!=null">
|
||||
and o.order_time >=#{params.query_order_st_time}
|
||||
</if>
|
||||
<if test="params.query_order_ed_time!=null">
|
||||
and o.order_time <=#{params.query_order_ed_time}
|
||||
</if>
|
||||
<if test="params.category_id!=null">
|
||||
and m.category_id=#{params.category_id}
|
||||
</if>
|
||||
<if test="params.product_name!=null">
|
||||
and b.product_name like concat('%', #{params.product_name}, '%')
|
||||
</if>
|
||||
<if test="params.product_id!=null">
|
||||
and m.product_id=#{params.product_id}
|
||||
</if>
|
||||
<if test="params.da_province_id!=null">
|
||||
and a.da_province_id =#{params.da_province_id}
|
||||
</if>
|
||||
<if test="params.da_city_id!=null">
|
||||
and a.da_city_id =#{params.da_city_id}
|
||||
</if>
|
||||
<if test="params.da_county_id!=null">
|
||||
and a.da_county_id =#{params.da_county_id}
|
||||
</if>
|
||||
<if test="params.da_address!=null">
|
||||
and a.da_address like concat('%', #{params.da_address}, '%')
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectOrderItemPrintInfo" resultType="java.util.Map">
|
||||
SELECT a.product_id,a.item_name,a.order_item_unit_price,a.order_item_quantity,a.order_item_amount,
|
||||
SELECT a.product_id,
|
||||
-- 条件判断:spec_info非空且item_name不包含spec_info时拼接
|
||||
CASE
|
||||
WHEN a.spec_info IS NOT NULL
|
||||
AND a.spec_info != ''
|
||||
AND a.spec_info != 'null'
|
||||
AND a.spec_info != 'none'
|
||||
AND a.spec_info != 'undefined'
|
||||
AND INSTR(a.item_name, a.spec_info) = 0 -- INSTR返回0表示不包含
|
||||
THEN CONCAT(a.item_name, ' ', a.spec_info)
|
||||
ELSE a.item_name
|
||||
END AS item_name,
|
||||
a.spec_info,
|
||||
a.order_item_unit_price,
|
||||
a.order_item_quantity,
|
||||
a.order_item_amount,
|
||||
"" as product_sn
|
||||
FROM shop_order_item a
|
||||
WHERE a.order_id=#{orderId}
|
||||
ORDER BY a.order_item_id asc
|
||||
FROM shop_order_item a WHERE a.order_id = #{orderId} ORDER BY a.order_item_id asc
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user