fix: 按物理箱贯通一件代发履约箱数
This commit is contained in:
+16
-8
@@ -17,8 +17,9 @@ public interface CargoDiscardInventoryMapper {
|
||||
"COUNT(c.id) available_packages FROM ll_order o " +
|
||||
"JOIN ll_dropship_order_profile p ON p.customer_id=o.customer_id AND p.order_id=o.id " +
|
||||
"JOIN ll_dropship_sku_inventory s ON s.customer_id=o.customer_id AND s.order_id=o.id AND s.profile_id=p.id " +
|
||||
"LEFT JOIN ll_dropship_carton c ON c.customer_id=o.customer_id AND c.order_id=o.id " +
|
||||
"AND c.profile_id=p.id AND c.sku_code=s.sku_code AND c.status='AVAILABLE' " +
|
||||
"JOIN ll_dropship_carton c ON c.customer_id=o.customer_id AND c.order_id=o.id " +
|
||||
"AND c.profile_id=p.id AND c.status='AVAILABLE' " +
|
||||
"JOIN ll_dropship_carton_sku cs ON cs.customer_id=c.customer_id AND cs.carton_id=c.id AND cs.sku_code=s.sku_code " +
|
||||
"WHERE o.customer_id=#{customerId} AND o.order_type='ONE_CLICK_DROPSHIP' " +
|
||||
"<if test='inboundCode != null and inboundCode != \"\"'>AND o.inbound_code LIKE CONCAT('%',#{inboundCode},'%') </if>" +
|
||||
"GROUP BY o.id,o.inbound_code,o.inbound_order_no,o.overseas_warehouse_id,o.overseas_warehouse_name,o.created_at," +
|
||||
@@ -26,21 +27,28 @@ public interface CargoDiscardInventoryMapper {
|
||||
List<CargoDiscardCandidateRow> candidates(@Param("customerId") String customerId,
|
||||
@Param("inboundCode") String inboundCode);
|
||||
|
||||
@Select("SELECT COUNT(*) FROM ll_dropship_carton WHERE customer_id=#{customerId} AND order_id=#{orderId} " +
|
||||
"AND sku_code=#{skuCode} AND status='AVAILABLE'")
|
||||
@Select("SELECT COUNT(*) FROM ll_dropship_carton c WHERE c.customer_id=#{customerId} AND c.order_id=#{orderId} " +
|
||||
"AND c.status='AVAILABLE' AND EXISTS (SELECT 1 FROM ll_dropship_carton_sku cs " +
|
||||
"WHERE cs.customer_id=c.customer_id AND cs.carton_id=c.id AND cs.sku_code=#{skuCode})")
|
||||
long countAvailable(@Param("customerId") String customerId, @Param("orderId") Long orderId,
|
||||
@Param("skuCode") String skuCode);
|
||||
|
||||
@Select("SELECT COUNT(*) FROM ll_dropship_carton WHERE customer_id=#{customerId} AND order_id=#{orderId} " +
|
||||
"AND profile_id=#{profileId} AND sku_code=#{skuCode} AND status='AVAILABLE'")
|
||||
@Select("SELECT COUNT(*) FROM ll_dropship_carton c WHERE c.customer_id=#{customerId} AND c.order_id=#{orderId} " +
|
||||
"AND c.profile_id=#{profileId} AND c.status='AVAILABLE' AND EXISTS (SELECT 1 FROM ll_dropship_carton_sku cs " +
|
||||
"WHERE cs.customer_id=c.customer_id AND cs.carton_id=c.id AND cs.sku_code=#{skuCode})")
|
||||
long countAvailableProfile(@Param("customerId") String customerId, @Param("orderId") Long orderId,
|
||||
@Param("profileId") Long profileId, @Param("skuCode") String skuCode);
|
||||
|
||||
@Select("SELECT * FROM ll_dropship_carton WHERE customer_id=#{customerId} AND order_id=#{orderId} " +
|
||||
"AND sku_code=#{skuCode} AND status='AVAILABLE' ORDER BY profile_id,carton_sequence,id LIMIT #{limit} FOR UPDATE")
|
||||
@Select("SELECT c.* FROM ll_dropship_carton c WHERE c.customer_id=#{customerId} AND c.order_id=#{orderId} " +
|
||||
"AND c.status='AVAILABLE' AND EXISTS (SELECT 1 FROM ll_dropship_carton_sku cs " +
|
||||
"WHERE cs.customer_id=c.customer_id AND cs.carton_id=c.id AND cs.sku_code=#{skuCode}) " +
|
||||
"ORDER BY c.profile_id,c.carton_sequence,c.id LIMIT #{limit} FOR UPDATE")
|
||||
List<DropshipCarton> lockAvailable(@Param("customerId") String customerId, @Param("orderId") Long orderId,
|
||||
@Param("skuCode") String skuCode, @Param("limit") int limit);
|
||||
|
||||
@Select("SELECT COUNT(*) FROM ll_dropship_carton WHERE customer_id=#{customerId} AND order_id=#{orderId} AND status='AVAILABLE'")
|
||||
long countAvailableOrder(@Param("customerId") String customerId, @Param("orderId") Long orderId);
|
||||
|
||||
@Update("UPDATE ll_dropship_carton SET status=#{toStatus},version=version+1,updated_at=NOW(3) " +
|
||||
"WHERE customer_id=#{customerId} AND id=#{cartonId} AND status=#{fromStatus}")
|
||||
int changeCartonStatus(@Param("customerId") String customerId, @Param("cartonId") Long cartonId,
|
||||
|
||||
+30
-2
@@ -7,9 +7,12 @@ import com.baiyue.lastleg.discard.entity.CargoDiscardItem;
|
||||
import com.baiyue.lastleg.discard.mapper.CargoDiscardInventoryMapper;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipCartonLedger;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipCartonSku;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipSkuInventory;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipCartonLedgerMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipCartonSkuMapper;
|
||||
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 jakarta.annotation.Resource;
|
||||
@@ -21,6 +24,7 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Final inventory mutation for a warehouse-approved cargo discard. */
|
||||
@@ -28,6 +32,8 @@ import java.util.Map;
|
||||
public class CargoDiscardInventoryAdjustmentService {
|
||||
@Resource private CargoDiscardInventoryMapper inventory;
|
||||
@Resource private DropshipCartonLedgerMapper cartonLedgers;
|
||||
@Resource private DropshipCartonSkuMapper cartonSkus;
|
||||
@Resource private DropshipSkuInventoryMapper skuInventories;
|
||||
@Resource private DropshipOrderProfileMapper profiles;
|
||||
@Resource private InventoryPositionMapper positions;
|
||||
@Resource private InventoryBalanceMapper balances;
|
||||
@@ -40,8 +46,25 @@ public class CargoDiscardInventoryAdjustmentService {
|
||||
DropshipSkuInventory sku = inventory.lockSkuInventory(customerId, item.getSkuInventoryId());
|
||||
if (sku == null) throw conflict("托盘 SKU 库存不存在: " + item.getSkuCode());
|
||||
long before = value(sku.getPackageCount());
|
||||
if (before < actualPackages || inventory.deductSkuInventory(customerId, sku.getId(), actualPackages) != 1) {
|
||||
throw conflict("托盘 SKU 库存不足: " + item.getSkuCode());
|
||||
Map<String, SkuDiscard> discardedSkus = new LinkedHashMap<>();
|
||||
for (int index = 0; index < actualPackages; index++) {
|
||||
CargoDiscardCarton link = links.get(index);
|
||||
DropshipCarton carton = inventory.lockCarton(customerId, link.getCartonId());
|
||||
if (carton == null) throw conflict("托盘预留箱不存在");
|
||||
List<DropshipCartonSku> facts = cartonSkus.listCarton(customerId, carton.getId());
|
||||
if (facts.isEmpty()) {
|
||||
discardedSkus.merge(carton.getSkuCode(), new SkuDiscard(1, value(carton.getProductQuantity())), SkuDiscard::add);
|
||||
} else {
|
||||
for (DropshipCartonSku fact : facts) {
|
||||
discardedSkus.merge(fact.getSkuCode(), new SkuDiscard(1, value(fact.getProductQuantity())), SkuDiscard::add);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, SkuDiscard> discarded : discardedSkus.entrySet()) {
|
||||
if (skuInventories.deduct(customerId, item.getProfileId(), discarded.getKey(),
|
||||
discarded.getValue().packages(), discarded.getValue().quantity()) != 1) {
|
||||
throw conflict("托盘 SKU 库存不足: " + discarded.getKey());
|
||||
}
|
||||
}
|
||||
var profile = profiles.selectById(item.getProfileId());
|
||||
var position = profile == null || profile.getInventoryPositionId() == null ? null
|
||||
@@ -120,6 +143,11 @@ public class CargoDiscardInventoryAdjustmentService {
|
||||
}
|
||||
|
||||
private static long value(Long value) { return value == null ? 0L : value; }
|
||||
private record SkuDiscard(long packages, long quantity) {
|
||||
private SkuDiscard add(SkuDiscard other) {
|
||||
return new SkuDiscard(Math.addExact(packages, other.packages), Math.addExact(quantity, other.quantity));
|
||||
}
|
||||
}
|
||||
private static String remarkSuffix(String value) {
|
||||
return value == null || value.isBlank() ? "" : "; " + value.trim();
|
||||
}
|
||||
|
||||
+5
-4
@@ -75,7 +75,9 @@ public class CargoDiscardService {
|
||||
CandidateAccumulator value = grouped.computeIfAbsent(row.getOrderId(), ignored -> new CandidateAccumulator(row));
|
||||
value.add(row);
|
||||
}
|
||||
return grouped.values().stream().map(CandidateAccumulator::response).toList();
|
||||
return grouped.values().stream()
|
||||
.map(value -> value.response(inventory.countAvailableOrder(customerId, value.first.getOrderId())))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -396,12 +398,11 @@ public class CargoDiscardService {
|
||||
skus.computeIfAbsent(row.getSkuCode(), ignored -> new CandidateSkuAccumulator(row.getSkuCode(), row.getProductName()))
|
||||
.packages += row.getAvailablePackages() == null ? 0 : row.getAvailablePackages();
|
||||
}
|
||||
private CargoDiscardResponses.Candidate response() {
|
||||
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();
|
||||
long packages = skuViews.stream().mapToLong(CargoDiscardResponses.CandidateSku::availablePackages).sum();
|
||||
return new CargoDiscardResponses.Candidate(first.getOrderId(), first.getInboundCode(), first.getInboundOrderNo(),
|
||||
first.getOverseasWarehouseId(), first.getOverseasWarehouseName(), first.getCreatedAt(), packages, skuViews);
|
||||
first.getOverseasWarehouseId(), first.getOverseasWarehouseName(), first.getCreatedAt(), physicalPackages, skuViews);
|
||||
}
|
||||
}
|
||||
private static final class CandidateSkuAccumulator {
|
||||
|
||||
Reference in New Issue
Block a user