diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java index 542b7cc..004abf2 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java @@ -2,22 +2,27 @@ package com.gxwebsoft.glt.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketTemplate; import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.entity.GltUserTicketLog; import com.gxwebsoft.glt.entity.GltUserTicketRelease; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.entity.ShopOrderGoods; +import com.gxwebsoft.shop.entity.ShopUserAddress; import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.service.ShopOrderService; +import com.gxwebsoft.shop.service.ShopUserAddressService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.support.TransactionTemplate; +import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -55,6 +60,8 @@ public class GltTicketIssueService { private final GltUserTicketService gltUserTicketService; private final GltUserTicketReleaseService gltUserTicketReleaseService; private final GltUserTicketLogService gltUserTicketLogService; + private final GltTicketOrderService gltTicketOrderService; + private final ShopUserAddressService shopUserAddressService; private final TransactionTemplate transactionTemplate; /** @@ -312,7 +319,15 @@ public class GltTicketIssueService { userTicket.setAvailableQty(availableBefore - toUse); userTicket.setUsedQty(usedBefore + toUse); userTicket.setUpdateTime(now); - gltUserTicketService.updateById(userTicket); + if (!gltUserTicketService.updateById(userTicket)) { + throw new IllegalStateException("起始送水自动核销:更新用户水票失败 userTicketId=" + userTicket.getId()); + } + + // 起始送水:自动核销成功后,生成一条送水订单(用于配送端/后台跟踪) + GltTicketOrder ticketOrder = buildStartSendTicketOrder(tenantId, order, userTicket, toUse, now); + if (!gltTicketOrderService.save(ticketOrder)) { + throw new IllegalStateException("起始送水自动核销:创建送水订单失败 userTicketId=" + userTicket.getId()); + } GltUserTicketLog writeOffLog = new GltUserTicketLog(); writeOffLog.setUserTicketId(userTicket.getId()); @@ -323,12 +338,12 @@ public class GltTicketIssueService { writeOffLog.setAvailableAfter(userTicket.getAvailableQty()); writeOffLog.setFrozenAfter(userTicket.getFrozenQty() != null ? userTicket.getFrozenQty() : 0); writeOffLog.setUsedAfter(userTicket.getUsedQty()); - // 关联原始商城订单,便于追溯该次自动核销来源 - writeOffLog.setOrderId(order.getOrderId()); - writeOffLog.setOrderNo(order.getOrderNo()); + // 关联送水订单(保持与“用户下单核销”的日志一致),并在备注里保留来源商城订单号便于追溯 + writeOffLog.setOrderId(ticketOrder.getId()); + writeOffLog.setOrderNo(ticketOrder.getId() == null ? null : String.valueOf(ticketOrder.getId())); writeOffLog.setUserId(order.getUserId()); writeOffLog.setSortNumber(0); - writeOffLog.setComments("起始送水自动核销"); + writeOffLog.setComments("起始送水自动核销(来源商城订单:" + safe(order.getOrderNo()) + ")"); writeOffLog.setStatus(0); writeOffLog.setDeleted(0); writeOffLog.setTenantId(tenantId); @@ -423,4 +438,78 @@ public class GltTicketIssueService { LocalDate adjusted = nextMonth.withDayOfMonth(day); return LocalDateTime.of(adjusted, time); } + + private static final DateTimeFormatter DATETIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private GltTicketOrder buildStartSendTicketOrder(Integer tenantId, + ShopOrder shopOrder, + GltUserTicket userTicket, + int totalNum, + LocalDateTime now) { + GltTicketOrder o = new GltTicketOrder(); + o.setUserTicketId(userTicket.getId()); + o.setUserId(shopOrder.getUserId()); + o.setStoreId(shopOrder.getStoreId()); + o.setWarehouseId(shopOrder.getWarehouseId()); + o.setRiderId(shopOrder.getRiderId()); + o.setTotalNum(totalNum); + o.setPrice(BigDecimal.ZERO); + o.setBuyerRemarks(shopOrder.getBuyerRemarks()); + + // 地址快照:优先使用地址表快照;兜底使用商城订单上的 address 字段 + Integer addressId = shopOrder.getAddressId(); + o.setAddressId(addressId); + String addressSnapshot = null; + if (addressId != null) { + ShopUserAddress addr = shopUserAddressService.getOne(new LambdaQueryWrapper() + .eq(ShopUserAddress::getId, addressId) + .eq(ShopUserAddress::getUserId, shopOrder.getUserId()) + .eq(ShopUserAddress::getTenantId, tenantId) + .last("limit 1")); + addressSnapshot = buildAddressSnapshot(addr); + } + if (addressSnapshot == null || addressSnapshot.isBlank()) { + addressSnapshot = shopOrder.getAddress(); + } + o.setAddress(addressSnapshot); + + String preferredSendTime = shopOrder.getSendStartTime(); + if (preferredSendTime == null || preferredSendTime.isBlank()) { + preferredSendTime = now.format(DATETIME_FMT); + } + o.setSendTime(preferredSendTime); + o.setDeliveryStatus(GltTicketOrderService.DELIVERY_STATUS_WAITING); + o.setSortNumber(0); + o.setComments("起始送水自动下单(来源商城订单:" + safe(shopOrder.getOrderNo()) + ")"); + o.setStatus(0); + o.setDeleted(0); + o.setTenantId(tenantId); + o.setCreateTime(now); + o.setUpdateTime(now); + return o; + } + + private static String buildAddressSnapshot(ShopUserAddress addr) { + if (addr == null) { + return null; + } + if (addr.getFullAddress() != null && !addr.getFullAddress().isBlank()) { + return addr.getFullAddress(); + } + // 兼容旧数据:fullAddress 为空时,拼接省市区 + 详细地址 + StringBuilder sb = new StringBuilder(); + if (addr.getProvince() != null) sb.append(addr.getProvince()); + if (addr.getCity() != null) sb.append(addr.getCity()); + if (addr.getRegion() != null) sb.append(addr.getRegion()); + if (addr.getAddress() != null) sb.append(addr.getAddress()); + String s = sb.toString(); + if (!s.isBlank()) { + return s; + } + return addr.getAddress(); + } + + private static String safe(String s) { + return s == null ? "" : s; + } }