|
|
@@ -11,22 +11,38 @@ import shop.alien.entity.store.StoreCuisine;
|
|
|
import shop.alien.entity.store.StoreOrder;
|
|
|
import shop.alien.entity.store.StoreOrderDetail;
|
|
|
import shop.alien.entity.store.StoreTable;
|
|
|
+import shop.alien.entity.store.UserReservation;
|
|
|
+import shop.alien.entity.store.UserReservationTable;
|
|
|
+import shop.alien.entity.store.dto.StoreBookingChangeTableDTO;
|
|
|
import shop.alien.entity.store.dto.StoreBookingPlaceOrderDTO;
|
|
|
import shop.alien.entity.store.dto.StoreBookingPlaceOrderItemDTO;
|
|
|
+import shop.alien.entity.store.vo.StoreBookingChangeTableResultVo;
|
|
|
+import shop.alien.entity.store.vo.StoreBookingChangeTableUnifiedResultVo;
|
|
|
import shop.alien.entity.store.vo.StoreBookingPlaceOrderResultVo;
|
|
|
import shop.alien.mapper.StoreCuisineMapper;
|
|
|
import shop.alien.mapper.StoreOrderDetailMapper;
|
|
|
import shop.alien.mapper.StoreOrderMapper;
|
|
|
import shop.alien.mapper.StoreTableMapper;
|
|
|
+import shop.alien.mapper.UserReservationMapper;
|
|
|
+import shop.alien.mapper.UserReservationTableMapper;
|
|
|
import shop.alien.store.service.StoreBookingOrderService;
|
|
|
+import shop.alien.store.service.StoreBookingTableService;
|
|
|
import shop.alien.util.common.JwtUtil;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Comparator;
|
|
|
import java.util.Date;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 预订下单:不依赖 alien-dining,直接写入订单主表与明细表。
|
|
|
@@ -43,6 +59,9 @@ public class StoreBookingOrderServiceImpl extends ServiceImpl<StoreOrderMapper,
|
|
|
private final StoreOrderDetailMapper storeOrderDetailMapper;
|
|
|
private final StoreTableMapper storeTableMapper;
|
|
|
private final StoreCuisineMapper storeCuisineMapper;
|
|
|
+ private final UserReservationMapper userReservationMapper;
|
|
|
+ private final UserReservationTableMapper userReservationTableMapper;
|
|
|
+ private final StoreBookingTableService storeBookingTableService;
|
|
|
|
|
|
@Override
|
|
|
public StoreBookingPlaceOrderResultVo placeOrder(StoreBookingPlaceOrderDTO dto) {
|
|
|
@@ -122,6 +141,362 @@ public class StoreBookingOrderServiceImpl extends ServiceImpl<StoreOrderMapper,
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 换桌统一入口:无源桌则只查空闲桌;有源桌则执行迁桌(1×1 / 1×多 / 多×1 / N×N)。
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public StoreBookingChangeTableUnifiedResultVo changeTable(StoreBookingChangeTableDTO dto) {
|
|
|
+ Integer storeId = dto.getStoreId();
|
|
|
+ if (storeId == null) {
|
|
|
+ throw new IllegalArgumentException("门店ID不能为空");
|
|
|
+ }
|
|
|
+ List<Integer> sourceTableIds = dto.getSourceTableIds();
|
|
|
+ if (sourceTableIds == null || sourceTableIds.isEmpty()) {
|
|
|
+ // 仅查询空闲桌(原独立 GET,现合并到本接口)
|
|
|
+ StoreBookingChangeTableUnifiedResultVo out = new StoreBookingChangeTableUnifiedResultVo();
|
|
|
+ out.setIdleTables(storeBookingTableService.listIdleTablesForChange(storeId));
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+ StoreBookingChangeTableUnifiedResultVo out = new StoreBookingChangeTableUnifiedResultVo();
|
|
|
+ out.setChangeResult(executeChangeTable(dto));
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行换桌:按源/目标桌数量关系处理 1×1、1×多、多×1(合并)、N×N 配对,并同步预约时段与桌台占用。
|
|
|
+ * <p>
|
|
|
+ * 约定:多桌合并为一桌时,多笔待支付合并为一笔,保证「多人加餐、一人结账」仅一笔待支付;明细与实付金额累加至主单。
|
|
|
+ */
|
|
|
+ private StoreBookingChangeTableResultVo executeChangeTable(StoreBookingChangeTableDTO dto) {
|
|
|
+ Integer storeId = dto.getStoreId();
|
|
|
+ List<Integer> sourceTableIds = dto.getSourceTableIds();
|
|
|
+ List<Integer> targetTableIds = dto.getTargetTableIds();
|
|
|
+ if (storeId == null) {
|
|
|
+ throw new IllegalArgumentException("门店ID不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getCarryReservationTime() == null) {
|
|
|
+ throw new IllegalArgumentException("执行换桌时请指定是否沿用原预约时间 carryReservationTime");
|
|
|
+ }
|
|
|
+ if (targetTableIds == null || targetTableIds.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("执行换桌时目标桌台不能为空");
|
|
|
+ }
|
|
|
+ if (new HashSet<>(sourceTableIds).size() != sourceTableIds.size()) {
|
|
|
+ throw new IllegalArgumentException("源桌列表存在重复");
|
|
|
+ }
|
|
|
+ if (new HashSet<>(targetTableIds).size() != targetTableIds.size()) {
|
|
|
+ throw new IllegalArgumentException("目标桌列表存在重复");
|
|
|
+ }
|
|
|
+ for (Integer a : sourceTableIds) {
|
|
|
+ if (targetTableIds.contains(a)) {
|
|
|
+ throw new IllegalArgumentException("源桌与目标桌不能包含相同桌ID");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Integer> src = sourceTableIds.stream().sorted().collect(Collectors.toList());
|
|
|
+ List<Integer> tgt = targetTableIds.stream().sorted().collect(Collectors.toList());
|
|
|
+ int n = src.size();
|
|
|
+ int m = tgt.size();
|
|
|
+
|
|
|
+ Integer userId = null;
|
|
|
+ try {
|
|
|
+ JSONObject jwt = JwtUtil.getCurrentUserInfo();
|
|
|
+ if (jwt != null) {
|
|
|
+ userId = jwt.getInteger("userId");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.debug("changeTable: 未解析到登录用户");
|
|
|
+ }
|
|
|
+ Date now = new Date();
|
|
|
+
|
|
|
+ // 源桌须属于本店且存在待支付订单;目标桌须空闲且可绑定订单
|
|
|
+ Map<Integer, StoreTable> sourceTableMap = loadAndAssertStoreTables(storeId, src, "源桌");
|
|
|
+ Map<Integer, StoreTable> targetTableMap = loadAndAssertStoreTables(storeId, tgt, "目标桌");
|
|
|
+ for (Integer tid : tgt) {
|
|
|
+ assertTargetTableIdle(targetTableMap.get(tid));
|
|
|
+ }
|
|
|
+
|
|
|
+ LinkedHashMap<Integer, StoreOrder> orderBySourceTable = new LinkedHashMap<>();
|
|
|
+ for (Integer sid : src) {
|
|
|
+ StoreOrder o = findSinglePendingOrderForTable(storeId, sid);
|
|
|
+ if (o == null) {
|
|
|
+ throw new IllegalArgumentException("源桌无待支付订单,tableId=" + sid);
|
|
|
+ }
|
|
|
+ orderBySourceTable.put(sid, o);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<StoreOrder> orders = src.stream().map(orderBySourceTable::get).collect(Collectors.toList());
|
|
|
+ validateReservationConsistency(orders, dto);
|
|
|
+
|
|
|
+ StoreBookingChangeTableResultVo resultVo = new StoreBookingChangeTableResultVo();
|
|
|
+ resultVo.setAffectedOrderIds(orders.stream().map(StoreOrder::getId).collect(Collectors.toList()));
|
|
|
+ resultVo.setMergedIntoPrimaryOrderIds(new ArrayList<>());
|
|
|
+
|
|
|
+ if (n == m) {
|
|
|
+ // N×N(含 1×1):按源桌、目标桌升序一一配对,分别改订单桌号
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
+ Integer sId = src.get(i);
|
|
|
+ Integer tId = tgt.get(i);
|
|
|
+ StoreOrder o = orderBySourceTable.get(sId);
|
|
|
+ StoreTable newT = targetTableMap.get(tId);
|
|
|
+ releaseTableIfCurrentOrder(storeTableMapper.selectById(sId), o.getId());
|
|
|
+ patchOrderTable(o, newT, userId, now);
|
|
|
+ assignTableToOrder(newT, o, o.getDinerCount());
|
|
|
+ }
|
|
|
+ Integer reservationId = unifiedReservationId(orders);
|
|
|
+ if (reservationId != null) {
|
|
|
+ replaceReservationTables(reservationId, tgt);
|
|
|
+ }
|
|
|
+ StoreOrder primary = orderBySourceTable.get(src.get(0));
|
|
|
+ resultVo.setPrimaryOrderId(primary.getId());
|
|
|
+ resultVo.setPrimaryOrderNo(primary.getOrderNo());
|
|
|
+ resultVo.setNewTableIds(tgt);
|
|
|
+ resultVo.setMessage("换桌成功(一一配对)");
|
|
|
+ return resultVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (n == 1 && m > 1) {
|
|
|
+ // 1×多:一单多桌,订单主表落在第一目标桌,多桌共用 current_order_id 便于各端同步同一笔待支付
|
|
|
+ StoreOrder o = orderBySourceTable.get(src.get(0));
|
|
|
+ StoreTable firstTarget = targetTableMap.get(tgt.get(0));
|
|
|
+ releaseTableIfCurrentOrder(sourceTableMap.get(src.get(0)), o.getId());
|
|
|
+ patchOrderTable(o, firstTarget, userId, now);
|
|
|
+ for (Integer tId : tgt) {
|
|
|
+ assignTableToOrder(targetTableMap.get(tId), o, o.getDinerCount());
|
|
|
+ }
|
|
|
+ Integer reservationId = o.getUserReservationId();
|
|
|
+ if (reservationId != null) {
|
|
|
+ replaceReservationTables(reservationId, tgt);
|
|
|
+ }
|
|
|
+ resultVo.setPrimaryOrderId(o.getId());
|
|
|
+ resultVo.setPrimaryOrderNo(o.getOrderNo());
|
|
|
+ resultVo.setNewTableIds(tgt);
|
|
|
+ resultVo.setMessage("换桌成功(一桌多单台)");
|
|
|
+ return resultVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (n > 1 && m == 1) {
|
|
|
+ // 多×1:合并订单至主单(ID 最小),其余订单取消,仅一笔待支付
|
|
|
+ orders.sort(Comparator.comparing(StoreOrder::getId));
|
|
|
+ StoreOrder primary = orders.get(0);
|
|
|
+ List<StoreOrder> secondaries = orders.subList(1, orders.size());
|
|
|
+ StoreTable newT = targetTableMap.get(tgt.get(0));
|
|
|
+
|
|
|
+ for (StoreOrder o : orders) {
|
|
|
+ releaseTableIfCurrentOrder(storeTableMapper.selectById(o.getTableId()), o.getId());
|
|
|
+ }
|
|
|
+ mergePendingOrdersIntoPrimary(primary, secondaries, userId, now);
|
|
|
+ patchOrderTable(primary, newT, userId, now);
|
|
|
+ assignTableToOrder(newT, primary, maxDinerCount(orders));
|
|
|
+
|
|
|
+ Integer reservationId = unifiedReservationId(orders);
|
|
|
+ if (reservationId != null) {
|
|
|
+ replaceReservationTables(reservationId, tgt);
|
|
|
+ }
|
|
|
+ resultVo.setPrimaryOrderId(primary.getId());
|
|
|
+ resultVo.setPrimaryOrderNo(primary.getOrderNo());
|
|
|
+ resultVo.setMergedIntoPrimaryOrderIds(secondaries.stream().map(StoreOrder::getId).collect(Collectors.toList()));
|
|
|
+ resultVo.setNewTableIds(tgt);
|
|
|
+ resultVo.setMessage("换桌成功(多桌合并,已合并为单笔待支付订单)");
|
|
|
+ return resultVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new IllegalArgumentException("不支持的换桌组合:源桌数=" + n + ",目标桌数=" + m + ",仅支持 N×N、1×多、多×1");
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 多桌合并时取最大就餐人数,避免汇总后人数偏小 */
|
|
|
+ private static int maxDinerCount(List<StoreOrder> orders) {
|
|
|
+ int max = 1;
|
|
|
+ for (StoreOrder o : orders) {
|
|
|
+ if (o.getDinerCount() != null) {
|
|
|
+ max = Math.max(max, o.getDinerCount());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return max;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将多笔待支付合并为一笔:明细归主单、金额累加、从单取消(状态=2),保证结账只处理主单。
|
|
|
+ */
|
|
|
+ private void mergePendingOrdersIntoPrimary(StoreOrder primary, List<StoreOrder> secondaries, Integer userId, Date now) {
|
|
|
+ BigDecimal total = primary.getTotalAmount() != null ? primary.getTotalAmount() : BigDecimal.ZERO;
|
|
|
+ BigDecimal pay = primary.getPayAmount() != null ? primary.getPayAmount() : BigDecimal.ZERO;
|
|
|
+ for (StoreOrder sec : secondaries) {
|
|
|
+ total = total.add(sec.getTotalAmount() != null ? sec.getTotalAmount() : BigDecimal.ZERO);
|
|
|
+ pay = pay.add(sec.getPayAmount() != null ? sec.getPayAmount() : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ LambdaQueryWrapper<StoreOrderDetail> dq = new LambdaQueryWrapper<>();
|
|
|
+ dq.eq(StoreOrderDetail::getOrderId, sec.getId());
|
|
|
+ List<StoreOrderDetail> lines = storeOrderDetailMapper.selectList(dq);
|
|
|
+ for (StoreOrderDetail d : lines) {
|
|
|
+ d.setOrderId(primary.getId());
|
|
|
+ d.setOrderNo(primary.getOrderNo());
|
|
|
+ d.setUpdatedUserId(userId);
|
|
|
+ d.setUpdatedTime(now);
|
|
|
+ storeOrderDetailMapper.updateById(d);
|
|
|
+ }
|
|
|
+ String remark = sec.getRemark() != null ? sec.getRemark() : "";
|
|
|
+ sec.setOrderStatus(2);
|
|
|
+ sec.setRemark((remark + " [换桌合并至" + primary.getOrderNo() + "]").trim());
|
|
|
+ sec.setUpdatedUserId(userId);
|
|
|
+ sec.setUpdatedTime(now);
|
|
|
+ this.updateById(sec);
|
|
|
+ }
|
|
|
+ primary.setTotalAmount(total.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ primary.setPayAmount(pay.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ if (primary.getUserReservationId() == null) {
|
|
|
+ for (StoreOrder sec : secondaries) {
|
|
|
+ if (sec.getUserReservationId() != null) {
|
|
|
+ primary.setUserReservationId(sec.getUserReservationId());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ primary.setUpdatedUserId(userId);
|
|
|
+ primary.setUpdatedTime(now);
|
|
|
+ this.updateById(primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void patchOrderTable(StoreOrder o, StoreTable newTable, Integer userId, Date now) {
|
|
|
+ o.setTableId(newTable.getId());
|
|
|
+ o.setTableNumber(newTable.getTableNumber());
|
|
|
+ o.setUpdatedUserId(userId);
|
|
|
+ o.setUpdatedTime(now);
|
|
|
+ this.updateById(o);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void assignTableToOrder(StoreTable table, StoreOrder order, Integer dinerCount) {
|
|
|
+ StoreTable patch = new StoreTable();
|
|
|
+ patch.setId(table.getId());
|
|
|
+ patch.setCurrentOrderId(order.getId());
|
|
|
+ patch.setStatus(1);
|
|
|
+ if (dinerCount != null) {
|
|
|
+ patch.setDinerCount(dinerCount);
|
|
|
+ }
|
|
|
+ storeTableMapper.updateById(patch);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 释放源桌:仅当 current_order_id 仍指向本订单时清空,避免误清其它会话。
|
|
|
+ */
|
|
|
+ private void releaseTableIfCurrentOrder(StoreTable table, Integer orderId) {
|
|
|
+ if (table == null || orderId == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (table.getCurrentOrderId() != null && table.getCurrentOrderId().equals(orderId)) {
|
|
|
+ StoreTable patch = new StoreTable();
|
|
|
+ patch.setId(table.getId());
|
|
|
+ patch.setCurrentOrderId(null);
|
|
|
+ patch.setStatus(0);
|
|
|
+ patch.setDinerCount(null);
|
|
|
+ storeTableMapper.updateById(patch);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<Integer, StoreTable> loadAndAssertStoreTables(Integer storeId, List<Integer> ids, String label) {
|
|
|
+ Map<Integer, StoreTable> map = new LinkedHashMap<>();
|
|
|
+ for (Integer id : ids) {
|
|
|
+ StoreTable t = storeTableMapper.selectById(id);
|
|
|
+ if (t == null || t.getStoreId() == null || !t.getStoreId().equals(storeId)) {
|
|
|
+ throw new IllegalArgumentException(label + "不存在或不属于该门店,tableId=" + id);
|
|
|
+ }
|
|
|
+ map.put(id, t);
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void assertTargetTableIdle(StoreTable t) {
|
|
|
+ if (t.getStatus() != null && t.getStatus() != 0) {
|
|
|
+ throw new IllegalArgumentException("目标桌非空闲,无法换入,tableId=" + t.getId());
|
|
|
+ }
|
|
|
+ if (t.getCurrentOrderId() != null) {
|
|
|
+ throw new IllegalArgumentException("目标桌已绑定订单,无法换入,tableId=" + t.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private StoreOrder findSinglePendingOrderForTable(Integer storeId, Integer tableId) {
|
|
|
+ LambdaQueryWrapper<StoreOrder> q = new LambdaQueryWrapper<>();
|
|
|
+ q.eq(StoreOrder::getStoreId, storeId)
|
|
|
+ .eq(StoreOrder::getTableId, tableId)
|
|
|
+ .eq(StoreOrder::getDeleteFlag, 0)
|
|
|
+ .eq(StoreOrder::getOrderStatus, 0)
|
|
|
+ .eq(StoreOrder::getPayStatus, 0)
|
|
|
+ .orderByDesc(StoreOrder::getId);
|
|
|
+ List<StoreOrder> list = this.list(q);
|
|
|
+ if (list.size() > 1) {
|
|
|
+ throw new IllegalStateException("该桌存在多笔待支付订单,数据异常,tableId=" + tableId);
|
|
|
+ }
|
|
|
+ return list.isEmpty() ? null : list.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验预约一致性:要么均无预约,要么同一 user_reservation_id;并按 carryReservationTime 决定是否改约。
|
|
|
+ */
|
|
|
+ private void validateReservationConsistency(List<StoreOrder> orders, StoreBookingChangeTableDTO dto) {
|
|
|
+ boolean hasNull = orders.stream().anyMatch(o -> o.getUserReservationId() == null);
|
|
|
+ boolean hasNonNull = orders.stream().anyMatch(o -> o.getUserReservationId() != null);
|
|
|
+ if (hasNull && hasNonNull) {
|
|
|
+ throw new IllegalArgumentException("所选订单部分含预约、部分为散客,无法一并换桌");
|
|
|
+ }
|
|
|
+ Set<Integer> resIds = orders.stream()
|
|
|
+ .map(StoreOrder::getUserReservationId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ if (resIds.size() > 1) {
|
|
|
+ throw new IllegalArgumentException("所选订单关联多笔不同预约,请分次换桌或联系管理员");
|
|
|
+ }
|
|
|
+ if (resIds.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Integer reservationId = resIds.iterator().next();
|
|
|
+ UserReservation ur = userReservationMapper.selectById(reservationId);
|
|
|
+ if (ur == null || (ur.getDeleteFlag() != null && ur.getDeleteFlag() != 0)) {
|
|
|
+ throw new IllegalArgumentException("预约不存在或已删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Boolean.TRUE.equals(dto.getCarryReservationTime())) {
|
|
|
+ // 多桌合并:若各订单曾对应不同预约已排除;此处仅校验「沿用」时不再写新字段
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (dto.getNewReservationDate() == null
|
|
|
+ || !StringUtils.hasText(dto.getNewStartTime())
|
|
|
+ || !StringUtils.hasText(dto.getNewEndTime())) {
|
|
|
+ throw new IllegalArgumentException("不沿用原预约时间时,请填写新预约日期与开始/结束时间");
|
|
|
+ }
|
|
|
+ UserReservation patch = new UserReservation();
|
|
|
+ patch.setId(reservationId);
|
|
|
+ patch.setReservationDate(dto.getNewReservationDate());
|
|
|
+ patch.setStartTime(dto.getNewStartTime().trim());
|
|
|
+ patch.setEndTime(dto.getNewEndTime().trim());
|
|
|
+ userReservationMapper.updateById(patch);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Integer unifiedReservationId(List<StoreOrder> orders) {
|
|
|
+ for (StoreOrder o : orders) {
|
|
|
+ if (o.getUserReservationId() != null) {
|
|
|
+ return o.getUserReservationId();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与 {@link shop.alien.store.service.impl.UserReservationServiceImpl#saveReservationTables} 一致:先物理删再插,保证预约与桌台一致。
|
|
|
+ */
|
|
|
+ private void replaceReservationTables(Integer reservationId, List<Integer> newTableIds) {
|
|
|
+ userReservationTableMapper.physicalDeleteByReservationId(reservationId);
|
|
|
+ if (newTableIds == null || newTableIds.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int sort = 0;
|
|
|
+ for (Integer tableId : newTableIds) {
|
|
|
+ UserReservationTable row = new UserReservationTable();
|
|
|
+ row.setReservationId(reservationId);
|
|
|
+ row.setTableId(tableId);
|
|
|
+ row.setSort(sort++);
|
|
|
+ userReservationTableMapper.insert(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 解析本桌待支付订单,用于首单/多次加餐。
|
|
|
* 优先级:显式 targetOrderId → 桌台 current_order_id → 按桌+店查询待支付(唯一一笔)。
|
|
|
*/
|