优化
This commit is contained in:
+15
@@ -10,6 +10,7 @@ import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.firstleg.dto.InboundOrderDetail;
|
||||
import com.baiyue.firstleg.dto.InboundOrderQuery;
|
||||
import com.baiyue.firstleg.dto.InboundOrderSummary;
|
||||
import com.baiyue.firstleg.dto.InboundCartonLabels;
|
||||
import com.baiyue.firstleg.dto.InboundHoldDtos.CommandRequest;
|
||||
import com.baiyue.firstleg.dto.InboundHoldDtos.Detail;
|
||||
import com.baiyue.firstleg.service.FirstlegScopeGuard;
|
||||
@@ -22,6 +23,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -29,6 +31,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -160,6 +163,18 @@ public class PlatformInboundOrderController {
|
||||
return cartonLabelPrintService.generate(tenantId, inboundId, cartonIndex, requestId);
|
||||
}
|
||||
|
||||
@Operation(summary = "批量生成入仓箱唛 PDF",
|
||||
description = "按所选客户和入库单聚合生成一个 PDF;首次调用冻结各入库单整单箱号。")
|
||||
@PostMapping("/carton-label-pdf")
|
||||
@PreAuthorize("hasAuthority('platform:firstleg:inbound:view')")
|
||||
public ResponseEntity<byte[]> printCartonLabelsBatch(
|
||||
@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@RequestBody @Size(min = 1, max = 200) List<@Valid InboundCartonLabels.PlatformBatchItem> items,
|
||||
@RequestHeader(value = "X-Request-Id", required = false) String requestId) {
|
||||
requirePlatform(user);
|
||||
return cartonLabelPrintService.generateForPlatformInbounds(items, requestId);
|
||||
}
|
||||
|
||||
private static void requirePlatformTenant(AuthenticatedUser user, long tenantId) {
|
||||
FirstlegScopeGuard.platform(user, tenantId);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.baiyue.firstleg.dto;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
|
||||
/** 稳定箱号分配、补打和测量解析契约。 */
|
||||
public final class InboundCartonLabels {
|
||||
private InboundCartonLabels() {
|
||||
@@ -12,6 +14,9 @@ public final class InboundCartonLabels {
|
||||
List<Label> labels) {
|
||||
}
|
||||
|
||||
public record PlatformBatchItem(@Min(1) long tenantId, @Min(1) long inboundId) {
|
||||
}
|
||||
|
||||
public record Label(Long id, Long inboundDetailId, Integer cargoItemNo, String cargoName,
|
||||
Integer detailPackageCount, String boxCode, Integer totalCount,
|
||||
Integer cartonIndex, String boxSpecification, BigDecimal lengthCm,
|
||||
|
||||
@@ -286,21 +286,21 @@ public class FbaPricingRepository {
|
||||
}
|
||||
|
||||
public int markInboundAdjusted(long tenantId, long inboundId, String processStatus, String feeStatus,
|
||||
java.math.BigDecimal selectedWeightKg,
|
||||
java.math.BigDecimal selectedVolumeCbm,
|
||||
String chargeUnit, java.math.BigDecimal chargeableQuantity) {
|
||||
LambdaUpdateWrapper<InboundPricingEntity> update = new LambdaUpdateWrapper<InboundPricingEntity>()
|
||||
.eq(InboundPricingEntity::getTenantId, tenantId)
|
||||
.eq(InboundPricingEntity::getId, inboundId)
|
||||
.eq(InboundPricingEntity::getProcessStatus, processStatus)
|
||||
.set(InboundPricingEntity::getFeeStatus, feeStatus);
|
||||
if ("KG".equals(chargeUnit)) {
|
||||
update.set(InboundPricingEntity::getChargeableWeightKg, chargeableQuantity);
|
||||
} else {
|
||||
update.set(InboundPricingEntity::getChargeableVolumeCbm, chargeableQuantity);
|
||||
}
|
||||
applyChargeableSnapshot(update, selectedWeightKg, selectedVolumeCbm, chargeUnit, chargeableQuantity);
|
||||
return inbounds.update(null, update);
|
||||
}
|
||||
|
||||
public int markInboundCalculated(long tenantId, long inboundId, String processStatus, String chargeMode,
|
||||
java.math.BigDecimal selectedWeightKg,
|
||||
java.math.BigDecimal selectedVolumeCbm,
|
||||
java.math.BigDecimal chargeable) {
|
||||
LambdaUpdateWrapper<InboundPricingEntity> update = new LambdaUpdateWrapper<InboundPricingEntity>()
|
||||
.eq(InboundPricingEntity::getTenantId, tenantId)
|
||||
@@ -312,12 +312,13 @@ public class FbaPricingRepository {
|
||||
.contains(processStatus)) {
|
||||
update.set(InboundPricingEntity::getProcessStatus, "FEE_CONFIRMING");
|
||||
}
|
||||
if ("KG".equals(chargeMode)) update.set(InboundPricingEntity::getChargeableWeightKg, chargeable);
|
||||
else update.set(InboundPricingEntity::getChargeableVolumeCbm, chargeable);
|
||||
applyChargeableSnapshot(update, selectedWeightKg, selectedVolumeCbm, chargeMode, chargeable);
|
||||
return inbounds.update(null, update);
|
||||
}
|
||||
|
||||
public int markInboundContainerFeeRecalculated(long tenantId, long inboundId, String processStatus,
|
||||
java.math.BigDecimal selectedWeightKg,
|
||||
java.math.BigDecimal selectedVolumeCbm,
|
||||
String chargeMode, java.math.BigDecimal chargeable) {
|
||||
LambdaUpdateWrapper<InboundPricingEntity> update = new LambdaUpdateWrapper<InboundPricingEntity>()
|
||||
.eq(InboundPricingEntity::getTenantId, tenantId)
|
||||
@@ -325,11 +326,21 @@ public class FbaPricingRepository {
|
||||
.eq(InboundPricingEntity::getProcessStatus, processStatus)
|
||||
.in(InboundPricingEntity::getFeeStatus, List.of("CALCULATED", "CONFIRMED"))
|
||||
.set(InboundPricingEntity::getFeeStatus, "CALCULATED");
|
||||
if ("KG".equals(chargeMode)) update.set(InboundPricingEntity::getChargeableWeightKg, chargeable);
|
||||
else update.set(InboundPricingEntity::getChargeableVolumeCbm, chargeable);
|
||||
applyChargeableSnapshot(update, selectedWeightKg, selectedVolumeCbm, chargeMode, chargeable);
|
||||
return inbounds.update(null, update);
|
||||
}
|
||||
|
||||
private void applyChargeableSnapshot(LambdaUpdateWrapper<InboundPricingEntity> update,
|
||||
java.math.BigDecimal selectedWeightKg,
|
||||
java.math.BigDecimal selectedVolumeCbm,
|
||||
String chargeUnit, java.math.BigDecimal chargeableQuantity) {
|
||||
// 列表同时展示两项:当前计费单位保存最终计费量,另一项保存本次计价选定值。
|
||||
update.set(InboundPricingEntity::getChargeableWeightKg,
|
||||
"KG".equals(chargeUnit) ? chargeableQuantity : selectedWeightKg)
|
||||
.set(InboundPricingEntity::getChargeableVolumeCbm,
|
||||
"CBM".equals(chargeUnit) ? chargeableQuantity : selectedVolumeCbm);
|
||||
}
|
||||
|
||||
public int confirmFee(long tenantId, long feeId, long operatorId, LocalDateTime now) {
|
||||
return fees.update(null, new LambdaUpdateWrapper<InboundFeeEntity>()
|
||||
.eq(InboundFeeEntity::getTenantId, tenantId).eq(InboundFeeEntity::getId, feeId)
|
||||
|
||||
@@ -166,7 +166,7 @@ public class FbaPricingService {
|
||||
repository.insertItem(baseItem(tenantId, fee, rate, chargeable, subtotal, now));
|
||||
if (additional.signum() > 0) repository.insertItem(additionalItem(tenantId, fee, additional, now));
|
||||
if (repository.markInboundCalculated(tenantId, inboundId, inbound.getProcessStatus(),
|
||||
estimate.chargeUnit(), chargeable) != 1) {
|
||||
estimate.chargeUnit(), weight, volume, chargeable) != 1) {
|
||||
throw conflict("入库单状态已变化,费用试算未保存");
|
||||
}
|
||||
feeDetails.materializeCalculatedFreight(tenantId, inboundId, fee.getId(), operatorId, now);
|
||||
@@ -342,7 +342,8 @@ public class FbaPricingService {
|
||||
recalculated.getSubtotalAmount(), now));
|
||||
if (additional.signum() > 0) repository.insertItem(additionalItem(tenantId, recalculated, additional, now));
|
||||
if (repository.markInboundContainerFeeRecalculated(tenantId, member.inbound().getId(),
|
||||
member.inbound().getProcessStatus(), estimate.chargeUnit(), member.chargeableQuantity()) != 1) {
|
||||
member.inbound().getProcessStatus(), member.current().getActualWeightKg(),
|
||||
member.current().getActualVolumeCbm(), estimate.chargeUnit(), member.chargeableQuantity()) != 1) {
|
||||
throw conflict("柜内入库单状态已变化,不能重算阶梯费用");
|
||||
}
|
||||
feeDetails.materializeCalculatedFreight(tenantId, member.inbound().getId(), recalculated.getId(),
|
||||
@@ -564,7 +565,7 @@ public class FbaPricingService {
|
||||
repository.insertItem(extra);
|
||||
}
|
||||
if (repository.markInboundAdjusted(tenantId, inboundId, inbound.getProcessStatus(), adjusted.getFeeStatus(),
|
||||
adjusted.getChargeUnit(), quantity) != 1) {
|
||||
adjusted.getActualWeightKg(), adjusted.getActualVolumeCbm(), adjusted.getChargeUnit(), quantity) != 1) {
|
||||
throw conflict("入库单状态已变化,费用调整未保存");
|
||||
}
|
||||
if (published) {
|
||||
|
||||
+21
@@ -92,6 +92,27 @@ public class InboundCartonLabelPrintService {
|
||||
return ResponseEntity.status(response.getStatusCode()).headers(headers).body(response.getBody());
|
||||
}
|
||||
|
||||
public ResponseEntity<byte[]> generateForPlatformInbounds(
|
||||
List<InboundCartonLabels.PlatformBatchItem> items, String requestId) {
|
||||
if (items == null || items.isEmpty() || items.size() > 200
|
||||
|| items.stream().anyMatch(item -> item == null || item.tenantId() <= 0 || item.inboundId() <= 0)) {
|
||||
throw new BizException(ResultCode.BAD_REQUEST, "批量打印必须选择1至200个入库单");
|
||||
}
|
||||
List<InboundCartonLabels.PlatformBatchItem> distinctItems = items.stream().distinct().toList();
|
||||
List<InboundCartonLabels.Label> labels = new ArrayList<>();
|
||||
for (InboundCartonLabels.PlatformBatchItem item : distinctItems) {
|
||||
labels.addAll(labelService.list(item.tenantId(), item.inboundId(), null).labels());
|
||||
}
|
||||
if (labels.isEmpty()) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "所选订单没有可生成的箱唛");
|
||||
}
|
||||
ResponseEntity<byte[]> response = generatePdf("carton-labels-" + labels.size() + ".pdf", labels, requestId);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.putAll(response.getHeaders());
|
||||
headers.set("X-Carton-Label-Order-Count", String.valueOf(distinctItems.size()));
|
||||
return ResponseEntity.status(response.getStatusCode()).headers(headers).body(response.getBody());
|
||||
}
|
||||
|
||||
/** 一件代发托盘标签:托盘号、入仓码、SKU箱数和托盘二维码。 */
|
||||
public ResponseEntity<byte[]> generateDropshipPallet(Pallet pallet, String requestId) {
|
||||
if (pallet == null || !StringUtils.hasText(pallet.palletNo()) || pallet.items().isEmpty()) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.repository.InboundCartonLabelRepository;
|
||||
import feign.FeignException;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -113,7 +114,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
throw new BizException(ResultCode.INTERNAL_ERROR, "预入库单补建后未能读取");
|
||||
}
|
||||
return prepared;
|
||||
} catch (FeignException exception) {
|
||||
} catch (FeignException | NoFallbackAvailableException exception) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "订单服务暂不可用,无法补建预入库单");
|
||||
}
|
||||
}
|
||||
@@ -177,7 +178,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
.thenComparing(OrderCargoClient.CargoLabelBinding::cargoId,
|
||||
java.util.Comparator.nullsLast(Long::compareTo)))
|
||||
.toList();
|
||||
} catch (FeignException exception) {
|
||||
} catch (FeignException | NoFallbackAvailableException exception) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "订单服务暂不可用,无法生成唛头");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user