发布当前测试版本至临时灰度环境 #19

Merged
admin merged 177 commits from test into main 2026-10-07 11:04:53 +08:00
2 changed files with 155 additions and 0 deletions
Showing only changes of commit 1a7e4800f5 - Show all commits
@@ -11,12 +11,24 @@ import java.util.List;
@Mapper
public interface LoadingPalletLabelMapper {
// Remainder slices inherit bound slots, not new weight records. Their slot/weight
// identity survives release or transfer; preserved empty slots are not pallets.
@Select("""
SELECT p.id AS plan_id,p.plan_no,p.plan_status,b.container_no,b.cabinet_no,b.warehouse_id,
i.id AS item_id,i.account_id,i.inbound_id,i.inbound_code,i.destination_warehouse_id,
i.destination_warehouse_code,i.destination_warehouse_name,
COALESCE(NULLIF(i.pallet_count,0),
CEIL(COALESCE(NULLIF(o.pallet_count,0),
NULLIF((SELECT COUNT(DISTINCT weight.id)
FROM fl_inbound_pallet_allocation allocation
JOIN fl_inbound_weight_result weight
ON weight.id=allocation.weight_result_id AND weight.tenant_id=allocation.tenant_id
AND weight.deleted=0 AND weight.recognition_status='CONFIRMED'
AND (weight.inbound_id=o.id OR weight.inbound_id=o.root_inbound_id)
WHERE allocation.tenant_id=i.account_id AND allocation.inbound_id=i.inbound_id
AND allocation.block_id>0 AND allocation.slot_no>0 AND allocation.reservation_id>0
AND allocation.allocated_package_count>0
AND allocation.allocation_status IN ('CONFIRMED','TRANSFERRED','RELEASED')),0),
(SELECT COUNT(*) FROM fl_inbound_weight_result weight
WHERE weight.tenant_id=i.account_id AND weight.inbound_id=i.inbound_id
AND weight.deleted=0 AND weight.recognition_status='CONFIRMED'),0)
@@ -0,0 +1,143 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
/** Execute the production MyBatis query, including inherited weight/slot joins. */
class LoadingPalletLabelMapperTest {
private SqlSession session;
@BeforeEach
void schema() throws Exception {
var dataSource = new UnpooledDataSource("org.h2.Driver",
"jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL", "sa", "");
var configuration = new Configuration(new Environment("test", new JdbcTransactionFactory(), dataSource));
configuration.setMapUnderscoreToCamelCase(true);
configuration.addMapper(LoadingPalletLabelMapper.class);
session = new SqlSessionFactoryBuilder().build(configuration).openSession();
execute("CREATE TABLE fl_loading_plan(id BIGINT PRIMARY KEY,plan_no VARCHAR,plan_status VARCHAR,container_booking_id BIGINT)");
execute("CREATE TABLE fl_container_booking(id BIGINT PRIMARY KEY,container_no VARCHAR,cabinet_no VARCHAR,warehouse_id BIGINT,record_status VARCHAR)");
// MySQL '/' preserves fractional results for integer operands; H2's integer
// division truncates. Decimal scale zero models MySQL's existing CEIL formula.
execute("CREATE TABLE fl_loading_plan_item(id BIGINT PRIMARY KEY,loading_plan_id BIGINT,account_id BIGINT,inbound_id BIGINT,inbound_code VARCHAR,destination_warehouse_id BIGINT,destination_warehouse_code VARCHAR,destination_warehouse_name VARCHAR,pallet_count INT,package_count DECIMAL(10,0),load_sequence INT,deleted INT)");
execute("CREATE TABLE fl_inbound_order(id BIGINT PRIMARY KEY,tenant_id BIGINT,root_inbound_id BIGINT,pallet_count INT,total_package_count DECIMAL(10,0),fulfillment_type VARCHAR,destination_type VARCHAR,deleted INT)");
execute("CREATE TABLE fl_inbound_weight_result(id BIGINT PRIMARY KEY,tenant_id BIGINT,inbound_id BIGINT,pallet_id BIGINT,recognition_status VARCHAR,deleted INT)");
execute("CREATE TABLE fl_inbound_pallet_allocation(id BIGINT PRIMARY KEY,tenant_id BIGINT,inbound_id BIGINT,block_id BIGINT,slot_no INT,reservation_id BIGINT,weight_result_id BIGINT,allocated_package_count INT,picked_package_count INT,allocation_status VARCHAR)");
execute("INSERT INTO fl_loading_plan VALUES(1,'LP-1','LOADING',2)");
execute("INSERT INTO fl_container_booking VALUES(2,'MSCU6639870','D0001',3,'ACTIVE')");
execute("INSERT INTO fl_inbound_order VALUES(20,100,30,0,2,'STANDARD','FBA',0)");
execute("INSERT INTO fl_loading_plan_item VALUES(10,1,100,20,'IN-CHILD',200,'ONT8','ONT8',0,2,1,0)");
}
@AfterEach
void close() { if (session != null) session.close(); }
private void execute(String sql) throws Exception {
try (var statement = session.getConnection().createStatement()) { statement.execute(sql); }
session.clearCache();
}
private void inherited(long id, int slot, int boxes) throws Exception {
execute("INSERT INTO fl_inbound_weight_result VALUES(" + id + ",100,30,900,'CONFIRMED',0)");
execute("INSERT INTO fl_inbound_pallet_allocation VALUES(" + id + ",100,20,600," + slot
+ "," + (700 + slot) + "," + id + "," + boxes + ",0,'CONFIRMED')");
}
private int count() {
var rows = session.getMapper(LoadingPalletLabelMapper.class).lockSources(1L);
assertThat(rows).hasSize(1);
assertThat(rows.get(0).getInboundId()).isEqualTo(20L);
assertThat(rows.get(0).getAccountId()).isEqualTo(100L);
return rows.get(0).getPalletCount();
}
@Test
void childUsesInheritedConfirmedSlotWithoutCreatingItsOwnWeightAndKeepsReleasedSnapshot() throws Exception {
inherited(50, 1, 2);
assertThat(count()).isEqualTo(1);
execute("UPDATE fl_inbound_pallet_allocation SET picked_package_count=allocated_package_count,allocation_status='RELEASED'");
assertThat(count()).isEqualTo(1);
execute("UPDATE fl_inbound_pallet_allocation SET allocation_status='TRANSFERRED'");
assertThat(count()).isEqualTo(1);
try (var statement = session.getConnection().createStatement();
var result = statement.executeQuery("SELECT COUNT(*) FROM fl_inbound_weight_result WHERE inbound_id=20")) {
result.next(); assertThat(result.getInt(1)).isZero();
}
}
@Test
void countsWeightSlotIdentityOnceAndDoesNotCollapseReusedPhysicalPalletIds() throws Exception {
inherited(50, 1, 1);
execute("INSERT INTO fl_inbound_pallet_allocation VALUES(51,100,20,601,1,702,50,1,0,'CONFIRMED')");
assertThat(count()).isEqualTo(1);
inherited(52, 2, 1);
assertThat(count()).isEqualTo(2);
}
@ParameterizedTest
@ValueSource(strings = {"empty", "no-weight", "wrong-customer", "wrong-child", "other-child-weight",
"unconfirmed", "deleted-weight", "invalid-block", "invalid-slot", "invalid-reservation", "reserved"})
void invalidOrUnrelatedSnapshotsNeverInventOnePallet(String scenario) throws Exception {
inherited(50, 1, 2);
execute(switch (scenario) {
case "empty" -> "UPDATE fl_inbound_pallet_allocation SET allocated_package_count=0";
case "no-weight" -> "UPDATE fl_inbound_pallet_allocation SET weight_result_id=NULL";
case "wrong-customer" -> "UPDATE fl_inbound_weight_result SET tenant_id=101";
case "wrong-child" -> "UPDATE fl_inbound_pallet_allocation SET inbound_id=21";
case "other-child-weight" -> "UPDATE fl_inbound_weight_result SET inbound_id=21";
case "unconfirmed" -> "UPDATE fl_inbound_weight_result SET recognition_status='PENDING'";
case "deleted-weight" -> "UPDATE fl_inbound_weight_result SET deleted=1";
case "invalid-block" -> "UPDATE fl_inbound_pallet_allocation SET block_id=0";
case "invalid-slot" -> "UPDATE fl_inbound_pallet_allocation SET slot_no=0";
case "invalid-reservation" -> "UPDATE fl_inbound_pallet_allocation SET reservation_id=0";
case "reserved" -> "UPDATE fl_inbound_pallet_allocation SET allocation_status='RESERVED'";
default -> throw new IllegalArgumentException(scenario);
});
assertThat(count()).isZero();
}
@Test
void preservesPlanThenInboundPriorityAndRoundsActualSliceUp() throws Exception {
inherited(50, 1, 1); inherited(51, 2, 1); inherited(52, 3, 1);
execute("UPDATE fl_inbound_order SET total_package_count=8");
execute("UPDATE fl_loading_plan_item SET package_count=3");
assertThat(count()).isEqualTo(2);
execute("UPDATE fl_inbound_order SET pallet_count=4");
assertThat(count()).isEqualTo(2);
execute("UPDATE fl_loading_plan_item SET pallet_count=5");
assertThat(count()).isEqualTo(5);
}
@ParameterizedTest
@ValueSource(strings = {"NULL", "0"})
void rootWithoutRootPointerStillUsesItsOwnConfirmedWeight(String rootId) throws Exception {
execute("UPDATE fl_inbound_order SET root_inbound_id=" + rootId);
execute("INSERT INTO fl_inbound_weight_result VALUES(50,100,20,900,'CONFIRMED',0)");
assertThat(count()).isEqualTo(1);
execute("INSERT INTO fl_inbound_pallet_allocation VALUES(50,100,20,600,1,701,50,2,0,'CONFIRMED')");
assertThat(count()).isEqualTo(1);
}
@Test
void anotherChildMayOnlyUseASourceWeightThroughItsOwnSnapshot() throws Exception {
inherited(50, 1, 2);
execute("INSERT INTO fl_inbound_order VALUES(21,100,30,0,2,'STANDARD','FBA',0)");
execute("UPDATE fl_loading_plan_item SET inbound_id=21,inbound_code='OTHER-CHILD'");
assertThat(session.getMapper(LoadingPalletLabelMapper.class).lockSources(1L).get(0).getPalletCount()).isZero();
execute("INSERT INTO fl_inbound_pallet_allocation VALUES(51,100,21,600,1,701,50,2,0,'CONFIRMED')");
assertThat(session.getMapper(LoadingPalletLabelMapper.class).lockSources(1L).get(0).getPalletCount()).isEqualTo(1);
}
}