优化
This commit is contained in:
-19
@@ -52,25 +52,6 @@ public class InboundCartonLabelRepository {
|
||||
.eq(InboundCartonLabelEntity::getBoxCode, boxCode));
|
||||
}
|
||||
|
||||
public int nextVersion(long tenantId, long inboundId) {
|
||||
InboundCartonLabelEntity latest = labels.selectOne(new LambdaQueryWrapper<InboundCartonLabelEntity>()
|
||||
.select(InboundCartonLabelEntity::getLabelVersion)
|
||||
.eq(InboundCartonLabelEntity::getTenantId, tenantId)
|
||||
.eq(InboundCartonLabelEntity::getInboundId, inboundId)
|
||||
.orderByDesc(InboundCartonLabelEntity::getLabelVersion)
|
||||
.last("LIMIT 1"));
|
||||
return latest == null || latest.getLabelVersion() == null ? 1 : latest.getLabelVersion() + 1;
|
||||
}
|
||||
|
||||
public void voidActive(long tenantId, long inboundId, java.time.LocalDateTime at) {
|
||||
labels.update(null, new LambdaUpdateWrapper<InboundCartonLabelEntity>()
|
||||
.eq(InboundCartonLabelEntity::getTenantId, tenantId)
|
||||
.eq(InboundCartonLabelEntity::getInboundId, inboundId)
|
||||
.eq(InboundCartonLabelEntity::getBatchStatus, "ACTIVE")
|
||||
.set(InboundCartonLabelEntity::getBatchStatus, "VOID")
|
||||
.set(InboundCartonLabelEntity::getVoidedAt, at));
|
||||
}
|
||||
|
||||
public void initializeLegacyFingerprint(long tenantId, long inboundId, int version, String fingerprint) {
|
||||
labels.update(null, new LambdaUpdateWrapper<InboundCartonLabelEntity>()
|
||||
.eq(InboundCartonLabelEntity::getTenantId, tenantId)
|
||||
|
||||
@@ -59,8 +59,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
return batch(inbound, consistent);
|
||||
}
|
||||
if (existingFingerprint.equals(fingerprint)) return batch(inbound, consistent);
|
||||
repository.voidActive(tenantId, inboundId, LocalDateTime.now());
|
||||
existing.clear();
|
||||
return batch(inbound, consistent);
|
||||
}
|
||||
int total = cargoes.stream().mapToInt(this::requirePackageCount).sum();
|
||||
if (total < 1 || total > MAX_LABELS) {
|
||||
@@ -68,8 +67,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
}
|
||||
repository.updatePackageCount(tenantId, inboundId, total);
|
||||
inbound.setTotalPackageCount(total);
|
||||
int labelVersion = repository.nextVersion(tenantId, inboundId);
|
||||
requirePrintableInboundCode(inbound.getInboundCode(), total, labelVersion);
|
||||
requirePrintableInboundCode(inbound.getInboundCode(), total);
|
||||
|
||||
int cartonIndex = 0;
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
@@ -77,7 +75,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
int detailCount = requirePackageCount(cargo);
|
||||
for (int offset = 0; offset < detailCount; offset++) {
|
||||
cartonIndex++;
|
||||
InboundCartonLabelEntity label = label(inbound, cargo, total, cartonIndex, labelVersion, fingerprint, now);
|
||||
InboundCartonLabelEntity label = label(inbound, cargo, total, cartonIndex, fingerprint, now);
|
||||
repository.insert(label);
|
||||
existing.add(label);
|
||||
}
|
||||
@@ -148,7 +146,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
InboundCartonLabelEntity label = repository.findByBoxCode(tenantId, boxCode.trim());
|
||||
if (label == null) throw new BizException(ResultCode.NOT_FOUND, "箱号不存在");
|
||||
if ("VOID".equals(label.getBatchStatus())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "箱唛版本已作废,请重新打印");
|
||||
throw new BizException(ResultCode.CONFLICT, "箱码已失效,请重新打印");
|
||||
}
|
||||
return label;
|
||||
}
|
||||
@@ -182,11 +180,11 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
return cargo.packageCount();
|
||||
}
|
||||
|
||||
private void requirePrintableInboundCode(String inboundCode, int total, int version) {
|
||||
private void requirePrintableInboundCode(String inboundCode, int total) {
|
||||
if (!StringUtils.hasText(inboundCode) || !inboundCode.matches("[A-Za-z0-9._:-]+")) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "入仓码不能生成可打印二维码");
|
||||
}
|
||||
String longest = inboundCode + "#V" + version + "#" + total + "-" + total;
|
||||
String longest = inboundCode + "#" + total + "-" + total;
|
||||
if (longest.codePointCount(0, longest.length()) > MAX_QR_CODE_POINTS) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED, "入仓码和箱号组合超过二维码长度限制");
|
||||
}
|
||||
@@ -194,7 +192,7 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
|
||||
private InboundCartonLabelEntity label(InboundOrderEntity inbound,
|
||||
OrderCargoClient.CargoLabelBinding cargo,
|
||||
int total, int index, int labelVersion, String fingerprint,
|
||||
int total, int index, String fingerprint,
|
||||
LocalDateTime now) {
|
||||
InboundCartonLabelEntity label = new InboundCartonLabelEntity();
|
||||
label.setId(IdWorker.getId());
|
||||
@@ -206,10 +204,10 @@ public class InboundCartonLabelService implements CartonLabelBindingResolver {
|
||||
label.setCargoName(cargo.cargoName());
|
||||
label.setDetailPackageCount(cargo.packageCount());
|
||||
label.setInboundCode(inbound.getInboundCode());
|
||||
label.setBoxCode(inbound.getInboundCode() + "#V" + labelVersion + "#" + total + "-" + index);
|
||||
label.setBoxCode(inbound.getInboundCode() + "#" + total + "-" + index);
|
||||
label.setTotalCartonCount(total);
|
||||
label.setCartonIndex(index);
|
||||
label.setLabelVersion(labelVersion);
|
||||
label.setLabelVersion(1);
|
||||
label.setBatchStatus("ACTIVE");
|
||||
label.setCargoFingerprint(fingerprint);
|
||||
label.setLengthCm(cargo.lengthCm());
|
||||
|
||||
@@ -12,7 +12,7 @@ BEGIN
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL phase2_carton_label_add_column('label_version', 'INT UNSIGNED NOT NULL DEFAULT 1 COMMENT ''箱唛批次版本,从1递增'' AFTER carton_index');
|
||||
CALL phase2_carton_label_add_column('label_version', 'INT UNSIGNED NOT NULL DEFAULT 1 COMMENT ''内部兼容批次字段,固定为1且不进入箱码'' AFTER carton_index');
|
||||
CALL phase2_carton_label_add_column('batch_status', 'VARCHAR(16) NOT NULL DEFAULT ''ACTIVE'' COMMENT ''批次状态:ACTIVE有效、VOID已作废'' AFTER label_version');
|
||||
CALL phase2_carton_label_add_column('cargo_fingerprint', 'CHAR(64) NULL COMMENT ''影响标签字段的SHA-256指纹'' AFTER batch_status');
|
||||
CALL phase2_carton_label_add_column('voided_at', 'DATETIME(3) NULL COMMENT ''批次作废时间'' AFTER cargo_fingerprint');
|
||||
@@ -23,9 +23,12 @@ UPDATE fl_inbound_carton_label
|
||||
batch_status = 'ACTIVE'
|
||||
WHERE label_version IS NULL OR batch_status IS NULL;
|
||||
|
||||
DELETE FROM fl_inbound_carton_label WHERE batch_status = 'VOID';
|
||||
|
||||
UPDATE fl_inbound_carton_label
|
||||
SET box_code = CONCAT(inbound_code, '#V', label_version, '#', total_carton_count, '-', carton_index)
|
||||
WHERE box_code NOT LIKE CONCAT(inbound_code, '#V%#%');
|
||||
SET label_version = 1,
|
||||
box_code = CONCAT(inbound_code, '#', total_carton_count, '-', carton_index)
|
||||
WHERE batch_status = 'ACTIVE';
|
||||
|
||||
SET @has_old_index := (SELECT COUNT(*) FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_carton_label'
|
||||
|
||||
@@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
|
||||
box_code VARCHAR(80) NOT NULL COMMENT '固定二维码内容:入仓码#总箱数-箱下标',
|
||||
total_carton_count INT UNSIGNED NOT NULL COMMENT '首次分配时整单总箱数',
|
||||
carton_index INT UNSIGNED NOT NULL COMMENT '整单从1开始的稳定箱下标',
|
||||
label_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '箱唛批次版本,从1递增',
|
||||
label_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '内部兼容批次字段,固定为1且不进入箱码',
|
||||
batch_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '批次状态:ACTIVE有效、VOID已作废',
|
||||
cargo_fingerprint CHAR(64) NULL COMMENT '影响标签字段的SHA-256指纹',
|
||||
voided_at DATETIME(3) NULL COMMENT '批次作废时间',
|
||||
|
||||
@@ -153,7 +153,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
|
||||
box_code VARCHAR(80) NOT NULL COMMENT '固定二维码内容:入仓码#总箱数-箱下标',
|
||||
total_carton_count INT UNSIGNED NOT NULL COMMENT '首次分配时整单总箱数',
|
||||
carton_index INT UNSIGNED NOT NULL COMMENT '整单从1开始的稳定箱下标',
|
||||
label_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '箱唛批次版本,从1递增',
|
||||
label_version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '内部兼容批次字段,固定为1且不进入箱码',
|
||||
batch_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '批次状态:ACTIVE有效、VOID已作废',
|
||||
cargo_fingerprint CHAR(64) NULL COMMENT '影响标签字段的SHA-256指纹',
|
||||
voided_at DATETIME(3) NULL COMMENT '批次作废时间',
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class InboundCartonLabelSqlContractTest {
|
||||
.contains("uk_carton_label_box_code")
|
||||
.contains("uk_carton_label_index")
|
||||
.contains("稳定箱号映射表未创建")
|
||||
.contains("箱唛版本化字段未完整创建")
|
||||
.contains("稳定箱码映射兼容字段未完整创建")
|
||||
.contains("箱唛有效批次索引未完整创建");
|
||||
}
|
||||
|
||||
|
||||
+22
-29
@@ -50,7 +50,6 @@ class InboundCartonLabelServiceTest {
|
||||
var first = cargo(80001L, 1, 3, "60", "40", "30");
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(second, first)));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(1);
|
||||
List<InboundCartonLabelEntity> inserted = new ArrayList<>();
|
||||
org.mockito.Mockito.doAnswer(invocation -> {
|
||||
inserted.add(invocation.getArgument(0));
|
||||
@@ -61,8 +60,8 @@ class InboundCartonLabelServiceTest {
|
||||
|
||||
assertThat(batch.totalCount()).isEqualTo(5);
|
||||
assertThat(batch.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V1#5-1", "PCHK2608040174#V1#5-2", "PCHK2608040174#V1#5-3",
|
||||
"PCHK2608040174#V1#5-4", "PCHK2608040174#V1#5-5");
|
||||
.containsExactly("PCHK2608040174#5-1", "PCHK2608040174#5-2", "PCHK2608040174#5-3",
|
||||
"PCHK2608040174#5-4", "PCHK2608040174#5-5");
|
||||
assertThat(batch.labels()).extracting(label -> label.inboundDetailId())
|
||||
.containsExactly(80001L, 80001L, 80001L, 80002L, 80002L);
|
||||
assertThat(batch.labels().get(0).boxSpecification()).isEqualTo("60x40x30cm");
|
||||
@@ -73,7 +72,7 @@ class InboundCartonLabelServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedAndPartialPrintsReadCurrentVersionWithoutReallocation() {
|
||||
void repeatedAndPartialPrintsReadFrozenMappingWithoutReallocation() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setTotalPackageCount(5);
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 5);
|
||||
@@ -92,7 +91,7 @@ class InboundCartonLabelServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void changedCargoCreatesNewVersion() {
|
||||
void changedCargoKeepsTheFirstFrozenBoxCodes() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setTotalPackageCount(4);
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
@@ -101,13 +100,11 @@ class InboundCartonLabelServiceTest {
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(2);
|
||||
org.mockito.Mockito.doAnswer(invocation -> null).when(repository).insert(any());
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V2#2-1", "PCHK2608040174#V2#2-2");
|
||||
verify(repository).voidActive(org.mockito.ArgumentMatchers.eq(10001L),
|
||||
org.mockito.ArgumentMatchers.eq(70001L), any());
|
||||
.containsExactly("PCHK2608040174#5-1", "PCHK2608040174#5-2", "PCHK2608040174#5-3",
|
||||
"PCHK2608040174#5-4", "PCHK2608040174#5-5");
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,14 +116,13 @@ class InboundCartonLabelServiceTest {
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(new ArrayList<>());
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(1);
|
||||
org.mockito.Mockito.doAnswer(invocation -> null).when(repository).insert(any());
|
||||
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
|
||||
assertThat(result.totalCount()).isEqualTo(2);
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V1#2-1", "PCHK2608040174#V1#2-2");
|
||||
.containsExactly("PCHK2608040174#2-1", "PCHK2608040174#2-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -143,7 +139,7 @@ class InboundCartonLabelServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void changedCargoAfterLoadingVoidsCurrentBatchAndCreatesNextVersion() {
|
||||
void changedCargoAfterLoadingKeepsTheFirstFrozenBoxCodes() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setProcessStatus("LOADING");
|
||||
List<InboundCartonLabelEntity> existing = labels(inbound, 1);
|
||||
@@ -155,22 +151,19 @@ class InboundCartonLabelServiceTest {
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(existing);
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(cargo(80001L, 1, 2, "60", "40", "30"))));
|
||||
when(repository.nextVersion(10001L, 70001L)).thenReturn(2);
|
||||
|
||||
var result = service.getOrCreate(10001L, 70001L);
|
||||
|
||||
assertThat(result.labels()).extracting(label -> label.boxCode())
|
||||
.containsExactly("PCHK2608040174#V2#2-1", "PCHK2608040174#V2#2-2");
|
||||
verify(repository).voidActive(org.mockito.ArgumentMatchers.eq(10001L),
|
||||
org.mockito.ArgumentMatchers.eq(70001L), any());
|
||||
.containsExactly("PCHK2608040174#1-1");
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesBoxCodeInsideCustomerBoundary() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#1-1")).thenReturn(label);
|
||||
|
||||
var resolved = service.resolveByBoxCode(10001L, " PCHK2608040174#V1#1-1 ");
|
||||
var resolved = service.resolveByBoxCode(10001L, " PCHK2608040174#1-1 ");
|
||||
|
||||
assertThat(resolved.inboundId()).isEqualTo(70001L);
|
||||
assertThat(resolved.inboundDetailId()).isEqualTo(80001L);
|
||||
@@ -178,30 +171,30 @@ class InboundCartonLabelServiceTest {
|
||||
assertThat(resolved.cartonIndex()).isEqualTo(1);
|
||||
assertThat(resolved.totalCartons()).isEqualTo(1);
|
||||
assertThat(resolved.boxSpecification()).isEqualTo("60x40x30cm");
|
||||
verify(repository).findByBoxCode(10001L, "PCHK2608040174#V1#1-1");
|
||||
verify(repository).findByBoxCode(10001L, "PCHK2608040174#1-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void exposesDetailedResolutionForFirstlegConsumers() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#1-1")).thenReturn(label);
|
||||
|
||||
var resolved = service.resolveDetailsByBoxCode(10001L, "PCHK2608040174#V1#1-1");
|
||||
var resolved = service.resolveDetailsByBoxCode(10001L, "PCHK2608040174#1-1");
|
||||
|
||||
assertThat(resolved.orderId()).isEqualTo(60001L);
|
||||
assertThat(resolved.boxCode()).isEqualTo("PCHK2608040174#V1#1-1");
|
||||
assertThat(resolved.boxCode()).isEqualTo("PCHK2608040174#1-1");
|
||||
assertThat(resolved.cargoItemNo()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsVoidedLabelVersionDuringScanResolution() {
|
||||
void rejectsInactiveBoxCodeDuringScanResolution() {
|
||||
InboundCartonLabelEntity label = labels(inbound(), 1).get(0);
|
||||
label.setBatchStatus("VOID");
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#V1#1-1")).thenReturn(label);
|
||||
when(repository.findByBoxCode(10001L, "PCHK2608040174#1-1")).thenReturn(label);
|
||||
|
||||
assertThatThrownBy(() -> service.resolveByBoxCode(10001L, "PCHK2608040174#V1#1-1"))
|
||||
assertThatThrownBy(() -> service.resolveByBoxCode(10001L, "PCHK2608040174#1-1"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessage("箱唛版本已作废,请重新打印");
|
||||
.hasMessage("箱码已失效,请重新打印");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -284,7 +277,7 @@ class InboundCartonLabelServiceTest {
|
||||
label.setCargoName("货物1");
|
||||
label.setDetailPackageCount(total);
|
||||
label.setInboundCode(inbound.getInboundCode());
|
||||
label.setBoxCode(inbound.getInboundCode() + "#V1#" + total + "-" + index);
|
||||
label.setBoxCode(inbound.getInboundCode() + "#" + total + "-" + index);
|
||||
label.setTotalCartonCount(total);
|
||||
label.setCartonIndex(index);
|
||||
label.setLabelVersion(1);
|
||||
|
||||
Reference in New Issue
Block a user