package com.linhelp.express; import com.linhelp.common.enums.ExpressOrderStatus; import com.linhelp.common.enums.OfflinePayStatus; import com.linhelp.common.exception.BizException; import com.linhelp.user.AddressResponse; import com.linhelp.user.UserAddressService; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @Service public class ExpressOrderService { private final UserAddressService addressService; private final AtomicLong orderIds = new AtomicLong(1L); private final AtomicLong logIds = new AtomicLong(1L); private final Map orders = new LinkedHashMap(); public ExpressOrderService(UserAddressService addressService) { this.addressService = addressService; } public synchronized ExpressOrderResponse create(Long userId, ExpressOrderRequest request) { AddressResponse address = addressService.detailMine(userId, request.getAddressId()); Long orderId = orderIds.getAndIncrement(); ExpressOrderResponse order = new ExpressOrderResponse(); order.setId(orderId); order.setOrderNo("EO" + String.format("%08d", orderId)); order.setTenantId(request.getTenantId()); order.setCommunityId(request.getCommunityId()); order.setUserId(userId); order.setAddressId(request.getAddressId()); order.setContactName(address.getContactName()); order.setContactPhone(address.getPhone()); order.setDeliveryAddress(buildDeliveryAddress(address)); order.setExpressCompany(request.getExpressCompany()); order.setPickupCode(request.getPickupCode()); order.setPickupAddress(request.getPickupAddress()); order.setReceiverPhone(request.getReceiverPhone()); order.setPackageCount(request.getPackageCount()); order.setFeeCent(ExpressFeeCalculator.calculateCent(request.getPackageCount())); order.setOfflinePayStatus(OfflinePayStatus.UNPAID); order.setStatus(ExpressOrderStatus.PENDING_CONFIRM); order.setRemark(request.getRemark()); order.setCreatedAt(LocalDateTime.now()); order.setUpdatedAt(order.getCreatedAt()); addLog(order, "CREATE", "用户提交快递代取"); orders.put(order.getId(), order); return copyOrder(order); } public synchronized ExpressOrderResponse detail(Long id) { return copyOrder(requireOrder(id)); } public synchronized List listMine(Long userId) { List result = new ArrayList(); for (ExpressOrderResponse order : orders.values()) { if (userId.equals(order.getUserId())) { result.add(copyOrder(order)); } } return result; } public synchronized List listAdmin(Long communityId, ExpressOrderStatus status) { List result = new ArrayList(); for (ExpressOrderResponse order : orders.values()) { if (!communityId.equals(order.getCommunityId())) { continue; } if (status != null && status != order.getStatus()) { continue; } result.add(copyOrder(order)); } return result; } public synchronized ExpressOrderResponse confirm(Long id) { ExpressOrderResponse order = requireOrder(id); move(order, ExpressOrderStatus.PENDING_PICKUP, "CONFIRM", "后台确认快递代取"); return copyOrder(order); } public synchronized ExpressOrderResponse adjustFee(Long id, int feeCent, String reason) { ExpressOrderResponse order = requireOrder(id); order.setFeeCent(feeCent); order.setUpdatedAt(LocalDateTime.now()); addLog(order, "ADJUST_FEE", "调整服务费为" + feeCent + "分:" + reason); return copyOrder(order); } public synchronized ExpressOrderResponse cancel(Long id, String reason) { ExpressOrderResponse order = requireOrder(id); order.setCancelReason(reason); move(order, ExpressOrderStatus.CANCELED, "CANCEL", "取消订单:" + nullToEmpty(reason)); return copyOrder(order); } public synchronized ExpressOrderResponse complete(Long id) { ExpressOrderResponse order = requireOrder(id); move(order, ExpressOrderStatus.COMPLETED, "COMPLETE", "订单完成"); return copyOrder(order); } public synchronized ExpressOrderResponse markPickingUp(Long id) { ExpressOrderResponse order = requireOrder(id); move(order, ExpressOrderStatus.PICKING_UP, "PICKING_UP", "配送员开始取件"); return copyOrder(order); } public synchronized ExpressOrderResponse markDelivering(Long id) { ExpressOrderResponse order = requireOrder(id); move(order, ExpressOrderStatus.DELIVERING, "DELIVERING", "配送员开始配送"); return copyOrder(order); } public synchronized ExpressOrderResponse markDelivered(Long id, String photoUrl) { ExpressOrderResponse order = requireOrder(id); order.setDeliveredPhotoUrl(photoUrl); move(order, ExpressOrderStatus.DELIVERED, "DELIVERED", "配送员送达"); return copyOrder(order); } public synchronized ExpressOrderResponse updateOfflinePayStatus(Long id, OfflinePayStatus status) { ExpressOrderResponse order = requireOrder(id); order.setOfflinePayStatus(status); order.setUpdatedAt(LocalDateTime.now()); addLog(order, "OFFLINE_PAY", "线下收款状态:" + status.name()); return copyOrder(order); } private void move(ExpressOrderResponse order, ExpressOrderStatus target, String action, String content) { if (!order.getStatus().canMoveTo(target)) { throw new BizException("订单状态不允许操作"); } order.setStatus(target); order.setUpdatedAt(LocalDateTime.now()); addLog(order, action, content); } private ExpressOrderResponse requireOrder(Long id) { ExpressOrderResponse order = orders.get(id); if (order == null) { throw new BizException(404, "快递代取订单不存在"); } return order; } private void addLog(ExpressOrderResponse order, String action, String content) { ExpressOrderLogResponse log = new ExpressOrderLogResponse(); log.setId(logIds.getAndIncrement()); log.setOrderId(order.getId()); log.setAction(action); log.setContent(content); log.setCreatedAt(LocalDateTime.now()); order.getLogs().add(log); } private String buildDeliveryAddress(AddressResponse address) { StringBuilder builder = new StringBuilder(); append(builder, address.getBuilding()); append(builder, address.getRoom()); append(builder, address.getDetail()); return builder.toString(); } private void append(StringBuilder builder, String value) { if (value == null || value.trim().isEmpty()) { return; } if (builder.length() > 0) { builder.append(' '); } builder.append(value); } private String nullToEmpty(String value) { return value == null ? "" : value; } private ExpressOrderResponse copyOrder(ExpressOrderResponse source) { ExpressOrderResponse target = new ExpressOrderResponse(); target.setId(source.getId()); target.setOrderNo(source.getOrderNo()); target.setTenantId(source.getTenantId()); target.setCommunityId(source.getCommunityId()); target.setUserId(source.getUserId()); target.setAddressId(source.getAddressId()); target.setContactName(source.getContactName()); target.setContactPhone(source.getContactPhone()); target.setDeliveryAddress(source.getDeliveryAddress()); target.setExpressCompany(source.getExpressCompany()); target.setPickupCode(source.getPickupCode()); target.setPickupAddress(source.getPickupAddress()); target.setReceiverPhone(source.getReceiverPhone()); target.setPackageCount(source.getPackageCount()); target.setFeeCent(source.getFeeCent()); target.setOfflinePayStatus(source.getOfflinePayStatus()); target.setStatus(source.getStatus()); target.setRemark(source.getRemark()); target.setCancelReason(source.getCancelReason()); target.setDeliveredPhotoUrl(source.getDeliveredPhotoUrl()); target.setCreatedAt(source.getCreatedAt()); target.setUpdatedAt(source.getUpdatedAt()); target.setLogs(copyLogs(source.getLogs())); return target; } private List copyLogs(List sourceLogs) { List logs = new ArrayList(); for (ExpressOrderLogResponse source : sourceLogs) { ExpressOrderLogResponse target = new ExpressOrderLogResponse(); target.setId(source.getId()); target.setOrderId(source.getOrderId()); target.setAction(source.getAction()); target.setContent(source.getContent()); target.setCreatedAt(source.getCreatedAt()); logs.add(target); } return logs; } }