优化
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
[INFO] Scanning for projects...
|
||||||
|
[INFO] ------------------------------------------------------------------------
|
||||||
|
[INFO] Reactor Build Order:
|
||||||
|
[INFO]
|
||||||
|
[INFO] °ØÔÃÍ·³Ìƽ̨ [pom]
|
||||||
|
[INFO] baiyue-common-core [jar]
|
||||||
|
[INFO] baiyue-common-web [jar]
|
||||||
|
[INFO] baiyue-common-security [jar]
|
||||||
|
[INFO] baiyue-common-openapi [jar]
|
||||||
|
[INFO] baiyue-common-audit [jar]
|
||||||
|
[INFO] firstleg-service [jar]
|
||||||
|
[INFO]
|
||||||
|
[INFO] ------------< com.baiyue.firstleg:baiyue-firstleg-platform >------------
|
||||||
|
[INFO] Building °ØÔÃÍ·³Ìƽ̨ 1.0.0-SNAPSHOT [1/7]
|
||||||
|
[INFO] from pom.xml
|
||||||
|
[INFO] --------------------------------[ pom ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-firstleg-platform ---
|
||||||
|
[INFO] Rule 0: org.apache.maven.enforcer.rules.version.RequireJavaVersion passed
|
||||||
|
[INFO] Rule 1: org.apache.maven.enforcer.rules.version.RequireMavenVersion passed
|
||||||
|
[INFO]
|
||||||
|
[INFO] ----------------< com.baiyue.shared:baiyue-common-core >----------------
|
||||||
|
[INFO] Building baiyue-common-core 1.0.0-SNAPSHOT [2/7]
|
||||||
|
[INFO] from common-core\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-common-core ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ baiyue-common-core ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-core\src\main\resources
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-core\src\main\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ baiyue-common-core ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ baiyue-common-core ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-core\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ baiyue-common-core ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ baiyue-common-core ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] ----------------< com.baiyue.shared:baiyue-common-web >-----------------
|
||||||
|
[INFO] Building baiyue-common-web 1.0.0-SNAPSHOT [3/7]
|
||||||
|
[INFO] from common-web\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-common-web ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ baiyue-common-web ---
|
||||||
|
[INFO] Copying 0 resource from src\main\resources to target\classes
|
||||||
|
[INFO] Copying 1 resource from src\main\resources to target\classes
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ baiyue-common-web ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ baiyue-common-web ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-web\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ baiyue-common-web ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ baiyue-common-web ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --------------< com.baiyue.shared:baiyue-common-security >--------------
|
||||||
|
[INFO] Building baiyue-common-security 1.0.0-SNAPSHOT [4/7]
|
||||||
|
[INFO] from common-security\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-common-security ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ baiyue-common-security ---
|
||||||
|
[INFO] Copying 0 resource from src\main\resources to target\classes
|
||||||
|
[INFO] Copying 1 resource from src\main\resources to target\classes
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ baiyue-common-security ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ baiyue-common-security ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-security\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ baiyue-common-security ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ baiyue-common-security ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --------------< com.baiyue.shared:baiyue-common-openapi >---------------
|
||||||
|
[INFO] Building baiyue-common-openapi 1.0.0-SNAPSHOT [5/7]
|
||||||
|
[INFO] from common-openapi\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-common-openapi ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ baiyue-common-openapi ---
|
||||||
|
[INFO] Copying 0 resource from src\main\resources to target\classes
|
||||||
|
[INFO] Copying 1 resource from src\main\resources to target\classes
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ baiyue-common-openapi ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ baiyue-common-openapi ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-openapi\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ baiyue-common-openapi ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ baiyue-common-openapi ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] ---------------< com.baiyue.shared:baiyue-common-audit >----------------
|
||||||
|
[INFO] Building baiyue-common-audit 1.0.0-SNAPSHOT [6/7]
|
||||||
|
[INFO] from common-audit\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[WARNING] 1 problem was encountered while building the effective model for org.javassist:javassist:jar:3.21.0-GA during dependency collection step for project (use -X to see details)
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ baiyue-common-audit ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ baiyue-common-audit ---
|
||||||
|
[INFO] Copying 0 resource from src\main\resources to target\classes
|
||||||
|
[INFO] Copying 1 resource from src\main\resources to target\classes
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ baiyue-common-audit ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ baiyue-common-audit ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\common-audit\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ baiyue-common-audit ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ baiyue-common-audit ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] ----------------< com.baiyue.firstleg:firstleg-service >----------------
|
||||||
|
[INFO] Building firstleg-service 1.0.0-SNAPSHOT [7/7]
|
||||||
|
[INFO] from firstleg\pom.xml
|
||||||
|
[INFO] --------------------------------[ jar ]---------------------------------
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- enforcer:3.4.1:enforce (УÑé¹¹½¨»·¾³) @ firstleg-service ---
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:resources (default-resources) @ firstleg-service ---
|
||||||
|
[INFO] Copying 3 resources from src\main\resources to target\classes
|
||||||
|
[INFO] Copying 48 resources from src\main\resources to target\classes
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:compile (default-compile) @ firstleg-service ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- resources:3.3.1:testResources (default-testResources) @ firstleg-service ---
|
||||||
|
[INFO] skip non existing resourceDirectory C:\Users\BY-OY\Desktop\code\chongchong-global\baiyue-firstleg\firstleg\src\test\resources
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ firstleg-service ---
|
||||||
|
[INFO] Nothing to compile - all classes are up to date.
|
||||||
|
[INFO]
|
||||||
|
[INFO] --- surefire:3.1.2:test (default-test) @ firstleg-service ---
|
||||||
|
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
|
||||||
|
[INFO]
|
||||||
|
[INFO] -------------------------------------------------------
|
||||||
|
[INFO] T E S T S
|
||||||
|
[INFO] -------------------------------------------------------
|
||||||
|
[INFO] Running com.baiyue.firstleg.repository.FinanceFeeSourceMigrationContractTest
|
||||||
|
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.116 s -- in com.baiyue.firstleg.repository.FinanceFeeSourceMigrationContractTest
|
||||||
|
[INFO] Running com.baiyue.firstleg.repository.Phase3FinalUnifiedSqlContractTest
|
||||||
|
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.170 s -- in com.baiyue.firstleg.repository.Phase3FinalUnifiedSqlContractTest
|
||||||
|
[INFO] Running com.baiyue.firstleg.service.FbaPricingServiceTest
|
||||||
|
Standard Commons Logging discovery in action with spring-jcl: please remove commons-logging.jar from classpath in order to avoid potential conflicts
|
||||||
|
16:57:57.743 [main] WARN org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer --
|
||||||
|
|
||||||
|
Found multiple occurrences of org.json.JSONObject on the class path:
|
||||||
|
|
||||||
|
jar:file:/C:/Users/BY-OY/.m2/repository/org/json/json/20240303/json-20240303.jar!/org/json/JSONObject.class
|
||||||
|
jar:file:/C:/Users/BY-OY/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar!/org/json/JSONObject.class
|
||||||
|
|
||||||
|
You may wish to exclude one of them to ensure predictable runtime behavior
|
||||||
|
|
||||||
|
[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.182 s -- in com.baiyue.firstleg.service.FbaPricingServiceTest
|
||||||
|
[INFO] Running com.baiyue.firstleg.service.FeeManagementServiceTest
|
||||||
|
16:57:59.556 [main] WARN org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer --
|
||||||
|
|
||||||
|
Found multiple occurrences of org.json.JSONObject on the class path:
|
||||||
|
|
||||||
|
jar:file:/C:/Users/BY-OY/.m2/repository/org/json/json/20240303/json-20240303.jar!/org/json/JSONObject.class
|
||||||
|
jar:file:/C:/Users/BY-OY/.m2/repository/com/vaadin/external/google/android-json/0.0.20131108.vaadin1/android-json-0.0.20131108.vaadin1.jar!/org/json/JSONObject.class
|
||||||
|
|
||||||
|
You may wish to exclude one of them to ensure predictable runtime behavior
|
||||||
|
|
||||||
|
[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.114 s -- in com.baiyue.firstleg.service.FeeManagementServiceTest
|
||||||
|
[INFO] Running com.baiyue.firstleg.service.FinanceFeeSourceOutboxServiceTest
|
||||||
|
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.484 s -- in com.baiyue.firstleg.service.FinanceFeeSourceOutboxServiceTest
|
||||||
|
[INFO]
|
||||||
|
[INFO] Results:
|
||||||
|
[INFO]
|
||||||
|
[INFO] Tests run: 41, Failures: 0, Errors: 0, Skipped: 0
|
||||||
|
[INFO]
|
||||||
|
[INFO] ------------------------------------------------------------------------
|
||||||
|
[INFO] Reactor Summary for °ØÔÃÍ·³Ìƽ̨ 1.0.0-SNAPSHOT:
|
||||||
|
[INFO]
|
||||||
|
[INFO] °ØÔÃÍ·³Ìƽ̨ ............................................. SUCCESS [ 0.320 s]
|
||||||
|
[INFO] baiyue-common-core ................................. SUCCESS [ 0.975 s]
|
||||||
|
[INFO] baiyue-common-web .................................. SUCCESS [ 0.297 s]
|
||||||
|
[INFO] baiyue-common-security ............................. SUCCESS [ 0.281 s]
|
||||||
|
[INFO] baiyue-common-openapi .............................. SUCCESS [ 0.216 s]
|
||||||
|
[INFO] baiyue-common-audit ................................ SUCCESS [ 0.577 s]
|
||||||
|
[INFO] firstleg-service ................................... SUCCESS [ 5.090 s]
|
||||||
|
[INFO] ------------------------------------------------------------------------
|
||||||
|
[INFO] BUILD SUCCESS
|
||||||
|
[INFO] ------------------------------------------------------------------------
|
||||||
|
[INFO] Total time: 8.377 s
|
||||||
|
[INFO] Finished at: 2026-08-13T16:58:00+08:00
|
||||||
|
[INFO] ------------------------------------------------------------------------
|
||||||
@@ -3,7 +3,20 @@ package com.baiyue.firstleg.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.baiyue.firstleg.entity.InboundFeeDetailEntity;
|
import com.baiyue.firstleg.entity.InboundFeeDetailEntity;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface InboundFeeDetailMapper extends BaseMapper<InboundFeeDetailEntity> {
|
public interface InboundFeeDetailMapper extends BaseMapper<InboundFeeDetailEntity> {
|
||||||
|
@Update("""
|
||||||
|
UPDATE fl_inbound_fee_detail
|
||||||
|
SET deleted = 1, updated_at = CURRENT_TIMESTAMP(3)
|
||||||
|
WHERE tenant_id = #{tenantId}
|
||||||
|
AND inbound_id = #{inboundId}
|
||||||
|
AND id = #{detailId}
|
||||||
|
AND deleted = 0
|
||||||
|
""")
|
||||||
|
int logicallyDelete(@Param("tenantId") long tenantId,
|
||||||
|
@Param("inboundId") long inboundId,
|
||||||
|
@Param("detailId") long detailId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,10 +165,8 @@ public class FeeItemRepository {
|
|||||||
.eq(InboundFeeDetailEntity::getId, detail.getId()));
|
.eq(InboundFeeDetailEntity::getId, detail.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int deleteDetail(long tenantId, long detailId) {
|
public int deleteDetail(long tenantId, long inboundId, long detailId) {
|
||||||
return feeDetails.delete(new LambdaQueryWrapper<InboundFeeDetailEntity>()
|
return feeDetails.logicallyDelete(tenantId, inboundId, detailId);
|
||||||
.eq(InboundFeeDetailEntity::getTenantId, tenantId)
|
|
||||||
.eq(InboundFeeDetailEntity::getId, detailId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int review(long tenantId, long inboundId, long detailId, String targetStatus,
|
public int review(long tenantId, long inboundId, long detailId, String targetStatus,
|
||||||
|
|||||||
@@ -159,7 +159,9 @@ public class InboundFeeDetailService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void delete(long tenantId, long inboundId, long detailId) {
|
public void delete(long tenantId, long inboundId, long detailId) {
|
||||||
requiredEditable(tenantId, inboundId, detailId);
|
requiredEditable(tenantId, inboundId, detailId);
|
||||||
if (repository.deleteDetail(tenantId, detailId) != 1) throw conflict("费用明细删除冲突");
|
if (repository.deleteDetail(tenantId, inboundId, detailId) != 1) {
|
||||||
|
throw conflict("费用明细删除冲突");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|||||||
+16
@@ -8,6 +8,22 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class FinanceFeeSourceMigrationContractTest {
|
class FinanceFeeSourceMigrationContractTest {
|
||||||
|
@Test
|
||||||
|
void freshSchemaAndMigrationExposeInboundFeePartnerSnapshotsUsedByAllFeeFlows() throws Exception {
|
||||||
|
String baseline = new ClassPathResource("db/phase2-fee-item-and-inbound-detail.sql")
|
||||||
|
.getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
String migration = new ClassPathResource("db/finance-fee-source-migration.sql")
|
||||||
|
.getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
assertThat(baseline).contains(
|
||||||
|
"partner_id BIGINT UNSIGNED NULL",
|
||||||
|
"partner_name VARCHAR(200) NULL");
|
||||||
|
assertThat(migration).contains(
|
||||||
|
"firstleg_finance_add_column('fl_inbound_fee_detail', 'partner_id'",
|
||||||
|
"firstleg_finance_add_column('fl_inbound_fee_detail', 'partner_name'",
|
||||||
|
"Firstleg Finance迁移失败:入库费用往来单位快照字段不完整");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void migrationDefinesIdempotentOutboxEnvelopeAndContainerFeeModel() throws Exception {
|
void migrationDefinesIdempotentOutboxEnvelopeAndContainerFeeModel() throws Exception {
|
||||||
String sql = new ClassPathResource("db/finance-fee-source-migration.sql")
|
String sql = new ClassPathResource("db/finance-fee-source-migration.sql")
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.baiyue.firstleg.repository;
|
||||||
|
|
||||||
|
import com.baiyue.firstleg.mapper.InboundFeeDetailMapper;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class InboundFeeDetailMapperContractTest {
|
||||||
|
@Test
|
||||||
|
void logicalDeleteIsScopedToCustomerInboundDetailAndActiveRow() throws Exception {
|
||||||
|
Method method = InboundFeeDetailMapper.class.getMethod(
|
||||||
|
"logicallyDelete", long.class, long.class, long.class);
|
||||||
|
String sql = String.join(" ", method.getAnnotation(Update.class).value())
|
||||||
|
.replaceAll("\\s+", " ").toLowerCase();
|
||||||
|
|
||||||
|
assertThat(sql)
|
||||||
|
.contains("set deleted = 1")
|
||||||
|
.contains("tenant_id = #{tenantid}")
|
||||||
|
.contains("inbound_id = #{inboundid}")
|
||||||
|
.contains("id = #{detailid}")
|
||||||
|
.contains("deleted = 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-6
@@ -112,15 +112,12 @@ class TenantScopedMutationRepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
void feeDetailDeleteMatchesTenantAndId() {
|
void feeDetailDeleteMatchesTenantAndId() {
|
||||||
when(feeDetails.delete(any(Wrapper.class))).thenReturn(1);
|
when(feeDetails.logicallyDelete(TENANT, 77L, ID)).thenReturn(1);
|
||||||
|
|
||||||
assertThat(feeRepository.deleteDetail(TENANT, ID)).isEqualTo(1);
|
assertThat(feeRepository.deleteDetail(TENANT, 77L, ID)).isEqualTo(1);
|
||||||
|
|
||||||
ArgumentCaptor<Wrapper<InboundFeeDetailEntity>> wrapper = ArgumentCaptor.forClass(Wrapper.class);
|
verify(feeDetails).logicallyDelete(TENANT, 77L, ID);
|
||||||
verify(feeDetails).delete(wrapper.capture());
|
|
||||||
assertTenantAndId(wrapper.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -56,7 +56,20 @@ class FeeManagementServiceTest {
|
|||||||
.hasMessageContaining("费用明细不存在");
|
.hasMessageContaining("费用明细不存在");
|
||||||
|
|
||||||
verify(repository).findDetail(10002L, 21L, 31L);
|
verify(repository).findDetail(10002L, 21L, 31L);
|
||||||
verify(repository, never()).deleteDetail(10002L, 31L);
|
verify(repository, never()).deleteDetail(10002L, 21L, 31L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("待审核费用明细按客户和入库单作用域删除")
|
||||||
|
void deletesPendingFeeDetailInInboundScope() {
|
||||||
|
InboundFeeDetailEntity pending = new InboundFeeDetailEntity();
|
||||||
|
pending.setReviewStatus("PENDING");
|
||||||
|
when(repository.findDetail(10001L, 21L, 31L)).thenReturn(pending);
|
||||||
|
when(repository.deleteDetail(10001L, 21L, 31L)).thenReturn(1);
|
||||||
|
|
||||||
|
details.delete(10001L, 21L, 31L);
|
||||||
|
|
||||||
|
verify(repository).deleteDetail(10001L, 21L, 31L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -416,7 +416,18 @@ export class AcceptanceRun {
|
|||||||
}
|
}
|
||||||
const customerAudit = this.apiSuccess(module, '按客户查询操作日志', customerAuditResponse)
|
const customerAudit = this.apiSuccess(module, '按客户查询操作日志', customerAuditResponse)
|
||||||
const customerAuditRow = customerAudit?.records?.find((item) => item.eventType === 'PLATFORM_TENANT_UPDATE' && String(item.accountId) === tenantId)
|
const customerAuditRow = customerAudit?.records?.find((item) => item.eventType === 'PLATFORM_TENANT_UPDATE' && String(item.accountId) === tenantId)
|
||||||
this.assert(module, '客户操作日志包含本轮编辑事件', customerAuditResponse, Boolean(customerAuditRow), `tenantId=${tenantId}, event=${customerAuditRow?.eventType || 'missing'}`)
|
let auditDiagnostic = 'event=missing'
|
||||||
|
if (!customerAuditRow) {
|
||||||
|
const unscopedResponse = await this.request('GET', `/api/platform/v1/audit/logs?eventType=PLATFORM_TENANT_UPDATE&resourceType=TENANT&resourceId=${tenantId}&page=1&size=20`)
|
||||||
|
const unscopedPage = unscopedResponse.http === 200 && String(unscopedResponse.body?.code) === '200'
|
||||||
|
? unscopedResponse.body?.data : null
|
||||||
|
const misplaced = unscopedPage?.records?.find((item) => item.eventType === 'PLATFORM_TENANT_UPDATE')
|
||||||
|
auditDiagnostic = misplaced
|
||||||
|
? `eventAccountId=${misplaced.accountId ?? 'missing'}, expectedAccountId=${tenantId}`
|
||||||
|
: `event=not-delivered, editRequestId=${editResponse.requestId || 'missing'}, editTraceId=${editResponse.traceId || 'missing'}`
|
||||||
|
}
|
||||||
|
this.assert(module, '客户操作日志包含本轮编辑事件', customerAuditResponse, Boolean(customerAuditRow),
|
||||||
|
`tenantId=${tenantId}, ${customerAuditRow ? `event=${customerAuditRow.eventType}` : auditDiagnostic}`)
|
||||||
if (customerAuditRow?.id) {
|
if (customerAuditRow?.id) {
|
||||||
const auditDetailResponse = await this.request('GET', `/api/platform/v1/audit/logs/${customerAuditRow.id}`)
|
const auditDetailResponse = await this.request('GET', `/api/platform/v1/audit/logs/${customerAuditRow.id}`)
|
||||||
const auditDetail = this.apiSuccess(module, '查询客户操作日志详情', auditDetailResponse)
|
const auditDetail = this.apiSuccess(module, '查询客户操作日志详情', auditDetailResponse)
|
||||||
@@ -434,7 +445,7 @@ export class AcceptanceRun {
|
|||||||
const qualificationImage = Uint8Array.from(Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', 'base64'))
|
const qualificationImage = Uint8Array.from(Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', 'base64'))
|
||||||
qualificationPackage.append('businessLicense', new Blob([qualificationImage], { type: 'image/png' }), `business-license-${suffix}.png`)
|
qualificationPackage.append('businessLicense', new Blob([qualificationImage], { type: 'image/png' }), `business-license-${suffix}.png`)
|
||||||
qualificationPackage.append('legalPersonId', new Blob([qualificationImage], { type: 'image/png' }), `legal-person-id-${suffix}.png`)
|
qualificationPackage.append('legalPersonId', new Blob([qualificationImage], { type: 'image/png' }), `legal-person-id-${suffix}.png`)
|
||||||
qualificationPackage.append('unifiedSocialCreditCode', `91440300${suffix.replace(/[^0-9A-Z]/gi, '').toUpperCase().padStart(10, '0').slice(-10)}`)
|
qualificationPackage.append('unifiedSocialCreditCode', `91440301${suffix.replace(/[^0-9A-Z]/gi, '').toUpperCase().padStart(10, '0').slice(-10)}`)
|
||||||
const packageResponse = await this.requestWithBody('POST', `/api/platform/v1/files/qualifications/${tenantId}/required-package`, qualificationPackage)
|
const packageResponse = await this.requestWithBody('POST', `/api/platform/v1/files/qualifications/${tenantId}/required-package`, qualificationPackage)
|
||||||
this.apiSuccess(module, '上传审核所需客户资质包', packageResponse, `tenantId=${tenantId}`)
|
this.apiSuccess(module, '上传审核所需客户资质包', packageResponse, `tenantId=${tenantId}`)
|
||||||
const qualificationResponse = await this.request('GET', `${detailPath}/qualifications`); const qualifications = this.apiSuccess(module, '业务概况查询资质', qualificationResponse)
|
const qualificationResponse = await this.request('GET', `${detailPath}/qualifications`); const qualifications = this.apiSuccess(module, '业务概况查询资质', qualificationResponse)
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ test('客户验收覆盖客户维度操作日志列表和详情快照', () => {
|
|||||||
assert.match(acceptance, /audit\/logs\/\$\{customerAuditRow\.id\}/)
|
assert.match(acceptance, /audit\/logs\/\$\{customerAuditRow\.id\}/)
|
||||||
assert.match(acceptance, /JSON\.parse\(auditDetail\[field\]\)/)
|
assert.match(acceptance, /JSON\.parse\(auditDetail\[field\]\)/)
|
||||||
assert.match(acceptance, /snapshotsAreRedacted/)
|
assert.match(acceptance, /snapshotsAreRedacted/)
|
||||||
|
assert.match(acceptance, /eventAccountId=.*expectedAccountId=/)
|
||||||
|
assert.match(acceptance, /event=not-delivered, editRequestId=/)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('客户资质场景使用独立社会信用代码命名空间', () => {
|
||||||
|
assert.match(acceptance, /unifiedSocialCreditCode', `91440301/)
|
||||||
|
assert.doesNotMatch(operatingStatistics, /unifiedSocialCreditCode/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('客户详情经营统计模块登记三项独立正式接口与精度字段', () => {
|
test('客户详情经营统计模块登记三项独立正式接口与精度字段', () => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict'
|
|||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import test from 'node:test'
|
import test from 'node:test'
|
||||||
|
|
||||||
import { cleanupSucceeded } from './fee-items.mjs'
|
import { cleanupSucceeded, isAcceptanceFeeItem } from './fee-items.mjs'
|
||||||
|
|
||||||
const source = readFileSync(new URL('./fee-items.mjs', import.meta.url), 'utf8')
|
const source = readFileSync(new URL('./fee-items.mjs', import.meta.url), 'utf8')
|
||||||
|
|
||||||
@@ -20,3 +20,14 @@ test('cleanup treats successful deletion and an already absent resource as clean
|
|||||||
assert.equal(cleanupSucceeded({ http: 404, body: {} }), true)
|
assert.equal(cleanupSucceeded({ http: 404, body: {} }), true)
|
||||||
assert.equal(cleanupSucceeded({ http: 200, body: { code: 'A0422' } }), false)
|
assert.equal(cleanupSucceeded({ http: 200, body: { code: 'A0422' } }), false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('stale cleanup only recognizes the acceptance-owned code and name pair', () => {
|
||||||
|
assert.equal(isAcceptanceFeeItem({ feeCode: 'ACPT_813083345572', feeTypeName: '全量验收费用-813083345572-已编辑' }), true)
|
||||||
|
assert.equal(isAcceptanceFeeItem({ feeCode: 'FEE_TYPE_001', feeTypeName: '全量验收费用-001' }), false)
|
||||||
|
assert.equal(isAcceptanceFeeItem({ feeCode: 'ACPT_813083345572', feeTypeName: '正式费用项目' }), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('baseline checks run only after stale acceptance cleanup', () => {
|
||||||
|
assert.ok(source.indexOf('cleanupStaleAcceptanceItems(context)')
|
||||||
|
< source.indexOf("'分页总数110且默认20条对应6页'"))
|
||||||
|
})
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ function payload(suffix, overrides = {}) {
|
|||||||
function expectedCodes() {
|
function expectedCodes() {
|
||||||
return Array.from({ length: 110 }, (_, index) => `FEE_TYPE_${String(index + 1).padStart(3, '0')}`)
|
return Array.from({ length: 110 }, (_, index) => `FEE_TYPE_${String(index + 1).padStart(3, '0')}`)
|
||||||
}
|
}
|
||||||
|
export function isAcceptanceFeeItem(row) {
|
||||||
|
return /^ACPT_\d+$/.test(String(row?.feeCode || ''))
|
||||||
|
&& String(row?.feeTypeName || '').startsWith('全量验收费用-')
|
||||||
|
}
|
||||||
function fixture(context) {
|
function fixture(context) {
|
||||||
const candidates = [context.createdResources?.orders, context.createdResources?.testInbound,
|
const candidates = [context.createdResources?.orders, context.createdResources?.testInbound,
|
||||||
context.createdResources?.inboundMeasurement, context.context?.testInbound]
|
context.createdResources?.inboundMeasurement, context.context?.testInbound]
|
||||||
@@ -57,7 +61,26 @@ async function listAll(context) {
|
|||||||
return { response, page, rows: records(page) }
|
return { response, page, rows: records(page) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function cleanupStaleAcceptanceItems(context) {
|
||||||
|
const listed = await listAll(context)
|
||||||
|
const stale = listed.rows.filter(isAcceptanceFeeItem)
|
||||||
|
const failed = []
|
||||||
|
for (const row of stale) {
|
||||||
|
const response = await context.request('DELETE', `${BASE}/${encodeURIComponent(id(row.id))}`)
|
||||||
|
if (!cleanupSucceeded(response)) failed.push({ row, response })
|
||||||
|
}
|
||||||
|
const response = failed[0]?.response || listed.response
|
||||||
|
context.assert(MODULE, '前置清理历史验收临时费用项目', response, failed.length === 0,
|
||||||
|
failed.length === 0
|
||||||
|
? `stale=${stale.length}, cleaned=${stale.length}`
|
||||||
|
: `failed=${failed.map(({ row, response: failure }) => `${row.feeCode}:${failure.body?.code || failure.http}`).join(',')}`,
|
||||||
|
OPTIONS)
|
||||||
|
return failed.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
export async function run(context) {
|
export async function run(context) {
|
||||||
|
if (!await cleanupStaleAcceptanceItems(context)) return
|
||||||
|
|
||||||
const initialPageResponse = await context.request('GET', query({ page: 1, size: 20 }))
|
const initialPageResponse = await context.request('GET', query({ page: 1, size: 20 }))
|
||||||
const initialPage = context.apiSuccess(MODULE, '费用项目查看权限与分页查询', initialPageResponse,
|
const initialPage = context.apiSuccess(MODULE, '费用项目查看权限与分页查询', initialPageResponse,
|
||||||
'page=1,size=20', OPTIONS)
|
'page=1,size=20', OPTIONS)
|
||||||
|
|||||||
@@ -42,5 +42,6 @@ test('客户详情财务账单验收覆盖客户过滤、详情结构与查看
|
|||||||
assert.match(finance, /statementId\(statementDetail\) === createdStatementId/)
|
assert.match(finance, /statementId\(statementDetail\) === createdStatementId/)
|
||||||
assert.match(finance, /Array\.isArray\(statementDetail\?\.lines\)/)
|
assert.match(finance, /Array\.isArray\(statementDetail\?\.lines\)/)
|
||||||
assert.match(finance, /Array\.isArray\(statementDetail\?\.revisions\)/)
|
assert.match(finance, /Array\.isArray\(statementDetail\?\.revisions\)/)
|
||||||
assert.match(finance, /platform:finance:bill:view/)
|
assert.match(finance, /grantedPermissions\.has\(['"]platform:finance:customer-statement:list['"]\)/)
|
||||||
|
assert.doesNotMatch(finance, /platform:finance:bill:view/)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export async function run(context) {
|
|||||||
const permissions = context.apiSuccess(MODULE, '客户详情财务账单查看权限链可用', permissionResponse, '', OPTIONS)
|
const permissions = context.apiSuccess(MODULE, '客户详情财务账单查看权限链可用', permissionResponse, '', OPTIONS)
|
||||||
const grantedPermissions = new Set(rows(permissions).map((item) => id(item?.permissionCode ?? item)))
|
const grantedPermissions = new Set(rows(permissions).map((item) => id(item?.permissionCode ?? item)))
|
||||||
context.assert(MODULE, '财务账单列表查看权限已授予', permissionResponse,
|
context.assert(MODULE, '财务账单列表查看权限已授予', permissionResponse,
|
||||||
grantedPermissions.has('platform:finance:bill:view') || grantedPermissions.has('platform:finance:customer-statement:list'),
|
grantedPermissions.has('platform:finance:customer-statement:list'),
|
||||||
`permissions=${[...grantedPermissions].filter((item) => item.includes('finance')).join(',')}`, OPTIONS)
|
`permissions=${[...grantedPermissions].filter((item) => item.includes('finance')).join(',')}`, OPTIONS)
|
||||||
|
|
||||||
const statementListResponse = await context.request('GET', `${BASE}/statements?customerId=${encodeURIComponent(customerId)}`)
|
const statementListResponse = await context.request('GET', `${BASE}/statements?customerId=${encodeURIComponent(customerId)}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user