贴标申请,仓储转运
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@ public final class CargoDiscardRequests {
|
||||
@NotBlank @Size(max = 255) String idempotencyKey,
|
||||
@Size(max = 1000) String remark) {}
|
||||
|
||||
public record Item(@NotNull Long orderId, @NotBlank @Size(max = 128) String skuCode,
|
||||
public record Item(Long orderId, Long returnCartonId, @NotBlank @Size(max = 128) String skuCode,
|
||||
@Positive int discardPackages) {}
|
||||
|
||||
public record Review(@NotBlank String decision, @Size(max = 1000) String remark) {}
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@ import java.util.List;
|
||||
public final class CargoDiscardResponses {
|
||||
private CargoDiscardResponses() {}
|
||||
|
||||
public record Candidate(Long orderId, String inboundCode, String inboundOrderNo,
|
||||
public record Candidate(Long orderId, String sourceType, Long returnCartonId, String cartonMark,
|
||||
String inboundCode, String inboundOrderNo,
|
||||
String overseasWarehouseId, String overseasWarehouseName,
|
||||
LocalDateTime inboundCreatedAt, long availablePackages,
|
||||
List<CandidateSku> skus) {}
|
||||
|
||||
@@ -14,6 +14,8 @@ public class CargoDiscardItem {
|
||||
private Long applicationId;
|
||||
private String customerId;
|
||||
private Long orderId;
|
||||
private String sourceType;
|
||||
private Long returnCartonId;
|
||||
private String inboundCode;
|
||||
private Long profileId;
|
||||
private Long skuInventoryId;
|
||||
|
||||
+24
-4
@@ -10,6 +10,8 @@ import com.baiyue.lastleg.discard.service.CargoDiscardService;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipOrderProfile;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipOrderProfileMapper;
|
||||
import com.baiyue.lastleg.pda.security.PdaWarehouseIdentity;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -27,6 +29,7 @@ public class PdaCargoDiscardService {
|
||||
@Resource private DropshipOrderProfileMapper profiles;
|
||||
@Resource private CargoDiscardInventoryAdjustmentService adjustments;
|
||||
@Resource private CargoDiscardService discardService;
|
||||
@Resource private ReturnInventoryCartonMapper returnCartons;
|
||||
|
||||
public List<PdaCargoDiscardDtos.PalletTask> tasks(PdaWarehouseIdentity identity) {
|
||||
return applications.selectList(new LambdaQueryWrapper<CargoDiscardApplication>()
|
||||
@@ -69,6 +72,9 @@ public class PdaCargoDiscardService {
|
||||
item.setActualDiscardPackages(actuals.get(item.getId())); item.setPdaStatus("COMPLETED");
|
||||
item.setPdaOperatorId(identity.operatorKey()); item.setPdaCompletedAt(now); items.updateById(item);
|
||||
}
|
||||
task.skus().stream().map(PdaCargoDiscardDtos.Sku::itemId).map(items::selectById)
|
||||
.filter(this::isReturnItem).map(CargoDiscardItem::getReturnCartonId).filter(Objects::nonNull).distinct()
|
||||
.forEach(cartonId -> adjustments.finishReturnCarton(application.getCustomerId(), cartonId));
|
||||
if (items.listApplication(application.getCustomerId(), application.getId()).stream()
|
||||
.allMatch(i -> "COMPLETED".equals(i.getPdaStatus()))) {
|
||||
int actualTotal = items.listApplication(application.getCustomerId(), application.getId()).stream()
|
||||
@@ -83,17 +89,31 @@ public class PdaCargoDiscardService {
|
||||
|
||||
private List<PdaCargoDiscardDtos.PalletTask> palletTasks(CargoDiscardApplication application) {
|
||||
return items.listApplication(application.getCustomerId(), application.getId()).stream()
|
||||
.collect(Collectors.groupingBy(CargoDiscardItem::getProfileId, LinkedHashMap::new, Collectors.toList()))
|
||||
.collect(Collectors.groupingBy(this::physicalGroupKey, LinkedHashMap::new, Collectors.toList()))
|
||||
.entrySet().stream().map(entry -> {
|
||||
DropshipOrderProfile profile = profiles.selectById(entry.getKey());
|
||||
if (profile == null || !application.getCustomerId().equals(profile.getCustomerId())) throw conflict("废弃明细关联托盘不存在");
|
||||
CargoDiscardItem first = entry.getValue().get(0);
|
||||
boolean returnSource = isReturnItem(first);
|
||||
DropshipOrderProfile profile = returnSource ? null : profiles.selectById(first.getProfileId());
|
||||
ReturnInventoryCarton returnCarton = returnSource ? returnCartons.selectById(first.getReturnCartonId()) : null;
|
||||
if (!returnSource && (profile == null || !application.getCustomerId().equals(profile.getCustomerId()))) throw conflict("废弃明细关联托盘不存在");
|
||||
if (returnSource && (returnCarton == null || !application.getCustomerId().equals(returnCarton.getCustomerId()))) throw conflict("废弃明细关联退货箱不存在");
|
||||
List<PdaCargoDiscardDtos.Sku> skus = entry.getValue().stream().map(i -> new PdaCargoDiscardDtos.Sku(
|
||||
i.getId(), i.getSkuCode(), i.getProductName(), i.getDiscardPackages(), i.getActualDiscardPackages(),
|
||||
i.getPdaStatus() == null ? "PENDING" : i.getPdaStatus())).toList();
|
||||
String status = skus.stream().allMatch(s -> "COMPLETED".equals(s.status())) ? "COMPLETED" : "PENDING";
|
||||
return new PdaCargoDiscardDtos.PalletTask(application.getDiscardNo(), application.getCustomerId(),
|
||||
application.getOverseasWarehouseId(), profile.getPalletNo(), profile.getId(), status, skus);
|
||||
application.getOverseasWarehouseId(), returnSource ? firstNonBlank(returnCarton.getPalletCode(), returnCarton.getCartonMark()) : profile.getPalletNo(),
|
||||
returnSource ? returnCarton.getId() : profile.getId(), status, skus);
|
||||
}).toList();
|
||||
}
|
||||
private String physicalGroupKey(CargoDiscardItem item) {
|
||||
return isReturnItem(item) ? "RETURN:" + item.getReturnCartonId() : "DROPSHIP:" + item.getProfileId();
|
||||
}
|
||||
private boolean isReturnItem(CargoDiscardItem item) {
|
||||
return "RETURN_CARTON".equals(item.getSourceType()) || item.getReturnCartonId() != null;
|
||||
}
|
||||
private static String firstNonBlank(String first, String second) {
|
||||
return first != null && !first.isBlank() ? first : second;
|
||||
}
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
}
|
||||
|
||||
+36
@@ -15,6 +15,9 @@ import com.baiyue.lastleg.dropship.mapper.DropshipOrderProfileMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipSkuInventoryMapper;
|
||||
import com.baiyue.lastleg.inventory.mapper.InventoryPositionMapper;
|
||||
import com.baiyue.lastleg.inventory.mapper.InventoryBalanceMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCartonItem;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonItemMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -37,11 +40,14 @@ public class CargoDiscardInventoryAdjustmentService {
|
||||
@Resource private DropshipOrderProfileMapper profiles;
|
||||
@Resource private InventoryPositionMapper positions;
|
||||
@Resource private InventoryBalanceMapper balances;
|
||||
@Resource private ReturnInventoryCartonMapper returnCartons;
|
||||
@Resource private ReturnInventoryCartonItemMapper returnCartonItems;
|
||||
|
||||
@Transactional(propagation = Propagation.MANDATORY)
|
||||
public AdjustmentResult discardPalletItem(String customerId, CargoDiscardApplication application,
|
||||
CargoDiscardItem item, List<CargoDiscardCarton> links,
|
||||
int actualPackages, String operatorId, LocalDateTime occurredAt) {
|
||||
if (isReturnItem(item)) return discardReturnItem(customerId, item, actualPackages);
|
||||
if (actualPackages < 0 || actualPackages > links.size()) throw conflict("实际废弃数量超出该托盘申请数量");
|
||||
DropshipSkuInventory sku = inventory.lockSkuInventory(customerId, item.getSkuInventoryId());
|
||||
if (sku == null) throw conflict("托盘 SKU 库存不存在: " + item.getSkuCode());
|
||||
@@ -88,6 +94,36 @@ public class CargoDiscardInventoryAdjustmentService {
|
||||
return new AdjustmentResult(before, actualPackages, after);
|
||||
}
|
||||
|
||||
private AdjustmentResult discardReturnItem(String customerId, CargoDiscardItem item, int actualPackages) {
|
||||
if (actualPackages < 0 || actualPackages > item.getDiscardPackages()) {
|
||||
throw conflict("实际废弃数量超出退货库存申请数量");
|
||||
}
|
||||
ReturnInventoryCartonItem sku = returnCartonItems.lockSku(item.getReturnCartonId(), item.getSkuCode());
|
||||
if (sku == null || !customerId.equals(sku.getCustomerId())) throw conflict("退货库存 SKU 不存在");
|
||||
long before = value(sku.getQuantity());
|
||||
if (before < actualPackages || (actualPackages > 0 && returnCartonItems.deduct(sku.getId(), actualPackages) != 1)) {
|
||||
throw conflict("退货库存数量不足");
|
||||
}
|
||||
return new AdjustmentResult(before, actualPackages, before - actualPackages);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.MANDATORY)
|
||||
public void finishReturnCarton(String customerId, long cartonId) {
|
||||
var carton = returnCartons.lockId(cartonId);
|
||||
if (carton == null || !customerId.equals(carton.getCustomerId())) throw conflict("退货库存箱不存在");
|
||||
if ("AVAILABLE".equals(carton.getStatus()) || "DISCARDED".equals(carton.getStatus())) return;
|
||||
long remaining = returnCartonItems.totalQuantity(cartonId);
|
||||
int skuTypes = returnCartonItems.skuTypes(cartonId);
|
||||
String status = remaining == 0 ? "DISCARDED" : "AVAILABLE";
|
||||
if (returnCartons.finishDiscard(cartonId, customerId, status, remaining, skuTypes) != 1) {
|
||||
throw conflict("退货库存箱状态已变化");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isReturnItem(CargoDiscardItem item) {
|
||||
return "RETURN_CARTON".equals(item.getSourceType()) || item.getReturnCartonId() != null;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.MANDATORY)
|
||||
public AdjustmentResult discard(String customerId, CargoDiscardApplication application,
|
||||
List<CargoDiscardItem> items,
|
||||
|
||||
+105
-14
@@ -22,6 +22,10 @@ import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCarton;
|
||||
import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCartonItem;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonItemMapper;
|
||||
import com.baiyue.lastleg.returnreceipt.mapper.ReturnInventoryCartonMapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -64,6 +68,8 @@ public class CargoDiscardService {
|
||||
@Resource private CargoDiscardInventoryAdjustmentService adjustments;
|
||||
@Resource private LastlegOrderMapper orders;
|
||||
@Resource private LastlegOrderStatusHistoryMapper orderHistories;
|
||||
@Resource private ReturnInventoryCartonMapper returnCartons;
|
||||
@Resource private ReturnInventoryCartonItemMapper returnCartonItems;
|
||||
@Resource private ObjectMapper objectMapper;
|
||||
@Value("${baiyue.lastleg.cargo-discard.fee-per-package-usd:5.00}")
|
||||
private BigDecimal feePerPackage = new BigDecimal("5.00");
|
||||
@@ -75,9 +81,25 @@ public class CargoDiscardService {
|
||||
CandidateAccumulator value = grouped.computeIfAbsent(row.getOrderId(), ignored -> new CandidateAccumulator(row));
|
||||
value.add(row);
|
||||
}
|
||||
return grouped.values().stream()
|
||||
List<CargoDiscardResponses.Candidate> result = grouped.values().stream()
|
||||
.map(value -> value.response(inventory.countAvailableOrder(customerId, value.first.getOrderId())))
|
||||
.toList();
|
||||
.collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new));
|
||||
String keyword = trim(inboundCode);
|
||||
if (returnCartons == null || returnCartonItems == null) return result;
|
||||
for (ReturnInventoryCarton carton : returnCartons.findAvailable(customerId, null)) {
|
||||
if (StringUtils.hasText(keyword) && !containsIgnoreCase(carton.getSourceReturnNo(), keyword)
|
||||
&& !containsIgnoreCase(carton.getCartonMark(), keyword)) continue;
|
||||
List<CargoDiscardResponses.CandidateSku> skus = returnCartonItems.listCarton(carton.getId()).stream()
|
||||
.filter(item -> value(item.getQuantity()) > 0)
|
||||
.map(item -> new CargoDiscardResponses.CandidateSku(item.getSkuCode(), item.getProductNameZh(), value(item.getQuantity())))
|
||||
.toList();
|
||||
long available = skus.stream().mapToLong(CargoDiscardResponses.CandidateSku::availablePackages).sum();
|
||||
if (available <= 0) continue;
|
||||
result.add(new CargoDiscardResponses.Candidate(null, "RETURN_CARTON", carton.getId(), carton.getCartonMark(),
|
||||
carton.getSourceReturnNo(), carton.getSourceReturnNo(), carton.getOverseasWarehouseId(), null,
|
||||
null, available, skus));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -94,18 +116,39 @@ public class CargoDiscardService {
|
||||
}
|
||||
Set<String> requestedDimensions = new LinkedHashSet<>();
|
||||
Map<Long, LastlegOrder> orderCache = new HashMap<>();
|
||||
Map<Long, ReturnInventoryCarton> returnCartonCache = new HashMap<>();
|
||||
String warehouseId = null;
|
||||
String warehouseName = null;
|
||||
int total = 0;
|
||||
for (CargoDiscardRequests.Item input : request.items()) {
|
||||
String dimension = input.orderId() + ":" + input.skuCode().trim();
|
||||
boolean returnSource = input.returnCartonId() != null;
|
||||
if (returnSource == (input.orderId() != null)) {
|
||||
throw badRequest("Each discard item must identify exactly one inventory source");
|
||||
}
|
||||
String dimension = (returnSource ? "RETURN:" + input.returnCartonId() : "ORDER:" + input.orderId())
|
||||
+ ":" + input.skuCode().trim();
|
||||
if (!requestedDimensions.add(dimension)) throw badRequest("Duplicate order/SKU discard item: " + dimension);
|
||||
LastlegOrder order = requireDropshipOrder(customerId, input.orderId());
|
||||
orderCache.put(order.getId(), order);
|
||||
String itemWarehouseId;
|
||||
String itemWarehouseName;
|
||||
if (returnSource) {
|
||||
ReturnInventoryCarton carton = requireReturnCarton(customerId, input.returnCartonId());
|
||||
ReturnInventoryCartonItem sku = returnCartonItems.lockSku(carton.getId(), input.skuCode().trim());
|
||||
if (sku == null || value(sku.getQuantity()) < input.discardPackages()) {
|
||||
throw conflict("Insufficient return inventory for SKU " + input.skuCode().trim());
|
||||
}
|
||||
returnCartonCache.put(carton.getId(), carton);
|
||||
itemWarehouseId = carton.getOverseasWarehouseId();
|
||||
itemWarehouseName = null;
|
||||
} else {
|
||||
LastlegOrder order = requireDropshipOrder(customerId, input.orderId());
|
||||
orderCache.put(order.getId(), order);
|
||||
itemWarehouseId = order.getOverseasWarehouseId();
|
||||
itemWarehouseName = order.getOverseasWarehouseName();
|
||||
}
|
||||
if (warehouseId == null) {
|
||||
warehouseId = required(order.getOverseasWarehouseId(), "Order has no operating overseas warehouse");
|
||||
warehouseName = trim(order.getOverseasWarehouseName());
|
||||
} else if (!warehouseId.equals(order.getOverseasWarehouseId())) {
|
||||
warehouseId = required(itemWarehouseId, "Inventory has no operating overseas warehouse");
|
||||
warehouseName = trim(itemWarehouseName);
|
||||
} else if (!warehouseId.equals(itemWarehouseId)) {
|
||||
throw conflict("One cargo discard application cannot span operating warehouses");
|
||||
}
|
||||
total = Math.addExact(total, input.discardPackages());
|
||||
@@ -116,7 +159,9 @@ public class CargoDiscardService {
|
||||
application.setId(IdWorker.getId()); application.setCustomerId(customerId);
|
||||
application.setDiscardNo(orderNoGenerator.next("DISCARD", warehouseId, application.getId()));
|
||||
application.setOverseasWarehouseId(warehouseId); application.setOverseasWarehouseName(warehouseName);
|
||||
application.setInboundCodes(orderCache.values().stream().map(LastlegOrder::getInboundCode)
|
||||
application.setInboundCodes(java.util.stream.Stream.concat(
|
||||
orderCache.values().stream().map(LastlegOrder::getInboundCode),
|
||||
returnCartonCache.values().stream().map(ReturnInventoryCarton::getSourceReturnNo))
|
||||
.distinct().sorted().collect(java.util.stream.Collectors.joining(",")));
|
||||
application.setTotalPackages(total); application.setFeePerPackage(feePerPackage);
|
||||
application.setTotalFee(feePerPackage.multiply(BigDecimal.valueOf(total)));
|
||||
@@ -157,8 +202,14 @@ public class CargoDiscardService {
|
||||
initialOrderHistory.setEventId("CARGO_DISCARD_CREATE:" + application.getId()); initialOrderHistory.setRemark(trim(request.remark())); initialOrderHistory.setCreatedAt(now);
|
||||
orderHistories.insert(initialOrderHistory);
|
||||
|
||||
Set<Long> reservedReturnCartons = new LinkedHashSet<>();
|
||||
for (CargoDiscardRequests.Item input : request.items()) {
|
||||
reserve(customerId, application, orderCache.get(input.orderId()), input, now);
|
||||
if (input.returnCartonId() != null) {
|
||||
reserveReturn(customerId, application, returnCartonCache.get(input.returnCartonId()), input, now,
|
||||
reservedReturnCartons);
|
||||
} else {
|
||||
reserve(customerId, application, orderCache.get(input.orderId()), input, now);
|
||||
}
|
||||
}
|
||||
history(customerId, application.getId(), null, PENDING_REVIEW, operatorId, request.remark(), now);
|
||||
return detail(customerId, application.getDiscardNo());
|
||||
@@ -215,7 +266,7 @@ public class CargoDiscardService {
|
||||
.collect(java.util.stream.Collectors.groupingBy(CargoDiscardCarton::getItemId));
|
||||
String historyRemark = request.remark();
|
||||
if (REJECTED.equals(next)) {
|
||||
release(customerId, links);
|
||||
release(customerId, links, applicationItems);
|
||||
}
|
||||
|
||||
LocalDateTime reviewedAt = now();
|
||||
@@ -275,7 +326,7 @@ public class CargoDiscardService {
|
||||
throw conflict("客户只能取消待审核的废弃申请");
|
||||
}
|
||||
List<CargoDiscardCarton> links = discardCartons.listApplication(customerId, application.getId());
|
||||
release(customerId, links);
|
||||
release(customerId, links, items.listApplication(customerId, application.getId()));
|
||||
LocalDateTime at = now();
|
||||
String from = application.getStatus();
|
||||
application.setStatus(CANCELLED); application.setReviewedBy(platform ? operatorId : application.getReviewedBy());
|
||||
@@ -309,6 +360,7 @@ public class CargoDiscardService {
|
||||
if (sku == null) throw conflict("SKU inventory disappeared while reserving cargo");
|
||||
CargoDiscardItem item = new CargoDiscardItem();
|
||||
item.setId(IdWorker.getId()); item.setApplicationId(application.getId()); item.setCustomerId(customerId);
|
||||
item.setSourceType("DROPSHIP");
|
||||
item.setOrderId(order.getId()); item.setInboundCode(order.getInboundCode()); item.setProfileId(entry.getKey());
|
||||
item.setSkuInventoryId(sku.getId()); item.setSkuCode(skuCode); item.setProductName(sku.getProductName());
|
||||
item.setAvailablePackagesSnapshot(Math.toIntExact(inventory.countAvailableProfile(
|
||||
@@ -326,14 +378,50 @@ public class CargoDiscardService {
|
||||
}
|
||||
}
|
||||
|
||||
private void release(String customerId, List<CargoDiscardCarton> links) {
|
||||
private void release(String customerId, List<CargoDiscardCarton> links, List<CargoDiscardItem> applicationItems) {
|
||||
for (CargoDiscardCarton link : links) {
|
||||
if (inventory.changeCartonStatus(customerId, link.getCartonId(), "DISCARD_PENDING", "AVAILABLE") != 1) {
|
||||
throw conflict("Reserved cargo status changed before rejection");
|
||||
}
|
||||
}
|
||||
applicationItems.stream().filter(this::isReturnItem).map(CargoDiscardItem::getReturnCartonId)
|
||||
.filter(java.util.Objects::nonNull).distinct().forEach(cartonId -> {
|
||||
if (returnCartons.releaseDiscard(cartonId, customerId) != 1) {
|
||||
throw conflict("Reserved return inventory status changed before rejection");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void reserveReturn(String customerId, CargoDiscardApplication application, ReturnInventoryCarton carton,
|
||||
CargoDiscardRequests.Item input, LocalDateTime now, Set<Long> reservedCartons) {
|
||||
ReturnInventoryCartonItem sku = returnCartonItems.lockSku(carton.getId(), input.skuCode().trim());
|
||||
if (sku == null || value(sku.getQuantity()) < input.discardPackages()) {
|
||||
throw conflict("Available return inventory changed; retry the discard request");
|
||||
}
|
||||
if (reservedCartons.add(carton.getId()) && returnCartons.markDiscardPending(carton.getId(), customerId) != 1) {
|
||||
throw conflict("Return inventory was reserved concurrently; retry the discard request");
|
||||
}
|
||||
CargoDiscardItem item = new CargoDiscardItem();
|
||||
item.setId(IdWorker.getId()); item.setApplicationId(application.getId()); item.setCustomerId(customerId);
|
||||
item.setSourceType("RETURN_CARTON"); item.setReturnCartonId(carton.getId()); item.setInboundCode(carton.getSourceReturnNo());
|
||||
item.setSkuCode(sku.getSkuCode()); item.setProductName(sku.getProductNameZh());
|
||||
item.setAvailablePackagesSnapshot(Math.toIntExact(value(sku.getQuantity())));
|
||||
item.setDiscardPackages(input.discardPackages()); item.setCreatedAt(now); items.insert(item);
|
||||
}
|
||||
|
||||
private ReturnInventoryCarton requireReturnCarton(String customerId, Long cartonId) {
|
||||
ReturnInventoryCarton carton = returnCartons.lockId(cartonId);
|
||||
if (carton == null || !customerId.equals(carton.getCustomerId())) throw notFound("Return inventory carton not found");
|
||||
if (!"AVAILABLE".equals(carton.getStatus())) throw conflict("Return inventory carton is not available");
|
||||
return carton;
|
||||
}
|
||||
|
||||
private boolean isReturnItem(CargoDiscardItem item) {
|
||||
return "RETURN_CARTON".equals(item.getSourceType()) || item.getReturnCartonId() != null;
|
||||
}
|
||||
|
||||
private static long value(Long value) { return value == null ? 0L : value; }
|
||||
|
||||
private LastlegOrder requireDropshipOrder(String customerId, Long orderId) {
|
||||
LastlegOrder order = orders.selectById(orderId);
|
||||
if (order == null || !customerId.equals(order.getCustomerId())) throw notFound("Inbound order not found");
|
||||
@@ -385,6 +473,9 @@ public class CargoDiscardService {
|
||||
|
||||
private static LocalDateTime now() { return LocalDateTime.now(); }
|
||||
private static String trim(String value) { return value == null || value.isBlank() ? null : value.trim(); }
|
||||
private static boolean containsIgnoreCase(String value, String keyword) {
|
||||
return value != null && keyword != null && value.toLowerCase(java.util.Locale.ROOT).contains(keyword.toLowerCase(java.util.Locale.ROOT));
|
||||
}
|
||||
private static String required(String value, String message) { String result = trim(value); if (result == null) throw conflict(message); return result; }
|
||||
private static ResponseStatusException badRequest(String message) { return new ResponseStatusException(HttpStatus.BAD_REQUEST, message); }
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
@@ -401,7 +492,7 @@ public class CargoDiscardService {
|
||||
private CargoDiscardResponses.Candidate response(long physicalPackages) {
|
||||
List<CargoDiscardResponses.CandidateSku> skuViews = skus.values().stream()
|
||||
.map(value -> new CargoDiscardResponses.CandidateSku(value.skuCode, value.productName, value.packages)).toList();
|
||||
return new CargoDiscardResponses.Candidate(first.getOrderId(), first.getInboundCode(), first.getInboundOrderNo(),
|
||||
return new CargoDiscardResponses.Candidate(first.getOrderId(), "DROPSHIP", null, null, first.getInboundCode(), first.getInboundOrderNo(),
|
||||
first.getOverseasWarehouseId(), first.getOverseasWarehouseName(), first.getCreatedAt(), physicalPackages, skuViews);
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -5,6 +5,7 @@ import com.baiyue.lastleg.returnreceipt.entity.ReturnInventoryCartonItem;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,4 +15,16 @@ public interface ReturnInventoryCartonItemMapper extends BaseMapper<ReturnInvent
|
||||
List<ReturnInventoryCartonItem> listCarton(@Param("cartonId") long cartonId);
|
||||
@Select("SELECT * FROM ll_return_inventory_carton_item WHERE carton_id=#{cartonId} ORDER BY sku_code FOR UPDATE")
|
||||
List<ReturnInventoryCartonItem> lockCarton(@Param("cartonId") long cartonId);
|
||||
|
||||
@Select("SELECT * FROM ll_return_inventory_carton_item WHERE carton_id=#{cartonId} AND sku_code=#{skuCode} LIMIT 1 FOR UPDATE")
|
||||
ReturnInventoryCartonItem lockSku(@Param("cartonId") long cartonId, @Param("skuCode") String skuCode);
|
||||
|
||||
@Update("UPDATE ll_return_inventory_carton_item SET quantity=quantity-#{quantity} WHERE id=#{id} AND quantity>=#{quantity}")
|
||||
int deduct(@Param("id") long id, @Param("quantity") long quantity);
|
||||
|
||||
@Select("SELECT COALESCE(SUM(quantity),0) FROM ll_return_inventory_carton_item WHERE carton_id=#{cartonId}")
|
||||
long totalQuantity(@Param("cartonId") long cartonId);
|
||||
|
||||
@Select("SELECT COUNT(*) FROM ll_return_inventory_carton_item WHERE carton_id=#{cartonId} AND quantity>0")
|
||||
int skuTypes(@Param("cartonId") long cartonId);
|
||||
}
|
||||
|
||||
+14
-1
@@ -25,7 +25,9 @@ public interface ReturnInventoryCartonMapper extends BaseMapper<ReturnInventoryC
|
||||
List<ReturnInventoryCarton> merchantPage(@Param("customerId") String customerId,
|
||||
@Param("query") com.baiyue.lastleg.returnreceipt.dto.ReturnInventoryRequests.Query query, @Param("offset") long offset);
|
||||
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE customer_id=#{customerId} AND overseas_warehouse_id=#{warehouseId} AND status='AVAILABLE' ORDER BY created_at DESC,id DESC LIMIT 500")
|
||||
@Select("<script>SELECT * FROM ll_return_inventory_carton WHERE customer_id=#{customerId} AND status='AVAILABLE' " +
|
||||
"<if test='warehouseId != null and warehouseId != \"\"'>AND overseas_warehouse_id=#{warehouseId} </if>" +
|
||||
"ORDER BY created_at DESC,id DESC LIMIT 500</script>")
|
||||
List<ReturnInventoryCarton> findAvailable(@Param("customerId") String customerId, @Param("warehouseId") String warehouseId);
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE carton_mark=#{cartonMark} LIMIT 1")
|
||||
ReturnInventoryCarton findMark(@Param("cartonMark") String cartonMark);
|
||||
@@ -36,6 +38,17 @@ public interface ReturnInventoryCartonMapper extends BaseMapper<ReturnInventoryC
|
||||
@Select("SELECT * FROM ll_return_inventory_carton WHERE id=#{id} FOR UPDATE")
|
||||
ReturnInventoryCarton lockId(@Param("id") long id);
|
||||
|
||||
@Update("UPDATE ll_return_inventory_carton SET status='DISCARD_PENDING',updated_at=NOW(3) WHERE id=#{id} AND customer_id=#{customerId} AND status='AVAILABLE'")
|
||||
int markDiscardPending(@Param("id") long id, @Param("customerId") String customerId);
|
||||
|
||||
@Update("UPDATE ll_return_inventory_carton SET status=#{status},total_quantity=#{totalQuantity},sku_types=#{skuTypes},updated_at=NOW(3) WHERE id=#{id} AND customer_id=#{customerId} AND status='DISCARD_PENDING'")
|
||||
int finishDiscard(@Param("id") long id, @Param("customerId") String customerId,
|
||||
@Param("status") String status, @Param("totalQuantity") long totalQuantity,
|
||||
@Param("skuTypes") int skuTypes);
|
||||
|
||||
@Update("UPDATE ll_return_inventory_carton SET status='AVAILABLE',updated_at=NOW(3) WHERE id=#{id} AND customer_id=#{customerId} AND status='DISCARD_PENDING'")
|
||||
int releaseDiscard(@Param("id") long id, @Param("customerId") String customerId);
|
||||
|
||||
@Select("SELECT COALESCE(SUM(ri.notified_package_count),0) FROM ll_relabel_item ri " +
|
||||
"JOIN ll_relabel_application ra ON ra.id=ri.application_id " +
|
||||
"WHERE ri.return_carton_id=#{cartonId} AND ri.sku_code=#{skuCode} " +
|
||||
|
||||
Reference in New Issue
Block a user