This commit is contained in:
2026-10-21 07:53:31 +08:00
parent af5cf1e3bd
commit f00d0e16cf
147 changed files with 1696 additions and 872 deletions
@@ -27,6 +27,10 @@ class ProcurementLifecycleAuthorizationTest {
private final ProcurementLifecycleService service=context.getBean(ProcurementLifecycleService.class);
@Configuration @EnableMethodSecurity(proxyTargetClass=true)
static class Config {
/** 为控制器权限测试中的服务替身补齐编号依赖。 */
@Bean com.baiyue.lastleg.service.LastlegDocumentNumberGenerator documentNumbers() {
return com.baiyue.lastleg.service.TestDocumentNumbers.documents();
}
@Bean ProcurementLifecycleService service(){return mock(ProcurementLifecycleService.class);}
@Bean ProcurementLifecycleController controller(ProcurementLifecycleService service){return new ProcurementLifecycleController(service);}
@Bean ProcurementPhysicalService physicalService(){return mock(ProcurementPhysicalService.class);}
@@ -43,7 +43,7 @@ class OverseasProcurementServiceTest {
@Mock OverseasProcurementOrderMapper orders;
@Mock OverseasProcurementStatusHistoryMapper histories;
@Mock ProcurementWarehouseDirectory warehouseDirectory;
@Mock ProcurementOrderNumberGenerator orderNoGenerator;
@Mock com.baiyue.lastleg.service.LastlegDocumentNumberGenerator orderNoGenerator;
@Mock OverseasProcurementFileMapper procurementFiles;
@Mock OverseasProcurementFeeMapper procurementFees;
@Mock ProcurementFileGateway fileGateway;
@@ -62,7 +62,7 @@ class OverseasProcurementServiceTest {
ReflectionTestUtils.setField(service, "procurementFiles", procurementFiles);
ReflectionTestUtils.setField(service, "procurementFees", procurementFees);
ReflectionTestUtils.setField(service, "fileGateway", fileGateway);
lenient().when(orderNoGenerator.next(anyString(), any())).thenReturn("ACME202609050001");
lenient().when(orderNoGenerator.next(anyString())).thenReturn("ACME202609050001");
lenient().when(procurementFiles.selectList(any())).thenReturn(List.of());
lenient().when(procurementFees.selectList(any())).thenReturn(List.of());
}
@@ -58,8 +58,11 @@ class ProcurementChargePersistenceTest {
when(commands.publish(anyString(),anyLong(),anyString(),anyString(),any(),anyString(),anyLong())).thenAnswer(i->"cmd-"+events.incrementAndGet());
when(commands.publishRefund(anyLong(),anyString(),anyString(),any(),anyString(),anyString(),anyLong())).thenAnswer(i->"cmd-"+events.incrementAndGet());
var json=new ObjectMapper().findAndRegisterModules();finance=new ProcurementFinanceService(fees,files,orders,converter,sources,commands,jdbc,json);
org.springframework.test.util.ReflectionTestUtils.setField(finance, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
org.springframework.test.util.ReflectionTestUtils.setField(finance, "feeNumbers", new com.baiyue.lastleg.procurement.repository.ProcurementFeeNumberRepository(fees));
lifecycle=new ProcurementLifecycleService(orders,files,mock(ProcurementWarehouseDirectory.class),finance,converter,jdbc,json);
charges=new ProcurementChargeService(lifecycle,finance,jdbc);adjustments=new ProcurementAdjustmentService(lifecycle,finance,jdbc);
org.springframework.test.util.ReflectionTestUtils.setField(adjustments, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
tx.execute(s->finance.confirm("9","PO-1","7",new ProcurementFinanceService.Confirmation(ProcurementFeePurpose.SAMPLE_PAYMENT,"SAMPLE_PAYMENT","货款","ZERO",BigDecimal.ZERO,"CNY",LocalDate.of(2026,9,1),null,"free")));
estimateId=tx.execute(s->finance.confirm("9","PO-1","7",new ProcurementFinanceService.Confirmation(ProcurementFeePurpose.INTERNATIONAL_ESTIMATE,"INTERNATIONAL_ESTIMATE","预估","ZERO",BigDecimal.ZERO,"CNY",LocalDate.of(2026,9,1),null,"zero estimate"))).getId();
}
@@ -51,6 +51,7 @@ class ProcurementControlPersistenceTest {
when(warehouses.required(92)).thenReturn(new ReceivingWarehouse(92L,"NEW","Correct receiving warehouse","US","ACTIVE"));
var json=new ObjectMapper().findAndRegisterModules();lifecycle=new ProcurementLifecycleService(orders,files,warehouses,finance,mock(OverseasFeeCurrencyConverter.class),jdbc,json);
service=new ProcurementControlService(lifecycle,finance,warehouses,jdbc,json);
org.springframework.test.util.ReflectionTestUtils.setField(service, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
}
@Test void purchasedButUnreceivedGoodsCanCloseOnlyWithAllSupplierDispositionAndCustomerEvidence() {
assertThat(service.read("9","PO-1").remaining()).containsExactly(new ProcurementControlService.Remaining("PURCHASE_REMAINDER",null,"PO-1",10));
@@ -68,6 +68,8 @@ class ProcurementFinancePersistenceTest {
when(commands.publishRefund(anyLong(),anyString(),anyString(),any(),anyString(),anyString(),anyLong()))
.thenAnswer(i -> "command-"+sequence.incrementAndGet());
service=new ProcurementFinanceService(fees,files,orders,converter,sources,commands,jdbc,new ObjectMapper().findAndRegisterModules());
org.springframework.test.util.ReflectionTestUtils.setField(service, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
org.springframework.test.util.ReflectionTestUtils.setField(service, "feeNumbers", new com.baiyue.lastleg.procurement.repository.ProcurementFeeNumberRepository(fees));
}
@Test void actualFeePublishesOnlyAfterSuccessfulConsumption() {
@@ -235,7 +237,13 @@ class ProcurementFinancePersistenceTest {
handle(result(fees.selectById(fee.getId()),"SETTLE","SUCCEEDED","SETTLED","100"));
jdbc.update("INSERT INTO ll_event_outbox VALUES('OVERSEAS_PROCUREMENT_FEE','901','PUBLISHED')");
var refund=tx.execute(s -> service.refund("9","PO-1","7",fee.getId(),new BigDecimal("20"),1,"correction","refund-key"));
assertThat(tx.execute(s -> service.refund("9","PO-1","7",fee.getId(),new BigDecimal("20"),1,"correction","refund-key")).getId()).isEqualTo(refund.getId());
assertThat(refund.getFeeNo()).matches("PF[0-9]{12}");
var replay = tx.execute(s -> service.refund("9","PO-1","7",fee.getId(),new BigDecimal("20"),1,"correction","refund-key"));
assertThat(replay.getId()).isEqualTo(refund.getId());
assertThat(replay.getFeeNo()).isEqualTo(refund.getFeeNo());
assertThatThrownBy(() -> tx.execute(s -> service.refund("9","PO-1","7",fee.getId(),new BigDecimal("21"),1,"correction","refund-key")))
.hasMessageContaining("退款幂等键对应不同");
verify(commands, times(1)).publishRefund(anyLong(),anyString(),anyString(),any(),anyString(),anyString(),anyLong());
assertThatThrownBy(() -> tx.execute(s -> service.refund("9","PO-1","7",fee.getId(),new BigDecimal("20"),1,"correction","another-key")))
.hasMessageContaining("未完成的调整或退款");
handle(new WalletCommandCompletedV1(refund.getWalletCommandEventId(),"REFUND",9,"PROCUREMENT_FEE",refund.getFeeNo(),
@@ -1,17 +0,0 @@
package com.baiyue.lastleg.procurement.service;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class ProcurementOrderNumberGeneratorTest {
@Test void convertsChineseCompanyNameToInitials() {
assertThat(ProcurementOrderNumberGenerator.initials("杭州积乐贸易有限公司")).isEqualTo("HZJLMYYX");
}
@Test void keepsOneInitialPerLatinWordAndUsesFallback() {
assertThat(ProcurementOrderNumberGenerator.initials("Great Ocean Trading LLC")).isEqualTo("GOTL");
assertThat(ProcurementOrderNumberGenerator.initials(" ")).isEqualTo("KH");
}
@Test void limitsInitialsToEightCharacters() {
assertThat(ProcurementOrderNumberGenerator.initials("一二三四五六七八九十")).hasSize(8);
}
}
@@ -55,6 +55,7 @@ class ProcurementPhysicalPersistenceTest {
when(finance.current(11,ProcurementFeePurpose.SAMPLE_PAYMENT,"SAMPLE_PAYMENT")).thenReturn(payment);when(finance.sourceLinked(payment)).thenReturn(true);
var lifecycle=new ProcurementLifecycleService(orders,files,warehouses,finance,mock(OverseasFeeCurrencyConverter.class),jdbc,new ObjectMapper().findAndRegisterModules());
service=new ProcurementPhysicalService(lifecycle,warehouses,finance,jdbc);
org.springframework.test.util.ReflectionTestUtils.setField(service, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
}
@Test void splitReceiptsAndCartonSourcesRemainConservedWithoutWms() {
@@ -24,7 +24,9 @@ class ProcurementQueryServiceTest {
var m=Pattern.compile("CREATE TABLE IF NOT EXISTS "+name+" \\(.*?\\) ENGINE=InnoDB[^;]*;",Pattern.DOTALL).matcher(schema);assertThat(m.find()).isTrue();jdbc.execute(m.group().replaceFirst("\\) ENGINE=InnoDB[^;]*;",");"));
}
var physical=new ProcurementPhysicalService(fixture.lifecycle,fixture.warehouses,fixture.finance,jdbc);
org.springframework.test.util.ReflectionTestUtils.setField(physical, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
transport=new ProcurementTransportService(fixture.lifecycle,physical,fixture.finance,fixture.warehouses,jdbc,json);
org.springframework.test.util.ReflectionTestUtils.setField(transport, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
base=mock(OverseasProcurementService.class);
when(base.detail("9","PO-1")).thenReturn(new OverseasProcurementResponses.Detail(null,null,null,null,null,null,"internal remark","operator","reviewer","internal review",null,List.of(),List.of(new OverseasProcurementResponses.FileInfo(1L,"EXCEPTION",1001L,"private.pdf","application/pdf",10,null)),List.of()));
query=new ProcurementQueryService(fixture.lifecycle,physical,transport,fixture.finance,mock(ProcurementAdjustmentService.class),fixture.service,base,jdbc);
@@ -68,7 +68,9 @@ class ProcurementTransportPersistenceTest {
var json=new ObjectMapper().findAndRegisterModules();
var lifecycle=new ProcurementLifecycleService(orders,files,warehouses,finance,mock(OverseasFeeCurrencyConverter.class),jdbc,json);
var physical=new ProcurementPhysicalService(lifecycle,warehouses,finance,jdbc);
org.springframework.test.util.ReflectionTestUtils.setField(physical, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
service=new ProcurementTransportService(lifecycle,physical,finance,warehouses,jdbc,json);
org.springframework.test.util.ReflectionTestUtils.setField(service, "documentNumbers", com.baiyue.lastleg.service.TestDocumentNumbers.documents());
}
@Test void entireBatchShipsOnceWithFrozenAddressLabelsAndSources() {
prepare();var request=shipRequest(Leg.OVERSEAS,"ship");