feat: finalize dropship pallet print documents

This commit is contained in:
2026-09-14 17:52:01 +08:00
parent b3d74c5441
commit 3910b8fcce
15 changed files with 34 additions and 50 deletions
@@ -55,7 +55,6 @@ public interface PrintPdfClient {
String downloadFileName, List<DropshipPalletDocument> documents) {}
record DropshipPalletDocument(String palletNo, String destinationWarehouse,
int palletSequence, int totalPallets,
String barcodeContent,
List<DropshipPalletInboundRow> inboundRows,
List<DropshipPalletSkuRow> skuRows) {}
@@ -150,6 +150,17 @@ public class PlatformDropshipPalletizationController {
return ApiResponse.success(service.inboundPallets(accountId, inboundId));
}
@GetMapping("/inbound-orders/{inboundId}/pallets/print")
@PreAuthorize("hasAuthority('platform:firstleg:inbound:list')")
public ResponseEntity<byte[]> printInboundPallets(@AuthenticationPrincipal AuthenticatedUser user,
@PathVariable @Positive long inboundId,
@RequestParam @Positive long accountId,
@RequestHeader(value = "X-Request-Id", required = false) String requestId) {
FirstlegScopeGuard.platform(user, accountId);
return printService.generateDropshipPallets(
service.inboundPallets(accountId, inboundId), service.inboundCode(accountId, inboundId), requestId);
}
@GetMapping("/inbound-orders/{inboundId}/pallets/{palletId}/print")
@PreAuthorize("hasAuthority('platform:firstleg:inbound:list')")
public ResponseEntity<byte[]> printPallet(@AuthenticationPrincipal AuthenticatedUser user,
@@ -254,15 +254,6 @@ public interface DropshipPalletizationMapper {
""")
List<PrintSkuRow> printSkuRows(@Param("palletId") long palletId);
@Select("""
SELECT (SELECT COUNT(*) FROM fl_dropship_pallet listed
WHERE listed.task_id=target.task_id AND listed.id<=target.id) sequence_no,
(SELECT COUNT(*) FROM fl_dropship_pallet listed
WHERE listed.task_id=target.task_id) total
FROM fl_dropship_pallet target
WHERE target.id=#{palletId}
""")
PalletPosition palletPosition(@Param("palletId") long palletId);
@Select("""
SELECT p.id pallet_id,p.pallet_no,'SEALED_PALLET' unit_type,TRUE indivisible,COUNT(DISTINCT c.id) carton_count,
(SELECT COUNT(DISTINCT sku.sku_code) FROM fl_dropship_pallet_carton pc
@@ -306,6 +297,5 @@ public interface DropshipPalletizationMapper {
record PalletMetrics(BigDecimal weightKg,BigDecimal volumeCbm) {}
@Getter @Setter class PrintInboundRow { private Long tenantId,inboundId; private String inboundCode,destinationWarehouse; private Integer cartonCount,itemQuantity; }
@Getter @Setter class PrintSkuRow { private String skuCode; private Integer cartonCount,itemQuantity,minUnitsPerCarton,maxUnitsPerCarton; }
record PalletPosition(int sequenceNo,int total) {}
@Getter @Setter class PalletLine { private Long palletId,tenantId,accountId,inboundId,orderId,warehouseId,destinationWarehouseId,inboundDetailId; private String palletNo,palletStatus,orderNo,inboundCode,channelCode,channelName,destinationWarehouseCode,destinationWarehouseName,customerName,skuCode,cargoName; private Integer cartonCount,actualSkuQuantity; private BigDecimal unitGrossWeightKg,unitNetWeightKg,unitVolumeCbm; }
}
@@ -172,12 +172,8 @@ public class InboundCartonLabelPrintService {
.stream().map(row -> new PrintPdfClient.DropshipPalletSkuRow(
row.getSkuCode(), number(row.getCartonCount()), number(row.getItemQuantity()),
unitsPerCarton(row))).toList();
DropshipPalletizationMapper.PalletPosition position =
palletizationMapper.palletPosition(pallet.palletId());
return new PrintPdfClient.DropshipPalletDocument(
pallet.palletNo(), destinationWarehouse,
position == null ? 1 : position.sequenceNo(), position == null ? 1 : position.total(),
pallet.palletNo(), inboundRows, skuRows);
pallet.palletNo(), destinationWarehouse, pallet.palletNo(), inboundRows, skuRows);
}
private String unitsPerCarton(DropshipPalletizationMapper.PrintSkuRow row) {
@@ -68,7 +68,7 @@ paths:
/api/platform/v1/first-leg/pda-dropship/tasks/{taskId}/pallets/{palletId}/print:
get:
summary: PDA 获取预生成托盘码的 A4 托盘信息单
description: 测量审核通过并生成托盘码后即可获取;每个托盘固定一页 A4,包含托盘号及其 Code 128 一维码、目的仓、托盘序号、入仓码/客户昵称/箱数/件数汇总以及 SKU/箱数/件数/每箱件数汇总,不展示作业状态、重量或体积。空托显示暂无已归托 SKU。仅当前仓库、当前操作员可访问。
description: 测量审核通过并生成托盘码后即可获取;每个托盘固定一页 A4,包含托盘号及其 Code 128 一维码、目的仓、入仓码/客户昵称/箱数/件数汇总以及 SKU/箱数/件数/每箱件数汇总,不展示托盘序号、作业状态、重量或体积。空托显示暂无已归托 SKU。仅当前仓库、当前操作员可访问。
x-required-authority: platform:firstleg:pda:view
parameters:
- {$ref: '#/components/parameters/TaskId'}
@@ -89,6 +89,13 @@ paths:
summary: Admin 查询入仓单权威托盘结果
x-required-authority: platform:firstleg:inbound:list
responses: {'200': {description: OK}}
/api/platform/v1/first-leg/pda-dropship/inbound-orders/{inboundId}/pallets/print:
get:
summary: Admin 合并打印入仓单关联的全部一件代发托盘
description: 测量审核预生成托盘码后即可打印;每托一页,空托也保留托盘码和当前入仓单信息,供电脑连接打印机后在 PDA 作业前贴码。
x-required-authority: platform:firstleg:inbound:list
responses:
'200': {description: 多页 A4 托盘信息单 PDF, content: {application/pdf: {schema: {type: string, format: binary}}}}
/api/platform/v1/first-leg/pda-dropship/inbound-orders/{inboundId}/pallets/{palletId}/print:
get:
summary: 获取包含托盘码、目的仓、入仓码和 SKU 汇总的 A4 托盘信息单
@@ -16,7 +16,8 @@ class DropshipPalletizationSqlContractTest {
void inboundPalletReadAndPrintUseTheRegisteredPlatformInboundPermission() throws Exception {
var controller = com.baiyue.firstleg.controller.PlatformDropshipPalletizationController.class;
for (var method : controller.getDeclaredMethods()) {
if (method.getName().equals("inboundPallets") || method.getName().equals("printPallet")) {
if (method.getName().equals("inboundPallets") || method.getName().equals("printPallet")
|| method.getName().equals("printInboundPallets")) {
assertThat(method.getAnnotation(org.springframework.security.access.prepost.PreAuthorize.class).value())
.isEqualTo("hasAuthority('platform:firstleg:inbound:list')");
}
@@ -24,6 +25,7 @@ class DropshipPalletizationSqlContractTest {
String api = new ClassPathResource("openapi/dropship-palletization-v1.yaml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(api).contains("x-required-authority: platform:firstleg:inbound:list")
.contains("/api/platform/v1/first-leg/pda-dropship/inbound-orders/{inboundId}/pallets/print:")
.doesNotContain("x-required-authority: firstleg:inbound:list");
}
@@ -45,7 +45,7 @@ class InboundCartonLabelPrintServiceTest {
@Test
void dropshipPalletLabelIsAvailableBeforeSeal() {
Pallet open = dropshipPallet("OPEN");
stubPalletFacts(90001L, 1, 2);
stubPalletFacts(90001L);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
when(print.generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.anyString(),
@@ -66,8 +66,6 @@ class InboundCartonLabelPrintServiceTest {
assertThat(request.getValue().documents()).singleElement().satisfies(document -> {
assertThat(document.palletNo()).isEqualTo("DP-260911-0001");
assertThat(document.destinationWarehouse()).isEqualTo("NJDF");
assertThat(document.palletSequence()).isEqualTo(1);
assertThat(document.totalPallets()).isEqualTo(2);
assertThat(document.inboundRows()).singleElement().satisfies(row -> {
assertThat(row.inboundCode()).isEqualTo("PCHK2608040174");
assertThat(row.customerNickname()).isEqualTo("小虫科技");
@@ -88,8 +86,8 @@ class InboundCartonLabelPrintServiceTest {
Pallet first = dropshipPallet("OPEN");
Pallet second = new Pallet(90002L, "DP-260911-0002", "OPEN", 0, 0, 0,
BigDecimal.ZERO, BigDecimal.ZERO, 1, List.of(), List.of(), null);
stubPalletFacts(90001L, 1, 2);
stubPalletFacts(90002L, 2, 2);
stubPalletFacts(90001L);
stubPalletFacts(90002L);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
when(print.generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.anyString(),
@@ -242,7 +240,7 @@ class InboundCartonLabelPrintServiceTest {
BigDecimal.ONE, BigDecimal.ONE, 1, List.of(item), List.of(), null);
}
private void stubPalletFacts(long palletId, int sequence, int total) {
private void stubPalletFacts(long palletId) {
DropshipPalletizationMapper.PrintInboundRow inbound =
new DropshipPalletizationMapper.PrintInboundRow();
inbound.setTenantId(10001L);
@@ -260,8 +258,6 @@ class InboundCartonLabelPrintServiceTest {
sku.setMaxUnitsPerCarton(19);
when(palletization.printSkuRows(palletId))
.thenReturn(palletId == 90001L ? List.of(sku) : List.of());
when(palletization.palletPosition(palletId))
.thenReturn(new DropshipPalletizationMapper.PalletPosition(sequence, total));
when(customerSnapshots.customerNickname(10001L)).thenReturn("小虫科技");
}
}