预订单时间槽列表逻辑调整,分账、提现 报文字段 保存
This commit is contained in:
parent
7810340cde
commit
0248a38268
@ -155,6 +155,9 @@ public class LklOrderDraw {
|
|||||||
@ApiModelProperty(value = "异步通知地址", example = "https://api.example.com/notify")
|
@ApiModelProperty(value = "异步通知地址", example = "https://api.example.com/notify")
|
||||||
private String notify_url;
|
private String notify_url;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "接口请求报文")
|
||||||
|
private String lkl_req;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步通知返回的JSON数据
|
* 异步通知返回的JSON数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -94,6 +94,9 @@ public class LklOrderSeparate {
|
|||||||
@ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功")
|
@ApiModelProperty(value = "处理状态:ACCEPTED-已受理, PROCESSING-处理中, FAIL-失败, SUCCESS-成功")
|
||||||
private String final_status;
|
private String final_status;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "接口请求报文")
|
||||||
|
private String lkl_req;
|
||||||
|
|
||||||
@ApiModelProperty(value = "异步通知数据")
|
@ApiModelProperty(value = "异步通知数据")
|
||||||
private String notify_resp;
|
private String notify_resp;
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,7 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.time.format.DateTimeFormatterBuilder;
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DateTimeUtils {
|
public class DateTimeUtils {
|
||||||
@ -363,6 +362,76 @@ public class DateTimeUtils {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算多个时间段之间的交集(不跨天)
|
||||||
|
* <p>
|
||||||
|
* 算法逻辑:
|
||||||
|
* 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<String, String> findTimeInterSection(List<Map<String, String>> timeList) {
|
||||||
|
// 参数校验
|
||||||
|
if (timeList == null || timeList.isEmpty()) {
|
||||||
|
log.warn("时间段列表为空或null,无法计算交集");
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
LocalTime latestStartTime = null;
|
||||||
|
LocalTime earliestEndTime = null;
|
||||||
|
|
||||||
|
// 遍历所有时间段
|
||||||
|
for (Map<String, String> 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<String, String> 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"));
|
// System.out.println(formatLocalDate(LocalDate.now(), "yyyy-MM-dd"));
|
||||||
|
|
||||||
// 判断当前时间是否在工作时间(9:00-18:00)内
|
// 判断当前时间是否在工作时间(9:00-18:00)内
|
||||||
boolean isWorkTime = isCurrentTimeInRange("09:00", "22:36");
|
// boolean isWorkTime = isCurrentTimeInRange("09:00", "22:36");
|
||||||
|
|
||||||
// 判断特定时间是否在夜间时间(22:00-06:00)内
|
// 判断特定时间是否在夜间时间(22:00-06:00)内
|
||||||
// LocalDateTime testTime = LocalDateTime.of(2025, 1, 1, 23, 30);
|
// LocalDateTime testTime = LocalDateTime.of(2025, 1, 1, 23, 30);
|
||||||
Date testTime = Date.from(LocalDateTime.of(2025, 10, 23, 21, 30).atZone(ZoneId.systemDefault()).toInstant());
|
// Date testTime = Date.from(LocalDateTime.of(2025, 10, 23, 21, 30).atZone(ZoneId.systemDefault()).toInstant());
|
||||||
boolean isNight = isTimeInRange("08:30", "22:20", testTime);
|
// boolean isNight = isTimeInRange("08:30", "22:20", testTime);
|
||||||
|
|
||||||
|
// System.out.println("当前时间是否在工作时间内:" + isWorkTime);
|
||||||
|
// System.out.println("多个时间段的交集结果:" + isNight);
|
||||||
|
|
||||||
|
System.out.println("=== 测试 findTimeIntersection ===");
|
||||||
|
|
||||||
|
// 测试正常交集情况
|
||||||
|
List<Map<String, String>> timeList1 = new ArrayList<>();
|
||||||
|
Map<String, String> range1 = new HashMap<>();
|
||||||
|
range1.put("startTimeStr", "06:00");
|
||||||
|
range1.put("endTimeStr", "17:00");
|
||||||
|
timeList1.add(range1);
|
||||||
|
|
||||||
|
Map<String, String> range2 = new HashMap<>();
|
||||||
|
range2.put("startTimeStr", "06:00");
|
||||||
|
range2.put("endTimeStr", "17:00");
|
||||||
|
timeList1.add(range2);
|
||||||
|
|
||||||
|
Map<String, String> intersection1 = findTimeInterSection(timeList1);
|
||||||
|
System.out.println("交集结果1: " + intersection1); // 应该是 10:00 - 17:00
|
||||||
|
|
||||||
|
// 测试无交集情况
|
||||||
|
List<Map<String, String>> timeList2 = new ArrayList<>();
|
||||||
|
Map<String, String> range3 = new HashMap<>();
|
||||||
|
range3.put("startTimeStr", "09:00");
|
||||||
|
range3.put("endTimeStr", "12:00");
|
||||||
|
timeList2.add(range3);
|
||||||
|
|
||||||
|
Map<String, String> range4 = new HashMap<>();
|
||||||
|
range4.put("startTimeStr", "13:00");
|
||||||
|
range4.put("endTimeStr", "17:00");
|
||||||
|
timeList2.add(range4);
|
||||||
|
|
||||||
|
Map<String, String> intersection2 = findTimeInterSection(timeList2);
|
||||||
|
System.out.println("交集结果2: " + intersection2); // 应该是空Map
|
||||||
|
|
||||||
|
// 测试空列表
|
||||||
|
Map<String, String> intersection3 = findTimeInterSection(null);
|
||||||
|
System.out.println("交集结果3 (null输入): " + intersection3); // 应该是空Map
|
||||||
|
|
||||||
|
|
||||||
System.out.println("当前时间是否在工作时间内:" + isWorkTime);
|
|
||||||
System.out.println("特定时间是否在夜间时间段内:" + isNight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.suisung.mall.common.api.ResultCode;
|
import com.suisung.mall.common.api.ResultCode;
|
||||||
import com.suisung.mall.common.api.StateCode;
|
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.domain.UserDto;
|
||||||
import com.suisung.mall.common.exception.ApiException;
|
import com.suisung.mall.common.exception.ApiException;
|
||||||
import com.suisung.mall.common.exception.ApiUserException;
|
import com.suisung.mall.common.exception.ApiUserException;
|
||||||
@ -648,8 +649,10 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl<ShopAct
|
|||||||
for (ShopActivityGroupbookingHistory history : historyList) {
|
for (ShopActivityGroupbookingHistory history : historyList) {
|
||||||
// 已支付
|
// 已支付
|
||||||
ShopOrderInfo order_info_data = shopOrderInfoService.get(history.getOrder_id());
|
ShopOrderInfo order_info_data = shopOrderInfoService.get(history.getOrder_id());
|
||||||
if (history.getGbh_flag() == 1) {
|
if (history.getGbh_flag() == 1) { // 已支付
|
||||||
boolean used = shopUserVoucherService.useNeedNotPin(history.getUser_id(), history.getOrder_id());
|
|
||||||
|
// 是否使用了免拼券
|
||||||
|
boolean used = shopUserVoucherService.tryUseFreeGroupVoucher(history.getUser_id(), history.getOrder_id());
|
||||||
|
|
||||||
if (used) {
|
if (used) {
|
||||||
if (order_info_data.getOrder_is_sync() == 2) {
|
if (order_info_data.getOrder_is_sync() == 2) {
|
||||||
@ -664,30 +667,33 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl<ShopAct
|
|||||||
// 如果使用免拼券成功,则改变参团人员拼单状态为成功.不往下走。
|
// 如果使用免拼券成功,则改变参团人员拼单状态为成功.不往下走。
|
||||||
ShopActivityGroupbookingHistory groupbookingHistory = new ShopActivityGroupbookingHistory();
|
ShopActivityGroupbookingHistory groupbookingHistory = new ShopActivityGroupbookingHistory();
|
||||||
groupbookingHistory.setGbh_id(history.getGbh_id());
|
groupbookingHistory.setGbh_id(history.getGbh_id());
|
||||||
groupbookingHistory.setGb_enable(1);
|
groupbookingHistory.setGb_enable(CommonConstant.Enable);
|
||||||
if (!shopActivityGroupbookingHistoryService.edit(groupbookingHistory)) {
|
if (!shopActivityGroupbookingHistoryService.edit(groupbookingHistory)) {
|
||||||
throw new ApiException(I18nUtil._("修正订单为可同步状态失败!"));
|
throw new ApiException(I18nUtil._("修正订单为可同步状态失败!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
free_fight_num++;
|
free_fight_num++;
|
||||||
|
|
||||||
|
// TODO 平团成功,需要发同城配送
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消订单
|
|
||||||
List<String> order_ids = Convert.toList(String.class, history.getOrder_id());
|
List<String> order_ids = Convert.toList(String.class, history.getOrder_id());
|
||||||
|
|
||||||
//只有一条记录
|
//只有一条记录
|
||||||
List<ShopOrderInfo> shopOrderInfos = shopOrderInfoService.gets(order_ids);
|
List<ShopOrderInfo> shopOrderInfos = shopOrderInfoService.gets(order_ids);
|
||||||
List<Map> rows = Convert.toList(Map.class, shopOrderInfos);
|
List<Map> rows = Convert.toList(Map.class, shopOrderInfos);
|
||||||
|
|
||||||
|
// 取消订单
|
||||||
flag = shopOrderBaseService.cancel(order_ids, rows, false);
|
flag = shopOrderBaseService.cancel(order_ids, rows, false);
|
||||||
//已经调用cancelActivity, 重复
|
//已经调用cancelActivity, 重复
|
||||||
if (flag) {
|
if (flag) {
|
||||||
// 改变参团人员拼单状态
|
// 改变参团人员拼单状态
|
||||||
ShopActivityGroupbookingHistory groupbookingHistory = new ShopActivityGroupbookingHistory();
|
ShopActivityGroupbookingHistory groupbookingHistory = new ShopActivityGroupbookingHistory();
|
||||||
groupbookingHistory.setGbh_id(history.getGbh_id());
|
groupbookingHistory.setGbh_id(history.getGbh_id());
|
||||||
groupbookingHistory.setGb_enable(0);
|
groupbookingHistory.setGb_enable(CommonConstant.Disable);
|
||||||
if (!shopActivityGroupbookingHistoryService.edit(groupbookingHistory)) {
|
if (!shopActivityGroupbookingHistoryService.edit(groupbookingHistory)) {
|
||||||
throw new ApiException(I18nUtil._("改变参团人员拼单状态失败!"));
|
throw new ApiException(I18nUtil._("改变参团人员拼单状态失败!"));
|
||||||
}
|
}
|
||||||
@ -727,12 +733,10 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl<ShopAct
|
|||||||
orderReturn.setReturn_tel("");
|
orderReturn.setReturn_tel("");
|
||||||
orderReturn.setReturn_store_user_id(buyer_store_id);
|
orderReturn.setReturn_store_user_id(buyer_store_id);
|
||||||
orderReturn.setReturn_telephone("");
|
orderReturn.setReturn_telephone("");
|
||||||
|
|
||||||
orderReturn.setSubsite_id(order_info_data.getSubsite_id());
|
orderReturn.setSubsite_id(order_info_data.getSubsite_id());
|
||||||
|
|
||||||
|
|
||||||
ShopOrderReturnItem orderReturnItem = new ShopOrderReturnItem();
|
ShopOrderReturnItem orderReturnItem = new ShopOrderReturnItem();
|
||||||
|
|
||||||
orderReturnItem.setOrder_item_id(order_item_row.getOrder_item_id()); // 退货商品编号(DOT):0为退款
|
orderReturnItem.setOrder_item_id(order_item_row.getOrder_item_id()); // 退货商品编号(DOT):0为退款
|
||||||
orderReturnItem.setOrder_id(history.getOrder_id()); // 订单编号
|
orderReturnItem.setOrder_id(history.getOrder_id()); // 订单编号
|
||||||
orderReturnItem.setReturn_item_num(order_item_row.getOrder_item_quantity()); // 退货商品编号(DOT):0为退款
|
orderReturnItem.setReturn_item_num(order_item_row.getOrder_item_quantity()); // 退货商品编号(DOT):0为退款
|
||||||
@ -760,7 +764,7 @@ public class ShopActivityGroupbookingServiceImpl extends BaseServiceImpl<ShopAct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果免拼数量等于成团数量,则此团完成
|
//如果使用免拼券人数等于成团数量,则此团完成
|
||||||
if (gb_quantity <= free_fight_num) {
|
if (gb_quantity <= free_fight_num) {
|
||||||
groupbooking.setGb_enable(1);
|
groupbooking.setGb_enable(1);
|
||||||
shopActivityGroupbookingService.saveOrUpdate(groupbooking);
|
shopActivityGroupbookingService.saveOrUpdate(groupbooking);
|
||||||
|
|||||||
@ -177,18 +177,6 @@ public interface LakalaApiService {
|
|||||||
*/
|
*/
|
||||||
CommonResult getBankCardBin(String bankCardNo);
|
CommonResult getBankCardBin(String bankCardNo);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拉卡拉订单分账,用户下单成功之后,进行分账
|
|
||||||
* 说明:分账指令是异步处理模式,响应报文成功时,指令状态是”status”: “PROCESSING”,需要等待分账结果通知,或者主动发起查询,建议主动发起查询与分账指令动作之间间隔15秒以上。
|
|
||||||
* 参考:https://o.lakala.com/#/home/document/detail?id=389
|
|
||||||
*
|
|
||||||
* @param orderId 平台订单号,必填参数
|
|
||||||
* @param storeId 商户门店编号,非必填参数
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Pair<Boolean, String> innerDoOrderSeparate(String orderId, String storeId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据商户号、交易号和收货流水号执行订单分账操作
|
* 根据商户号、交易号和收货流水号执行订单分账操作
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@ -65,7 +65,6 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -2265,270 +2264,6 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行拉卡拉订单分账操作
|
|
||||||
* <p>
|
|
||||||
* 用户确认收货成功之后(大约15秒后),进行分账操作。
|
|
||||||
* 分账指令是异步处理模式,响应报文成功时,指令状态是"status": "PROCESSING",
|
|
||||||
* 需要等待分账结果通知,或者主动发起查询。
|
|
||||||
* 建议主动发起查询与分账指令动作之间间隔15秒以上。
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* 参考文档:https://o.lakala.com/#/home/document/detail?id=389
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param orderId 平台订单Id
|
|
||||||
* @param storeId 店铺Id,可为空
|
|
||||||
* @return Pair<Boolean, String> 处理结果对,first为是否成功,second为结果描述信息
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Pair<Boolean, String> innerDoOrderSeparate(String orderId, String storeId) {
|
|
||||||
// 1. 输入参数校验
|
|
||||||
if (StrUtil.isBlank(orderId)) {
|
|
||||||
log.warn("[分账操作] 参数校验失败:订单号为空");
|
|
||||||
return Pair.of(false, "订单号不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// TODO 检查可分账余额是否足够?
|
|
||||||
|
|
||||||
// 2. 查询订单信息
|
|
||||||
log.info("[分账操作] 开始执行订单[{}]分账操作", orderId);
|
|
||||||
List<ShopOrderLkl> 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<V3SacsSeparateRecvDatas> 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<LklLedgerMerReceiverBind> 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<String, Integer> 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, "系统异常,请稍后重试");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据商户号、交易号和收货流水号执行订单分账操作
|
* 根据商户号、交易号和收货流水号执行订单分账操作
|
||||||
* <p>
|
* <p>
|
||||||
@ -2838,6 +2573,9 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
|||||||
separateRecord.setTotal_amt(separateRequest.getTotalAmt());
|
separateRecord.setTotal_amt(separateRequest.getTotalAmt());
|
||||||
separateRecord.setActual_separate_amt(Convert.toStr(refCanSeparateAmt));
|
separateRecord.setActual_separate_amt(Convert.toStr(refCanSeparateAmt));
|
||||||
separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTO.getLklAmount()));
|
separateRecord.setTotal_fee_amt(Convert.toStr(lklSeparateDTO.getLklAmount()));
|
||||||
|
if (separateRequest != null) {
|
||||||
|
separateRecord.setLkl_req(JSONUtil.toJsonStr(separateRequest));
|
||||||
|
}
|
||||||
|
|
||||||
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
|
if (lklOrderSeparateService.addOrUpdateByReceiverNo(separateRecord)) {
|
||||||
log.info("[分账操作] 分账记录保存成功, orderId={}, separateNo={}, status={}, logNo={}",
|
log.info("[分账操作] 分账记录保存成功, orderId={}, separateNo={}, status={}, logNo={}",
|
||||||
@ -3798,6 +3536,9 @@ public class LakalaApiServiceImpl implements LakalaApiService {
|
|||||||
lklOrderDraw.setBatch_auto_settle(payType);
|
lklOrderDraw.setBatch_auto_settle(payType);
|
||||||
lklOrderDraw.setNotify_url(request.getNotifyUrl());
|
lklOrderDraw.setNotify_url(request.getNotifyUrl());
|
||||||
lklOrderDraw.setNotify_resp(responseStr);
|
lklOrderDraw.setNotify_resp(responseStr);
|
||||||
|
if (request != null) {
|
||||||
|
lklOrderDraw.setLkl_req(JSONUtil.toJsonStr(request));
|
||||||
|
}
|
||||||
lklOrderDraw.setRemark(remark);
|
lklOrderDraw.setRemark(remark);
|
||||||
if (StrUtil.isNotBlank(summary)) {
|
if (StrUtil.isNotBlank(summary)) {
|
||||||
lklOrderDraw.setSummary(summary);
|
lklOrderDraw.setSummary(summary);
|
||||||
|
|||||||
@ -324,7 +324,7 @@ public class UserOrderController extends BaseControllerImpl {
|
|||||||
|
|
||||||
@ApiOperation(value = "可预约订单的时间槽", notes = "可预约订单的时间槽")
|
@ApiOperation(value = "可预约订单的时间槽", notes = "可预约订单的时间槽")
|
||||||
@RequestMapping(value = "/booking_time_args", method = RequestMethod.GET)
|
@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<BookingArgDTO> list = shopOrderInfoService.genBookingOrderArgList(store_id);
|
List<BookingArgDTO> list = shopOrderInfoService.genBookingOrderArgList(store_id);
|
||||||
return CommonResult.success(list);
|
return CommonResult.success(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,8 +139,8 @@ public interface ShopOrderInfoService extends IBaseService<ShopOrderInfo> {
|
|||||||
/**
|
/**
|
||||||
* 根据店铺的营业时间范围生成可预约下单的参数
|
* 根据店铺的营业时间范围生成可预约下单的参数
|
||||||
*
|
*
|
||||||
* @param storeId 店铺ID
|
* @param storeId 店铺ID,多个店铺,使用英文半角逗号隔开,如:57,58,59
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<BookingArgDTO> genBookingOrderArgList(Integer storeId);
|
List<BookingArgDTO> genBookingOrderArgList(String storeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.suisung.mall.shop.order.service.impl;
|
package com.suisung.mall.shop.order.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
@ -1017,36 +1018,20 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
|
|||||||
/**
|
/**
|
||||||
* 根据店铺的营业时间范围生成可预约下单的参数
|
* 根据店铺的营业时间范围生成可预约下单的参数
|
||||||
*
|
*
|
||||||
* @param storeId 店铺ID
|
* @param storeIds 店铺ID,多个店铺,使用英文半角逗号隔开,如:57,58,59
|
||||||
* @return 预约参数列表
|
* @return 预约参数列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<BookingArgDTO> genBookingOrderArgList(Integer storeId) {
|
public List<BookingArgDTO> genBookingOrderArgList(String storeIds) {
|
||||||
// 初始化默认营业时间
|
// 初始化默认营业时间
|
||||||
String openingHours = "09:00";
|
Map<String, String> timesMap = new HashMap<>();
|
||||||
String closeHours = "18:00";
|
|
||||||
|
|
||||||
// 如果storeId不为空,则尝试获取店铺信息
|
// 如果storeId不为空,则尝试获取店铺信息
|
||||||
if (storeId != null) {
|
if (StrUtil.isNotBlank(storeIds)) {
|
||||||
try {
|
List<Map<String, String>> timesMapList = selStoreBizTimeMapList(storeIds);
|
||||||
ShopStoreInfo shopStoreInfo = shopStoreInfoService.getShopStoreInfoByStoreId(storeId);
|
if (!CollUtil.isEmpty(timesMapList)) {
|
||||||
if (shopStoreInfo != null) {
|
timesMap = DateTimeUtils.findTimeInterSection(timesMapList);
|
||||||
// 检查并使用店铺设置的营业时间
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.warn("[生成预约参数] 店铺ID为空,使用默认营业时间");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BookingArgDTO> result = new ArrayList<>();
|
List<BookingArgDTO> result = new ArrayList<>();
|
||||||
@ -1082,18 +1067,98 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
|
|||||||
bookingArgDTO.setDate(dateStr);
|
bookingArgDTO.setDate(dateStr);
|
||||||
|
|
||||||
// 生成时间项
|
// 生成时间项
|
||||||
List<BookingArgDTO.BookingArgItem> items = generateTimeSlots(dateStr, openingHours, closeHours, i == 0);
|
List<BookingArgDTO.BookingArgItem> items = new ArrayList<>();
|
||||||
bookingArgDTO.setItems(items != null ? 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<BookingArgDTO.BookingArgItem> 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);
|
result.add(bookingArgDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("[生成预约参数] 成功生成预约参数,storeId: {}, opening: {}, close: {}, 参数数量: {}",
|
logger.debug("[生成预约参数] 成功生成预约参数,storeId: {}, timesMap: {}, 参数数量: {}",
|
||||||
storeId, openingHours, closeHours, result.size());
|
storeIds, timesMap, result.size());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 storeIds(一个或多个 storeid,如 34,23,43,23,),先对id去重,再获取多个店铺的营业时间 List<map{startTimeStr, endTimeStr}> 列表list
|
||||||
|
*
|
||||||
|
* @param storeIds 以逗号分隔的店铺ID字符串
|
||||||
|
* @return 包含店铺营业时间信息的列表,每个元素为包含opening_hours和close_hours的Map
|
||||||
|
*/
|
||||||
|
private List<Map<String, String>> selStoreBizTimeMapList(String storeIds) {
|
||||||
|
// 参数校验
|
||||||
|
if (StrUtil.isBlank(storeIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 解析并去重店铺ID
|
||||||
|
List<String> 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<ShopStoreInfo> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.select("store_opening_hours", "store_close_hours"); // 只查询必要字段
|
||||||
|
queryWrapper.in("store_id", storeIds);
|
||||||
|
|
||||||
|
List<ShopStoreInfo> shopStoreInfos = shopStoreInfoService.find(queryWrapper);
|
||||||
|
|
||||||
|
// 4. 转换为营业时间映射列表
|
||||||
|
return shopStoreInfos.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(storeInfo -> {
|
||||||
|
Map<String, String> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成时间槽列表
|
* 生成时间槽列表
|
||||||
*
|
*
|
||||||
|
|||||||
@ -39,7 +39,7 @@ public interface ShopUserVoucherService extends IBaseService<ShopUserVoucher> {
|
|||||||
|
|
||||||
Map getLists(QueryWrapper<ShopUserVoucher> voucherQueryWrapper, int page, int rows);
|
Map getLists(QueryWrapper<ShopUserVoucher> 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);
|
boolean exitWriteoffUserVoucher(ShopUserVoucher shopUserVoucher);
|
||||||
|
|||||||
@ -331,17 +331,20 @@ public class ShopUserVoucherServiceImpl extends BaseServiceImpl<ShopUserVoucherM
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户使用免拼券
|
* 用户是否使用了免拼券
|
||||||
*
|
*
|
||||||
* @param user_id
|
* @param user_id
|
||||||
* @param order_id
|
* @param order_id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean useNeedNotPin(Integer user_id, String order_id) {
|
public boolean tryUseFreeGroupVoucher(Integer user_id, String order_id) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
QueryWrapper<ShopUserVoucher> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<ShopUserVoucher> 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);
|
ShopUserVoucher user_voucher_row = findOne(queryWrapper);
|
||||||
|
|
||||||
if (user_voucher_row != null) {
|
if (user_voucher_row != null) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user