diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderDraw.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderDraw.java index 0a3afff3..0a7dce49 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderDraw.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderDraw.java @@ -155,6 +155,9 @@ public class LklOrderDraw { @ApiModelProperty(value = "异步通知地址", example = "https://api.example.com/notify") private String notify_url; + @ApiModelProperty(value = "接口请求报文") + private String lkl_req; + /** * 异步通知返回的JSON数据 */ diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java index 46536d69..c14720c3 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/lakala/LklOrderSeparate.java @@ -94,6 +94,9 @@ public class LklOrderSeparate { @ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功") private String final_status; + @ApiModelProperty(value = "接口请求报文") + private String lkl_req; + @ApiModelProperty(value = "异步通知数据") private String notify_resp; diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java index c94b058c..499e9f8f 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/DateTimeUtils.java @@ -10,8 +10,7 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; -import java.util.Calendar; -import java.util.Date; +import java.util.*; @Slf4j public class DateTimeUtils { @@ -363,6 +362,76 @@ public class DateTimeUtils { return count; } + /** + * 计算多个时间段之间的交集(不跨天) + *

+ * 算法逻辑: + * 1. 遍历所有时间段,找到最晚的开始时间和最早的结束时间 + * 2. 如果最晚开始时间小于等于最早结束时间,则存在交集 + * 3. 如果最晚开始时间大于最早结束时间,则不存在交集 + * + * @param timeList 时间段列表,每个时间段是一个Map,包含开始时间startTimeStr和结束时间endTimeStr + * startTimeStr 开始时间字符串,支持格式如 HH:mm, HH:mm:ss, HH:mm:ss.SSS 等 + * endTimeStr 结束时间字符串,支持格式如 HH:mm, HH:mm:ss, HH:mm:ss.SSS 等 + * @return 返回一个Map,包含交集的时间段(startTimeStr和endTimeStr),如果无交集则返回空Map + */ + public static Map findTimeInterSection(List> timeList) { + // 参数校验 + if (timeList == null || timeList.isEmpty()) { + log.warn("时间段列表为空或null,无法计算交集"); + return new HashMap<>(); + } + + try { + LocalTime latestStartTime = null; + LocalTime earliestEndTime = null; + + // 遍历所有时间段 + for (Map timeMap : timeList) { + if (timeMap == null || !timeMap.containsKey("startTimeStr") || !timeMap.containsKey("endTimeStr")) { + log.warn("时间段数据不完整或格式不正确: {}", timeMap); + continue; + } + + String startTimeStr = timeMap.get("startTimeStr"); + String endTimeStr = timeMap.get("endTimeStr"); + + if (startTimeStr == null || endTimeStr == null) { + log.warn("时间段的开始或结束时间为空: startTime={}, endTime={}", startTimeStr, endTimeStr); + continue; + } + + LocalTime startTime = parseTime(startTimeStr); + LocalTime endTime = parseTime(endTimeStr); + + // 更新最晚开始时间和最早结束时间 + if (latestStartTime == null || startTime.isAfter(latestStartTime)) { + latestStartTime = startTime; + } + + if (earliestEndTime == null || endTime.isBefore(earliestEndTime)) { + earliestEndTime = endTime; + } + } + + // 检查是否存在交集 + if (latestStartTime != null && earliestEndTime != null && !latestStartTime.isAfter(earliestEndTime)) { + Map result = new HashMap<>(); + result.put("startTimeStr", latestStartTime.toString()); + result.put("endTimeStr", earliestEndTime.toString()); + return result; + } else { + // 无交集情况 + log.debug("给定的时间段列表无交集"); + return new HashMap<>(); + } + } catch (Exception e) { + log.error("计算时间段交集时发生异常", e); + return new HashMap<>(); + } + } + + /** * 判断指定时间是否在两个时间点之间(包含边界) * @@ -537,14 +606,52 @@ public class DateTimeUtils { // System.out.println(formatLocalDate(LocalDate.now(), "yyyy-MM-dd")); // 判断当前时间是否在工作时间(9:00-18:00)内 - boolean isWorkTime = isCurrentTimeInRange("09:00", "22:36"); +// boolean isWorkTime = isCurrentTimeInRange("09:00", "22:36"); // 判断特定时间是否在夜间时间(22:00-06:00)内 // LocalDateTime testTime = LocalDateTime.of(2025, 1, 1, 23, 30); - Date testTime = Date.from(LocalDateTime.of(2025, 10, 23, 21, 30).atZone(ZoneId.systemDefault()).toInstant()); - boolean isNight = isTimeInRange("08:30", "22:20", testTime); +// Date testTime = Date.from(LocalDateTime.of(2025, 10, 23, 21, 30).atZone(ZoneId.systemDefault()).toInstant()); +// boolean isNight = isTimeInRange("08:30", "22:20", testTime); + +// System.out.println("当前时间是否在工作时间内:" + isWorkTime); +// System.out.println("多个时间段的交集结果:" + isNight); + + System.out.println("=== 测试 findTimeIntersection ==="); + + // 测试正常交集情况 + List> timeList1 = new ArrayList<>(); + Map range1 = new HashMap<>(); + range1.put("startTimeStr", "06:00"); + range1.put("endTimeStr", "17:00"); + timeList1.add(range1); + + Map range2 = new HashMap<>(); + range2.put("startTimeStr", "06:00"); + range2.put("endTimeStr", "17:00"); + timeList1.add(range2); + + Map intersection1 = findTimeInterSection(timeList1); + System.out.println("交集结果1: " + intersection1); // 应该是 10:00 - 17:00 + + // 测试无交集情况 + List> timeList2 = new ArrayList<>(); + Map range3 = new HashMap<>(); + range3.put("startTimeStr", "09:00"); + range3.put("endTimeStr", "12:00"); + timeList2.add(range3); + + Map range4 = new HashMap<>(); + range4.put("startTimeStr", "13:00"); + range4.put("endTimeStr", "17:00"); + timeList2.add(range4); + + Map intersection2 = findTimeInterSection(timeList2); + System.out.println("交集结果2: " + intersection2); // 应该是空Map + + // 测试空列表 + Map intersection3 = findTimeInterSection(null); + System.out.println("交集结果3 (null输入): " + intersection3); // 应该是空Map + - System.out.println("当前时间是否在工作时间内:" + isWorkTime); - System.out.println("特定时间是否在夜间时间段内:" + isNight); } } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityGroupbookingServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityGroupbookingServiceImpl.java index bb547180..fd33a9a4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityGroupbookingServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/activity/service/impl/ShopActivityGroupbookingServiceImpl.java @@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.api.ResultCode; import com.suisung.mall.common.api.StateCode; +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.exception.ApiUserException; @@ -648,8 +649,10 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl order_ids = Convert.toList(String.class, history.getOrder_id()); //只有一条记录 List shopOrderInfos = shopOrderInfoService.gets(order_ids); List rows = Convert.toList(Map.class, shopOrderInfos); + // 取消订单 flag = shopOrderBaseService.cancel(order_ids, rows, false); //已经调用cancelActivity, 重复 if (flag) { // 改变参团人员拼单状态 ShopActivityGroupbookingHistory groupbookingHistory = new ShopActivityGroupbookingHistory(); groupbookingHistory.setGbh_id(history.getGbh_id()); - groupbookingHistory.setGb_enable(0); + groupbookingHistory.setGb_enable(CommonConstant.Disable); if (!shopActivityGroupbookingHistoryService.edit(groupbookingHistory)) { throw new ApiException(I18nUtil._("改变参团人员拼单状态失败!")); } @@ -727,12 +733,10 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl innerDoOrderSeparate(String orderId, String storeId); - + /** * 根据商户号、交易号和收货流水号执行订单分账操作 *

diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java index 22ca1c65..97423d30 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/service/impl/LakalaApiServiceImpl.java @@ -65,7 +65,6 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Map; @Slf4j @@ -1838,7 +1837,7 @@ public class LakalaApiServiceImpl implements LakalaApiService { // 10. 检查商户绑定状态是否完成, 更改总的审核状态 shopMchEntryService.checkMerchEntryFinished(mchId); - + // 11. 日志记录并返回成功响应 log.info("商家绑定分账接收方异步通知处理完成,mchId:{} merCupNo:{}", mchId, merCupNo); return JSONUtil.createObj().set("code", "SUCCESS").set("message", "分账接收方绑定成功"); @@ -2265,270 +2264,6 @@ public class LakalaApiServiceImpl implements LakalaApiService { } - /** - * 执行拉卡拉订单分账操作 - *

- * 用户确认收货成功之后(大约15秒后),进行分账操作。 - * 分账指令是异步处理模式,响应报文成功时,指令状态是"status": "PROCESSING", - * 需要等待分账结果通知,或者主动发起查询。 - * 建议主动发起查询与分账指令动作之间间隔15秒以上。 - *

- *

- * 参考文档:https://o.lakala.com/#/home/document/detail?id=389 - *

- * - * @param orderId 平台订单Id - * @param storeId 店铺Id,可为空 - * @return Pair 处理结果对,first为是否成功,second为结果描述信息 - */ - @Override - public Pair innerDoOrderSeparate(String orderId, String storeId) { - // 1. 输入参数校验 - if (StrUtil.isBlank(orderId)) { - log.warn("[分账操作] 参数校验失败:订单号为空"); - return Pair.of(false, "订单号不能为空"); - } - - try { - // TODO 检查可分账余额是否足够? - - // 2. 查询订单信息 - log.info("[分账操作] 开始执行订单[{}]分账操作", orderId); - List shopOrderLklList = shopOrderLklService.selectByOrderId(orderId, "", storeId); - if (CollectionUtil.isEmpty(shopOrderLklList)) { - log.warn("[分账操作] 失败:订单[{}]不存在", orderId); - return Pair.of(false, "订单不存在"); - } - - int totalCount = shopOrderLklList.size(); - int successCount = 0; - StringBuilder errorMessages = new StringBuilder(); - - // 3. 初始化拉卡拉SDK - initLKLSDK(); - - // 4. 遍历处理每个店铺订单的分账 - log.info("[分账操作] 订单[{}]包含{}个子订单,开始逐一处理", orderId, totalCount); - for (ShopOrderLkl shopOrderLkl : shopOrderLklList) { - log.debug("[分账操作] 处理子订单:storeId={}, subLogNo={}, receive_log_no={}", shopOrderLkl.getStore_id(), shopOrderLkl.getLkl_sub_log_no(), shopOrderLkl.getLkl_receive_log_no()); - - if (!CommonConstant.Enable.equals(shopOrderLkl.getReceive_status()) || StrUtil.isBlank(shopOrderLkl.getLkl_receive_log_no())) { - log.warn("[分账操作] 订单[{}]对账流水号[{}]未被确认收货,跳过处理", orderId, shopOrderLkl.getLkl_receive_log_no()); - continue; - } - - // 5. 检查分账状态,避免重复处理 - LklOrderSeparate existingSeparateRecord = lklOrderSeparateService.getByLogNoAndOutTradeNo(shopOrderLkl.getLkl_sub_log_no(), orderId); - if (existingSeparateRecord != null) { - String status = existingSeparateRecord.getStatus(); - if ("SUCCESS".equals(status)) { - log.info("[分账操作] 订单[{}]交易对账流水号[{}]已完成分账,跳过处理", orderId, shopOrderLkl.getLkl_sub_log_no()); - successCount++; - continue; - } - if ("PROCESSING".equals(status) || "ACCEPTED".equals(status)) { - log.info("[分账操作] 订单[{}]交易对账流水号[{}]分账处理中或已受理,跳过处理", orderId, shopOrderLkl.getLkl_sub_log_no()); - successCount++; - continue; - } - } - - // 6. 获取订单分账相关参数 - String merchantNo = shopOrderLkl.getLkl_merchant_no(); - - // 分账金额 = 应付总金额-运费(支付时已计算好) - Integer splitAmount = shopOrderLkl.getSplit_amt(); - splitAmount = CheckUtil.isEmpty(splitAmount) ? 0 : splitAmount; - - // 7. 分账金额校验 - if (splitAmount < 1) { - String errorMsg = String.format("[分账操作] 店铺[%s]订单[%s]分账金额[%d]低于1分钱,跳过分账", - shopOrderLkl.getStore_id(), orderId, splitAmount); - log.error(errorMsg); - errorMessages.append(errorMsg).append("; "); - if (existingSeparateRecord != null) { - lklOrderSeparateService.updateRemark(existingSeparateRecord.getId(), errorMsg); - } - continue; - } - - // 获取分账平台接收方信息 - LklLedgerMerReceiverBind platformReceiver = lklLedgerMerReceiverBindService.getPlatformByMerCupNo(merchantNo); - - if (platformReceiver == null) { - String errorMsg = String.format("[分账操作] 店铺[%s]未绑定平台方接收账户,跳过分账", shopOrderLkl.getStore_id()); - log.error(errorMsg); - errorMessages.append(errorMsg).append("; "); - continue; - } - - // 8. 构建分账接收方列表 - List recvDatas = new ArrayList<>(); - - // 9. 获取商家分账比例并校验 - BigDecimal merchantSplitRatioRaw = shopOrderLkl.getSplit_ratio(); // 如:94 代表94% - // 判断商家分账比例是否有效(必须在(0, 100]范围内) - boolean canSplitForMerchant = merchantSplitRatioRaw != null - && merchantSplitRatioRaw.compareTo(BigDecimal.ZERO) > 0 - && merchantSplitRatioRaw.compareTo(new BigDecimal(100)) <= 0; - if (!canSplitForMerchant) { - String errorMsg = String.format("[分账操作] 店铺[%s]商家分账比例[%s]不在(0-100]范围内,无法分账", - shopOrderLkl.getStore_id(), merchantSplitRatioRaw); - log.error(errorMsg); - errorMessages.append(errorMsg).append("; "); - continue; - } - // 商家分账 - BigDecimal merchantSplitRatio = merchantSplitRatioRaw.divide(new BigDecimal(100)); // 比如:94% - - BigDecimal distributorSplitRatio = BigDecimal.ZERO; - BigDecimal platformSplitRatio = BigDecimal.ONE; - // 分账代理商接收方信息 - List distributorReceivers = lklLedgerMerReceiverBindService.selectAgentByMerCupNo(merchantNo); - if (distributorReceivers != null && !distributorReceivers.isEmpty()) { - distributorSplitRatio = new BigDecimal("0.8"); - platformSplitRatio = new BigDecimal("0.2"); - } - - // 记录关键分账参数,便于问题排查 - log.info("[分账操作] 参数信息:订单={}, 商户={}, 总金额={}分, 商家比例={}, 平台比例={}, 代理商比例={}, 是否有代理商={}", - orderId, merchantNo, splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio, - (distributorReceivers != null && !distributorReceivers.isEmpty())); - - // 返回值如下:{platformAmount=6, merchantAmount=94, agentAmount=0} - Map splitAmountMap = CommonUtil.calculateProfitSharing(splitAmount, merchantSplitRatio, platformSplitRatio, distributorSplitRatio); - Integer merchantAmount = splitAmountMap.get("merchantAmount"); - Integer platformAmount = splitAmountMap.get("platformAmount"); - Integer agentAmount = splitAmountMap.get("agentAmount"); - - // 记录分账结果,便于问题排查 - log.info("[分账操作] 金额计算结果:订单={}, 商户={}, 总金额={}分, 商家分得={}分, 平台分得={}分, 代理商分得={}分", - orderId, merchantNo, splitAmount, merchantAmount, platformAmount, agentAmount); - - if (merchantAmount > 0) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvMerchantNo(merchantNo); - receiver.setSeparateValue(merchantAmount.toString()); - recvDatas.add(receiver); - } - - if (platformAmount > 0) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(platformReceiver.getReceiver_no()); - receiver.setSeparateValue(platformAmount.toString()); - recvDatas.add(receiver); - } - - if (agentAmount > 0 && distributorReceivers != null && !distributorReceivers.isEmpty()) { - V3SacsSeparateRecvDatas receiver = new V3SacsSeparateRecvDatas(); - receiver.setRecvNo(distributorReceivers.get(0).getReceiver_no()); - receiver.setSeparateValue(agentAmount.toString()); - recvDatas.add(receiver); - } - - // 14. 构建分账请求对象 - V3SacsSeparateRequest separateRequest = new V3SacsSeparateRequest(); - separateRequest.setMerchantNo(merchantNo); - separateRequest.setLogNo(shopOrderLkl.getLkl_receive_log_no()); // 合单和非合单的流水号保存在此字段 - separateRequest.setLogDate(shopOrderLkl.getLkl_log_date()); - separateRequest.setOutSeparateNo(shopOrderLkl.getOut_separate_no()); - separateRequest.setTotalAmt(splitAmount.toString()); - separateRequest.setLklOrgNo(orgCode); - separateRequest.setCalType("0"); // 0- 按照指定金额,1- 按照指定比例。默认 0 - separateRequest.setNotifyUrl(projectDomain + "/api/mobile/shop/lakala/sacs/separateNotify"); - - // 15. 设置分账接收方列表 - separateRequest.setRecvDatas(recvDatas); - log.info("[分账操作] 请求参数: 订单={}, 商户={}, 金额={}分, 分账接收方数量={}", - orderId, merchantNo, splitAmount, recvDatas.size()); - - log.debug("[分账操作] 请求详细参数: {}", JSONUtil.toJsonStr(separateRequest)); - - // 16. 发送分账请求 - log.info("[分账操作] 向拉卡拉发送分账请求:订单={}, 商户={}, 分账流水号={}", - orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no()); - String response = LKLSDK.httpPost(separateRequest); - if (StrUtil.isBlank(response)) { - String errorMsg = String.format("[分账操作] 拉卡拉无响应,订单=%s,商户=%s,分账流水号=%s", - orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no()); - log.error(errorMsg); - errorMessages.append(errorMsg).append("; "); - continue; - } - - log.debug("[分账操作] 响应结果: {}", response); - - // 17. 解析响应结果 - JSONObject respJson = JSONUtil.parseObj(response); - if (respJson == null || !lklSacsSuccessCode.equals(respJson.getStr("code")) || respJson.getJSONObject("resp_data") == null) { - String errorMsg = String.format("[分账操作] 拉卡拉返回格式异常,订单=%s,商户=%s,分账流水号=%s,响应=%s,respJson=%s", - orderId, merchantNo, shopOrderLkl.getLkl_sub_log_no(), response, respJson); - log.error(errorMsg); - errorMessages.append(errorMsg).append("; "); - continue; - } - - // 18. 保存分账记录 - JSONObject respData = respJson.getJSONObject("resp_data"); - LklOrderSeparate separateRecord = new LklOrderSeparate(); - separateRecord.setSeparate_no(respData.getStr("separate_no")); - separateRecord.setOut_separate_no(separateRequest.getOutSeparateNo()); - separateRecord.setMerchant_no(merchantNo); - separateRecord.setLog_no(separateRequest.getLogNo()); // 发货完成交易流水号后14位 。分账商户用该流水号发起分账 - separateRecord.setLog_date(separateRequest.getLogDate()); - separateRecord.setOrder_id(shopOrderLkl.getOrder_id()); - separateRecord.setNotify_url(separateRequest.getNotifyUrl()); - separateRecord.setLkl_org_no(separateRequest.getLklOrgNo()); - separateRecord.setRecv_datas(JSONUtil.toJsonStr(separateRequest.getRecvDatas())); - separateRecord.setStatus(respData.getStr("status")); - separateRecord.setTotal_amt(separateRequest.getTotalAmt()); - separateRecord.setActual_separate_amt(Convert.toStr(shopOrderLkl.getSplit_amt())); - - try { - if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) { - log.info("[分账操作] 记录保存成功:订单={}, 分账单号={}, 状态={}, 分账流水号={}", - orderId, separateRecord.getSeparate_no(), separateRecord.getStatus(), separateRecord.getLog_no()); - successCount++; - } else { - String errorMsg = String.format("[分账操作] 保存分账记录失败,订单=%s,分账单号=%s,分账流水号=%s", - orderId, separateRecord.getSeparate_no(), separateRecord.getLog_no()); - log.error(errorMsg); - lklOrderSeparateService.updateRemark(separateRecord.getLog_no(), separateRecord.getSeparate_no(), errorMsg); - errorMessages.append(errorMsg).append("; "); - } - } catch (Exception e) { - String errorMsg = String.format("[分账操作] 保存分账记录异常,订单=%s,分账单号=%s,流水号=%s,错误=%s", - orderId, - separateRecord.getSeparate_no(), - separateRecord.getLog_no(), - e.getMessage()); - log.error(errorMsg, e); - errorMessages.append(errorMsg).append("; "); - } - } - - // 19. 返回最终处理结果 - log.info("[分账操作] 处理完成:总订单数={},成功处理数={}", orderId, totalCount, successCount); - if (successCount == 0) { - String result = "分账全部失败: " + errorMessages; - log.warn("[分账操作] 结果:订单[{}] {}", orderId, result); - return Pair.of(false, result); - } else if (successCount < totalCount) { - String result = "部分分账成功,处理中: " + errorMessages; - log.info("[分账操作] 结果:订单[{}] {}", orderId, result); - return Pair.of(true, result); - } else { - String result = "全部订单分账已提交处理"; - log.info("[分账操作] 结果:订单[{}] {}", orderId, result); - return Pair.of(true, result); - } - } catch (Exception e) { - String errorMsg = String.format("[分账操作] 系统异常,订单=%s,错误=%s", orderId, e.getMessage()); - log.error(errorMsg, e); - return Pair.of(false, "系统异常,请稍后重试"); - } - } - /** * 根据商户号、交易号和收货流水号执行订单分账操作 *

@@ -2838,6 +2573,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { separateRecord.setTotal_amt(separateRequest.getTotalAmt()); separateRecord.setActual_separate_amt(Convert.toStr(refCanSeparateAmt)); separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTO.getLklAmount())); + if (separateRequest != null) { + separateRecord.setLkl_req(JSONUtil.toJsonStr(separateRequest)); + } if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) { log.info("[分账操作] 分账记录保存成功, orderId={}, separateNo={}, status={}, logNo={}", @@ -3798,6 +3536,9 @@ public class LakalaApiServiceImpl implements LakalaApiService { lklOrderDraw.setBatch_auto_settle(payType); lklOrderDraw.setNotify_url(request.getNotifyUrl()); lklOrderDraw.setNotify_resp(responseStr); + if (request != null) { + lklOrderDraw.setLkl_req(JSONUtil.toJsonStr(request)); + } lklOrderDraw.setRemark(remark); if (StrUtil.isNotBlank(summary)) { lklOrderDraw.setSummary(summary); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserOrderController.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserOrderController.java index 6935b3a7..9d496ec8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserOrderController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/controller/mobile/UserOrderController.java @@ -324,7 +324,7 @@ public class UserOrderController extends BaseControllerImpl { @ApiOperation(value = "可预约订单的时间槽", notes = "可预约订单的时间槽") @RequestMapping(value = "/booking_time_args", method = RequestMethod.GET) - public CommonResult listInvoice(@RequestParam(name = "store_id", defaultValue = "0") Integer store_id) { + public CommonResult listInvoice(@RequestParam(name = "store_id", defaultValue = "0") String store_id) { List list = shopOrderInfoService.genBookingOrderArgList(store_id); return CommonResult.success(list); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderInfoService.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderInfoService.java index 9f400d2a..b0027f30 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderInfoService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderInfoService.java @@ -139,8 +139,8 @@ public interface ShopOrderInfoService extends IBaseService { /** * 根据店铺的营业时间范围生成可预约下单的参数 * - * @param storeId 店铺ID + * @param storeId 店铺ID,多个店铺,使用英文半角逗号隔开,如:57,58,59 * @return */ - List genBookingOrderArgList(Integer storeId); + List genBookingOrderArgList(String storeId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderInfoServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderInfoServiceImpl.java index 52af4f9b..a3837c5d 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderInfoServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderInfoServiceImpl.java @@ -1,5 +1,6 @@ package com.suisung.mall.shop.order.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.NumberUtil; @@ -1017,36 +1018,20 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl genBookingOrderArgList(Integer storeId) { + public List genBookingOrderArgList(String storeIds) { // 初始化默认营业时间 - String openingHours = "09:00"; - String closeHours = "18:00"; + Map timesMap = new HashMap<>(); // 如果storeId不为空,则尝试获取店铺信息 - if (storeId != null) { - try { - ShopStoreInfo shopStoreInfo = shopStoreInfoService.getShopStoreInfoByStoreId(storeId); - if (shopStoreInfo != null) { - // 检查并使用店铺设置的营业时间 - if (StrUtil.isNotBlank(shopStoreInfo.getStore_opening_hours())) { - openingHours = shopStoreInfo.getStore_opening_hours(); - } - if (StrUtil.isNotBlank(shopStoreInfo.getStore_close_hours())) { - closeHours = shopStoreInfo.getStore_close_hours(); - } - logger.debug("[生成预约参数] 使用店铺营业时间,storeId: {}, opening: {}, close: {}", storeId, openingHours, closeHours); - } else { - logger.warn("[生成预约参数] 未找到店铺信息,使用默认营业时间,storeId: {}", storeId); - } - } catch (Exception e) { - logger.error("[生成预约参数] 获取店铺信息异常,使用默认营业时间,storeId: {}", storeId, e); + if (StrUtil.isNotBlank(storeIds)) { + List> timesMapList = selStoreBizTimeMapList(storeIds); + if (!CollUtil.isEmpty(timesMapList)) { + timesMap = DateTimeUtils.findTimeInterSection(timesMapList); } - } else { - logger.warn("[生成预约参数] 店铺ID为空,使用默认营业时间"); } List result = new ArrayList<>(); @@ -1082,18 +1067,98 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl items = generateTimeSlots(dateStr, openingHours, closeHours, i == 0); - bookingArgDTO.setItems(items != null ? items : new ArrayList<>()); + List items = new ArrayList<>(); + // 如果是今天,始终添加"立即送出"选项 + if (i == 0) { + BookingArgDTO.BookingArgItem immediateItem = new BookingArgDTO.BookingArgItem(); + immediateItem.setTime_title("立即送出"); + immediateItem.setBooking_at(0L); + immediateItem.setBooking_state(1); + immediateItem.setBooking_begin_time(""); + immediateItem.setBooking_end_time(""); + items.add(immediateItem); + } + + // 只有当timesMap不为空时才生成其他时间槽 + if (!ObjectUtil.isEmpty(timesMap) && StrUtil.isNotBlank(timesMap.get("startTimeStr")) && StrUtil.isNotBlank(timesMap.get("endTimeStr"))) { + List timeSlots = generateTimeSlots(dateStr, timesMap.get("startTimeStr"), timesMap.get("endTimeStr"), i == 0); + if (i == 0) { + // 对于今天,移除除"立即送出"外的所有时间槽 + items.addAll(timeSlots.stream().filter(item -> item.getBooking_state() != 1).collect(Collectors.toList())); + } else { + // 对于其他日期,添加所有时间槽 + items.addAll(timeSlots); + } + } else if (i == 0) { + // 如果timesMap为空,今天只保留"立即送出"选项 + logger.debug("[生成预约参数] timesMap为空,今天只生成立即送出选项"); + } else { + // 如果timesMap为空,其他日期不生成任何时间槽 + logger.debug("[生成预约参数] timesMap为空,不生成{}的预约时间槽", dateStr); + continue; // 跳过当前日期 + } + + bookingArgDTO.setItems(items); result.add(bookingArgDTO); } - logger.debug("[生成预约参数] 成功生成预约参数,storeId: {}, opening: {}, close: {}, 参数数量: {}", - storeId, openingHours, closeHours, result.size()); + logger.debug("[生成预约参数] 成功生成预约参数,storeId: {}, timesMap: {}, 参数数量: {}", + storeIds, timesMap, result.size()); return result; } + /** + * 根据 storeIds(一个或多个 storeid,如 34,23,43,23,),先对id去重,再获取多个店铺的营业时间 List 列表list + * + * @param storeIds 以逗号分隔的店铺ID字符串 + * @return 包含店铺营业时间信息的列表,每个元素为包含opening_hours和close_hours的Map + */ + private List> selStoreBizTimeMapList(String storeIds) { + // 参数校验 + if (StrUtil.isBlank(storeIds)) { + return Collections.emptyList(); + } + + try { + // 1. 解析并去重店铺ID + List uniqueStoreIds = Arrays.stream(storeIds.split(",")) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.toList()); + + // 2. 如果没有有效的店铺ID,返回空列表 + if (uniqueStoreIds.isEmpty()) { + return Collections.emptyList(); + } + + // 3. 批量获取店铺信息 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("store_opening_hours", "store_close_hours"); // 只查询必要字段 + queryWrapper.in("store_id", storeIds); + + List shopStoreInfos = shopStoreInfoService.find(queryWrapper); + + // 4. 转换为营业时间映射列表 + return shopStoreInfos.stream() + .filter(Objects::nonNull) + .map(storeInfo -> { + Map timeSlot = new HashMap<>(); + timeSlot.put("startTimeStr", storeInfo.getStore_opening_hours()); + timeSlot.put("endTimeStr", storeInfo.getStore_close_hours()); + return timeSlot; + }) + .collect(Collectors.toList()); + + } catch (Exception e) { + logger.error("[获取店铺营业时间] 处理店铺营业时间异常,storeIds: {}", storeIds, e); + return Collections.emptyList(); + } + } + + /** * 生成时间槽列表 * diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/user/service/ShopUserVoucherService.java b/mall-shop/src/main/java/com/suisung/mall/shop/user/service/ShopUserVoucherService.java index 0e946c25..3a46559a 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/user/service/ShopUserVoucherService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/user/service/ShopUserVoucherService.java @@ -39,7 +39,7 @@ public interface ShopUserVoucherService extends IBaseService { Map getLists(QueryWrapper voucherQueryWrapper, int page, int rows); - boolean useNeedNotPin(Integer user_id, String order_id); + boolean tryUseFreeGroupVoucher(Integer user_id, String order_id); // 线下优惠券核销 boolean exitWriteoffUserVoucher(ShopUserVoucher shopUserVoucher); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/user/service/impl/ShopUserVoucherServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/user/service/impl/ShopUserVoucherServiceImpl.java index 61236faf..19b0db7f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/user/service/impl/ShopUserVoucherServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/user/service/impl/ShopUserVoucherServiceImpl.java @@ -65,7 +65,7 @@ public class ShopUserVoucherServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("voucher_type", 1).eq("user_id", user_id).eq("voucher_state_id", StateCode.VOUCHER_STATE_UNUSED).ge("voucher_end_date", date); + queryWrapper.eq("voucher_type", 1) + .eq("user_id", user_id) + .eq("voucher_state_id", StateCode.VOUCHER_STATE_UNUSED) + .ge("voucher_end_date", date); ShopUserVoucher user_voucher_row = findOne(queryWrapper); if (user_voucher_row != null) {