fix(firstleg): project completed loading lists from actual picked cargo
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import com.baiyue.firstleg.dto.LoadingListDtos.ConfirmedQuery;
|
||||
import com.baiyue.firstleg.dto.LoadingListDtos.PreloadQuery;
|
||||
import com.baiyue.firstleg.entity.ContainerBookingEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPlanEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPlanItemEntity;
|
||||
import com.baiyue.firstleg.mapper.LoadingListQueryMapper;
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/** Executes the real SQL, including pagination COUNT and correlated physical-pallet totals. */
|
||||
class LoadingListActualCargoTest {
|
||||
private JdbcTemplate jdbc;
|
||||
private LoadingListQueryMapper mapper;
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
var ds = new JdbcDataSource();
|
||||
ds.setURL("jdbc:h2:mem:loaded-list-" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1");
|
||||
jdbc = new JdbcTemplate(ds);
|
||||
table("fl_loading_plan", LoadingPlanEntity.class);
|
||||
table("fl_loading_plan_item", LoadingPlanItemEntity.class);
|
||||
table("fl_container_booking", ContainerBookingEntity.class);
|
||||
table("fl_inbound_order", InboundOrderEntity.class);
|
||||
jdbc.execute("CREATE TABLE fl_outbound_dispatch(container_booking_id BIGINT, confirmed_at TIMESTAMP, reversed_at TIMESTAMP, status VARCHAR)");
|
||||
jdbc.execute("CREATE TABLE fl_preload_loading_plan_link(loading_plan_id BIGINT, preload_plan_id BIGINT)");
|
||||
jdbc.execute("CREATE TABLE fl_preload_plan(id BIGINT, status VARCHAR)");
|
||||
jdbc.execute("CREATE TABLE fl_ocean_booking_container_allocation(container_booking_id BIGINT, ocean_booking_id BIGINT)");
|
||||
jdbc.execute("CREATE TABLE fl_ocean_booking(id BIGINT, status VARCHAR)");
|
||||
jdbc.execute("CREATE TABLE fl_loading_pick_task(id BIGINT, loading_plan_id BIGINT, task_status VARCHAR)");
|
||||
jdbc.execute("CREATE TABLE fl_loading_pick_item(loading_plan_item_id BIGINT, pick_task_id BIGINT, item_status VARCHAR, picked_package_count INT)");
|
||||
jdbc.execute("CREATE TABLE fl_dropship_pallet_carton(id BIGINT, pallet_id BIGINT, inbound_id BIGINT, tenant_id BIGINT)");
|
||||
jdbc.execute("CREATE TABLE fl_inbound_weight_result(tenant_id BIGINT, inbound_id BIGINT, deleted INT, recognition_status VARCHAR)");
|
||||
jdbc.update("INSERT INTO fl_container_booking(id,warehouse_id,record_status) VALUES(10,1,'ACTIVE')");
|
||||
jdbc.update("INSERT INTO fl_loading_plan(id,container_booking_id,plan_status,created_at) VALUES(1,10,'COMPLETED',CURRENT_TIMESTAMP)");
|
||||
jdbc.update("INSERT INTO fl_loading_pick_task VALUES(100,1,'COMPLETED'),(200,2,'COMPLETED')");
|
||||
var configuration = new MybatisConfiguration();
|
||||
configuration.setMapUnderscoreToCamelCase(true);
|
||||
configuration.addMapper(LoadingListQueryMapper.class);
|
||||
var pagination = new MybatisPlusInterceptor();
|
||||
pagination.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
|
||||
var factory = new MybatisSqlSessionFactoryBean();
|
||||
factory.setDataSource(ds);
|
||||
factory.setConfiguration(configuration);
|
||||
factory.setPlugins(pagination);
|
||||
mapper = new SqlSessionTemplate(factory.getObject()).getMapper(LoadingListQueryMapper.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void completedDetailAndListExcludeSkippedAndUnsettledRowsFromAllMeasures() {
|
||||
ordinaryCargo();
|
||||
assertActualTotals(mapper.selectAggregate(1));
|
||||
assertActualTotals(mapper.selectAggregateByBooking(10));
|
||||
assertThat(mapper.selectItems(1)).extracting(LoadingListQueryMapper.ItemRow::getItemId)
|
||||
.containsExactly(1L, 2L);
|
||||
var page = mapper.selectConfirmedPage(new Page<>(1, 1), query(null));
|
||||
assertThat(page.getTotal()).isEqualTo(1);
|
||||
assertThat(page.getRecords()).singleElement().satisfies(this::assertActualTotals);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customerWithOnlySkippedCargoCannotMatchCompletedListCountOrRows() {
|
||||
ordinaryCargo();
|
||||
var skipped = mapper.selectConfirmedPage(new Page<>(1, 1), query(22L));
|
||||
assertThat(skipped.getTotal()).isZero();
|
||||
assertThat(skipped.getRecords()).isEmpty();
|
||||
var loaded = mapper.selectConfirmedPage(new Page<>(1, 1), query(11L));
|
||||
assertThat(loaded.getTotal()).isEqualTo(1);
|
||||
assertThat(loaded.getRecords()).singleElement().satisfies(this::assertActualTotals);
|
||||
}
|
||||
|
||||
@Test
|
||||
void emptyActualScopeDoesNotHideThePlanIdentityOrFallBackToPlannedTotals() {
|
||||
item(1, 22, 1, null, "SKIPPED", 0, 100);
|
||||
var row = mapper.selectAggregate(1);
|
||||
assertThat(row.getPlanId()).isEqualTo(1);
|
||||
assertThat(row.getPlanStatus()).isEqualTo("COMPLETED");
|
||||
assertThat(row.getTotalPackageCount()).isZero();
|
||||
assertThat(row.getTotalGrossWeightKg()).isEqualByComparingTo("0");
|
||||
assertThat(mapper.selectItems(1)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void unfinishedPreloadKeepsPlannedCargoIncludingPendingAndSkippedItems() {
|
||||
ordinaryCargo();
|
||||
jdbc.update("UPDATE fl_loading_plan SET plan_status='LOADING' WHERE id=1");
|
||||
assertThat(mapper.selectItems(1)).hasSize(6);
|
||||
assertThat(mapper.selectAggregate(1).getTotalPackageCount()).isEqualTo(8);
|
||||
var page = mapper.selectPreloadPage(new Page<>(1, 1),
|
||||
new PreloadQuery(null, null, 22L, null, null, null, 1, 1));
|
||||
assertThat(page.getTotal()).isEqualTo(1);
|
||||
assertThat(page.getRecords()).singleElement().satisfies(row ->
|
||||
assertThat(row.getTotalPackageCount()).isEqualTo(8));
|
||||
}
|
||||
|
||||
@Test
|
||||
void physicalPalletTotalsIgnoreUnloadedPalletsAndDoNotCountSkuFragmentsTwice() {
|
||||
item(1, 11, 2, 501L, "PICKED", 2, 100);
|
||||
item(2, 11, 2, 501L, "PICKED", 2, 100);
|
||||
item(3, 22, 1, 502L, "SKIPPED", 0, 100);
|
||||
jdbc.update("INSERT INTO fl_inbound_order(id,tenant_id,total_package_count,actual_gross_weight_kg,actual_net_weight_kg,actual_volume_cbm) VALUES(700,11,2,20,16,4),(701,22,1,999,999,999)");
|
||||
jdbc.update("INSERT INTO fl_dropship_pallet_carton VALUES(1,501,700,11),(2,501,700,11),(3,502,701,22)");
|
||||
var actual = mapper.selectAggregate(1);
|
||||
assertThat(actual.getTotalPackageCount()).isEqualTo(2);
|
||||
assertThat(actual.getTotalGrossWeightKg()).isEqualByComparingTo("20");
|
||||
assertThat(actual.getTotalNetWeightKg()).isEqualByComparingTo("16");
|
||||
assertThat(actual.getTotalVolumeCbm()).isEqualByComparingTo("4");
|
||||
assertThat(actual.getTotalQuantity()).isEqualTo(40);
|
||||
assertThat(mapper.selectItems(1)).hasSize(2);
|
||||
assertThat(mapper.selectConfirmedPage(new Page<>(1, 1), query(22L)).getTotal()).isZero();
|
||||
jdbc.update("UPDATE fl_loading_plan SET plan_status='EDITING' WHERE id=1");
|
||||
assertThat(mapper.selectAggregate(1).getTotalPackageCount()).isEqualTo(3);
|
||||
assertThat(mapper.selectAggregate(1).getTotalGrossWeightKg()).isEqualByComparingTo("1019");
|
||||
assertThat(mapper.selectItems(1)).hasSize(3);
|
||||
}
|
||||
|
||||
private void ordinaryCargo() {
|
||||
item(1, 11, 2, null, "PICKED", 2, 100);
|
||||
item(2, 11, 1, null, "PARTIAL", 1, 100);
|
||||
item(3, 22, 1, null, "SKIPPED", 0, 100);
|
||||
item(4, 22, 1, null, "PENDING", 0, 100);
|
||||
item(5, 22, 1, null, "PICKED", 1, 200); // wrong task belongs to a different plan
|
||||
item(6, 22, 2, null, "PARTIAL", 1, 100); // not reconciled to the final fragment
|
||||
item(7, 11, 9, null, "PICKED", 9, 100);
|
||||
jdbc.update("UPDATE fl_loading_plan_item SET deleted=1 WHERE id=7");
|
||||
}
|
||||
|
||||
private void item(long id, long customer, int packages, Long pallet, String status, int picked, long task) {
|
||||
jdbc.update("INSERT INTO fl_loading_plan_item(id,loading_plan_id,account_id,sku_code,package_count,product_quantity,gross_weight_kg,net_weight_kg,volume_cbm,pallet_id,pallet_count,deleted,load_sequence) VALUES(?,1,?,?,?,?,?,?,?,?,1,0,?)",
|
||||
id, customer, "SKU-" + id, packages, packages * 10, packages * 5, packages * 4, packages, pallet, id);
|
||||
jdbc.update("INSERT INTO fl_loading_pick_item VALUES(?,?,?,?)", id, task, status, picked);
|
||||
}
|
||||
|
||||
private ConfirmedQuery query(Long customer) {
|
||||
return new ConfirmedQuery(null, customer, null, null, null, 1, 1);
|
||||
}
|
||||
|
||||
private void assertActualTotals(LoadingListQueryMapper.AggregateRow row) {
|
||||
assertThat(row.getTotalPackageCount()).isEqualTo(3);
|
||||
assertThat(row.getTotalQuantity()).isEqualTo(30);
|
||||
assertThat(row.getSkuCount()).isEqualTo(2);
|
||||
assertThat(row.getTotalGrossWeightKg()).isEqualByComparingTo("15");
|
||||
assertThat(row.getTotalNetWeightKg()).isEqualByComparingTo("12");
|
||||
assertThat(row.getTotalVolumeCbm()).isEqualByComparingTo("3");
|
||||
}
|
||||
|
||||
private void table(String name, Class<?> entity) {
|
||||
var columns = new ArrayList<String>();
|
||||
for (var type = entity; type != Object.class; type = type.getSuperclass()) {
|
||||
for (var field : type.getDeclaredFields()) {
|
||||
var annotation = field.getAnnotation(TableField.class);
|
||||
if (Modifier.isStatic(field.getModifiers()) || annotation != null && !annotation.exist()) continue;
|
||||
String column = field.getName().replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase();
|
||||
Class<?> value = field.getType();
|
||||
String sqlType = value == Long.class || value == long.class ? "BIGINT"
|
||||
: value == Integer.class || value == int.class || value == Boolean.class || value == boolean.class ? "INT"
|
||||
: value == BigDecimal.class ? "DECIMAL(20,6)"
|
||||
: value == java.time.LocalDateTime.class ? "TIMESTAMP" : "VARCHAR(2000)";
|
||||
columns.add(column + " " + sqlType);
|
||||
}
|
||||
}
|
||||
jdbc.execute("CREATE TABLE " + name + " (" + String.join(",", columns) + ")");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user