Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d95298e5d |
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"deploy/sql/README.md": "4c7475566d5b3ab7ebaeb26a9369c3b2daa2911adf648bd9df1cae348de9f5c1",
|
||||
"deploy/sql/头程数据库统一增量-MySQL8.sql": "55c9736c6998f59d48a76c5ba60e2a801dd0b8acbf209fcf0dae4830fb3fb485",
|
||||
"deploy/sql/海外区域统一增量-MySQL8.sql": "3fda99ff623735dc42844a50d9a80090ab478aaf916ebdf5fa21e5a6d054117a",
|
||||
"firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/controller/ContainerCalendarSourceController.java": "74f1f56fb224798004382e0f4b36140cf81a073f50a1ac212bc393e0d2dde159",
|
||||
"firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/dto/ContainerCalendarSource.java": "58edea28fff5a8357aa662b794d23983d7da987f7f11f9b4bc64a8b406e466c5",
|
||||
"firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/mapper/ContainerCalendarSourceMapper.java": "76556dc0b615c19d8b3aa8c4453af56dce72bb8782343fce6a09b8a36163a467",
|
||||
"firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/repository/ContainerCalendarSourceRepository.java": "881f000a5f9a2ebe10858ee4ab97fb2595189aef641bb90dc73b9c37bc6d1d7b",
|
||||
"firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/service/ContainerCalendarSourceService.java": "44c3927abb813c5d6f5c8d553795c8bf50fb945e9862984f1fe011da20d3695d",
|
||||
"firstleg/src/main/resources/openapi/appointment-calendar-sources-v1.yaml": "8fffd13df663c6eaaf7eaffaa063b24d531f33241d7adb94850ee146af6d22dd",
|
||||
"firstleg/src/test/java/com/baiyue/firstleg/terminaldrayage/mapper/ContainerCalendarSourceMapperTest.java": "f38e11e2509a030854c0b6f40f8f9577ed729bcbbff0666b180504f38aa93c0b",
|
||||
"firstleg/src/test/java/com/baiyue/firstleg/terminaldrayage/service/ContainerCalendarSourceServiceTest.java": "87a0fbe6f7b9a271e331641c7c8da27282a6f1df2ae9b3167d543bf78119f7e6",
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/calendar/WarehouseCalendarController.java": "17102d4a32640ccfd92a7e7e738a248d4c1f5ae8906b8b965f455eb9be572603",
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/calendar/WarehouseCalendarMapper.java": "80f3a96bee0fa7630afff100ddb051977e283902c4e7ef247b8152fb37c2400f",
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/calendar/WarehouseCalendarModels.java": "88824f1a88d24b9bd34c9e7023aaa00d2653849a9131bf619d7df0f5fd3a7a0f",
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/calendar/WarehouseCalendarRepository.java": "4395cce32c574ebee0b4437f6ec8bbe0a5aee62c19a6a451ee0f243eab7be558",
|
||||
"lastleg-service/src/main/java/com/baiyue/lastleg/calendar/WarehouseCalendarService.java": "886e9e5460e47962f5701ceeb5e94ba9d2a123c4c83f2791b739178c8bfe874a",
|
||||
"lastleg-service/src/main/resources/openapi/appointment-calendar-warehouse-v1.yaml": "06965771d34d761b869f90ee6ff3f2dca7589121c67a5adbe2081677ce5a563c",
|
||||
"lastleg-service/src/test/java/com/baiyue/lastleg/calendar/WarehouseCalendarMapperTest.java": "a17e359b39000036fd9bd80d6b0744018541fc7bbe846a0585ece629ff09dc6c",
|
||||
"lastleg-service/src/test/java/com/baiyue/lastleg/calendar/WarehouseCalendarServiceTest.java": "9ed34bea7163166d0f79f882f12b23033dae13ad13bd4eedc7e202aed5defb8f",
|
||||
"lastleg-service/src/test/java/com/baiyue/lastleg/fleet/trip/FleetTripApiContractTest.java": "c3a4cedac09f16f37442a6709b9d704a607f2e0238e9997687e44153c378f27a",
|
||||
"lastleg-service/src/test/java/com/baiyue/lastleg/fleet/trip/FleetTripAuthorizationTest.java": "5d9e8aded16aa4de3338d65edd1a2e6b4e42961498f22d99c702e0f8d491bcd6"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import subprocess, shutil, xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
root=Path.cwd()
|
||||
report=root/'lastleg-service/target/surefire-reports/TEST-com.baiyue.lastleg.dispatch.service.DispatchAggregatePersistenceTest.xml'
|
||||
properties=ET.parse(report).getroot().find('properties')
|
||||
classpath=next(item.attrib['value'] for item in properties if item.attrib['name']=='java.class.path')
|
||||
sources=[str(root/'lastleg-service/src/test/java/com/baiyue/lastleg/fleet/trip'/name) for name in ['FleetTripCalendarServiceTest.java','FleetTripCalendarMapperTest.java']]
|
||||
subprocess.run(['javac','-encoding','UTF-8','--release','17','-cp',classpath,'-d',str(root/'lastleg-service/target/test-classes'),*sources],check=True)
|
||||
result=subprocess.run([shutil.which('mvn'),' -T'.strip(),'1','-DforkCount=1','-DreuseForks=true','-pl','lastleg-service','surefire:test','-Dtest=FleetTripCalendarServiceTest,FleetTripCalendarMapperTest'],check=False)
|
||||
raise SystemExit(result.returncode)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,256 +0,0 @@
|
||||
{
|
||||
"capturedAt": "2026-10-19T23:34:24.6121293+08:00",
|
||||
"frozenManifest": ".logs/dispatch-merged-final-inputs.json",
|
||||
"frozenManifestSha256": "55373c9dd7d5a2cc9ab0756893650ab27d5691c6b7cc4086c03140b76b86c136",
|
||||
"firstPostRunAudit": {
|
||||
"files": 65,
|
||||
"unchanged": 65,
|
||||
"drift": 0
|
||||
},
|
||||
"currentAudit": {
|
||||
"files": 65,
|
||||
"unchanged": 64,
|
||||
"drift": [
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/FbaAppointmentRepartitionPersistenceTest.java",
|
||||
"frozen": "66071beb3fe6787894055c74f236fb4c72fffdb75565ed0ccb2932f546903cda",
|
||||
"actual": "f2f7174dd6e52f5d9caae36f8fc24aa2dc78145c1c390e8e16857bb066948a86"
|
||||
}
|
||||
]
|
||||
},
|
||||
"affectedRun": {
|
||||
"finishedAt": "2026-10-19T23:01:03+08:00",
|
||||
"log": ".logs/dispatch-merged-final-affected-consumers.maven.log",
|
||||
"total": 111,
|
||||
"passed": 110,
|
||||
"failures": 1,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"result": "FAILURE",
|
||||
"classes": [
|
||||
{
|
||||
"class": "com.baiyue.lastleg.controller.Phase4BrowserApiBoundaryTest",
|
||||
"total": 7,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.dispatch.service.DispatchMergedRelabelPersistenceTest",
|
||||
"total": 11,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.dispatch.service.DispatchRepairWorkflowTest",
|
||||
"total": 9,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.dispatch.service.DispatchServiceTest",
|
||||
"total": 5,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.dispatch.service.ReturnDispatchCandidatePersistenceTest",
|
||||
"total": 1,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.inboundplan.service.FbaAppointmentRepartitionPersistenceTest",
|
||||
"total": 8,
|
||||
"failures": 1,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.inboundplan.service.InboundPlanPaginationTest",
|
||||
"total": 3,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.inboundplan.work.AppointmentWorkDomainMapperTest",
|
||||
"total": 1,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.relabel.service.RelabelDispatchSourcePersistenceTest",
|
||||
"total": 16,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.transfer.service.WarehouseTransferServiceTest",
|
||||
"total": 50,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0
|
||||
}
|
||||
],
|
||||
"failure": "FbaAppointmentRepartitionPersistenceTest.existingTransportAndConcurrentRepartitionCannotDuplicateWork",
|
||||
"rootCause": "Fixture allocation dispatch_item_id=11/plan_pallet_id=12 did not match inserted item id=1/plan_pallet_id=NULL; current production join correctly requires matching dispatch, item, customer and plan pallet. Parent owns correction; original assertions retained."
|
||||
},
|
||||
"priorFullModule": {
|
||||
"total": 3075,
|
||||
"passed": 3056,
|
||||
"failures": 6,
|
||||
"errors": 4,
|
||||
"skipped": 9,
|
||||
"log": ".logs/dispatch-merged-final-full-module.maven.log"
|
||||
},
|
||||
"pending": {
|
||||
"nativeCancellation": "Local backend implementation and directly affected regressions complete: 94/94 directed; Lastleg full 3072 pass, 9 conditional skips, 0 failure/error; File full 242/242",
|
||||
"environment": "Deployment, test database, real HTTP and four UI browser acceptance newly authorized; parent coordinates execution, no environment verification performed by this chat"
|
||||
},
|
||||
"cancellationAffectedRun": {
|
||||
"finishedAt": "2026-10-19T23:18:32+08:00",
|
||||
"log": ".logs/dispatch-native-cancellation-affected.maven.log",
|
||||
"result": "SUCCESS",
|
||||
"total": 94,
|
||||
"passed": 94,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"inputManifest": ".logs/dispatch-native-cancellation-inputs.json",
|
||||
"frozenFiles": 74,
|
||||
"postRunDrift": 0,
|
||||
"classes": [
|
||||
{
|
||||
"class": "DispatchDeliveryArrangementPersistenceTest",
|
||||
"total": 3
|
||||
},
|
||||
{
|
||||
"class": "DispatchDeliveryFeesTest",
|
||||
"total": 6
|
||||
},
|
||||
{
|
||||
"class": "DispatchDeliveryServiceTest",
|
||||
"total": 6
|
||||
},
|
||||
{
|
||||
"class": "DeliveryTransferServiceTest",
|
||||
"total": 59
|
||||
},
|
||||
{
|
||||
"class": "ReturnOutboundClosureTest",
|
||||
"total": 11
|
||||
},
|
||||
{
|
||||
"class": "DispatchDeliveryCompletionWorkerTest",
|
||||
"total": 1
|
||||
},
|
||||
{
|
||||
"class": "FbaAppointmentRepartitionPersistenceTest",
|
||||
"total": 8
|
||||
}
|
||||
],
|
||||
"inputManifestSha256": "187ef121ef3c75686717c2dc009604943462889dff63b9b2ac4441e7e765591b"
|
||||
},
|
||||
"finalFullModule": {
|
||||
"result": "SUCCESS",
|
||||
"finishedAt": "2026-10-19T23:25:33+08:00",
|
||||
"log": ".logs/dispatch-final-full-module-closed.maven.log",
|
||||
"inputManifest": ".logs/dispatch-final-full-reactor-inputs.json",
|
||||
"frozenFiles": 1706,
|
||||
"preRunDrift": 0,
|
||||
"postRunDrift": 0,
|
||||
"total": 3081,
|
||||
"passed": 3072,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 9,
|
||||
"skippedCases": [
|
||||
{
|
||||
"class": "com.baiyue.lastleg.discard.CargoDiscardMysqlAcceptanceTest",
|
||||
"name": "createApprovalRejectionPendingAndInsufficientStockScenarios",
|
||||
"reason": "System property [cargo.discard.acceptance] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.service.TaillegRealConsumerAcceptanceTest",
|
||||
"name": "consumesRealOutboxAndCreatesEveryTaillegOrderType",
|
||||
"reason": "System property [tailleg.real.consumer] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.selfoperated.analytics.outbound.OutboundCandidateBuildMySqlAcceptanceTest",
|
||||
"name": "realCandidateBuildOnIndependentSyntheticFacts",
|
||||
"reason": "Environment variable [SELFOP_TEST_MYSQL_CANDIDATE_BUILD] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.selfoperated.analytics.inventory.InventoryPublicationMySqlAcceptanceTest",
|
||||
"name": "crossMidnightPublicationHasNoDailyMarkerAndCannotBackfill",
|
||||
"reason": "Environment variable [SELFOP_TEST_MYSQL_PUBLICATION] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.selfoperated.analytics.inventory.InventoryPublicationMySqlAcceptanceTest",
|
||||
"name": "successfulPublicationAndPublishedRecoveryKeepExactCommittedResult",
|
||||
"reason": "Environment variable [SELFOP_TEST_MYSQL_PUBLICATION] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.selfoperated.analytics.inventory.InventoryPublicationMySqlAcceptanceTest",
|
||||
"name": "laterSameDayPublicationPreservesFirstRepresentativeAndItsRows",
|
||||
"reason": "Environment variable [SELFOP_TEST_MYSQL_PUBLICATION] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.selfoperated.analytics.inventory.InventoryPublicationMySqlAcceptanceTest",
|
||||
"name": "pointerRunTaskSupersededAndDailyElectionRollBackAfterRealSqlFault",
|
||||
"reason": "Environment variable [SELFOP_TEST_MYSQL_PUBLICATION] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.returnreceipt.service.ReturnSkuConversionPersistenceTest",
|
||||
"name": "mysqlPageLocksConvertedSkuUntilConfirmationWithoutChangingPhysicalUnit(String)",
|
||||
"reason": "System property [returnSku.test.mysql] does not exist"
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.returnreceipt.service.ReturnSkuConversionPersistenceTest",
|
||||
"name": "mysqlPageCollatesCaseAndAccentsWithoutJoiningOtherCustomerWarehouseOrSku(String)",
|
||||
"reason": "System property [returnSku.test.mysql] does not exist"
|
||||
}
|
||||
],
|
||||
"inputManifestSha256": "4ac18b73c5b9e6599a8c7f9729ab4a2a34f8145aeddb6d72c8935efaf7287cc2"
|
||||
},
|
||||
"fileProviderRun": {
|
||||
"result": "SUCCESS",
|
||||
"finishedAt": "2026-10-19T23:33:52+08:00",
|
||||
"log": ".logs/dispatch-evidence-file-final-full.maven.log",
|
||||
"inputManifest": ".logs/dispatch-evidence-file-final-inputs.json",
|
||||
"inputManifestSha256": "f49a0707b7ea2241d7c11c90311d25b9a50eec0310fc192d445bc351c9ba78ae",
|
||||
"frozenFiles": 289,
|
||||
"preRunDrift": 0,
|
||||
"postRunDrift": 0,
|
||||
"total": 242,
|
||||
"passed": 242,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"scope": [
|
||||
{
|
||||
"path": "file/AGENTS.md",
|
||||
"sha256": "c3236c7e89151f8f7b1da540ed8b591982e1200aafb89f45cb49230815d320c7"
|
||||
},
|
||||
{
|
||||
"path": "file/src/main/java/com/baiyue/file/service/BusinessFileCategory.java",
|
||||
"sha256": "b274532a0e4a263c56558eae68eb5717182791dec8e399e21bd459f6dffd32ff"
|
||||
},
|
||||
{
|
||||
"path": "file/src/main/resources/openapi/dispatch-evidence-v1.yaml",
|
||||
"sha256": "b3bc23d9f25513b258f0282886743e4323cb65b89c0203d4d2921ac89da08d14"
|
||||
},
|
||||
{
|
||||
"path": "file/src/test/java/com/baiyue/file/service/DispatchEvidenceFileTest.java",
|
||||
"sha256": "bba87946457fb1290960218127087552de95b59f443eb6d5dacf354084d04a19"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
{
|
||||
"capturedAt": "2026-10-19T22:57:12.4378746+08:00",
|
||||
"log": ".logs/dispatch-merged-final-affected-consumers.maven.log",
|
||||
"fullModulePrior": {
|
||||
"total": 3075,
|
||||
"passed": 3056,
|
||||
"failures": 6,
|
||||
"errors": 4,
|
||||
"skipped": 9,
|
||||
"log": ".logs/dispatch-merged-final-full-module.maven.log"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchPlanningModels.java",
|
||||
"sha256": "47489d22ab81913ab23c319c04561371cbdf1e1c43034fe5b1d24fe94038137e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchViews.java",
|
||||
"sha256": "d34d5a810ea7658ffd2623f53970435ecee116663bd969339de84432e38cd573"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchContracts.java",
|
||||
"sha256": "5086523d9df7c7d00840d391e9608b1685e4edb71d19154b1608339afe7421e2"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPalletLock.java",
|
||||
"sha256": "2988eee05074b78728878fef6dd45d0df3dba8cc7c219ebfd583bf7650a379b3"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPhysicalPalletLock.java",
|
||||
"sha256": "3044dc6d8780f96b4ff7d6303a2b15ed458c201496788a98c3b28cad7449e0f8"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchItemSource.java",
|
||||
"sha256": "02dc868bef1646a02143969f7aad13b4e92cd04d4a8d69c8c71ffc07f7a50360"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchSourceMapper.java",
|
||||
"sha256": "1bec0687e9d1d3a2404d25a37aad092d18b7134eab605594f352a5432360ac76"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchPhysicalClaimMapper.java",
|
||||
"sha256": "9ae01c8669beb2fcf5e359d2e26e13e07c2a496bbe22036a408f3dd49d2ec2fa"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchItemSourceMapper.java",
|
||||
"sha256": "8d6b4bf84e27c18b3c8faad15dbf73018485996ca5d4dbb00bdf9ba2ab158d2d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchExecutionReadMapper.java",
|
||||
"sha256": "54666dbd5968ebd9d2cb8fc9678a8a385e60591f62c90a850be513f93546906d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchCandidateMapper.java",
|
||||
"sha256": "7c0269c3e5179add0ebb772cd7674ddf899039afad179bff06f7524017934573"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/ReturnDispatchCandidateMapper.java",
|
||||
"sha256": "a99080e851a6d22c5ecb1229e761382d846d1f5e4b92a3c69d30716af125746d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchSourceRepository.java",
|
||||
"sha256": "04b5d5160614b17a31030f23167d9e32aa89e13be7ef2e33c9d91359ef684348"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchPhysicalClaimRepository.java",
|
||||
"sha256": "27f37b5e683b92d82d9cf63a88b2135ada5f597e652474eef52d7c985b870b31"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchItemSourceRepository.java",
|
||||
"sha256": "2bcef5d9952750235ecabcf429e4eab9b9a9c0a3cac0b3e02b083120f85df28e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java",
|
||||
"sha256": "c95a0d4075df7628e4443f87be4d2d906aee5cbb95148d5fd3869d6ec7932465"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchAggregateService.java",
|
||||
"sha256": "ec0ce406d4244a0abf34ee9ede97b788675b39234fbb8e6d0ff9579dde360145"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPickingService.java",
|
||||
"sha256": "17a461a599cc0702b519d1333c5e136860eff7b638d739dde7e0bd203bcfc4ec"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPdaQueryService.java",
|
||||
"sha256": "0f59acc9c3ed6fd2995c1ed59810146c0056d1462e4e23d85f52198a1ffe0296"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDepartureService.java",
|
||||
"sha256": "fc9440c6755316c58572f3fed5a576c5721098a3d5d7a036eecd3d6d752f1ea0"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimService.java",
|
||||
"sha256": "063b557cd488bf2281516df744f12123473269be12f56a5155facad018e6408e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourceService.java",
|
||||
"sha256": "ee42766e7f86f896df1839e15987382c8aebc3484449b2104312378eaababbba"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/entity/DispatchPdaPickOrder.java",
|
||||
"sha256": "3d66df6566b467580c89aa5f9f585aba610b05ca2de07ad28a3d6a6f30ab10e3"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionService.java",
|
||||
"sha256": "83947030468892ee1d4a02b354e855d7977f55fcc17de440f324cf24940a10d8"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/mapper/DispatchWholePdaReadMapper.java",
|
||||
"sha256": "4df97c47b2ca481eb5f8f32e7735bb15a80aa4e561bea7ab349f09352ca9db1e"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDraftService.java",
|
||||
"sha256": "a2682e87f8bbf47a799d8d54ae05b8acdef52414016cab116eb9a40fe1364e04"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchDraftRepository.java",
|
||||
"sha256": "f28b7aff08afdf634387e6abb7919a807fd6a2ff54ff7869b3e1e4d453f2c92b"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchDraftClaimMapper.java",
|
||||
"sha256": "32dd25dc737d7c36f3a35f1a97bd2865cf433368aaccce2162585a30d6b07641"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchMergedRelabelPersistenceTest.java",
|
||||
"sha256": "1c36d64a389bf12e55cfb8cbb29b7dd333bc952f66e8bb88d441ddf42f83c653"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAggregatePersistenceTest.java",
|
||||
"sha256": "8f5907aa180db30a2b56fb6b251f9ae7a94fa550666239947b660cb5431fe978"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPickingPersistenceTest.java",
|
||||
"sha256": "0971e32ae147a03a730c16f1a75f0576e3a9122f92c5c65608db0cb9a76a3510"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimPersistenceTest.java",
|
||||
"sha256": "02bd34b71fdb237566e99fab0b748c3ed333ace4ae65042aaf315b06695299f6"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchWholeSourcePersistenceTest.java",
|
||||
"sha256": "0143045a52df440dc8be72706d69cbc45a9d210ddfb4ce77762423533dcc1a55"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPdaReadPersistenceTest.java",
|
||||
"sha256": "9b4402d0dd3f0eefa8b6b9bfe65e20f42f3e60619ac6989b18c9a74cbebad0ad"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAppointmentCancellationPersistenceTest.java",
|
||||
"sha256": "0be4d1f344374147149f248bbc2aaac486484ad4a0e9ba1681295aa6fd5ae21d"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionServiceTest.java",
|
||||
"sha256": "ec3ab8341cec7ae692501ba264178d5d520923b7c2dcf20dfaa620313c9d03d4"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchDraftPersistenceTest.java",
|
||||
"sha256": "35b7c411e452dce2189c22f8cf31d77083f8854062435a9223e306a1a9d44a6a"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourcePersistenceTest.java",
|
||||
"sha256": "24e1b3f0dba4d4f9c1f724840c7a263ff0d1561cb5cb509fb0c410be8187afb0"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchRepairWorkflowTest.java",
|
||||
"sha256": "4a4d01424e91fd1b55b0af4721e02c4acad065e958ff4a0b9726cf726691fbdf"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/resources/db/lastleg.sql",
|
||||
"sha256": "61946a41d773e856e3d3f9463f7ff5bfe0e904856598e4a64c8cbd0936ef55b5"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "deploy/sql/海外区域统一增量-MySQL8.sql",
|
||||
"sha256": "4f31c8731dbb54955555d13f027c24a537aee8a317f744f7bf50b59cb22694b1"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryHoldConcurrencyPersistenceTest.java",
|
||||
"sha256": "e146136299db24b1cf618faf2161fa284d9eec15a26a75e8352548cd7dbe7e94"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java",
|
||||
"sha256": "c3a4ceba06b722d5a0bba810eaa948bd364a09ff5599c3176207d5c28b39b7fc"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/mapper/PdaPalletOperationMapper.java",
|
||||
"sha256": "960bb99f8432524e5a4bc76a61ccde8273929ad9de5e21ae0b44d941edeb6c9d"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/repository/PdaPalletOperationRepository.java",
|
||||
"sha256": "55d243f6f419f112d3f89005ce37af0d6446e7b21d3b00f5931b56f3ea556302"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java",
|
||||
"sha256": "eae67e13f9d1d3e8ff8a76b30a8a72d445e54b3cd6a30394c5ea41f763f48a7c"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletDispatchFreezePersistenceTest.java",
|
||||
"sha256": "a8ef7e364e4d0fb97f83515dd1d3b983cdac4f367a9335fe181c39a47719720f"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "../docs/海外仓业务/排车列表接口与数据设计.md",
|
||||
"sha256": "521169378de4ee51c9af4f8cbe331284f35bf60f137253d9751f2ba3480e95ea"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/port/RelabelDispatchSourcePort.java",
|
||||
"sha256": "af771fd474faf6c411543b077c646479e6368b98ab3cab875c4cd6c0b3b24978"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/service/RelabelDispatchSourceService.java",
|
||||
"sha256": "949ea59036d710af0cc0b81848a77e17da0da3de049e44124a36be141ee81fe0"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/repository/RelabelDispatchSourceRepository.java",
|
||||
"sha256": "12b9577391f0908d94e4e2b307f7572e4825f556307145f8a83d0294516a2c46"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/mapper/RelabelDispatchSourceMapper.java",
|
||||
"sha256": "6dd3902b7f64d40f8db5ae1f3dd3640e91a69cadd6c895b1f3a81ac48b93ebf0"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/relabel/service/RelabelDispatchSourcePersistenceTest.java",
|
||||
"sha256": "6eb43b35de92364884e9ffbd36c18c3921ac8c21c959602383f9ca9cc8c4ece5"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/port/PhysicalPalletSerialPort.java",
|
||||
"sha256": "4aa97a0c9bf0f4a9138ec15ac32e512ff13224e9a6f0e0817c5b0852f9635746"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/service/PhysicalPalletSerialService.java",
|
||||
"sha256": "4876ed0fc6267d9b5986fde0f2e8096ec01db35cd2f0cadbaeb3ebad2e03b76b"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/repository/PhysicalPalletSerialRepository.java",
|
||||
"sha256": "0489e8fa5806fd0faa4a61c4a0c7a9bf89d086537752f218dcbcaed08475487e"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/mapper/PhysicalPalletSerialMapper.java",
|
||||
"sha256": "237fe76c88d572b0d70eb25d84d191dcc0d2fdbc3a031e728e6bbbf88a8aa25f"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inventory/service/PhysicalPalletSerialPersistenceTest.java",
|
||||
"sha256": "444bd8d361f4d90fbdaf1e4d1d205906b5452096670f57bd3459906716e36c7e"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/controller/Phase4BrowserApiBoundaryTest.java",
|
||||
"sha256": "4fbf6bab69cfaff409d0d228a1169c63db0f092e9c1c6e2f70bb956f1d3ed70f"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java",
|
||||
"sha256": "a9a2e25ff22e326925104e48ff1cfed34fec3350dfb569f1e7f19a4e186925c7"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/ReturnDispatchCandidatePersistenceTest.java",
|
||||
"sha256": "4170a35b6f57d9058577941ef665130e0f3a3faeef37c92c9e93a69dd9f0f60a"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/FbaAppointmentRepartitionPersistenceTest.java",
|
||||
"sha256": "66071beb3fe6787894055c74f236fb4c72fffdb75565ed0ccb2932f546903cda"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanPaginationTest.java",
|
||||
"sha256": "b9196d489830c2f4bf24ebcaf3e94adf4e0484f414f373c300b0f4a2a538679b"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/AppointmentWorkDomainMapperTest.java",
|
||||
"sha256": "5fbe3b3be8be194d1f31006e4e05187cd629236c376e01da2d291a2593e70e0a"
|
||||
},
|
||||
{
|
||||
"group": "final-related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/transfer/service/WarehouseTransferServiceTest.java",
|
||||
"sha256": "787e78907d019458e3533325ed2bfe8cc09eb8de7ca1db2c0b98a54239a56fe5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
{
|
||||
"capturedAt": "2026-10-19T22:39:26.3372438+08:00",
|
||||
"command": "mvn -pl lastleg-service -am test",
|
||||
"log": ".logs/dispatch-merged-final-full-module.maven.log",
|
||||
"files": [
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchPlanningModels.java",
|
||||
"sha256": "47489d22ab81913ab23c319c04561371cbdf1e1c43034fe5b1d24fe94038137e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchViews.java",
|
||||
"sha256": "d34d5a810ea7658ffd2623f53970435ecee116663bd969339de84432e38cd573"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchContracts.java",
|
||||
"sha256": "5086523d9df7c7d00840d391e9608b1685e4edb71d19154b1608339afe7421e2"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPalletLock.java",
|
||||
"sha256": "2988eee05074b78728878fef6dd45d0df3dba8cc7c219ebfd583bf7650a379b3"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPhysicalPalletLock.java",
|
||||
"sha256": "3044dc6d8780f96b4ff7d6303a2b15ed458c201496788a98c3b28cad7449e0f8"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchItemSource.java",
|
||||
"sha256": "02dc868bef1646a02143969f7aad13b4e92cd04d4a8d69c8c71ffc07f7a50360"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchSourceMapper.java",
|
||||
"sha256": "1bec0687e9d1d3a2404d25a37aad092d18b7134eab605594f352a5432360ac76"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchPhysicalClaimMapper.java",
|
||||
"sha256": "9ae01c8669beb2fcf5e359d2e26e13e07c2a496bbe22036a408f3dd49d2ec2fa"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchItemSourceMapper.java",
|
||||
"sha256": "8d6b4bf84e27c18b3c8faad15dbf73018485996ca5d4dbb00bdf9ba2ab158d2d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchExecutionReadMapper.java",
|
||||
"sha256": "54666dbd5968ebd9d2cb8fc9678a8a385e60591f62c90a850be513f93546906d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchCandidateMapper.java",
|
||||
"sha256": "7c0269c3e5179add0ebb772cd7674ddf899039afad179bff06f7524017934573"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/ReturnDispatchCandidateMapper.java",
|
||||
"sha256": "a99080e851a6d22c5ecb1229e761382d846d1f5e4b92a3c69d30716af125746d"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchSourceRepository.java",
|
||||
"sha256": "04b5d5160614b17a31030f23167d9e32aa89e13be7ef2e33c9d91359ef684348"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchPhysicalClaimRepository.java",
|
||||
"sha256": "27f37b5e683b92d82d9cf63a88b2135ada5f597e652474eef52d7c985b870b31"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchItemSourceRepository.java",
|
||||
"sha256": "2bcef5d9952750235ecabcf429e4eab9b9a9c0a3cac0b3e02b083120f85df28e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java",
|
||||
"sha256": "c95a0d4075df7628e4443f87be4d2d906aee5cbb95148d5fd3869d6ec7932465"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchAggregateService.java",
|
||||
"sha256": "ec0ce406d4244a0abf34ee9ede97b788675b39234fbb8e6d0ff9579dde360145"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPickingService.java",
|
||||
"sha256": "17a461a599cc0702b519d1333c5e136860eff7b638d739dde7e0bd203bcfc4ec"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPdaQueryService.java",
|
||||
"sha256": "0f59acc9c3ed6fd2995c1ed59810146c0056d1462e4e23d85f52198a1ffe0296"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDepartureService.java",
|
||||
"sha256": "fc9440c6755316c58572f3fed5a576c5721098a3d5d7a036eecd3d6d752f1ea0"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimService.java",
|
||||
"sha256": "063b557cd488bf2281516df744f12123473269be12f56a5155facad018e6408e"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourceService.java",
|
||||
"sha256": "ee42766e7f86f896df1839e15987382c8aebc3484449b2104312378eaababbba"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/entity/DispatchPdaPickOrder.java",
|
||||
"sha256": "3d66df6566b467580c89aa5f9f585aba610b05ca2de07ad28a3d6a6f30ab10e3"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionService.java",
|
||||
"sha256": "83947030468892ee1d4a02b354e855d7977f55fcc17de440f324cf24940a10d8"
|
||||
},
|
||||
{
|
||||
"group": "dispatch",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/mapper/DispatchWholePdaReadMapper.java",
|
||||
"sha256": "4df97c47b2ca481eb5f8f32e7735bb15a80aa4e561bea7ab349f09352ca9db1e"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDraftService.java",
|
||||
"sha256": "a2682e87f8bbf47a799d8d54ae05b8acdef52414016cab116eb9a40fe1364e04"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchDraftRepository.java",
|
||||
"sha256": "f28b7aff08afdf634387e6abb7919a807fd6a2ff54ff7869b3e1e4d453f2c92b"
|
||||
},
|
||||
{
|
||||
"group": "sharedDraft",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchDraftClaimMapper.java",
|
||||
"sha256": "32dd25dc737d7c36f3a35f1a97bd2865cf433368aaccce2162585a30d6b07641"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchMergedRelabelPersistenceTest.java",
|
||||
"sha256": "1c36d64a389bf12e55cfb8cbb29b7dd333bc952f66e8bb88d441ddf42f83c653"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAggregatePersistenceTest.java",
|
||||
"sha256": "8f5907aa180db30a2b56fb6b251f9ae7a94fa550666239947b660cb5431fe978"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPickingPersistenceTest.java",
|
||||
"sha256": "0971e32ae147a03a730c16f1a75f0576e3a9122f92c5c65608db0cb9a76a3510"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimPersistenceTest.java",
|
||||
"sha256": "02bd34b71fdb237566e99fab0b748c3ed333ace4ae65042aaf315b06695299f6"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchWholeSourcePersistenceTest.java",
|
||||
"sha256": "0143045a52df440dc8be72706d69cbc45a9d210ddfb4ce77762423533dcc1a55"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPdaReadPersistenceTest.java",
|
||||
"sha256": "9b4402d0dd3f0eefa8b6b9bfe65e20f42f3e60619ac6989b18c9a74cbebad0ad"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAppointmentCancellationPersistenceTest.java",
|
||||
"sha256": "0be4d1f344374147149f248bbc2aaac486484ad4a0e9ba1681295aa6fd5ae21d"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionServiceTest.java",
|
||||
"sha256": "ec3ab8341cec7ae692501ba264178d5d520923b7c2dcf20dfaa620313c9d03d4"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchDraftPersistenceTest.java",
|
||||
"sha256": "35b7c411e452dce2189c22f8cf31d77083f8854062435a9223e306a1a9d44a6a"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourcePersistenceTest.java",
|
||||
"sha256": "24e1b3f0dba4d4f9c1f724840c7a263ff0d1561cb5cb509fb0c410be8187afb0"
|
||||
},
|
||||
{
|
||||
"group": "tests",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchRepairWorkflowTest.java",
|
||||
"sha256": "4a4d01424e91fd1b55b0af4721e02c4acad065e958ff4a0b9726cf726691fbdf"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/resources/db/lastleg.sql",
|
||||
"sha256": "61946a41d773e856e3d3f9463f7ff5bfe0e904856598e4a64c8cbd0936ef55b5"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "deploy/sql/海外区域统一增量-MySQL8.sql",
|
||||
"sha256": "4f31c8731dbb54955555d13f027c24a537aee8a317f744f7bf50b59cb22694b1"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryHoldConcurrencyPersistenceTest.java",
|
||||
"sha256": "e146136299db24b1cf618faf2161fa284d9eec15a26a75e8352548cd7dbe7e94"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java",
|
||||
"sha256": "c3a4ceba06b722d5a0bba810eaa948bd364a09ff5599c3176207d5c28b39b7fc"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/mapper/PdaPalletOperationMapper.java",
|
||||
"sha256": "960bb99f8432524e5a4bc76a61ccde8273929ad9de5e21ae0b44d941edeb6c9d"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/repository/PdaPalletOperationRepository.java",
|
||||
"sha256": "55d243f6f419f112d3f89005ce37af0d6446e7b21d3b00f5931b56f3ea556302"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java",
|
||||
"sha256": "eae67e13f9d1d3e8ff8a76b30a8a72d445e54b3cd6a30394c5ea41f763f48a7c"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletDispatchFreezePersistenceTest.java",
|
||||
"sha256": "a8ef7e364e4d0fb97f83515dd1d3b983cdac4f367a9335fe181c39a47719720f"
|
||||
},
|
||||
{
|
||||
"group": "related",
|
||||
"path": "../docs/海外仓业务/排车列表接口与数据设计.md",
|
||||
"sha256": "e3986c47f1b0a093a9dfd53038328211d96194eeb0abf0374df0a45d3090ebe6"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,302 +0,0 @@
|
||||
{
|
||||
"capturedAt": "2026-10-19T23:12:11.1283856+08:00",
|
||||
"log": ".logs/dispatch-native-cancellation-affected.maven.log",
|
||||
"files": [
|
||||
{
|
||||
"path": "../docs/海外仓业务/排车列表接口与数据设计.md",
|
||||
"sha256": "521169378de4ee51c9af4f8cbe331284f35bf60f137253d9751f2ba3480e95ea"
|
||||
},
|
||||
{
|
||||
"path": "deploy/sql/海外区域统一增量-MySQL8.sql",
|
||||
"sha256": "4f31c8731dbb54955555d13f027c24a537aee8a317f744f7bf50b59cb22694b1"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/delivery/repository/DeliveryCancellationRepository.java",
|
||||
"sha256": "52409141461491b48ac5828c3d85a8ee5d578678d2d670c87cc73a707225bcdb"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java",
|
||||
"sha256": "bb036a0cfb01324eba14bb36b623047367bf31c2727be82b6d3728635fb591ce"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchItemSource.java",
|
||||
"sha256": "02dc868bef1646a02143969f7aad13b4e92cd04d4a8d69c8c71ffc07f7a50360"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPalletLock.java",
|
||||
"sha256": "2988eee05074b78728878fef6dd45d0df3dba8cc7c219ebfd583bf7650a379b3"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchPhysicalPalletLock.java",
|
||||
"sha256": "3044dc6d8780f96b4ff7d6303a2b15ed458c201496788a98c3b28cad7449e0f8"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchCandidateMapper.java",
|
||||
"sha256": "7c0269c3e5179add0ebb772cd7674ddf899039afad179bff06f7524017934573"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchDraftClaimMapper.java",
|
||||
"sha256": "32dd25dc737d7c36f3a35f1a97bd2865cf433368aaccce2162585a30d6b07641"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchExecutionReadMapper.java",
|
||||
"sha256": "54666dbd5968ebd9d2cb8fc9678a8a385e60591f62c90a850be513f93546906d"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchItemSourceMapper.java",
|
||||
"sha256": "8d6b4bf84e27c18b3c8faad15dbf73018485996ca5d4dbb00bdf9ba2ab158d2d"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchPhysicalClaimMapper.java",
|
||||
"sha256": "9ae01c8669beb2fcf5e359d2e26e13e07c2a496bbe22036a408f3dd49d2ec2fa"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchSourceMapper.java",
|
||||
"sha256": "1bec0687e9d1d3a2404d25a37aad092d18b7134eab605594f352a5432360ac76"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/ReturnDispatchCandidateMapper.java",
|
||||
"sha256": "a99080e851a6d22c5ecb1229e761382d846d1f5e4b92a3c69d30716af125746d"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/entity/DispatchPdaPickOrder.java",
|
||||
"sha256": "3d66df6566b467580c89aa5f9f585aba610b05ca2de07ad28a3d6a6f30ab10e3"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/mapper/DispatchWholePdaReadMapper.java",
|
||||
"sha256": "4df97c47b2ca481eb5f8f32e7735bb15a80aa4e561bea7ab349f09352ca9db1e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionService.java",
|
||||
"sha256": "83947030468892ee1d4a02b354e855d7977f55fcc17de440f324cf24940a10d8"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchContracts.java",
|
||||
"sha256": "5086523d9df7c7d00840d391e9608b1685e4edb71d19154b1608339afe7421e2"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchPlanningModels.java",
|
||||
"sha256": "47489d22ab81913ab23c319c04561371cbdf1e1c43034fe5b1d24fe94038137e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/port/DispatchViews.java",
|
||||
"sha256": "d34d5a810ea7658ffd2623f53970435ecee116663bd969339de84432e38cd573"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchDraftRepository.java",
|
||||
"sha256": "f28b7aff08afdf634387e6abb7919a807fd6a2ff54ff7869b3e1e4d453f2c92b"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchItemSourceRepository.java",
|
||||
"sha256": "2bcef5d9952750235ecabcf429e4eab9b9a9c0a3cac0b3e02b083120f85df28e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchPhysicalClaimRepository.java",
|
||||
"sha256": "27f37b5e683b92d82d9cf63a88b2135ada5f597e652474eef52d7c985b870b31"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/repository/DispatchSourceRepository.java",
|
||||
"sha256": "04b5d5160614b17a31030f23167d9e32aa89e13be7ef2e33c9d91359ef684348"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchAggregateService.java",
|
||||
"sha256": "ec0ce406d4244a0abf34ee9ede97b788675b39234fbb8e6d0ff9579dde360145"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDepartureService.java",
|
||||
"sha256": "fc9440c6755316c58572f3fed5a576c5721098a3d5d7a036eecd3d6d752f1ea0"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchDraftService.java",
|
||||
"sha256": "a2682e87f8bbf47a799d8d54ae05b8acdef52414016cab116eb9a40fe1364e04"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourceService.java",
|
||||
"sha256": "ee42766e7f86f896df1839e15987382c8aebc3484449b2104312378eaababbba"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPdaQueryService.java",
|
||||
"sha256": "0f59acc9c3ed6fd2995c1ed59810146c0056d1462e4e23d85f52198a1ffe0296"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimService.java",
|
||||
"sha256": "063b557cd488bf2281516df744f12123473269be12f56a5155facad018e6408e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchPickingService.java",
|
||||
"sha256": "17a461a599cc0702b519d1333c5e136860eff7b638d739dde7e0bd203bcfc4ec"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchService.java",
|
||||
"sha256": "c95a0d4075df7628e4443f87be4d2d906aee5cbb95148d5fd3869d6ec7932465"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/mapper/PhysicalPalletSerialMapper.java",
|
||||
"sha256": "237fe76c88d572b0d70eb25d84d191dcc0d2fdbc3a031e728e6bbbf88a8aa25f"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/port/PhysicalPalletSerialPort.java",
|
||||
"sha256": "4aa97a0c9bf0f4a9138ec15ac32e512ff13224e9a6f0e0817c5b0852f9635746"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/repository/PhysicalPalletSerialRepository.java",
|
||||
"sha256": "0489e8fa5806fd0faa4a61c4a0c7a9bf89d086537752f218dcbcaed08475487e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/inventory/service/PhysicalPalletSerialService.java",
|
||||
"sha256": "4876ed0fc6267d9b5986fde0f2e8096ec01db35cd2f0cadbaeb3ebad2e03b76b"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/mapper/PdaPalletOperationMapper.java",
|
||||
"sha256": "960bb99f8432524e5a4bc76a61ccde8273929ad9de5e21ae0b44d941edeb6c9d"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/repository/PdaPalletOperationRepository.java",
|
||||
"sha256": "55d243f6f419f112d3f89005ce37af0d6446e7b21d3b00f5931b56f3ea556302"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java",
|
||||
"sha256": "c3a4ceba06b722d5a0bba810eaa948bd364a09ff5599c3176207d5c28b39b7fc"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/mapper/RelabelDispatchSourceMapper.java",
|
||||
"sha256": "6dd3902b7f64d40f8db5ae1f3dd3640e91a69cadd6c895b1f3a81ac48b93ebf0"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/port/RelabelDispatchSourcePort.java",
|
||||
"sha256": "af771fd474faf6c411543b077c646479e6368b98ab3cab875c4cd6c0b3b24978"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/repository/RelabelDispatchSourceRepository.java",
|
||||
"sha256": "12b9577391f0908d94e4e2b307f7572e4825f556307145f8a83d0294516a2c46"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/relabel/service/RelabelDispatchSourceService.java",
|
||||
"sha256": "949ea59036d710af0cc0b81848a77e17da0da3de049e44124a36be141ee81fe0"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/resources/db/lastleg.sql",
|
||||
"sha256": "61946a41d773e856e3d3f9463f7ff5bfe0e904856598e4a64c8cbd0936ef55b5"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/controller/Phase4BrowserApiBoundaryTest.java",
|
||||
"sha256": "4fbf6bab69cfaff409d0d228a1169c63db0f092e9c1c6e2f70bb956f1d3ed70f"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/DeliveryDispatchFixtures.java",
|
||||
"sha256": "1dc488f6d614d0038a54ea81ecf1ca15c40887bcf951f5f96df436511a8cec86"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/DispatchDeliveryArrangementPersistenceTest.java",
|
||||
"sha256": "b989d8db720bd10aa4c928297ed387486353a06922d043d298b234bbc3c26b29"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/DispatchDeliveryFeesTest.java",
|
||||
"sha256": "57928866a589890689ff729a234a5a1b1a93e39e2ad6a11dae7c05bb312261e4"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/DispatchDeliveryServiceTest.java",
|
||||
"sha256": "cd2b7753a44aeb34f5b2f88bae8349ecb8eeea5c96ecd3796391570a8662b9ca"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/DeliveryTransferServiceTest.java",
|
||||
"sha256": "6e37ddaf197138e06b6b0d2d3ca908c58e23f8a2e01fb18791cb38b8ff1fd5be"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/delivery/service/ReturnOutboundClosureTest.java",
|
||||
"sha256": "178d6781adf4c6f08be8569ec869566ea97391ead064ca460b9b3e812ca9e585"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/pda/service/DispatchPickOrderAttributionServiceTest.java",
|
||||
"sha256": "ec3ab8341cec7ae692501ba264178d5d520923b7c2dcf20dfaa620313c9d03d4"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAggregatePersistenceTest.java",
|
||||
"sha256": "8f5907aa180db30a2b56fb6b251f9ae7a94fa550666239947b660cb5431fe978"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchAppointmentCancellationPersistenceTest.java",
|
||||
"sha256": "0be4d1f344374147149f248bbc2aaac486484ad4a0e9ba1681295aa6fd5ae21d"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchDeliveryCompletionWorkerTest.java",
|
||||
"sha256": "cf2812520b6c1025b3b8ab8084b9d21064427811dd62f12a734cf90c4c035c12"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchDraftPersistenceTest.java",
|
||||
"sha256": "35b7c411e452dce2189c22f8cf31d77083f8854062435a9223e306a1a9d44a6a"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchItemSourcePersistenceTest.java",
|
||||
"sha256": "24e1b3f0dba4d4f9c1f724840c7a263ff0d1561cb5cb509fb0c410be8187afb0"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchMergedRelabelPersistenceTest.java",
|
||||
"sha256": "1c36d64a389bf12e55cfb8cbb29b7dd333bc952f66e8bb88d441ddf42f83c653"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPdaReadPersistenceTest.java",
|
||||
"sha256": "9b4402d0dd3f0eefa8b6b9bfe65e20f42f3e60619ac6989b18c9a74cbebad0ad"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPhysicalClaimPersistenceTest.java",
|
||||
"sha256": "02bd34b71fdb237566e99fab0b748c3ed333ace4ae65042aaf315b06695299f6"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchPickingPersistenceTest.java",
|
||||
"sha256": "0971e32ae147a03a730c16f1a75f0576e3a9122f92c5c65608db0cb9a76a3510"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchRepairWorkflowTest.java",
|
||||
"sha256": "4a4d01424e91fd1b55b0af4721e02c4acad065e958ff4a0b9726cf726691fbdf"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchServiceTest.java",
|
||||
"sha256": "a9a2e25ff22e326925104e48ff1cfed34fec3350dfb569f1e7f19a4e186925c7"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/DispatchWholeSourcePersistenceTest.java",
|
||||
"sha256": "0143045a52df440dc8be72706d69cbc45a9d210ddfb4ce77762423533dcc1a55"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/dispatch/service/ReturnDispatchCandidatePersistenceTest.java",
|
||||
"sha256": "4170a35b6f57d9058577941ef665130e0f3a3faeef37c92c9e93a69dd9f0f60a"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/FbaAppointmentRepartitionPersistenceTest.java",
|
||||
"sha256": "f2f7174dd6e52f5d9caae36f8fc24aa2dc78145c1c390e8e16857bb066948a86"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/service/InboundPlanPaginationTest.java",
|
||||
"sha256": "b9196d489830c2f4bf24ebcaf3e94adf4e0484f414f373c300b0f4a2a538679b"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inboundplan/work/AppointmentWorkDomainMapperTest.java",
|
||||
"sha256": "5fbe3b3be8be194d1f31006e4e05187cd629236c376e01da2d291a2593e70e0a"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inventory/command/InventoryHoldConcurrencyPersistenceTest.java",
|
||||
"sha256": "e146136299db24b1cf618faf2161fa284d9eec15a26a75e8352548cd7dbe7e94"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/inventory/service/PhysicalPalletSerialPersistenceTest.java",
|
||||
"sha256": "444bd8d361f4d90fbdaf1e4d1d205906b5452096670f57bd3459906716e36c7e"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletDispatchFreezePersistenceTest.java",
|
||||
"sha256": "a8ef7e364e4d0fb97f83515dd1d3b983cdac4f367a9335fe181c39a47719720f"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationServiceTest.java",
|
||||
"sha256": "eae67e13f9d1d3e8ff8a76b30a8a72d445e54b3cd6a30394c5ea41f763f48a7c"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/relabel/service/RelabelDispatchSourcePersistenceTest.java",
|
||||
"sha256": "6eb43b35de92364884e9ffbd36c18c3921ac8c21c959602383f9ca9cc8c4ece5"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/transfer/service/WarehouseTransferServiceTest.java",
|
||||
"sha256": "787e78907d019458e3533325ed2bfe8cc09eb8de7ca1db2c0b98a54239a56fe5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
{
|
||||
"createdAtUtc": "2026-10-19T11:12:23.053116+00:00",
|
||||
"scope": "C52 route pruning only: actual origin, supported old stops retain relative order, new cargo stops append, active external booking stops required; invalid commitments fail atomically",
|
||||
"sources": [
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/fleet/trip/FleetBookingReservations.java",
|
||||
"sha256": "84906c28ccaf94125a41c03a30c9df392400af74569ed26c2da8abd5c116144c",
|
||||
"modifiedAtUtc": "2026-10-19T11:06:24.471699+00:00"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/main/java/com/baiyue/lastleg/fleet/trip/FleetTripService.java",
|
||||
"sha256": "28eca09b87337b07a04955039a50c3c55805289955c24db75fe9df6fbf0b3bcc",
|
||||
"modifiedAtUtc": "2026-10-19T11:06:24.472698+00:00"
|
||||
},
|
||||
{
|
||||
"path": "lastleg-service/src/test/java/com/baiyue/lastleg/fleet/trip/FleetDispatchRoutePersistenceTest.java",
|
||||
"sha256": "687248640255a40456f4197cab28dd32e8a16f97a833858fc868e171dcf2b62c",
|
||||
"modifiedAtUtc": "2026-10-19T11:08:07.884938+00:00"
|
||||
}
|
||||
],
|
||||
"aggregateMethod": "normalized path + space + lowercase SHA256, Unicode lexicographic path sort, LF joined, no trailing LF",
|
||||
"aggregateSha256": "9fab733033d4fffaeb716b4cb2720dd72b26c14ece1b97d6bd6d2e30db502aa2",
|
||||
"compileCommand": [
|
||||
"./scripts/local-check.ps1",
|
||||
"-WorkingDirectory",
|
||||
".",
|
||||
"-Label",
|
||||
"Dispatch route test-compile",
|
||||
"-Command",
|
||||
[
|
||||
"mvn",
|
||||
"-pl",
|
||||
"lastleg-service",
|
||||
"-am",
|
||||
"-DskipTests",
|
||||
"test-compile"
|
||||
]
|
||||
],
|
||||
"testCommand": [
|
||||
"./scripts/local-check.ps1",
|
||||
"-WorkingDirectory",
|
||||
".",
|
||||
"-Label",
|
||||
"Dispatch route regression",
|
||||
"-Command",
|
||||
[
|
||||
"mvn",
|
||||
"-pl",
|
||||
"lastleg-service",
|
||||
"-am",
|
||||
"-Dtest=FleetDispatchRoutePersistenceTest,DispatchAggregatePersistenceTest,FleetTripPersistenceTest,FleetReceiptCapacityTest,FleetTripMatchedStopsTest",
|
||||
"-Dsurefire.failIfNoSpecifiedTests=false",
|
||||
"test"
|
||||
]
|
||||
],
|
||||
"compileExit": 0,
|
||||
"testExit": 0,
|
||||
"jvmPolicy": "local-check defaults; JAVA_TOOL_OPTIONS ActiveProcessorCount=2 Xmx1536m; no memory override",
|
||||
"logs": [
|
||||
{
|
||||
"path": ".logs/dispatch-route-test-compile.log",
|
||||
"sha256": "d52d00bd3b3d16b0ced516f4649367a94b012fb8ed831a1ca933b1d4ef6acb39"
|
||||
},
|
||||
{
|
||||
"path": ".logs/dispatch-route-test-compile.maven.log",
|
||||
"sha256": "9071174d9e9248a6655a1ca815043d17e607adb1d4f1ab8b5f914c2e51fc9d4b"
|
||||
},
|
||||
{
|
||||
"path": ".logs/dispatch-route-regression.log",
|
||||
"sha256": "1edb3d4afb3b03e35f4192b855ec80c607b4ae5a88e9261a431a79e97dbaa68a"
|
||||
},
|
||||
{
|
||||
"path": ".logs/dispatch-route-regression.maven-tail.log",
|
||||
"sha256": "b17e27d2466c4b63d9c4a976bea598b6af45a50f2b53fb387bb8fdbbb48bdfab"
|
||||
}
|
||||
],
|
||||
"results": [
|
||||
{
|
||||
"class": "com.baiyue.lastleg.dispatch.service.DispatchAggregatePersistenceTest",
|
||||
"tests": 11,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"xmlSha256": "edb055fa5c2d9ddaa446aec702a00f17db76e8e95c3c5d4ddb411e0df40e2573",
|
||||
"testCases": [
|
||||
"incompleteAttributionCannotPassLoadingThroughMatchingHeaderTotals",
|
||||
"reviewsUseActualRootRoundAndImmutableCommandsBeforeAndAfterLoading",
|
||||
"operationItemsAndRouteUseActualIdsAndPersistedStopOrder",
|
||||
"emptyCreateHasOneRealTruckAndNoCustomerHeader",
|
||||
"multiCustomerSelectionCreatesOneTruckAndKeepsAllDocumentsAndBatchReads",
|
||||
"realPickBlocksReturnEvenWhenHeaderCountersAreZero",
|
||||
"laterCargoConflictRollsBackTruckResourcesEarlierLocksAndItems",
|
||||
"loadingUsesActualSourcesMeasurementsAndNeverAutoCompletesFromCounters",
|
||||
"cancelledOutboundHistoryDoesNotBlockZeroPickCancellationButAnActiveDocumentDoes",
|
||||
"updateSavesCurrentVehiclePlanAndReplayWithoutAnyVehicleAppointmentField",
|
||||
"removalCancellationAndOldCommandRecoveryNeverReleaseNewTruckClaims"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.fleet.trip.FleetDispatchRoutePersistenceTest",
|
||||
"tests": 7,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"xmlSha256": "12404cd4a8e98eecd01e18b7ea12f915032a4f5f175d2d1e0b26daebc4766b8d",
|
||||
"testCases": [
|
||||
"failureAfterTripRouteWriteRollsBackMainClaimsQuantitiesAndLedgerThenTheSameKeyCanSucceed",
|
||||
"missingRequiredBookingStopRejectsTheWholeRemovalAndDoesNotInventAStop",
|
||||
"lastPalletRemovalPrunesOnlyItsStopPreservesOrderAndAppendsNewDestinations",
|
||||
"activeBookingKeepsItsOriginalStopAndCancelledBookingsDoNotLeaveGhostStops(String)[1]",
|
||||
"activeBookingKeepsItsOriginalStopAndCancelledBookingsDoNotLeaveGhostStops(String)[2]",
|
||||
"activeBookingKeepsItsOriginalStopAndCancelledBookingsDoNotLeaveGhostStops(String)[3]",
|
||||
"anotherPalletAtTheSameDestinationKeepsTheStopAndAnEmptyTruckKeepsOnlyItsOrigin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.fleet.trip.FleetReceiptCapacityTest",
|
||||
"tests": 5,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"xmlSha256": "a86f409a17999c90c88791bbc64e98c0e6fcd69db6e1f52c5aada0676ab8b53b",
|
||||
"testCases": [
|
||||
"firstReceiptOrMissingPreviousReceiptStillRequiresValidOwnPlan",
|
||||
"receivedReconfirmationFitsWithoutCreatingAnOwnCargoPlan",
|
||||
"otherConfirmedReservationsStillConsumeCapacity",
|
||||
"nonemptyStaleOwnPlanRemainsBlocked",
|
||||
"remeasuredExternalCargoStillCannotExceedVehicleWeight"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.fleet.trip.FleetTripMatchedStopsTest",
|
||||
"tests": 3,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"xmlSha256": "0f1d101f1d479c0f8d86fd3ec0d06649addc999bacfb3fa43c39361a42691b4c",
|
||||
"testCases": [
|
||||
"rejectsMissingIdentityWithoutUsingDisplayNameAsKey",
|
||||
"replacesOnlyInitialPlaceholderAndDeduplicatesByIdentity",
|
||||
"preservesExistingStopIndexesAndAppendsDifferentIdentityEvenWhenNamesMatch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "com.baiyue.lastleg.fleet.trip.FleetTripPersistenceTest",
|
||||
"tests": 7,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"xmlSha256": "2f5eba7a2776a9c19829fba55ed379a84e19d6a5d7095ec7f2ec6f4dfccfba67",
|
||||
"testCases": [
|
||||
"capacityFailureOrStaleFingerprintDoesNotWritePlanOrHistory",
|
||||
"boundCorePlanAndResourcesMustUseTheCommonMainVersionAndReview",
|
||||
"externalVehicleCapacityPlanUsesActualWholeTruckStopsAndSnapshots",
|
||||
"oneWholeTruckProjectsBothReviewsFromTheRealMain",
|
||||
"laterFullSignatureReturnDoesNotReopenOriginalTransport",
|
||||
"partialSignatureCannotCloseCargoOrEndExternalTasks",
|
||||
"externalCargoCompletionAndTwoTaskEndsAreIndependentAndReplayable"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": 33,
|
||||
"failures": 0,
|
||||
"errors": 0,
|
||||
"skipped": 0,
|
||||
"limitations": "H2 service/mapper/transaction regression with controlled catalogue/source providers and seeded persisted bookings; no environment HTTP, production SQL, deployment, UI or real PDA acceptance; no 501 rerun"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@
|
||||
### 后端任务最小读取集
|
||||
|
||||
- 单服务 Controller/Service/Mapper 任务:本文件、目标服务 `AGENTS.md`、目标类及其直接调用点。
|
||||
- 跨服务 API/事件任务:在上述基础上增加直接调用方、被调用方及受影响的 OpenAPI/事件契约;公开路径、访问域或入口鉴权变化才增加 Gateway,内部调用和事件不经公网 Gateway。不因业务关键词自动加载整个业务专题。
|
||||
- 跨服务 API/事件任务:在上述基础上增加直接调用方、被调用方和对应 Gateway/OpenAPI;不因业务关键词自动加载整个业务专题。
|
||||
- 只有状态、权限、数据库或验收边界无法从上述入口确定时,才读取 `docs/业务快速索引.md`、专题 README 或完整契约。
|
||||
- 读取预算遵循工作区根指引:超过约 250 行或 8000 字符时先读职责、硬边界和验证章节,再检索任务命中段;不得仅因行数少而全文加载长业务表。聚合构建或架构任务才读取相关 `README.md`、`pom.xml` 和目录结构文档,已知单模块任务不增加概览文档。
|
||||
|
||||
@@ -78,9 +78,6 @@
|
||||
| 国内船节点向海外接柜门禁事件 | `firstleg/`、`common-event-contract/`、`lastleg-service/` |
|
||||
| 海外仓库目录、海外库位、海外托盘、资源锁 | 国内仓库目录归 `warehouse/`,海外资源归 `warehouse-overseas-service/` |
|
||||
| Lastleg 内部模块化与依赖基线 | `lastleg-service/` |
|
||||
| 自营领星采集、经营统计、SKU 日销量 | `lastleg-service/selfoperated/` 查询与采集编排;领星签名/分页/外部接口查 `integration-service/`,不因采集页面任务同时读取两服务 |
|
||||
| 跨客户同仓预约、预约跟进、到港日历 | `lastleg-service/inboundplan/`、`appointmentplanning/`;到港事实查 `firstleg/portschedule/` |
|
||||
| 车辆、司机证照、车次、外接预订、车队报价、出车记录 | `lastleg-service/fleet/`;先读 `lastleg-service/AGENTS.md` 对应入口,客户排车关联再沿 `dispatch/fleet/` 实际调用 |
|
||||
| PDF 标签、审计、业务事件直投 | `print/`、`audit-service/`、`common-event-contract/` |
|
||||
|
||||
## 公共模块快速索引
|
||||
@@ -106,22 +103,9 @@
|
||||
- 装柜、船节点、卸柜、暂扣、派送、费用与资金按统一通信契约的逐事件表直接投递。保留本地 Outbox、消费幂等、重试与失败处置,不携带用户 JWT;旧 Bridge 源码已退出聚合和发布清单,退役待清理;实际停机仍须替代链验证与授权,不得据源码状态认定已部署。
|
||||
- `lastleg-service` 不读取头程数据库,`warehouse-overseas-service` 不读取尾程订单库。共用测试 MySQL 实例不改变服务数据归属。准确路由、ACK、撤销矩阵和切换门槛只维护在新的两份主契约中。
|
||||
|
||||
## 数据库访问与中文代码注释(所有服务及公共模块强制)
|
||||
|
||||
- 本节适用于全部后端服务和公共模块;新增代码遵守下列规范,存量分层仅在影响本次正确性或用户明确要求时整改,不因局部修改迁移整条链路;以上为目标规范,不代表存量均已达标。
|
||||
- 生产代码的关系型数据库读写统一经 MyBatis/MyBatis-Plus Mapper 执行;Controller、Service、定时任务、消费者、编号生成器和公共基础组件不得直接使用 `JdbcTemplate`、`NamedParameterJdbcTemplate`、原生 JDBC/Connection/Statement 或其他通道执行 SQL。仅改成 Repository 包装 JDBC 不算整改,SQL 必须进入 Mapper;无数据库职责的模块不得为满足本条新增数据库访问。
|
||||
- 正常业务数据库访问路径统一为 `Controller → Service → Repository → Mapper`,四层职责明确,不得省略 Repository,也不得由 Controller 直接调用 Repository/Mapper,或由 Service 直接调用 Mapper。定时任务、消费者等非 HTTP 入口从 Service 进入,同样经 Repository → Mapper 完成持久化访问。
|
||||
- Controller 负责请求接收、参数校验、入口权限和响应转换;Service 负责业务规则、编排及业务事务;Repository 负责领域数据访问封装、查询组合与持久化模型转换,对 Service 提供有业务含义的数据操作;Mapper 负责 SQL 执行及数据库记录映射。Repository 不承载业务状态流转,不直接用 JDBC 执行 SQL;Service 不继承 MyBatis-Plus `ServiceImpl` 等方式绕过 Repository。
|
||||
- 复杂查询、批量处理、原子计数、锁定读取、Outbox 和数据库监控查询同样经 Repository → Mapper,不以 SQL 特殊或实现方便为由跳层。公共模块需要数据库能力时,按现有模块边界定义 Repository/持久化接口,由所属服务的 Repository → Mapper 实现,禁止借此跨服务读库。
|
||||
- 迁移数据库操作须保留客户隔离条件、事务传播、行锁、幂等和并发语义;`LAST_INSERT_ID()` 等连接级操作必须在同一事务连接完成,并明确关闭相关读取缓存,不能仅机械搬移 SQL。Mapper 注册及扫描仍遵守下文统一规范。
|
||||
- 测试代码可用 `JdbcTemplate` 创建隔离测试表、准备数据及核对结果;被测生产路径仍必须调用实际 Mapper,不得把测试造数做法带入生产。数据库基线和迁移脚本按现有部署契约管理。
|
||||
- 本次新增或修改的手写方法及构造器须有简短中文业务注释,通常 1—3 行;接口与 Mapper 方法优先用中文 Javadoc,覆盖方法同样适用,关键规则就地说明。不补齐未修改或自动生成方法的注释。
|
||||
- 核心业务、复杂 SQL、状态流转、资金与库存变更、权限隔离、事务、锁、幂等、并发、重试和补偿逻辑,须在关键代码前增加适量中文注释,解释业务规则、处理原因、约束边界及失败影响;不逐行翻译代码,不添加无信息量或与实现不符的注释。
|
||||
- 新增和修改的代码说明注释统一使用中文;必要的技术标识、协议名、类名可保留原文,第三方许可证和生成标记保持原样。修改方法时同步更新相关存量英文或过期说明;审查时同时核对 Controller → Service → Repository → Mapper 分层及中文方法、核心逻辑注释。
|
||||
|
||||
## 契约、数据库与验证入口
|
||||
|
||||
- 对外 Controller/API 新增、改名或删除时,同时核对调用端、统一 Gateway、OpenAPI 和权限;提交前运行 `node --test scripts/gateway-route-contract.test.mjs`,自动发现生产 Controller 并校验网关目标服务与内部路径隔离。失败不得提交或标记完成;网关配置变化必须列入部署清单,不以业务服务单测代替入口检查。
|
||||
- 对外 Controller/API 新增、改名或删除时,同时核对调用端、区域 Gateway、OpenAPI 和权限;提交前运行 `node --test scripts/gateway-route-contract.test.mjs`,自动发现生产 Controller 并校验网关目标服务与内部路径隔离。失败不得提交或标记完成;网关配置变化必须列入部署清单,不以业务服务单测代替入口检查。
|
||||
|
||||
- 跨服务修改先检查调用方 `client/`、被调用方 Controller/DTO、`src/main/resources/openapi/` 和双方契约测试;禁止共享领域 Entity。
|
||||
- 修改 Java 方法、构造器、Controller、Client、DTO 或 Mapper 参数签名时,先用 `rg` 定向查找符号及旧参数形态,并同步更新 `src/main/`、`src/test/`、Mock、Fixture、契约测试和脚本中的全部调用点。新增可选参数也必须补齐旧测试调用,不能因生产调用已更新就视为完成。
|
||||
@@ -132,11 +116,7 @@
|
||||
- 数据库只访问所属服务库。模块表结构位于 `<module>/src/main/resources/db/`;开发环境按最新模块基线和 `deploy/sql/头程数据库统一增量-MySQL8.sql` 收敛,不为历史开发数据新增兼容迁移。已有名称含 `migration` 的脚本仅作结构来源和追溯,部署说明见 `deploy/sql/README.md`;生产升级另按明确发布规则处理。
|
||||
- 后端同样遵守根指引中的“开发数据和上传文件可丢弃”边界:不得为现有开发库孤儿文件、旧文件归属或历史部分失败新增删除补偿接口、兼容复用、回填或清理链路;只修复当前正式上传与持久化路径,既有开发文件由人工重新上传。
|
||||
- 通用配置在 `config/nacos/test/`;服务日志、上传文件、`target/`、`reports/` 不属于源码。
|
||||
- 后端本地验证默认使用 `scripts/backend-check.ps1`,必须显式指定 `-Modules`,不传模块直接拒绝;命令及参数见 `scripts/README.md` 的“后端分层检查”。入口自动经 `local-check.ps1` 限流,`-DryRun` 只检查选择范围,不代表测试通过。
|
||||
- 局部逻辑使用 `-Mode Focused -Tests <精确测试类名>`,覆盖修改行为及必要边界即可交付,不因收尾再跑 `Module`。Java 签名变化须覆盖生产与测试源码编译;定向测试已编译时不重复跑 `-Mode Compile`。只有影响扩及服务内多个行为且定向覆盖不足才选 `Module`,先说明原因。跨服务 DTO、接口或事件变化显式列入生产者和实际消费者;`-am` 仅补上游构建依赖,不自动包含下游或 HTTP/事件消费者。
|
||||
- 仅注释/文档调整不触发 Java 回归;脚本调整执行受影响脚本测试和登记合同。API、Mapper、AGENTS 等静态合同仍按各自触发条件执行。纯重构也应覆盖受影响行为,不能只用编译宣称回归通过。`-Dmaven.test.skip=true` 跳过测试编译,不得作为签名变更交付验证。
|
||||
- 全仓回归仅用于已确认影响广泛且定向覆盖不足的公共依赖/聚合拓扑/认证/序列化/基础模型变化,或用户要求的全量/跨域集成验收;先说明具体影响,不能因未查清范围而全跑。根 POM、依赖或测试配置改动先按实际影响选编译或测试,不一律全仓。入口为 `scripts/backend-full-regression.ps1`,CI 全量保留。普通提交、单服务任务或对话收尾不触发;有效结果复用,输入变化只补跑受影响范围。
|
||||
- 不以缩短耗时为由删除金额、库存、权限隔离、状态流转、幂等和并发测试;冗余测试须根据重复场景及维护成本单独评估。不要在本地启动 Java/Nacos/数据库,除非用户明确要求。
|
||||
- Java 签名变更的最低编译门禁是 `mvn -pl <module> -am test-compile`,它必须在部署前完成并覆盖测试源码;有行为变化时继续运行 `mvn -pl <module> -am test`。`-DskipTests` 可跳过测试执行但仍须保留测试编译,`-Dmaven.test.skip=true` 会跳过测试编译,不得作为签名变更的交付验证。全量验证仍使用 `mvn -DskipTests validate`、`mvn test`;不要在本地启动 Java/Nacos/数据库,除非用户明确要求。
|
||||
- 同一批 `AGENTS.md` 索引修改完成后从后端根统一运行一次 `./scripts/agents-index-contract.ps1`;脚本只读源码目录和指定指引,不访问 HTTP、数据库或部署环境。
|
||||
- Mapper 注册静态合同为 `scripts/mapper-scan-contract.mjs`、`mapper-scan-contract.test.mjs`:自动发现聚合模块、生产 `*Mapper` 接口、服务启动类和分散扫描配置,不启动 Spring、不连接数据库;遗漏注解、扫描根漂移或重新引入子域扫描时直接失败并输出类与文件路径。
|
||||
- 单服务镜像构建/部署从 `Jenkinsfile.service`、`deploy/docker/Dockerfile`、`deploy/scripts/deploy-built-service.sh` 进入;新镜像启动失败或健康检查失败时只允许回滚到同服务先前镜像,并保持任务失败,离线合同见 `scripts/deploy-built-service-rollback.test.mjs`。实际部署仍须当前对话明确授权。
|
||||
@@ -160,7 +140,7 @@
|
||||
|
||||
- 订单与客户:`../docs/订单与客户/README.md`、`../docs/订单与客户/订单与客户头程订单闭环设计.md`
|
||||
- 入库测量与计费:`../docs/入库测量与计费/README.md`;流程细节按 `../docs/头程到尾程/README.md` 指向的当前阶段文档读取,需求确认和联调报告仅在历史追溯或验收证据任务中读取
|
||||
- 国内货柜履约:`../docs/国内货柜履约/README.md`,报关规则变化再查 `../docs/国内货柜履约/报关资料与船期价格接入梳理.md`。规划、确认与验收材料按归档位置及文档角色判断,当前入口指定的有效规则仍按需核对,历史材料只用于追溯或证据任务
|
||||
- 国内货柜履约:`../docs/国内货柜履约/README.md`、`../docs/国内货柜履约/报关资料与船期价格接入梳理.md`;开发规划、开工门禁、需求确认和验收材料已归档,只有历史追溯或验收证据任务才读取
|
||||
- 海外仓业务:`../docs/海外仓业务/README.md`;统一入口 `gateway/`,尾程与入仓库存 `lastleg-service/`,海外仓储资源 `warehouse-overseas-service/`
|
||||
- 海外仓全流程:以正式 Controller、前端路由、权限、SQL 与跨区事件契约为范围依据;海外接柜、入仓、库存、库内服务、排车、出库、派送、一件代发、异常退回和客户回访进入 `lastleg-service/`,国内 SKU/箱唛及暂扣协同进入 `order/`、`firstleg/`、`common-event-contract/`
|
||||
- 财务:`../docs/财务管理/README.md` 中已确认的范围、对象、状态和接口约束
|
||||
|
||||
Vendored
+3
-39
@@ -67,8 +67,6 @@ def parseAutoBuildState(String description, List<String> allowedServices) {
|
||||
List<String> failedServices = []
|
||||
if (state.startsWith('RESULTS')) {
|
||||
String summary = state.substring('RESULTS'.length()).trim()
|
||||
int metadataIndex = summary.indexOf(' | ')
|
||||
if (metadataIndex >= 0) summary = summary.substring(0, metadataIndex).trim()
|
||||
summary.split(',').collect { it.trim() }.findAll { it }.each { item ->
|
||||
int separator = item.indexOf('=')
|
||||
if (separator > 0) {
|
||||
@@ -105,25 +103,6 @@ def previousAutoBuildState(def previousBuild, List<String> allowedServices) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 测试范围必须相对成功门禁,而非失败/取消轮次;否则补跑可能遗漏前次未通过的变更。
|
||||
def previousSuccessfulTestCommit(def previousBuild, List<String> requiredServices) {
|
||||
def candidate = previousBuild
|
||||
int inspected = 0
|
||||
while (candidate != null && inspected < 30) {
|
||||
String description = candidate.description ?: ''
|
||||
String marker = ' | TESTS=PASSED '
|
||||
int markerIndex = description.lastIndexOf(marker)
|
||||
if (candidate.result == 'SUCCESS' && markerIndex >= 0) {
|
||||
List metadata = description.substring(markerIndex + marker.length()).trim().split(' ')
|
||||
if (metadata.size() == 2 && metadata[0] ==~ /[0-9a-fA-F]{7,40}/ &&
|
||||
requiredServices.every { metadata[1].split(',').contains(it) }) return metadata[0]
|
||||
}
|
||||
candidate = candidate.previousBuild
|
||||
inspected++
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
def environmentChoicesForJob(String jobBaseName) {
|
||||
return [fixedEnvironmentForJob(jobBaseName) ?: 'test']
|
||||
}
|
||||
@@ -182,9 +161,7 @@ pipeline {
|
||||
choice(name: 'ENVIRONMENT', choices: environmentChoicesForJob(env.JOB_BASE_NAME), description: '部署环境')
|
||||
booleanParam(name: 'DEPLOY', defaultValue: false, description: '各服务构建成功后是否独立部署')
|
||||
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试执行(仍编译测试源码)')
|
||||
choice(name: 'TEST_SCOPE', choices: ['AUTO', 'MODULE'], description: 'AUTO 对已支持的局部变更执行关联测试;公共/未知变更自动完整模块回归;MODULE 显式完整模块回归')
|
||||
// 地址由当前 Job 配置提供;参数声明刷新时保留已配置值,不将环境地址写入源码。
|
||||
string(name: 'IMAGE_REPOSITORY', defaultValue: params.IMAGE_REPOSITORY ?: '', description: '沿用当前 Job 已配置的镜像仓库地址;首次配置或更换仓库时填写 host[:port]/owner/image')
|
||||
string(name: 'IMAGE_REPOSITORY', defaultValue: 'registry.example.com/team/baiyue-firstleg', description: '共享镜像仓库地址')
|
||||
string(name: 'DOCKER_BASE_IMAGE', defaultValue: 'eclipse-temurin:17-jre-alpine', description: 'Java 17 基础镜像')
|
||||
choice(name: 'DOWNSTREAM_JOB_PREFIX', choices: downstreamJobPrefixChoicesForJob(env.JOB_BASE_NAME), description: '由当前总控 Job 固定的单服务 Job 前缀')
|
||||
}
|
||||
@@ -213,12 +190,9 @@ pipeline {
|
||||
|
||||
|
||||
String requestedRepository = params.IMAGE_REPOSITORY?.trim()
|
||||
if (!requestedRepository) {
|
||||
if (!requestedRepository || requestedRepository == 'registry.example.com/your-group/baiyue-firstleg') {
|
||||
error('必须填写真实镜像仓库地址')
|
||||
}
|
||||
if (requestedRepository.tokenize('/')[0] ==~ /(?i)(?:[a-z0-9-]+\.)*example\.(?:com|net|org)(?::[0-9]+)?/) {
|
||||
error('IMAGE_REPOSITORY 不能使用 example 示例域名,请填写已核实的镜像仓库地址')
|
||||
}
|
||||
if (requestedRepository.contains('://') || !requestedRepository.contains('/')) {
|
||||
error('IMAGE_REPOSITORY 格式错误:请填写 host[:port]/owner/image,不要包含 http:// 或 https://')
|
||||
}
|
||||
@@ -291,7 +265,6 @@ pipeline {
|
||||
selected = selected.unique()
|
||||
|
||||
env.SELECTED_SERVICES = selected.join(',')
|
||||
env.TEST_BASE_COMMIT = previousSuccessfulTestCommit(currentBuild.previousBuild, selected)
|
||||
env.NO_SERVICE_CHANGE = selected ? 'false' : 'true'
|
||||
if (!selected) {
|
||||
currentBuild.description = params.BUILD_MODE == 'AUTO'
|
||||
@@ -358,22 +331,16 @@ pipeline {
|
||||
.findAll { it }
|
||||
.join(',')
|
||||
echo "统一测试本次选中的服务及其公共依赖: ${selectedModules}"
|
||||
String testPlan = "${pwd(tmp: true)}/ci-test-plan.json"
|
||||
lock(resource: 'firstleg-test-maven') {
|
||||
timeout(time: 50, unit: 'MINUTES') {
|
||||
sh """
|
||||
test \"\$(git rev-parse HEAD)\" = \"${env.SOURCE_COMMIT}\"
|
||||
find . -type f -path '*/target/surefire-reports/TEST-*.xml' -delete
|
||||
node deploy/scripts/ci-test-scope.mjs plan --modules '${selectedModules}' --base '${env.TEST_BASE_COMMIT ?: ''}' --mode '${env.RESOLVED_ENVIRONMENT == 'test' ? (params.TEST_SCOPE ?: 'AUTO') : 'MODULE'}' --plan '${testPlan}'
|
||||
node deploy/scripts/ci-test-scope.mjs checks --plan '${testPlan}'
|
||||
test_arguments=\"\$(node deploy/scripts/ci-test-scope.mjs args --plan '${testPlan}')\"
|
||||
sh deploy/scripts/run-ci-maven.sh --settings deploy/maven/settings-ci.xml --batch-mode --errors -pl ${selectedModules} -am test \$test_arguments
|
||||
node deploy/scripts/ci-test-scope.mjs verify --plan '${testPlan}'
|
||||
sh deploy/scripts/run-ci-maven.sh --settings deploy/maven/settings-ci.xml --batch-mode --errors -pl ${selectedModules} -am test
|
||||
"""
|
||||
}
|
||||
}
|
||||
echo "统一测试门禁通过: ${env.SOURCE_COMMIT};下游单服务任务不再重复执行测试"
|
||||
env.TEST_GATE_PASSED = 'true'
|
||||
}
|
||||
}
|
||||
post {
|
||||
@@ -430,9 +397,6 @@ pipeline {
|
||||
currentBuild.description = params.BUILD_MODE == 'AUTO'
|
||||
? "AUTO ${env.IMAGE_TAG} | RESULTS ${summary}"
|
||||
: "${env.IMAGE_TAG} | ${summary}"
|
||||
if (env.TEST_GATE_PASSED == 'true') {
|
||||
currentBuild.description += " | TESTS=PASSED ${env.SOURCE_COMMIT} ${env.SELECTED_SERVICES}"
|
||||
}
|
||||
if (failed) {
|
||||
unstable("部分服务执行失败,但其他服务已独立完成:${failed.join(', ')}")
|
||||
}
|
||||
|
||||
+1
-5
@@ -49,8 +49,7 @@ pipeline {
|
||||
booleanParam(name: 'ALLOW_SAME_CONTRACT_ROLLBACK', defaultValue: false, description: '仅确认相同协议与Schema时允许回滚;架构切换保持关闭')
|
||||
booleanParam(name: 'DEPLOY', defaultValue: false, description: '构建成功后是否部署本服务')
|
||||
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试')
|
||||
// 独立构建沿用本 Job 配置,总控调度时保留其明确传入的地址。
|
||||
string(name: 'IMAGE_REPOSITORY', defaultValue: params.IMAGE_REPOSITORY ?: '', description: '沿用当前 Job 已配置的镜像仓库基础路径,不包含服务名和标签;首次配置或更换仓库时填写')
|
||||
string(name: 'IMAGE_REPOSITORY', defaultValue: 'registry.example.com/team/baiyue-firstleg', description: '共享镜像仓库基础路径,不包含服务名和标签')
|
||||
string(name: 'DOCKER_BASE_IMAGE', defaultValue: 'eclipse-temurin:17-jre-alpine', description: 'Java 17 基础镜像')
|
||||
}
|
||||
|
||||
@@ -102,9 +101,6 @@ pipeline {
|
||||
if (!imageRepository || imageRepository.contains('://')) {
|
||||
error('IMAGE_REPOSITORY 不能为空且不能包含协议前缀')
|
||||
}
|
||||
if (imageRepository.tokenize('/')[0] ==~ /(?i)(?:[a-z0-9-]+\.)*example\.(?:com|net|org)(?::[0-9]+)?/) {
|
||||
error('IMAGE_REPOSITORY 不能使用 example 示例域名,请填写已核实的镜像仓库地址')
|
||||
}
|
||||
if (!imageRepository.contains('/')) {
|
||||
error('IMAGE_REPOSITORY 必须使用 host[:port]/owner/image 格式')
|
||||
}
|
||||
|
||||
@@ -23,16 +23,11 @@
|
||||
## 本地构建
|
||||
|
||||
```powershell
|
||||
# 日常按受影响模块检查;跨服务变更显式列入消费者。
|
||||
.\scripts\backend-check.ps1 -Modules order -Mode Compile
|
||||
.\scripts\backend-check.ps1 -Modules order
|
||||
# 根构建/拓扑变化等全量触发条件见 AGENTS.md。
|
||||
.\scripts\local-check.ps1 -Command @('node', '--test', 'scripts/java-topology-contract.test.mjs')
|
||||
.\scripts\backend-full-regression.ps1
|
||||
mvn -DskipTests validate
|
||||
node --test scripts/java-topology-contract.test.mjs
|
||||
mvn test
|
||||
```
|
||||
|
||||
开发中可通过 `backend-check.ps1 -Mode Focused -Modules <模块> -Tests <精确测试类名>` 快速反馈;参数、DryRun 和结果边界见 [后端分层检查](scripts/README.md#后端分层检查)。单服务修改收尾执行模块回归,不默认执行上面的全仓命令。
|
||||
|
||||
GitLab 在独立 Node 镜像中自动执行拓扑合同,随后才允许服务制品打包。Maven `verify` 会为执行过测试且产生覆盖率数据的模块生成 `target/site/jacoco/index.html` 与 `jacoco.xml`;当前只生成报告,不设置覆盖率阈值,也不改变测试选择。Jenkins 的 `java-builder` 尚未在仓库中声明 Node 运行时,因此暂不重复执行该 Node 合同,以 GitLab 门禁和上述本地命令为准。
|
||||
|
||||
2026-07-30 订单与客户前端联调缺口已完成真实回归:19 个 Reactor 项目构建成功,75 项单元及组件测试、68 项认证与 IAM 真实 API、37 项订单与仓库真实 API 全部通过。详细证据见 `docs/phase1-business-maturity-regression-report.md`。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Audit Service 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- Mapper 只由 `BaiyueAuditApplication.java` 对 `com.baiyue.audit` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Auth Service 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责与边界
|
||||
|
||||
- Mapper 只由 `BaiyueAuthApplication.java` 对 `com.baiyue.auth` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common Audit 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 负责业务审计事件采集、注解切面、敏感字段脱敏以及日志/HTTP 输出。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common Core 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 提供不依赖具体业务域的返回模型、异常、基础实体和 MyBatis-Plus 通用配置。
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.baiyue.common.core.number;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
/** 统一业务单号格式;序列仍由各服务自己的 Repository/Mapper 分配。 */
|
||||
public final class DailyDocumentNumber {
|
||||
public static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
|
||||
|
||||
/** 工具类不允许实例化。 */
|
||||
private DailyDocumentNumber() {}
|
||||
|
||||
/** 先固定北京时间业务日,再使用前缀和日期分配跨客户、跨仓库日流水。 */
|
||||
public static String next(String prefix, Clock clock, ToLongFunction<String> sequences) {
|
||||
requirePrefix(prefix);
|
||||
LocalDate date = LocalDate.now(clock.withZone(BUSINESS_ZONE));
|
||||
String dateText = date.format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
long value = sequences.applyAsLong(prefix + ":" + dateText);
|
||||
return format(prefix, date, value);
|
||||
}
|
||||
|
||||
/** 严格四位流水,不允许溢出后产生五位号码或退回随机编号。 */
|
||||
public static String format(String prefix, LocalDate date, long value) {
|
||||
requirePrefix(prefix);
|
||||
if (value < 1 || value > 9999) {
|
||||
throw new BizException(ResultCode.CONFLICT, "当日" + prefix + "单据四位流水号已用尽或分配失败");
|
||||
}
|
||||
return prefix + date.format(DateTimeFormatter.BASIC_ISO_DATE)
|
||||
+ String.format(Locale.ROOT, "%04d", value);
|
||||
}
|
||||
|
||||
/** 业务类型只能使用两至四位大写字母。 */
|
||||
private static void requirePrefix(String prefix) {
|
||||
if (prefix == null || !prefix.matches("[A-Z]{2,4}")) {
|
||||
throw new IllegalArgumentException("业务单据前缀必须为2至4位大写字母");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.baiyue.common.core.number;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.time.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
class DailyDocumentNumberTest {
|
||||
/** 午夜前后取号使用北京时间日期,与主机和 Clock 的时区无关。 */
|
||||
@Test void rollsAtShanghaiMidnightAndKeepsPrefixesIndependent() {
|
||||
var values = new HashMap<String, Long>();
|
||||
java.util.function.ToLongFunction<String> allocate = key -> values.merge(key, 1L, Long::sum);
|
||||
var before = Clock.fixed(Instant.parse("2026-10-19T15:59:59Z"), ZoneOffset.UTC);
|
||||
var after = Clock.fixed(Instant.parse("2026-10-19T16:00:00Z"), ZoneId.of("America/Los_Angeles"));
|
||||
assertThat(DailyDocumentNumber.next("FL", before, allocate)).isEqualTo("FL202610190001");
|
||||
assertThat(DailyDocumentNumber.next("FL", after, allocate)).isEqualTo("FL202610200001");
|
||||
assertThat(DailyDocumentNumber.next("FL", after, allocate)).isEqualTo("FL202610200002");
|
||||
assertThat(DailyDocumentNumber.next("ZGRK", after, allocate)).isEqualTo("ZGRK202610200001");
|
||||
}
|
||||
|
||||
/** 字符集和流水上限为硬边界,未知输入不能生成近似号码。 */
|
||||
@Test void rejectsInvalidPrefixAndSequence() {
|
||||
for (String prefix : new String[]{"F", "ABCDE", "Fl", "F1", " FL", ""}) {
|
||||
assertThatThrownBy(() -> DailyDocumentNumber.format(prefix, LocalDate.of(2026, 10, 20), 1))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
for (long value : new long[]{-1, 0, 10000}) {
|
||||
assertThatThrownBy(() -> DailyDocumentNumber.format("FL", LocalDate.of(2026, 10, 20), value))
|
||||
.isInstanceOf(BizException.class);
|
||||
}
|
||||
assertThat(DailyDocumentNumber.format("FL", LocalDate.of(2026, 10, 20), 9999)).isEqualTo("FL202610209999");
|
||||
}
|
||||
|
||||
/** 全局 Locale 不得让数字变为本地化字符。 */
|
||||
@Test void alwaysUsesAsciiDigits() {
|
||||
Locale old = Locale.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.forLanguageTag("ar"));
|
||||
assertThat(DailyDocumentNumber.format("FL", LocalDate.of(2026, 10, 20), 1)).isEqualTo("FL202610200001");
|
||||
} finally { Locale.setDefault(old); }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common Event Contract 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 维护 Firstleg、Lastleg、Finance 之间稳定、可版本化的业务事件契约。
|
||||
|
||||
+1
-2
@@ -56,7 +56,6 @@ public record BusinessFeeSourceChangedV1(
|
||||
String reviewStatus,
|
||||
String publicationStatus,
|
||||
String sourceStatus,
|
||||
String sourceHash,
|
||||
WalletSettlementReference walletSettlement
|
||||
String sourceHash
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -2,11 +2,15 @@ package com.baiyue.common.event;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/** 跨服务业务事实使用的真实集装箱号,只规范化空白和大小写,不校验 ISO 格式。 */
|
||||
/** Canonical physical container number used by cross-region business facts. */
|
||||
public final class ContainerNumbers {
|
||||
private static final int[] LETTER_VALUES = {
|
||||
10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38
|
||||
};
|
||||
|
||||
private ContainerNumbers() { }
|
||||
|
||||
/** 柜号必须非空;统一移除格式空白并转大写,保留业务录入值。 */
|
||||
public static String normalizeRequired(String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
throw new IllegalArgumentException("containerNo is required");
|
||||
@@ -15,13 +19,21 @@ public final class ContainerNumbers {
|
||||
value.codePoints().filter(codePoint -> !Character.isWhitespace(codePoint)
|
||||
&& !Character.isSpaceChar(codePoint)).forEach(compact::appendCodePoint);
|
||||
String normalized = compact.toString().toUpperCase(Locale.ROOT);
|
||||
if (normalized.isEmpty()) {
|
||||
throw new IllegalArgumentException("containerNo is required");
|
||||
if (!normalized.matches("[A-Z]{3}[UJZ][0-9]{7}")) {
|
||||
throw new IllegalArgumentException("containerNo must comply with ISO 6346");
|
||||
}
|
||||
int sum = 0;
|
||||
for (int index = 0; index < 10; index++) {
|
||||
char current = normalized.charAt(index);
|
||||
int number = Character.isDigit(current) ? current - '0' : LETTER_VALUES[current - 'A'];
|
||||
sum += number * (1 << index);
|
||||
}
|
||||
if (normalized.charAt(10) - '0' != sum % 11 % 10) {
|
||||
throw new IllegalArgumentException("containerNo must comply with ISO 6346 check digit");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/** 冻结事实必须已规范化,避免生产与消费端的快照或哈希发生漂移。 */
|
||||
public static String requireCanonical(String value) {
|
||||
String normalized = normalizeRequired(value);
|
||||
if (!normalized.equals(value)) {
|
||||
|
||||
+1
-3
@@ -15,9 +15,7 @@ public record WalletCommandCompletedV1(
|
||||
BigDecimal amount,
|
||||
String errorCode,
|
||||
String errorMessage,
|
||||
Instant completedAt,
|
||||
String walletHoldId,
|
||||
String walletLedgerId
|
||||
Instant completedAt
|
||||
) {
|
||||
public static final int VERSION = 1;
|
||||
}
|
||||
|
||||
+2
-9
@@ -3,13 +3,7 @@ package com.baiyue.common.event;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* 海外业务向 Finance 发起的客户资金指令。
|
||||
* FREEZE 的 amount 为预留金额;SETTLE 全额结算;RELEASE 释放原冻结。
|
||||
* SETTLE_ACTUAL 的 amount 为最终正额 CNY 实扣,原子补差或释放余款,原冻结金额保留。
|
||||
* 实际零元使用 RELEASE,不发送零元结算。结算和释放按原业务冻结身份关联。
|
||||
* REFUND 使用独立业务退款号并携带 originalLedgerId,关联原成功消费,不创建充值。
|
||||
*/
|
||||
/** 海外业务向国内 Finance 发起的客户资金冻结、结算或释放指令。 */
|
||||
public record WalletCommandRequestedV1(
|
||||
String operation,
|
||||
long customerId,
|
||||
@@ -18,8 +12,7 @@ public record WalletCommandRequestedV1(
|
||||
BigDecimal amount,
|
||||
String remark,
|
||||
String idempotencyKey,
|
||||
Instant requestedAt,
|
||||
String originalLedgerId
|
||||
Instant requestedAt
|
||||
) {
|
||||
public static final int VERSION = 1;
|
||||
}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.baiyue.common.event;
|
||||
|
||||
/** 成功扣款凭据;资金业务身份独立于费用对应的实际服务订单。 */
|
||||
public record WalletSettlementReference(String commandEventId, String holdId, String ledgerId,
|
||||
@com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
|
||||
String walletBusinessType,
|
||||
@com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
|
||||
String walletBusinessNo) {
|
||||
/** 原有资金身份与服务订单一致的来源继续使用原三项凭据。 */
|
||||
public WalletSettlementReference(String commandEventId, String holdId, String ledgerId) {
|
||||
this(commandEventId, holdId, ledgerId, null, null);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* 国内与海外业务单元共享的稳定事件契约。
|
||||
*
|
||||
* <p>海外费用的 walletSettlement 引用成功扣款的 commandEventId、holdId、ledgerId。
|
||||
* 独立资金流程另外携带 walletBusinessType、walletBusinessNo:人工费用为
|
||||
* OVERSEAS_MANUAL_FEE / 来源费用ID-冻结次数,仓租为 STORAGE_RENT / 出库预占ID。
|
||||
* 外层 businessType、businessNo 始终表示实际服务订单,不能替换为资金流程编号。
|
||||
* Finance 同时核对冻结、实扣流水、成功指令结果及客户金额,一个 hold 只能关联一个费用来源。
|
||||
* 资金身份与服务订单一致的既有引用省略这两个字段,保持既有快照哈希。</p>
|
||||
*/
|
||||
package com.baiyue.common.event;
|
||||
|
||||
+6
-27
@@ -1,41 +1,20 @@
|
||||
package com.baiyue.common.event;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class ContainerNumbersTest {
|
||||
/** 规范化仍保持确定性,事件只能接受已冻结的规范值。 */
|
||||
@Test
|
||||
void normalizesWhitespaceAndCaseButCanonicalFactsRequireExactValue() {
|
||||
void normalizesWhitespaceAndCaseButCanonicalFactsRequireExactIso6346Value() {
|
||||
assertThat(ContainerNumbers.normalizeRequired(" zcsu 7881970 ")).isEqualTo("ZCSU7881970");
|
||||
assertThat(ContainerNumbers.requireCanonical("ZCSU7881970")).isEqualTo("ZCSU7881970");
|
||||
assertThatThrownBy(() -> ContainerNumbers.requireCanonical("zcsu7881970"))
|
||||
.hasMessageContaining("normalized");
|
||||
assertThatThrownBy(() -> ContainerNumbers.requireCanonical(" JZXH10231043 "))
|
||||
.hasMessageContaining("normalized");
|
||||
}
|
||||
|
||||
/** 非 ISO 柜号可以作为事件事实,不在下游重新阻断。 */
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"JZXH10231043", "ZCSU7881971", "MSCA6639870", "ABC", "ABCU123456789012", "LOCAL-2026-001"})
|
||||
void acceptsNonIsoNumber(String containerNo) {
|
||||
assertThat(ContainerNumbers.normalizeRequired(" " + containerNo.toLowerCase(java.util.Locale.ROOT) + " "))
|
||||
.isEqualTo(containerNo);
|
||||
assertThat(ContainerNumbers.requireCanonical(containerNo)).isEqualTo(containerNo);
|
||||
}
|
||||
|
||||
/** 规范化前后均不得将空白柜号作为业务事实。 */
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", "\u00a0\u3000"})
|
||||
void rejectsMissingNumber(String containerNo) {
|
||||
assertThatThrownBy(() -> ContainerNumbers.normalizeRequired(containerNo))
|
||||
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining("required");
|
||||
assertThatThrownBy(() -> ContainerNumbers.requireCanonical(containerNo))
|
||||
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining("required");
|
||||
assertThatThrownBy(() -> ContainerNumbers.normalizeRequired("ZCSU7881971"))
|
||||
.hasMessageContaining("check digit");
|
||||
assertThatThrownBy(() -> ContainerNumbers.normalizeRequired("CAB-260831-0001"))
|
||||
.hasMessageContaining("ISO 6346");
|
||||
}
|
||||
}
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package com.baiyue.common.event;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WalletSettlementReferenceTest {
|
||||
private final ObjectMapper json = new ObjectMapper();
|
||||
|
||||
@Test
|
||||
void oldReferencesRetainExactHashShape() throws Exception {
|
||||
String original = "{\"commandEventId\":\"c1\",\"holdId\":\"9\",\"ledgerId\":\"72\"}";
|
||||
var reference = json.readValue(original, WalletSettlementReference.class);
|
||||
assertThat(json.readTree(json.writeValueAsString(reference))).isEqualTo(json.readTree(original));
|
||||
}
|
||||
|
||||
@Test
|
||||
void dedicatedFundingIdentitySurvivesRoundTrip() throws Exception {
|
||||
var reference = new WalletSettlementReference("c1", "9", "72", "STORAGE_RENT", "445");
|
||||
assertThat(json.readValue(json.writeValueAsString(reference), WalletSettlementReference.class)).isEqualTo(reference);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common OpenAPI 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 为 Spring MVC 服务提供 SpringDoc/OpenAPI 自动配置和统一文档元数据。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common Security 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 提供业务服务通用的 JWT 解码、认证过滤、Redis Access Token 会话校验、认证用户上下文及 401/403 JSON 响应。
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Common Web 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责边界
|
||||
|
||||
- 提供 Servlet Web 通用能力:请求链路标识、上下文和统一异常响应。
|
||||
|
||||
@@ -40,14 +40,8 @@ public class GlobalExceptionHandler {
|
||||
@Autowired(required = false)
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
/** 系统类业务失败必须记录链路和异常,普通业务校验仍只返回统一响应。 */
|
||||
@ExceptionHandler(BizException.class)
|
||||
public ResponseEntity<ApiResponse<Void>> handleBusiness(BizException exception, HttpServletRequest request) {
|
||||
if (exception.getResultCode().httpStatus().is5xxServerError()) {
|
||||
log.error("系统业务请求失败 method={} path={} code={} requestId={} traceId={}",
|
||||
request.getMethod(), request.getRequestURI(), exception.getResultCode().code(),
|
||||
CorrelationContext.requestId(request), CorrelationContext.traceId(request), exception);
|
||||
}
|
||||
return failure(exception.getResultCode(), exception.getMessage(), request);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ import com.baiyue.common.core.exception.BizException;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
@@ -42,37 +39,6 @@ class GlobalExceptionHandlerTest {
|
||||
assertThat(response.getBody().requestId()).isEqualTo("r1");
|
||||
}
|
||||
|
||||
/** 系统类业务失败留下路径、关联标识和根因,但不打印请求参数或令牌。 */
|
||||
@Test
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
void systemBusinessFailureLogsCorrelationAndCause(CapturedOutput output) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/api/platform/v1/orders/status-counts");
|
||||
request.setAttribute(CorrelationContext.REQUEST_ID, "status-count-request");
|
||||
request.setAttribute(CorrelationContext.TRACE_ID, "status-count-trace");
|
||||
request.setQueryString("keyword=private-query");
|
||||
request.addHeader("X-Internal-Service-Token", "private-service-token");
|
||||
BizException exception = new BizException(ResultCode.SERVICE_UNAVAILABLE, "统计暂不可用");
|
||||
exception.initCause(new IllegalStateException("缺少尾程来源"));
|
||||
|
||||
var response = handler.handleBusiness(exception, request);
|
||||
|
||||
assertThat(response.getStatusCode().value()).isEqualTo(200);
|
||||
assertThat(response.getBody().code()).isEqualTo("S0503");
|
||||
assertThat(response.getBody().message()).isEqualTo("统计暂不可用");
|
||||
assertThat(output.getOut()).contains("ERROR", "GET", "/api/platform/v1/orders/status-counts",
|
||||
"S0503", "status-count-request", "status-count-trace", "缺少尾程来源")
|
||||
.doesNotContain("private-query", "private-service-token");
|
||||
}
|
||||
|
||||
/** 预期的业务冲突不应升级为系统错误日志。 */
|
||||
@Test
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
void normalBusinessFailureDoesNotLogSystemError(CapturedOutput output) {
|
||||
handler.handleBusiness(new BizException(ResultCode.CONFLICT, "normal-business-conflict"),
|
||||
new MockHttpServletRequest());
|
||||
assertThat(output.getAll()).doesNotContain("系统业务请求失败", "normal-business-conflict");
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidQueryParameterTypeMapsToBadRequest() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
@@ -123,85 +123,4 @@ baiyue:
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 500
|
||||
LAST_MILE_ORDER_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/LAST_MILE_ORDER_LIST/batches
|
||||
required-permission: platform:overseas-warehouse:last-mile-order:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
OVERSEAS_INVENTORY_BALANCE:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/OVERSEAS_INVENTORY_BALANCE/batches
|
||||
required-permission: platform:overseas-warehouse:inventory:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
SELFOP_INVENTORY_TURNOVER:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/SELFOP_INVENTORY_TURNOVER/batches
|
||||
required-permission: platform:self-operated-analytics:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 100
|
||||
OVERSEAS_INVENTORY_LEDGER:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/OVERSEAS_INVENTORY_LEDGER/batches
|
||||
required-permission: platform:overseas-warehouse:inventory:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
OVERSEAS_QUOTE_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/OVERSEAS_QUOTE_LIST/batches
|
||||
required-permission: platform:overseas-master-data:quote:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
MONTHLY_EXCHANGE_RATE_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/MONTHLY_EXCHANGE_RATE_LIST/batches
|
||||
required-permission: platform:overseas-master-data:exchange-rate:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
VEHICLE_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/VEHICLE_LIST/batches
|
||||
required-permission: platform:overseas-master-data:vehicle:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
FLEET_QUOTE_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/FLEET_QUOTE_LIST/batches
|
||||
required-permission: platform:fleet:quote:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
TRIP_OPERATIONS_LIST:
|
||||
provider-service: lastleg-service
|
||||
provider-path: /internal/exports/v1/TRIP_OPERATIONS_LIST/batches
|
||||
required-permission: platform:fleet:operations:export
|
||||
app-scope: PLATFORM
|
||||
enabled: true
|
||||
max-rows: 200000
|
||||
max-attempts: 3
|
||||
batch-size: 200
|
||||
baiyue.clients.finance.url: ${FINANCE_SERVICE_URL:}
|
||||
|
||||
@@ -5,8 +5,7 @@ spring:
|
||||
password: ${FINANCE_DB_PASSWORD}
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
baiyue.clients.warehouse.url: ${WAREHOUSE_SERVICE_URL:}
|
||||
# TEST 流程验收复用 Client 的示例图片,图片标注不可付款且不含真实收款信息。
|
||||
baiyue.finance.recharge.qr-code-url: ${FINANCE_RECHARGE_QR_CODE_URL:/customer-recharge-qr.svg}
|
||||
baiyue.finance.recharge.qr-code-url: ${FINANCE_RECHARGE_QR_CODE_URL:}
|
||||
baiyue.finance.wallet.default-credit-limit: ${FINANCE_WALLET_DEFAULT_CREDIT_LIMIT:0.00}
|
||||
baiyue.event-delivery.operations-token: ${EVENT_OPERATIONS_TOKEN:}
|
||||
baiyue.event-delivery.connect-timeout-ms: ${EVENT_CONNECT_TIMEOUT_MS:3000}
|
||||
|
||||
@@ -218,12 +218,6 @@ services:
|
||||
environment:
|
||||
<<: *common-environment
|
||||
SERVER_PORT: 9210
|
||||
LINGXING_WMS_ENABLED: ${LINGXING_WMS_ENABLED:-false}
|
||||
LINGXING_COLLECTION_MODE: ${SELFOP_COLLECTION_MODE:-OFF}
|
||||
LINGXING_ENVIRONMENT_LABEL: ${DEPLOY_ENV:-test}
|
||||
LINGXING_SOURCE_ACCOUNT: ${SELFOP_SOURCE_ACCOUNT:-lingxing-primary}
|
||||
LINGXING_OMS_APP_KEY: ${LINGXING_OMS_APP_KEY:-}
|
||||
LINGXING_OMS_APP_SECRET: ${LINGXING_OMS_APP_SECRET:-}
|
||||
BAIDU_OCR_ENABLED: ${BAIDU_OCR_ENABLED:-false}
|
||||
BAIDU_OCR_API_KEY: ${BAIDU_OCR_API_KEY:-}
|
||||
BAIDU_OCR_SECRET_KEY: ${BAIDU_OCR_SECRET_KEY:-}
|
||||
@@ -285,20 +279,9 @@ services:
|
||||
image: ${IMAGE_REPOSITORY}/lastleg-service:${IMAGE_TAG}
|
||||
container_name: firstleg-${DEPLOY_ENV:-test}-lastleg
|
||||
expose: ["9303"]
|
||||
# 仅限制尾程服务,避免 JVM 异常时拖垮测试服务器.
|
||||
mem_limit: 3g
|
||||
memswap_limit: 3g
|
||||
cpus: "2.0"
|
||||
environment:
|
||||
<<: *common-environment
|
||||
SERVER_PORT: 9303
|
||||
JAVA_TOOL_OPTIONS: "-Xms512m -Xmx1536m -XX:+ExitOnOutOfMemoryError -Dfile.encoding=UTF-8"
|
||||
SELFOP_EXECUTION_ENABLED: ${SELFOP_EXECUTION_ENABLED:-false}
|
||||
SELFOP_COLLECTION_MODE: ${SELFOP_COLLECTION_MODE:-OFF}
|
||||
SELFOP_SOURCE_ACCOUNT: ${SELFOP_SOURCE_ACCOUNT:-lingxing-primary}
|
||||
SELFOP_DAILY_REQUEST_BUDGET: ${SELFOP_DAILY_REQUEST_BUDGET:-0}
|
||||
SELFOP_MIN_REQUEST_INTERVAL_MS: ${SELFOP_MIN_REQUEST_INTERVAL_MS:-5000}
|
||||
SELFOP_SALES_PUBLICATION_ENABLED: ${SELFOP_SALES_PUBLICATION_ENABLED:-false}
|
||||
EVENT_CONNECT_TIMEOUT_MS: ${EVENT_CONNECT_TIMEOUT_MS:-3000}
|
||||
EVENT_READ_TIMEOUT_MS: ${EVENT_READ_TIMEOUT_MS:-15000}
|
||||
EVENT_LEASE_SECONDS: ${EVENT_LEASE_SECONDS:-60}
|
||||
@@ -338,5 +321,3 @@ networks:
|
||||
infra-network:
|
||||
external: true
|
||||
name: ${INFRA_NETWORK:-firstleg-${DEPLOY_ENV:-test}-infra-network}
|
||||
|
||||
|
||||
|
||||
Vendored
-10
@@ -21,16 +21,6 @@ IMAGE_TAG=
|
||||
FILE_UPLOADS_HOST_DIR=/data/firstleg/uploads
|
||||
CORS_ALLOWED_ORIGINS=
|
||||
INTERNAL_SERVICE_TOKEN=
|
||||
# 领星唯一账号;凭据仅注入 integration-service。
|
||||
LINGXING_OMS_APP_KEY=
|
||||
LINGXING_OMS_APP_SECRET=
|
||||
LINGXING_WMS_ENABLED=false
|
||||
SELFOP_COLLECTION_MODE=OFF
|
||||
SELFOP_SOURCE_ACCOUNT=lingxing-primary
|
||||
# 未核准额度使用0,真实出口拒绝请求;有效模式仍需显式的独占交接证明与截止时间。
|
||||
SELFOP_DAILY_REQUEST_BUDGET=0
|
||||
SELFOP_MIN_REQUEST_INTERVAL_MS=5000
|
||||
SELFOP_SALES_PUBLICATION_ENABLED=false
|
||||
REDIS_PASSWORD=
|
||||
AUTH_DB_URL=jdbc:mysql://host.docker.internal:3306/baiyue_auth?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
|
||||
AUTH_DB_USERNAME=
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { readFileSync, readdirSync, writeFileSync, statSync } from 'node:fs'
|
||||
import { resolve, relative, basename } from 'node:path'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const moduleName = 'lastleg-service'
|
||||
const testClass = /(?:^Test.+|.+(?:Test|Tests|TestCase))\.java$/
|
||||
const words = source => new Set(source.match(/[A-Za-z_$][A-Za-z0-9_$]*/g) || [])
|
||||
const tables = source => new Set(source.match(/\bll_[a-z0-9_]+\b/g) || [])
|
||||
const writtenTables = source => new Set([...source.matchAll(/\b(?:UPDATE|INSERT\s+(?:IGNORE\s+)?INTO|DELETE\s+FROM)\s+(ll_[a-z0-9_]+)/gi)].map(match => match[1]))
|
||||
|
||||
// 按完整注解比较 SQL,避免只改 SELECT 时把同一 Mapper 内未改的全部写语句扩大为全域回归。
|
||||
function writeStatements(source) {
|
||||
const result = []
|
||||
for (const match of source.matchAll(/@(?:Insert|Update|Delete)\s*\(/g)) {
|
||||
let depth = 1, quote = '', index = match.index + match[0].length
|
||||
for (; index < source.length && depth; index++) {
|
||||
if (quote) {
|
||||
if (source.startsWith(quote, index)) { index += quote.length - 1; quote = '' }
|
||||
else if (source[index] === '\\' && quote.length === 1) index++
|
||||
} else if (source.startsWith('"""', index)) { quote = '"""'; index += 2 }
|
||||
else if (source[index] === '"' || source[index] === "'") quote = source[index]
|
||||
else if (source[index] === '(') depth++
|
||||
else if (source[index] === ')') depth--
|
||||
}
|
||||
if (depth) throw new Error('Cannot parse SQL annotation; use MODULE test scope')
|
||||
result.push(source.slice(match.index, index))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function changedWrites(node) {
|
||||
if (node.previousSource === undefined) return writtenTables(node.source)
|
||||
const before = writeStatements(node.previousSource), after = writeStatements(node.source)
|
||||
const changed = [...before.filter(sql => !after.includes(sql)), ...after.filter(sql => !before.includes(sql))]
|
||||
const oldRest = before.reduce((text, sql) => text.replace(sql, ''), node.previousSource)
|
||||
const newRest = after.reduce((text, sql) => text.replace(sql, ''), node.source)
|
||||
if (oldRest !== newRest) changed.push(oldRest, newRest)
|
||||
return writtenTables(changed.join('\n'))
|
||||
}
|
||||
|
||||
/** 宁可扩大范围,不用文件名猜测唯一测试;未识别的输入保留完整模块门禁。 */
|
||||
export function planTests({ modules, mode = 'AUTO', changes = [], sources = [], baseline = '' }) {
|
||||
const architectureScript = `${moduleName}/scripts/analyze-lastleg-dependencies`
|
||||
const staticChecks = changes.some(path => path.startsWith(architectureScript))
|
||||
? [`${architectureScript}.test.mjs`] : []
|
||||
const full = reason => ({ scope: 'MODULE', reason, modules, baseline, tests: [], staticChecks })
|
||||
if (mode !== 'AUTO' && mode !== 'MODULE') throw new Error('TEST_SCOPE must be AUTO or MODULE')
|
||||
if (mode === 'MODULE') return full('显式完整模块回归')
|
||||
if (!baseline) return full('没有成功测试基线')
|
||||
if (modules.length !== 1 || modules[0] !== moduleName) return full('多服务或尚未核对的服务采用完整模块回归')
|
||||
const prefix = `${moduleName}/`
|
||||
const relevant = changes.filter(path => path.startsWith(prefix))
|
||||
const shared = changes.some(path => path !== 'scripts/agents-index-contract.ps1' && !path.startsWith(prefix)
|
||||
&& /^(?:common-[^/]+\/|platform-bom\/|pom\.xml$|Jenkinsfile|deploy\/|config\/|scripts\/.*\.(?:mjs|sh|ps1)$)/.test(path))
|
||||
if (shared) return full('公共能力、发布或测试基础设施变更')
|
||||
if (!relevant.length) return full('补跑服务没有可验证的业务差异')
|
||||
const java = `${prefix}src/main/java/com/baiyue/lastleg/`
|
||||
const supported = path => path.startsWith(`${prefix}src/test/java/`)
|
||||
|| path.startsWith(`${prefix}src/main/resources/openapi/`)
|
||||
|| path.startsWith(architectureScript)
|
||||
|| (path.startsWith(java) && path.slice(java.length).includes('/')
|
||||
&& !/^(?:config|security|entity|dto|model|mapper|repository|service|client)\//.test(path.slice(java.length)))
|
||||
|| /\.(?:md)$/.test(path)
|
||||
if (relevant.some(path => !supported(path))) return full('共享模型、配置、SQL、资源或未识别路径变更')
|
||||
|
||||
const nodes = sources.map(({ path, source, previousSource }) => ({ path, source, previousSource,
|
||||
symbol: basename(path, '.java'), tokens: words(source), tables: tables(source),
|
||||
test: path.startsWith(`${prefix}src/test/java/`),
|
||||
name: `${source.match(/\bpackage\s+([\w.]+)\s*;/)?.[1] || ''}.${basename(path, '.java')}` }))
|
||||
const byPath = new Map(nodes.map(node => [node.path, node]))
|
||||
const bySymbol = new Map()
|
||||
for (const node of nodes) {
|
||||
if (!bySymbol.has(node.symbol)) bySymbol.set(node.symbol, [])
|
||||
bySymbol.get(node.symbol).push(node)
|
||||
}
|
||||
const reverse = new Map(nodes.map(node => [node.path, new Set()]))
|
||||
for (const node of nodes) {
|
||||
// 包含反射字符串、静态 import、同包引用及测试夹具;重名类全部纳入。
|
||||
for (const token of node.tokens) for (const dependency of bySymbol.get(token) || []) {
|
||||
if (dependency !== node) reverse.get(dependency.path).add(node.path)
|
||||
}
|
||||
// 实现变化也要覆盖只依赖接口/基类的调用者,不能仅沿显式 import 反查。
|
||||
for (const match of node.source.matchAll(/\b(?:implements|extends)\s+([^{};]+)/g)) {
|
||||
for (const token of words(match[1])) for (const contract of bySymbol.get(token) || []) {
|
||||
if (contract !== node) reverse.get(node.path).add(contract.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
const seeds = new Set()
|
||||
const changedTables = new Set()
|
||||
for (const path of relevant.filter(path => path.endsWith('.java'))) {
|
||||
const node = byPath.get(path)
|
||||
if (node) {
|
||||
seeds.add(path)
|
||||
// 读查询变化不改变其他查询的数据;潜在写入变化则纳入同表读写消费者。
|
||||
if (!node.test) for (const table of changedWrites(node)) changedTables.add(table)
|
||||
} else {
|
||||
// 删除/移动旧类型时,仍按旧类名查现存消费者。
|
||||
const symbol = basename(path, '.java')
|
||||
const consumers = nodes.filter(consumer => consumer.tokens.has(symbol))
|
||||
if (!consumers.length) return full('删除类型缺少可追踪的现存消费者')
|
||||
for (const consumer of consumers) seeds.add(consumer.path)
|
||||
}
|
||||
}
|
||||
if (!seeds.size) return full('没有可追踪的 Java 行为差异')
|
||||
for (const node of nodes) if ([...node.tables].some(table => changedTables.has(table))) seeds.add(node.path)
|
||||
const affected = new Set(seeds)
|
||||
const queue = [...seeds]
|
||||
for (let index = 0; index < queue.length; index++) {
|
||||
for (const consumer of reverse.get(queue[index]) || []) if (!affected.has(consumer)) {
|
||||
affected.add(consumer); queue.push(consumer)
|
||||
}
|
||||
}
|
||||
const allTests = nodes.filter(node => node.test && testClass.test(basename(node.path))
|
||||
&& /@(?:Test|ParameterizedTest|RepeatedTest|TestFactory|TestTemplate)\b/.test(node.source))
|
||||
const contractChange = relevant.some(path => path.startsWith(`${prefix}src/main/resources/openapi/`))
|
||||
const candidates = allTests.filter(node => affected.has(node.path)
|
||||
|| /(?:Security|Isolation|MapperRegistrationArchitecture|QueryBinding)/.test(node.symbol)
|
||||
|| (contractChange && /(?:Contract|OpenApi|Schema|Architecture|Permission)/.test(node.symbol)))
|
||||
// 显式依赖真实环境的类仍由 MODULE/专项授权入口负责,不能把它们默认跳过算作执行成功。
|
||||
const optIn = node => /@(?:EnabledIf(?:SystemProperty|EnvironmentVariable)|Disabled(?:IfSystemProperty|IfEnvironmentVariable)?\b)/
|
||||
.test(node.source.slice(0, node.source.indexOf(`class ${node.symbol}`)))
|
||||
const tests = candidates.filter(node => !optIn(node))
|
||||
if (!tests.some(node => affected.has(node.path))) return full('没有匹配到行为测试,拒绝零测试通过')
|
||||
if (tests.some(node => !/^com\.[\w.$]+$/.test(node.name))) return full('测试类名无法安全传入 Maven')
|
||||
return { scope: 'AFFECTED', reason: 'Java 反向引用、接口实现、测试夹具、共享 SQL 表和相关静态合同',
|
||||
modules, baseline, tests: tests.map(node => node.name).sort(), totalTests: allTests.length, staticChecks,
|
||||
optInTests: candidates.filter(optIn).map(node => node.name).sort() }
|
||||
}
|
||||
|
||||
function walk(root) {
|
||||
const files = []
|
||||
for (const item of readdirSync(root, { withFileTypes: true })) {
|
||||
const path = resolve(root, item.name)
|
||||
if (item.isDirectory()) files.push(...walk(path))
|
||||
else if (item.isFile() && item.name.endsWith('.java')) files.push(path)
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
/** 每个所选类必须有本轮实际执行的报告;允许上游零匹配不能变成整个门禁零测试。 */
|
||||
export function verifyReports(plan, reports) {
|
||||
if (plan.scope !== 'AFFECTED') return
|
||||
for (const name of plan.tests) {
|
||||
const matches = reports.filter(report => report.name === name || report.name.startsWith(`${name}$`))
|
||||
if (!matches.length || matches.some(report => report.failures || report.errors
|
||||
|| ['tests', 'skipped', 'failures', 'errors'].some(key => !Number.isInteger(report[key]) || report[key] < 0)
|
||||
|| report.skipped > report.tests)
|
||||
|| matches.reduce((sum, report) => sum + report.tests - report.skipped, 0) <= 0) {
|
||||
throw new Error(`Missing, skipped or failed fresh test report: ${name}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function main(args) {
|
||||
const [action, ...options] = args
|
||||
const values = {}
|
||||
for (let i = 0; i < options.length; i += 2) {
|
||||
if (!options[i].startsWith('--') || options[i + 1] === undefined) throw new Error('Expected --name value')
|
||||
values[options[i].slice(2)] = options[i + 1]
|
||||
}
|
||||
const root = process.cwd()
|
||||
const planFile = values.plan
|
||||
if (!planFile) throw new Error('--plan is required')
|
||||
if (action === 'plan') {
|
||||
const modules = (values.modules || '').split(',')
|
||||
if (modules.some(module => !/^[a-z][a-z0-9-]+$/.test(module))) throw new Error('Invalid modules')
|
||||
let baseline = values.base || ''
|
||||
let changes = []
|
||||
if (baseline) {
|
||||
if (!/^[0-9a-f]{7,40}$/i.test(baseline)) throw new Error('Invalid baseline commit')
|
||||
try {
|
||||
execFileSync('git', ['merge-base', '--is-ancestor', baseline, 'HEAD'], { stdio: 'pipe' })
|
||||
changes = execFileSync('git', ['diff', '--name-only', '-z', baseline, 'HEAD'], { encoding: 'utf8' }).split('\0').filter(Boolean)
|
||||
} catch { baseline = '' }
|
||||
}
|
||||
const sources = modules.length === 1 && modules[0] === moduleName
|
||||
? ['main', 'test'].flatMap(set => walk(resolve(root, moduleName, 'src', set, 'java')))
|
||||
.map(path => {
|
||||
const key = relative(root, path).replaceAll('\\', '/')
|
||||
const entry = { path: key, source: readFileSync(path, 'utf8') }
|
||||
if (baseline && changes.includes(key)) {
|
||||
try { entry.previousSource = execFileSync('git', ['show', `${baseline}:${key}`], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }) }
|
||||
catch { entry.previousSource = '' }
|
||||
}
|
||||
return entry
|
||||
}) : []
|
||||
const plan = { ...planTests({ modules, mode: values.mode || 'AUTO', baseline, changes, sources }), startedAt: Date.now() }
|
||||
writeFileSync(planFile, JSON.stringify(plan))
|
||||
console.log(`CI test scope: ${plan.scope}; ${plan.reason}`)
|
||||
if (plan.scope === 'AFFECTED') console.log(`Selected ${plan.tests.length}/${plan.totalTests} test classes:\n${plan.tests.join('\n')}`)
|
||||
if (plan.optInTests?.length) console.log(`Explicit environment tests remain opt-in (not counted as passed): ${plan.optInTests.join(',')}`)
|
||||
return
|
||||
}
|
||||
const plan = JSON.parse(readFileSync(planFile, 'utf8'))
|
||||
if (action === 'args') {
|
||||
if (plan.scope === 'AFFECTED') process.stdout.write(`-Dtest=${plan.tests.join(',')} -Dsurefire.failIfNoSpecifiedTests=false -Dci.sql-semantic.skip=true`)
|
||||
} else if (action === 'checks') {
|
||||
for (const check of plan.staticChecks || []) {
|
||||
if (check !== `${moduleName}/scripts/analyze-lastleg-dependencies.test.mjs`) throw new Error('Unsupported static check')
|
||||
execFileSync(process.execPath, ['--test', '--test-concurrency=2', check], { stdio: 'inherit' })
|
||||
}
|
||||
} else if (action === 'verify') {
|
||||
const reports = []
|
||||
if (plan.scope === 'AFFECTED') for (const module of plan.modules) {
|
||||
const directory = resolve(root, module, 'target/surefire-reports')
|
||||
for (const filename of readdirSync(directory)) {
|
||||
if (!/^TEST-.*\.xml$/.test(filename)) continue
|
||||
const path = resolve(directory, filename)
|
||||
if (statSync(path).mtimeMs < plan.startedAt - 2000) continue
|
||||
const xml = readFileSync(path, 'utf8').match(/<testsuite\b([^>]+)>/)?.[1]
|
||||
if (!xml) continue
|
||||
const attrs = Object.fromEntries([...xml.matchAll(/([\w-]+)="([^"]*)"/g)].map(match => [match[1], match[2]]))
|
||||
reports.push({ name: attrs.name || '', ...Object.fromEntries(['tests', 'failures', 'errors', 'skipped'].map(key => [key, Number(attrs[key] || 0)])) })
|
||||
}
|
||||
}
|
||||
verifyReports(plan, reports)
|
||||
console.log(`CI test reports verified: ${plan.scope}`)
|
||||
} else throw new Error(`Unknown action: ${action}`)
|
||||
}
|
||||
|
||||
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
try { main(process.argv.slice(2)) } catch (error) { console.error(error.message); process.exitCode = 1 }
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
# 2026-10-16 拉取合并数据库变更汇总
|
||||
|
||||
范围:IDEA 更新前暂存基点 `cda5f3dc3` 到远程 `test` 的 `4e2ea8940`,加上本次恢复的本地改动。不是任意历史版本的一键全量升级脚本。没有连接或执行实际数据库。
|
||||
|
||||
## 数据库对应关系
|
||||
|
||||
| 服务 | 数据库 | 本次处理 |
|
||||
|---|---|---|
|
||||
| lastleg-service | `baiyue_lastleg` | 执行下列 V28 增量,新增表、字段、索引并放宽四个字段的可空性 |
|
||||
| warehouse-overseas-service | `baiyue_lastlag_warehouse` | 仅业务代码变化,无新增表或字段,无需 SQL;数据库名称保留正式的 lastlag 拼写 |
|
||||
| 其他服务 | 各服务原数据库 | 本次比较范围内无 SQL 结构新增,无需 SQL |
|
||||
|
||||
已有尾程库使用:[V28 可重复执行 SQL](migrations/overseas/baiyue_lastleg/V28__merge_transfer_measurement_and_compact_numbers.sql)。由单 schema 执行器选定 `baiyue_lastleg`,文件内不切库,不访问其他服务数据库。2026-10-20 按尚未执行候选的边界移除内部切库语句,其余结构内容不变;本次未执行此候选。
|
||||
|
||||
## 新表与字段
|
||||
|
||||
| 表 | 字段 | 定义/用途 |
|
||||
|---|---|---|
|
||||
| `ll_compact_number_clock`(新表) | `number_key` | VARCHAR(16),主键,业务前缀及客户名称缩写 |
|
||||
| 同上 | `last_second` | BIGINT NOT NULL,短单号分配逻辑秒,防止同秒及多实例重号 |
|
||||
| `ll_warehouse_transfer_item` | `declared_quantity` | BIGINT NULL,SKU 申报件数,独立于箱数 |
|
||||
| `ll_warehouse_transfer_carton` | `length_cm`、`width_cm`、`height_cm`、`gross_weight_kg` | DECIMAL(12,2) NULL,逐箱实测尺寸、重量 |
|
||||
| 同上 | `counted_quantity` | BIGINT NULL,实点 SKU 件数 |
|
||||
| 同上 | `count_idempotency_key` | VARCHAR(255) NULL,清点幂等键 |
|
||||
| 同上 | `count_request_hash` | VARCHAR(64) NULL,清点请求摘要 |
|
||||
| 同上 | `counted_by` | VARCHAR(128) NULL,清点操作人 |
|
||||
| 同上 | `counted_at` | DATETIME(3) NULL,清点时间 |
|
||||
| 同上 | `discrepancy_reason` | VARCHAR(1000) NULL,实收差异原因 |
|
||||
| 同上 | `transfer_pallet_id` | BIGINT NULL,所属转运托盘事实 ID |
|
||||
| 同上 | `sku_items_json` | JSON NULL,一箱多 SKU 清点明细 |
|
||||
| 同上 | `customer_carton_mark` | VARCHAR(255) NULL,客户原箱唛及现场换标绑定 |
|
||||
|
||||
合计:1 张新表(2 列)、既有表补齐 14 列。逐箱清点等字段在旧版独立增量中已有,本次合并统一纳入 V28,避免漏执行;已存在的列会跳过。
|
||||
|
||||
## 索引及既有字段调整
|
||||
|
||||
| 表 | 调整 |
|
||||
|---|---|
|
||||
| `ll_cargo_discard_item` | 缺失时增加普通索引 `idx_ll_cargo_discard_return_carton(customer_id,return_carton_id)` |
|
||||
| `ll_warehouse_transfer_order` | `estimated_arrival_at` 改为 DATETIME(3) NULL,库存转运无需填写预计入仓时间 |
|
||||
| `ll_delivery_order` | `total_volume_cbm` 改为 DECIMAL(18,4) NULL,未知体积保持空值 |
|
||||
| `ll_outbound_order`、`ll_outbound_pallet_item` | `volume_cbm` 改为 DECIMAL(18,4) NULL,未知体积保持空值 |
|
||||
|
||||
远程同时完善了 `ll_relabel_application.delivery_method` 的业务说明及照片、预约表的中文注释,没有新增对应字段,不需要因此另建表。照片回显和箱子订单归属校验复用已有结构。
|
||||
|
||||
## 执行与重跑
|
||||
|
||||
1. 确认连接为需要升级的 MySQL 8 实例,已有 `baiyue_lastleg` 及之前版本的业务表。通过数据库客户端打开并完整执行 V28,失败时停止,不启用忽略错误继续执行。
|
||||
2. 新表采用 `CREATE TABLE IF NOT EXISTS`;每个新增字段和索引单独检查 `information_schema`,部分完成后可重跑。四个可空字段仅在当前为 NOT NULL 时调整。不会回填、删除或重算历史业务数据。
|
||||
3. DDL 在 MySQL 中会自动提交,不能整体事务回滚;脚本不会修复同名但定义不一致的已有列、索引或新表,执行前应核对这些对象的结构。脚本末尾提供字段结构查询。
|
||||
4. 此前 V1–V27 和其他已发布增量仍按原版本顺序管理,V28 不替代它们;缺失整个业务表的旧库应先完成对应历史升级。
|
||||
|
||||
空库使用原有海外统一初始化入口,已同步最终建表结构与 209 张表计数。名称含“增量”的海外统一文件仍仅用于空库,不应向已有业务库执行。
|
||||
|
||||
## 本地合并记录
|
||||
|
||||
远程分支已拉取,当前本地 HEAD 与 `origin/test` 一致。本次异常来自 IDEA 恢复更新前暂存补丁不完整;48 个文件按当前文件、原始基点、暂存内容做三方合并。唯一文本冲突保留远程 `bindingGuard` 与本地 `compactNumbers` 两项测试依赖初始化。
|
||||
|
||||
恢复前文件及三方版本保存在 `D:/project/.codex-temp/pull-resolution-20261016`;IDEA 原 shelf 保留。没有自动提交或推送代码。
|
||||
|
||||
本地验证:相关业务 Maven 定向测试通过;初始化基线、入库费用/扣货及网关路由合同共 27 项通过;Git 无未解决索引、无残留冲突标记,差异格式检查通过。SQL 仅完成离线核对,未进行 MySQL 实库执行或二次重跑验证。
|
||||
|
||||
指引索引检查 `scripts/agents-index-contract.ps1` 因工作区缺少 `D:/project/docs/业务快速索引.md` 而中止,此项未通过;未为消除检查错误而创建替代业务文档。
|
||||
@@ -1,46 +0,0 @@
|
||||
# 海外费用与仓租数据库定义汇总
|
||||
|
||||
本次功能的数据库定义已统一到下面两份 SQL,五份重复版本脚本和两份专项汇总 SQL 已移除。仅整理文件,未连接数据库、执行 SQL 或部署。
|
||||
|
||||
## 两个统一入口
|
||||
|
||||
| 文件 | 相关数据库 | 本次内容 |
|
||||
|---|---|---|
|
||||
| [头程数据库统一增量-MySQL8.sql](头程数据库统一增量-MySQL8.sql) | `baiyue_iam` | 海外费用管理菜单及默认平台管理员授权;保留既有财务编辑、审核按钮和授权 |
|
||||
| [海外区域统一增量-MySQL8.sql](海外区域统一增量-MySQL8.sql) | `baiyue_lastleg` | 资金与仓租四表、费用关联及换标快照、审核人名称、采购退款请求幂等字段与唯一索引 |
|
||||
|
||||
两份文件虽然名称包含“增量”,仍只用于对应区域的空库初始化。新增列、索引和约束直接维护在最终 `CREATE TABLE` 中,菜单及授权使用初始化种子;不追加存量改造、权限版本回填或动态迁移段。目标 schema 必须为空,按文件原有初始化流程执行;不能向已有业务库重放。
|
||||
|
||||
已有库只按实际缺项执行定向结构补齐,不能把删除重复文件理解为已有库已完成升级。指定 TEST 的最小执行集合如下;文件准备不代表获得执行授权或已部署。
|
||||
|
||||
| 顺序 | 文件 | 允许的变更与核对结果 |
|
||||
|---|---|---|
|
||||
| 1 | [表与审核人字段补齐](overseas-fees-storage-rent-structure-add.sql) | 只补 `ll_storage_rent_inbound`、`ll_finance_fee_source.reviewer_name`;已存在且匹配时跳过,同名异构则停止;成功回查表结构、字段并输出 `TABLE_COLUMN_READY` |
|
||||
| 2 | [免费仓租定向修复](overseas-storage-rent-zero-fee-repair.sql) | 仅自动应收仓租允许原币/结算双零与空汇率;保留其他费用正额及有效汇率约束,保留已有汇率精度与数值默认值;最终核对 `SHOW CREATE TABLE` 中金额、汇率两项 CHECK 和汇率可空性 |
|
||||
|
||||
两步均固定 `baiyue_lastleg`,使用独立连接、支持 `DELIMITER` 的客户端,禁止遇错继续;不执行业务 DML、不补历史计租记录、不变更余额、汇率配置或权限。DDL 隐式提交,不能宣称整体可回滚;失败保留错误并只读复查,已完成项不删除重建。两步是已核缺项的补齐方案,不是任意版本升级工具;重新执行前仍需核对目标实例与结构。
|
||||
|
||||
## 海外表和字段
|
||||
|
||||
| 类型 | 表 / 字段 | 用途 |
|
||||
|---|---|---|
|
||||
| 新表 | `ll_finance_fee_funding` | 人工费用冻结、审核扣款、释放及财务流水引用 |
|
||||
| 新表 | `ll_storage_rent_lot` | 实际入库计租原批次、数量及入库时间 |
|
||||
| 新表 | `ll_storage_rent_inbound` | 头程每次实收凭证去重,关联同单同仓计租批次 |
|
||||
| 新表 | `ll_storage_rent_share` | 库存与原计租批次份额关联,保留原库龄 |
|
||||
| 新表 | `ll_storage_rent_preparation` | 出库计租快照、汇率、资金预占及实际出库记录 |
|
||||
| 可空字段 | `ll_destuff_pallet_cost_allocation.fee_source_id` | `BIGINT NULL`,允许人工审核后关联海外费用来源 |
|
||||
| 字段 | `ll_return_sku_conversion.storage_rent_shares_json` | `LONGTEXT NULL`,退货 SKU 换标的原仓租份额快照 |
|
||||
| 字段 | `ll_finance_fee_source.reviewer_name` | `VARCHAR(255) NULL`,审核人名称快照 |
|
||||
| 字段 | `ll_overseas_procurement_fee.idempotency_key` | `VARCHAR(128) NULL`,采购退款请求幂等键 |
|
||||
| 唯一索引 | `uk_ll_procurement_refund_request(order_id,purpose,idempotency_key)` | 同一采购订单、用途和退款请求去重 |
|
||||
|
||||
## 国内菜单和权限
|
||||
|
||||
海外业务 → 海外费用管理,菜单 ID `5117200`、权限 `platform:overseas-fee:list`、路由 `/overseas-business/fees`;默认仅授予 `PLATFORM_ADMIN`。编辑和审核分别复用 `platform:finance:fee-source:edit` 与 `platform:finance:fee-source:review`,列表权限不包含写操作。国内基线已包含两项既有按钮及管理员授权。
|
||||
|
||||
已有库的 [费用写权限修复](overseas-fee-canonical-write-permissions-repair.sql) 是单独的定向补丁,继续保留原适用条件和授权边界,不是结构升级或菜单初始化入口。其他独立修复脚本与历史迁移不在本次清理范围。
|
||||
|
||||
费用项目继续使用 Firstleg 现有目录及 `FEE_TYPE_077 / 仓储费`,不重复插入项目、不批量覆盖客户专价、不回填历史仓租或费用、不修改钱包余额。
|
||||
|
||||
配套服务、页面、配置及验收边界见 [首版发布验收](../../lastleg-service/docs/overseas-fees-storage-rent-release.md)。
|
||||
+5
-109
@@ -1,102 +1,19 @@
|
||||
# 单测试环境数据库空库初始化
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V35__widen_finance_fee_command_action.sql` 修复海外人工费用资金重试报 S0500:仅将 `baiyue_lastleg.ll_finance_fee_command.action` 扩为 `VARCHAR(32)`,容纳 20 字符的 `MANUAL_FUNDING_RETRY`,保留中文备注、非空及原幂等唯一键。Lastleg 源基线和海外空库基线同步。已有环境先核对目标库及列定义,经授权执行 V35、回查列长度和记录总数,再通过原费用重试入口验证;可重复执行,不修改费用、审核、余额或资金记录,不重放空库基线。DDL 隐式提交,遇错停止;本次仅准备修复文件,尚未执行测试环境 SQL 或部署,文件存在不表示已经执行。
|
||||
|
||||
`overseas-fee-menu-finance-parent-repair.sql` 为已有 `baiyue_iam` 的定向权限修复:将菜单 `platform:overseas-fee:list` 改名为“海外费用明细”,父菜单设为 `platform:finance`(财务管理),保留原路由和 PLATFORM_ADMIN 授权;可重复执行,目标菜单缺失或权限身份冲突时停止。
|
||||
|
||||
`overseas-procurement-test-data-reset.sql` 为用户已确认可丢弃采购造数后的测试专用重置脚本:仅清空六张当前采购专属表,删除二十一张旧采购表;不会修改共用费用、余额、文件对象、库存或其他业务表,也不处理共用表的历史采购关联记录或退款。先停止采购写入并更新分离后的后端,完整执行文件、遇错停止,禁止 `--force`;DELETE 使用事务,后续 DROP 为隐式提交,不能整体回滚。无需存储过程、DELIMITER 或确认变量;成功返回 `procurement_test_reset_complete`,两个数量均为 0,成功后可重复执行。2026-10-27 已在本地隔离 MySQL 8.0.40 使用真实 27 表定义、三张 APPROVED 单及收货/出库/旧费用记录验证两次执行成功,共用表对照数据不变;未连接用户目标数据库,不表示部署完成。
|
||||
|
||||
`finance-receivable-active-uniqueness-repair.sql` 为 TEST 应收作废后重新建单的定向约束修复,仅以一条原子 ALTER 将 `baiyue_finance.fin_settlement` 的全历史唯一键替换为有效应收唯一键;作废历史仍保留原对账单关联,同一客户、同一对账单最多一张未作废应收。须先具备 Finance 重开校验版本 `fe89b8a2b875`,再单独授权执行 SQL;不修改业务金额、不清理或回填数据、不重放空库基线。执行前后核对表结构与记录总数,遇错停止,结果不明确先回查;脚本存在不表示已执行。
|
||||
|
||||
`overseas-procurement-workflow.sql` 新增简化采购的分批收货、分批出库与幂等三表,目标 `baiyue_lastleg`。新采购审核后直接分批收货,客户确认后创建出库,签收才扣采购库存;配套发布 Lastleg、Admin 和 Client。源基线与海外空库基线同步,不回填旧采购事实;结构脚本尚未执行。
|
||||
|
||||
`overseas-procurement-table-cleanup-review.sql` 为海外采购 27 表的只读核查,元数据行数为估算,另输出可手工执行的精确 COUNT。2026-10-27 已解除 21 张旧采购专属表的生产代码依赖,当前基线只保留六表。`overseas-procurement-legacy-tables-retire.sql` 为单独审阅执行的 MySQL 8.0+ 精确删表清单:仅 `baiyue_lastleg` 的 21 张旧采购表,不修改共用财务、资金、文件或仓储表。须先备份、停止旧版本写入、部署分离版本并验证,在维护窗口同连接设置脚本指定发布确认变量;六表缺失、旧状态采购或旧资金记录存在时拒绝。前置检查在业务 DROP 前完成,不关闭外键校验,使用一条 DROP TABLE IF EXISTS,可在完整成功后重跑;DDL 隐式提交,失败立即停止,禁止 --force。凭据及实例由执行者选择,不内置或自动连接。本轮未执行数据库或部署;[范围、清单及顺序](../../lastleg-service/docs/procurement-table-cleanup.md)。V14—V21 旧采购迁移仅供追溯,退役后不得重放。
|
||||
|
||||
`overseas-fees-storage-rent-structure-add.sql` 为指定 TEST 海外费用/仓租的定向结构补齐,只增加缺失的 `ll_storage_rent_inbound` 和 `ll_finance_fee_source.reviewer_name`。全部前置检查在首个业务 DDL 前完成;已有结构匹配时跳过,不匹配则停止,不覆盖或回填。随后按单独授权执行已有 `overseas-storage-rent-zero-fee-repair.sql`,补齐自动免费仓租的金额与汇率约束。使用独立连接、遇错停止,不重放空库初始化;DDL 隐式提交,失败先回查,不删除已完成项。两步范围与发布清单见[海外费用数据库定义汇总](20261022-海外费用仓租数据库变更汇总.md)及[发布配套](../../lastleg-service/docs/overseas-fees-storage-rent-release.md#发布配套)。文件准备不代表已执行或部署。
|
||||
|
||||
车辆与司机档案照片复用:先执行 `lastleg-fleet-resource-photos.sql` 新增照片版本表,再配套发布 File、Lastleg 和 Admin。车辆详情/司机详情维护照片,排车保存时复制缺失照片为当趟证据;已有照片不被后续档案替换覆盖。驾驶证统一接受 PDF/JPG/PNG。源基线与海外空库基线已同步;本次未执行环境 SQL 或部署。
|
||||
|
||||
放舱后预计到港窄维护需要配套更新 `trg_ocean_booking_before_update`:仅从冻结比较中移除 `estimated_arrival_at`,其余运输、预报、关系方及柜型冻结不变。定义已同步 `firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql` 与国内统一基线;已有 TEST 需另行审阅并授权替换该触发器,不重放空库文件,不回填数据。本轮只准备定义,未执行 SQL 或部署。
|
||||
|
||||
货柜关联已放舱订舱时不再限制 ISO 柜号格式,Firstleg 模块基线与国内统一空库基线已移除 `chk_container_booking_iso6346`,保留同订舱柜号唯一键。既有 TEST 发布前需核对并单独授权移除该约束:`ALTER TABLE baiyue_firstleg.fl_container_booking DROP CHECK chk_container_booking_iso6346;`。配套发布 Firstleg 与 Admin;不重放空库初始化、不修改业务数据。本次仅准备源码与 SQL 定义,未执行环境 SQL 或部署。
|
||||
|
||||
船节点日志在 `fl_carrier_schedule_node_fact.operator_id/operator_name` 保存操作时的账号与用户名快照;人工补录和确认出仓写入,船司自动采集为空。两列定义同步于 Firstleg 船节点模块基线与国内统一空库基线,更新结构后配套发布 Firstleg 与 Admin。既有 TEST 的字段变更须单独授权执行,不重放空库初始化,不回填历史节点。
|
||||
|
||||
`overseas-storage-rent-zero-fee-repair.sql` 为免费仓租的定向结构修复,固定 `baiyue_lastleg.ll_finance_fee_source`:先检查列类型、既有金额约束及存量行,再以单次原子 ALTER 仅放行自动应收仓租的原币及结算双零金额和空汇率,其余费用仍须正额及有效汇率。不更新费用、余额或库存;禁止重放空库初始化。源码基线与海外统一空库基线同步。脚本待审阅执行,文件存在不代表已执行。
|
||||
|
||||
`overseas-fee-remark-add.sql` 为海外人工费用说明的独立结构增量,固定目标 `baiyue_lastleg.ll_finance_fee_source`,仅在缺失时增加允许为空的 `fee_remark VARCHAR(500)`,保留旧费用与审核记录,不回填、不扣款、不改菜单。Lastleg 源基线与海外统一空库基线已同步;已有开发库须逐项授权执行本脚本后才能加载配套 Lastleg 版本。文件准备不表示已执行。
|
||||
|
||||
`finance-overseas-fee-hash-width-repair.sql` 用于明确授权的本机开发环境海外费用推送修复,固定目标 `baiyue_finance`。先核对 `fin_inbox_event.payload_hash`、`fin_fee_source.source_hash` 两列;仅将不足71位的长度扩至71位,兼容 `sha256:` 前缀,保留空值约束和字符集排序规则,不更新业务数据。缺列、异常类型或小于64位时停止;已有足够长度则跳过。使用独立连接、遇错停止,执行后回查结构,再通过原费用事件重试验证,禁止重新生成费用或扣款。脚本包含执行后移除的专用校验过程;创建或执行失败须停止,不扩大修复范围。文件准备不表示已执行。
|
||||
|
||||
`warehouse-supplier-query-structure-repair.sql` 用于明确授权的本机开发环境供应商查询结构修复,固定目标 `baiyue_warehouse`:仅在缺失时新增 `wh_supplier.trucking_scope`,并按当前模块基线创建缺失的 `wh_supplier_carrier` 空表。结构存在则跳过,不更新供应商类别、费用或资金,不推断历史拖车的国内/海外归属。使用独立连接、遇错停止,执行后回查结构并通过正式供应商列表 API 验证;不需要重启服务。文件准备不表示已获授权或已执行。
|
||||
|
||||
仓储转运到仓取货、本土卡车接入现有排车的**可重复执行汇总SQL**为 `lastleg-dispatch-transport-tasks.sql`,文件内固定 `USE baiyue_lastleg`,对已存在字段、表安全跳过。新增 `ll_dispatch_order.task_type` 字段、`ll_dispatch_truck_task`、`ll_dispatch_transport_create`、`ll_dispatch_transport_command` 三张表,并确保既有正式排车单号日流水表存在;不回填或删除业务数据。前置是目标库已具备现有整车排车主表、FleetTrip、取货任务及本土卡车原单结构。按序先执行此 SQL,再配套发布 Lastleg 与 Admin;取消释放有效原单关联、完成保留关联。`migrations/overseas/baiyue_lastleg/V32__dispatch_transport_tasks.sql` 是迁移系统中的新增结构记录。本次仅在已授权本机执行并验收,不代表远端已部署。
|
||||
|
||||
排车单号使用`PCyyyyMMdd0001`,日期取`Asia/Shanghai`,全平台跨客户/仓库共用独立日流水。`ll_dispatch_daily_sequence`同步Lastleg源基线与海外空库基线;已有结构的定向新增入口为`lastleg-dispatch-daily-sequence.sql`,只建序列表,不改已有业务号、不回填历史、不重放空库初始化。源码和DDL须配套发布;文件存在不表示已执行或部署。流水在独立短事务分配,回滚或取消不复用,四位范围每日0001至9999,准确单量以主单统计为准。
|
||||
|
||||
自有业务运营视图的结构在 Lastleg 源基线及海外统一空库基线新增四张附加表:`ll_fleet_owned_business_ownership/record/command/history`,分别保存原排车装车完成时的车辆归属证据、运营信息、命令与不可变历史;不新增排车主单或第二套运输状态。权限为 IAM `lastleg-permissions.sql` 中的自有业务 list/edit/upload,并同步国内统一空库基线。业务唯一规则见工作区 `docs/海外仓业务/自有业务首版开发契约.md`。本次仅准备源码基线,无 SQL 执行、存量回填或部署;旧已装车 TEST 数据不倒推历史归属,匹配版本按新原生样本验收。
|
||||
|
||||
客户“确认计费重”统一使用 `fl_inbound_fee` 最新已推送费用版本及其客户确认记录,不再维护独立重量确认表或接口。源建表定义、旧创建脚本与空库基线已移除;已有 TEST 先发布移除旧引用的 Firstleg 版本,再执行 `migrations/cn/baiyue_firstleg/V9__drop_chargeable_weight_confirmation.sql` 删除 `fl_chargeable_weight_confirmation`,不修改费用、订单或测量数据。脚本存在不表示已执行或部署。
|
||||
|
||||
费用项目默认价格结构:Firstleg 源基线 `phase2-fee-item-and-inbound-detail.sql` 与国内统一空库基线均增加可空的 `fl_fee_item.default_price DECIMAL(12,2)`。字段业务规则见工作区 `docs/入库测量与计费/README.md`;需与匹配的 Firstleg 和 Admin 一起发布。本次仅修改基线,不表示 SQL 已执行,也不能向已有测试库重放空库脚本。
|
||||
|
||||
排车整车作业结构同步于 Lastleg 源基线及海外统一空库基线:整车主单移除客户头部,真实客户归属保留在货物、出库、派送和费用;新增公共命令账本、主单历史、派送安排及签收待汇总信号。空排车的计划时间可暂缺,提交审核前由业务校验补齐;`ll_dispatch_physical_pallet_lock` 独立保存无代表客户的实托排他占用,`ll_dispatch_pallet_lock.physical_lock_id` 关联逐客户逻辑来源,同车可共享、跨主单或草稿容器仍排他。`ll_dispatch_item` 按主单和完整来源键唯一,`ll_dispatch_item_source` 冻结换标明细的实际位置、绑定箱数、真实件数(未知为空)及原货源事实;拣货归属新增 `dispatch_item_source_id`,与实收、退回实收、原生退货箱三类凭据四者互斥,不伪造普通收货凭据。智能草稿按拥有者、起运仓和版本维护,一容器转换一整车;独立草稿命令保存原请求和结果。必须与匹配的 Lastleg、IAM、File、Admin 和 PDA 一起核对,空库脚本不能向已有 TEST 重放。本条仅说明代码基线,不表示 SQL 已执行、已部署或全流程已验收;唯一业务规则见工作区 `docs/海外仓业务/排车列表统一作业改造契约.md`。
|
||||
|
||||
`ll_physical_pallet_guard` 以真实全局实托ID和首次创建时间提供排车冻结与仓内改托的共同串行点,独立于运输占用,不保存客户、状态、有效期或第三种拥有者。`ll_dispatch_item_source.relabel_round_key`保存真实作业轮次,不能把扫码引起的库存和申请状态变化误当作换标轮次变化。排车、草稿和仓内调用必须使用匹配的公共锁实现;本条只说明空库基线结构,不表示已执行或已部署。
|
||||
|
||||
本土散板简化下单的当前结构同步于 Lastleg 源基线及海外统一空库基线:移除散板柜型与旧要求日期,增加商品名称、申报预计托数及当地取货/送达时间,移除运输方式,增加起运地及目的地各自的联系人和联系电话;四项联系信息、取货及送货时间均必填;打盘与运输安排允许未知。预计托数不代表实收。字段语义唯一见工作区 `docs/海外仓业务/README.md`,不回填测试存量,不提供自动重置或启动时 SQL;需与匹配 Lastleg、Admin 和 Client 一起发布。本说明不表示 SQL 已执行。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V23__align_return_movement_collation.sql` 将退货进销存 UNION 涉及的八张表、22 个文本字段及表默认规则显式统一为 `utf8mb4_unicode_ci`,同步 Lastleg 两份源基线与海外统一空库基线。执行前核对字段长度、默认值、可空性及目标规则下唯一索引无冲突;只修改规则,不回填或删除数据,不重放空库基线。DDL 非事务,失败时停止并复查实际已完成项;可按最终定义重跑。脚本存在不表示测试库已执行,执行后用原始计数/分页查询验证,无需发布查询转换代码。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V22__selfop_warehouse_daily_sales.sql` 新增自营仓库每日汇总表及销量版本 `warehouse_daily_ready` 标记。与匹配 Lastleg 一起发布;汇总随 SKU 日事实批次原子构建,完整性验证后方可发布。已有未构建汇总的销量版本须重新构建发布,不回填旧版本、不回退旧查询;空版本同样必须有就绪证据。源基线与海外空库基线同步。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V21__procurement_fee_confirmation_origin.sql` 增加采购费用核定入口,区分业务节点与财务操作,用于独立新增费用、替代核定及其重试权限。同步源基线和海外统一空库基线;不回填测试存量,不表示已执行。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V20__procurement_exception_control.sql` 增加采购事实更正/阻断说明、异常关闭及逐来源最终去向三表。服务端保持原收货和发运记录,关闭不产生库存、退款或退货运输;需与采购详情聚合和节点阻断校验的匹配版本发布。源基线和海外统一基线同步,本文件存在不表示已执行。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V19__procurement_fee_correction.sql` 保存费用链修正目标、原汇率及确认前净实扣,并关联逐笔正差额/退款费用。同步进入 Lastleg 源基线与海外统一空库基线,不新增资金账本,不重算或回填旧消费;只有匹配版本能够发送本次费用链请求。本文件存在不代表已执行。
|
||||
|
||||
采购实物与运输结构分别见 `migrations/overseas/baiyue_lastleg/V17__procurement_physical_facts.sql` 和 `V18__procurement_transport_facts.sql`:V17 保存分次实收、差异、装箱及两段整批交寄七表;V18 保存面单版本、逐箱贴单、预估核对和一对一换包装四表,并补齐采购附件的 LABEL/PURCHASE/BUDGET/EXCEPTION 分类约束。源基线及海外统一空库基线同步,节点权限统一维护于采购 V5 权限脚本。File 同时发布对应文件类型约束;不补写历史收货、装箱或发运事实,不代表已执行或已验收。
|
||||
|
||||
采购购买节点结构使用 `migrations/overseas/baiyue_lastleg/V16__procurement_purchase_facts.sql`,新增单批履约事实、节点幂等审计及预算授权历史三表。独立购买/取消权限使用 `migrations/cn/baiyue_iam/V5__procurement_node_permissions.sql`,源种子为 IAM `procurement-permissions.sql`,同步进入国内统一空库基线;只给现有平台管理员角色默认授权,不新增岗位。上述结构与权限必须随采购节点匹配版本发布,不补造旧订单购买事实,不代表已执行或已验收。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V15__procurement_fee_versions.sql` 为采购费用增加用途、确认版本、原币汇率、原冻结及实际流水引用,并建立 `ll_procurement_wallet_attempt` 保存每次资金请求及最终结果。零元费用可以落核定事实但不生成资金命令;字段和约束与源基线、海外统一空库基线同步。执行前核对新增列、索引和表均未存在,先发布准备完整匹配版本;不回填旧费用、不释放或重扣测试存量。该脚本仅完成费用结构,后续履约表按相应变更单独核对。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V14__procurement_wallet_reference.sql` 为采购已实扣费用来源新增 `wallet_settlement` JSON 引用,保存 Finance 原资金命令、冻结及消费流水身份。源基线与海外统一空库基线同步维护;指定测试环境执行前核对列不存在,不回填历史费用,不重新收费。需与 Finance 资金回执、费用关联及 Lastleg 采购生产端的匹配版本一起发布;本文件存在不表示已经执行。
|
||||
|
||||
`reset-test-fba-appointments.sql` 仅用于明确授权的 TEST 预约模型重建:删除并按当前基线重建 `ll_inbound_fba_appointment`、`ll_inbound_fba_appointment_item`,并首次创建 `ll_fba_appointment_command` 保存同事务幂等结果与历史。执行任何DROP前必须确认命令表尚不存在;若已存在,先核对上次执行结果,本脚本不清空命令历史、不支持盲目重试。它会丢弃旧预约及关联明细,但不修改订单、入仓计划、库存和排车。调用者必须核对测试连接及两张表的具体重置授权;不得作为自动启动脚本或用于生产。主单区分计划日期/时段、系统单号、外部确认号和确认UTC/IANA时区;明细按稳定货源占用,不再依赖入仓计划明细。结构必须与匹配Lastleg和Admin一同发布,失败立即停止,不回填旧数据。权限从IAM种子核对;文件存在不表示已执行。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V13__widen_inbound_plan_creation_mode.sql` 仅将 `ll_inbound_plan.creation_mode` 从旧统一基线的 `VARCHAR(16)` 扩至模块基线已有的 `VARCHAR(32)`,容纳实际来货审核写入的 `WAREHOUSE_TRANSFER`(18字符)。保留 `utf8mb4_unicode_ci`、非空及 `AUTO` 默认值;不更新已有计划或状态。执行前核对目标库该列的长度、排序规则、可空性和默认值,已符合最终定义则核对后跳过;执行结果不确定时先只读复查,不盲目重试。统一空库基线同步最终定义,不重放模块历史初始化脚本。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V12__preserve_unknown_pool_order_fields.sql` 仅放开散板打盘需求及两类本土订单柜型三列为空、默认空,供未提供这些事实的拼车商业订单使用;普通订单输入校验仍由原服务端请求合同执行。对应源及统一空库基线同步最终定义,不回填已生成订单或把托盘数量解释成打盘服务需求。
|
||||
|
||||
内部拼车需求池的当前结构在 Lastleg 源基线和海外统一空库基线同步维护,独立五项权限在 IAM 源种子和国内统一基线维护。已存在基础表的指定环境结构补齐使用 `migrations/overseas/baiyue_lastleg/V10__fleet_capacity_pool.sql` 与 `migrations/cn/baiyue_iam/V4__fleet_capacity_offer_permissions.sql`;执行前确认三张新表、六个新增字段均未存在,并单独核对目标环境。随后 `V11__align_capacity_pool_collation.sql` 将预订与商业桥的客户关联字段显式统一为 `utf8mb4_unicode_ci`,与原订单域一致,避免依赖MySQL实例默认排序规则导致JOIN失败。它们不回填、删除或重置业务数据,不能重放整个空库基线。候选文件存在不表示已经执行。
|
||||
|
||||
平台自营领星统计十张 `ll_selfop_*` 表直接同步 Lastleg 源基线及海外统一空库基线;时间使用 UTC 存储及已确认北京时间业务日,数量使用 DECIMAL 保留 PCS 精度,维持独立发布版本。包含账号共享预算/冷却、验证根用途与硬预算、TEST BUSINESS 根会话持久预算、稳定任务号、阶段进度/心跳和旧版替代时间;任务的 `business_root_task_id` 标记共享根,只有根保存 `business_budget_json`,生产任务不使用该测试预算。库存 run 包含每日代表日期、选择规则及账号/仓库/日期唯一约束,代表库存与 profile 不适用销量副本淘汰。IAM 权限源为 `iam/src/main/resources/db/selfoperated-analytics-permissions.sql`,自营业务下经营总览、销量分析、库存分析、数据采集的菜单资源与独立读写权限同步国内统一基线,仅平台管理员默认授权。执行和部署状态只维护于工作区测试环境主契约;真实采集模式默认 OFF。
|
||||
|
||||
客户/商品资料基线为 `lastleg-service/src/main/resources/db/selfop-master-data.sql`,仅新增 `ll_selfop_owner`、`ll_selfop_product` 两表,并同步在 Lastleg 和海外统一空库基线。按来源账号、货主编码、SKU 和完整资料版本关联,不创建平台客户、收费对象或独立映射表;未知实测尺寸保持 NULL。对 TEST 已有库只审阅并授权这两张新表的 CREATE,不能重放统一初始化文件,也不重置采集数据。
|
||||
|
||||
历史库存还原基线为 `lastleg-service/src/main/resources/db/selfop-inventory-history.sql`,新增流水事实、历史日版本和日库存三表;同步 Lastleg 与海外空库基线。仅执行这三表 CREATE,不重放原始库存或销量表。匹配版本复用 `sync_task/run/stage` 的 `INVENTORY_FLOW_HISTORY`、`INVENTORY_HISTORY_BUILD` 与 `INVENTORY_FLOW/HISTORY_INPUT`,原库存快照不改写。完成三表并部署 Integration、Lastleg、Admin 后,才启用 `baiyue.self-operated-analytics.inventory-history-enabled=true`;默认关闭,历史目标30日优先再60日。保留当前账号出口、1200ms间隔和所有被历史版本引用的证据;现有销量副本淘汰不得删除这些引用。
|
||||
|
||||
预约工作事项新增结构由 `lastleg-service/src/main/resources/db/appointment-work.sql` 提供五张表:完整范围协调锁、工作关系、不可变历史、承诺影响版本与逐票批次实物分配,已同步 Lastleg 和海外空库初始化入口;对已有 TEST 仅审阅并授权这五表 CREATE 及协调锁初始行。直送目的仓实际卸货独立表由 `firstleg/src/main/resources/db/phase3-direct-delivery-schema.sql` 提供并同步国内空库入口,不产生海外库存。两项独立写权限见 `iam/src/main/resources/db/appointment-work-permissions.sql`,先校验精确权限身份再写入;默认只授权平台管理员。旧预约表的有损重建只允许单独审阅 `reset-test-fba-appointments.sql`;若历史、核实或工作/分配表已存在,前置检查会在 DROP 前拒绝,不能重放或擅自扩大重置范围。以上只维护脚本,不代表已执行或已部署。
|
||||
|
||||
换标直接出库的实物体积快照在 `ll_outbound_order.volume_cbm`、`ll_outbound_pallet_item.volume_cbm`、`ll_delivery_order.total_volume_cbm` 三列均允许 NULL,表示来源尚未确认;已有实盘尺寸按箱计算,不能用默认 0 代替未知,也不按 SKU 件数重复累计。两份初始化基线同步此定义,已有 TEST 只能在核对结构和授权后精确调整这三列,不重放空库文件或回填历史行。
|
||||
|
||||
排车内部散板需求发布选项由 `lastleg-service/src/main/resources/db/dispatch-capacity-demand.sql` 提供精确结构变更:仅向 `ll_dispatch_order` 新增默认勾选的 `publish_looseboard_demand` 列,Lastleg与海外空库基线同步。该文件不是自动启动脚本;执行须单独授权,不能重放完整空库文件,不新增业务数据回填或清理。实际执行与部署状态仍归测试环境主契约。
|
||||
|
||||
订舱委/实资料在 `firstleg/src/main/resources/db/phase3-ocean-booking-schema.sql` 与国内统一空库基线同步维护:订舱主表增加条款、包装、品名、唛头和委/实三项货量,关系方增加邮箱、税号;已放舱主表触发器仅允许实际货量及更新审计元数据变化,运输、预报和创建信息冻结。匹配发布单元为 Firstleg 与 Admin;Print 继续使用现有模板。本轮只准备初始化定义,不执行 SQL、不回填测试存量、不提供新旧兼容。已有测试库须另行审阅、授权结构更新,不能重放完整空库基线。
|
||||
|
||||
## 唯一入口与区域边界
|
||||
|
||||
V13 收货覆盖由 `lastleg-service/src/main/resources/db/appointment-receiving.sql` 提供四表:独立收货预约、当前/历史客户成员、待确认变化和不可变覆盖版本;同步 Lastleg 与海外空库基线。有效外部约号唯一性归收货预约的目的仓与约号,批次头表不再独立占用约号。部署前必须核对四表及旧头表唯一索引;本批只准备基线,不提供测试存量回填或自动重置。旧 `reset-test-fba-appointments.sql` 已拒绝存在这些新表的环境,不能用于重放 V13 初始化。实际 SQL 与部署须逐项授权。
|
||||
|
||||
两个统一 SQL 文件仍只用于空库初始化,名称中的“增量”不表示可向已有业务库重放。已有生产库的受控结构补齐单独放在 `migrations/`,只允许明确审阅过的增量变更;不提供存量数据回填、清理或兼容入口。
|
||||
|
||||
| 区域 | 完整入口 | 服务 schema | 表数 |
|
||||
|---|---|---|---:|
|
||||
| 国内 | `头程数据库统一增量-MySQL8.sql` | `baiyue_auth`、`baiyue_iam`、`baiyue_order`、`baiyue_warehouse`、`baiyue_firstleg`、`baiyue_file`、`baiyue_audit`、`baiyue_finance` | 229 |
|
||||
| 海外 | `海外区域统一增量-MySQL8.sql` | `baiyue_lastleg`、`baiyue_lastlag_warehouse` | 222 |
|
||||
|
||||
| 国内 | `头程数据库统一增量-MySQL8.sql` | `baiyue_auth`、`baiyue_iam`、`baiyue_order`、`baiyue_warehouse`、`baiyue_firstleg`、`baiyue_file`、`baiyue_audit`、`baiyue_finance` | 226 |
|
||||
| 海外 | `海外区域统一增量-MySQL8.sql` | `baiyue_lastleg`、`baiyue_lastlag_warehouse` | 157 |
|
||||
|
||||
- 所有服务位于同一测试环境;两份文件只分组组织服务 schema,不代表两个部署区域。`baiyue_lastlag_warehouse` 保留当前正式的 `lastlag` 拼写。
|
||||
- 两份文件必须在同一测试数据库实例中完成初始化;业务服务仍只访问本服务 schema,经内部接口访问 IAM/Warehouse。已移除事件桥两个 schema 的创建,不对已有数据库执行 DROP。
|
||||
@@ -105,7 +22,7 @@ V13 收货覆盖由 `lastleg-service/src/main/resources/db/appointment-receiving
|
||||
- 外接预订的`quote_source_json`保存可选销售报价来源版本快照,实际成交价仍在货物快照及`agreed_amount`中;手填成交价时无报价来源。该字段随Lastleg模块基线与海外统一入口维护,执行状态只见正式部署契约。
|
||||
- 异常退回的`return_context_json`保存取消时所需的原始业务状态;逐来源`received_packages`累计实际入仓量且不得超过批准退回量。同一派送可以保留多张已取消/已结束的历史退回单,活动退回仍由派送行锁内校验;普通`idx_ll_exception_delivery_return`替代跨全部历史的唯一索引。数量和状态不能通过回填旧单据伪造。
|
||||
- 派送`ll_delivery_order.signed_packages`保存签收资料确认时冻结的实际签收箱数;NULL表示未确认,不当作全量签收,数量须在0到本次实发箱数之间。后续退回保留原签收历史,不用当前退回量倒改实签。
|
||||
- `ll_return_stock_receipt`与真实退回库存入账同事务保存,按客户/入账流水唯一,保留原订单和出库位置以及实际入仓位置。重派候选、草稿锁及拣货显式引用该凭据;`receipt_id`、`return_receipt_id`、`return_carton_id`、`dispatch_item_source_id` 四类拣货归属凭据恰有一个非空。退回不增加原订单箱数,不回退历史出库流水;可重新发运量由实际退回及已消耗凭据核平。
|
||||
- `ll_return_stock_receipt`与真实退回库存入账同事务保存,按客户/入账流水唯一,保留原订单和出库位置以及实际入仓位置。重派候选、草稿锁及拣货显式引用该凭据;拣货`receipt_id`与`return_receipt_id`恰有一个非空。退回不增加原订单箱数,不回退历史出库流水;可重新发运量由实际退回及已消耗凭据核平。
|
||||
- 国内 Warehouse 管理包括海外仓在内的公共仓库主档;海外 Warehouse 只保存资源与主档 ID 引用。
|
||||
- Gateway、Print、Integration 不新增数据库。Compose 继续使用 `SPRING_SQL_INIT_MODE=never`,服务启动不执行这些文件。
|
||||
|
||||
@@ -118,7 +35,7 @@ V13 收货覆盖由 `lastleg-service/src/main/resources/db/appointment-receiving
|
||||
5. DDL 隐式提交,不可整体回滚。失败后停止并保留错误;经另行授权准备空库后从头执行,不针对半初始化库追加迁移或从失败行续跑。
|
||||
6. Firstleg 测量项与拆分项互为外键:建空表期间暂设会话 `foreign_key_checks=0`,随后立即恢复 `1`,再插入种子。失败时关闭连接。两边外键完整保留在 CREATE TABLE 内。
|
||||
|
||||
成功时只在最末输出一行 `initialization_status=PASS`,并带 `region=CN/OVERSEAS`、`initialized_tables=229/222`。必须同时确认客户端退出码 0;忽略错误后出现的 PASS 不算成功。
|
||||
成功时只在最末输出一行 `initialization_status=PASS`,并带 `region=CN/OVERSEAS`、`initialized_tables=226/157`。必须同时确认客户端退出码 0;忽略错误后出现的 PASS 不算成功。
|
||||
|
||||
## 平台管理员密码
|
||||
|
||||
@@ -134,7 +51,7 @@ V13 收货覆盖由 `lastleg-service/src/main/resources/db/appointment-receiving
|
||||
|
||||
| 所属库 | 保留内容 | 不包含 |
|
||||
|---|---|---|
|
||||
| Auth / IAM | 平台主体、唯一平台管理员、8 个系统角色及企业管理员模板、454 个权限、618 条角色权限、7 个数据范围、客户编号起点;无人工完成订单权限 | 测试客户、固定客户账号、额外扩权 |
|
||||
| Auth / IAM | 平台主体、唯一平台管理员、8 个系统角色及企业管理员模板、417 个权限、598 条角色权限、7 个数据范围、客户编号起点;无人工完成订单权限 | 测试客户、固定客户账号、额外扩权 |
|
||||
| Warehouse | 既有公共仓目录 318 条及地址;义乌、东莞、洛杉矶、纽约 4 个作业仓收货能力 | 示例供应商、快递、往来单位、托盘、库位、预占、库存 |
|
||||
| Firstleg | 112 个费用项目、15 个渠道目录、7 个始发地别名、4 个公共仓映射 | 客户报价、订单、入库、实测或履约记录 |
|
||||
| File / Finance | 导出互斥键 `GLOBAL_CREATE`、默认平台财务主体 | 文件任务、资金、账单或交易流水 |
|
||||
@@ -206,24 +123,3 @@ node --test scripts/admin-test-env-modules/initialization-baseline-contract.test
|
||||
本次整理使用隔离 MySQL 8.4,国内与海外分别在不存在对方区域 schema 的空库执行两轮,逐表比对整理前最终字段、默认值、索引、约束、注释及业务触发器。SHOW CREATE 的冗余字符集显示与运行态自增计数不视为结构差异;移除示例种子和强制改密是明确行为变更。这不代表已部署或完成真实 HTTP 验收。
|
||||
|
||||
码头车队邮件配置见 [Firstleg 车队邮件](../../firstleg/docs/terminal-drayage-mail.md)。
|
||||
|
||||
`migrations/overseas/baiyue_lastleg/V24__cargo_discard_photos.sql` 仅新增废弃照片关联表,按客户、申请和托盘关联文件及提交时间。与 Lastleg、File 和三端照片功能共同发布;不回填历史废弃单,不修改库存。脚本存在不表示目标环境已执行。
|
||||
|
||||
自营库存周转后端导出权限见 `selfop-turnover-export-permission.sql`,仅新增 `platform:self-operated-analytics:export` 并授予平台管理员;同步 IAM 自营权限源及国内统一基线。配套部署 Lastleg、File、Admin,File 注册 `SELFOP_INVENTORY_TURNOVER`(Nacos同名配置同步);无业务建表及采集配置变更。执行前须逐项授权。
|
||||
|
||||
货物废弃通用库存与散箱字段迁移:`migrations/overseas/baiyue_lastleg/V25__cargo_discard_generic_inventory.sql`。新增库存仓位关联及箱唛快照,须先迁移再部署 Lastleg;不回填历史废弃单。
|
||||
|
||||
2026-10-16 拉取合并配套结构清单及执行边界见 [数据库变更汇总](20261016-数据库变更汇总.md),已有尾程库使用 `migrations/overseas/baiyue_lastleg/V28__merge_transfer_measurement_and_compact_numbers.sql`;空库初始化海外表数同步为 209。该增量可重复执行,尚未执行到任何实际数据库。
|
||||
|
||||
## 统一业务单号
|
||||
|
||||
编号规则见 `../../../docs/业务单据编号契约.md`。Order、Warehouse、Lastleg 空库基线新增各自的 `ord_document_sequence`、`wh_document_sequence`、`ll_document_sequence`;Firstleg 与 Finance 复用本库编号表。Lastleg 空库基线移除无生产调用的客户日序列、逻辑秒时钟及旧尾程日序列表,保留排车日序列。采购费用新增可空 `idempotency_key` 及订单/用途/请求键唯一约束,用于退款重放,业务号统一使用 PF。此处只准备基线,不执行 SQL、回填或删除测试存量。
|
||||
|
||||
海外费用与仓租首版统一维护在 `头程数据库统一增量-MySQL8.sql` 的 IAM 菜单/管理员授权种子及 `海外区域统一增量-MySQL8.sql` 的最终建表定义中。海外基线包含资金与仓租四表、拆柜成本可空费用引用、退货 SKU 换标仓租快照及审核人名称;采购旧费用与退款专属表已在简化流程退役,不再进入空库初始化。同步模块源基线、国内权限种子及海外空库 222 表,复用现有 `FEE_TYPE_077 / 仓储费`,不新增费用项目种子。发布须同时更新 Firstleg、Lastleg、Admin 与海外 PDA;规则、配置及资金验收见 [首版发布验收](../../lastleg-service/docs/overseas-fees-storage-rent-release.md)。仅整理文件,未执行 SQL 或部署。
|
||||
|
||||
本次重复的五份版本脚本和两份专项汇总 SQL 已移除,内容清单见 [20261022-海外费用仓租数据库变更汇总](20261022-海外费用仓租数据库变更汇总.md)。两份统一文件仍只用于空库初始化,不能向已有业务库重放;本次不再提供这项功能的独立升级脚本,已有库升级须另按实际结构和明确授权准备、审阅增量。其他独立修复补丁及历史迁移保持各自适用边界。
|
||||
|
||||
采购方向扩展:`migrations/overseas/baiyue_lastleg/V34__procurement_direction.sql` 先于匹配 Lastleg 版本执行,为采购单增加 `procurement_direction`;历史订单默认海外采购回国内,不修改既有实物和资金记录。国内采购通过既有国内仓目录选起运收货仓;源基线与统一空库基线同步。本地验证不表示测试库已执行或服务已发布。
|
||||
|
||||
|
||||
2026-10-29 客户采购驳回和下单预算冻结:源结构与海外空库入口同步,已有 Lastleg 库使用 `overseas-order-budget-and-procurement-rejection.sql` 增加两列和预算预占表,不向已有库重放空库入口。需要匹配的 Lastleg、Admin、Client;本轮仅交付脚本,未执行数据库变更。
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
-- 本机开发环境海外费用推送结构修复。固定目标:baiyue_finance。
|
||||
-- 仅将两个既有摘要字段不足 71 位的长度扩至 71;不改数据、费用、账单或余额。
|
||||
-- 保留原字段的空值约束、字符集及排序规则;缺表、缺列或异常字段类型时拒绝执行。
|
||||
-- 执行须单独授权。使用独立连接、遇错停止;不得以本文件代替完整数据库初始化。
|
||||
USE baiyue_finance;
|
||||
|
||||
-- 执行前只读核对;sha256: 前缀 7 位加摘要 64 位,共 71 位。
|
||||
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE,
|
||||
CHARACTER_SET_NAME, COLLATION_NAME
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'baiyue_finance'
|
||||
AND ((TABLE_NAME = 'fin_inbox_event' AND COLUMN_NAME = 'payload_hash')
|
||||
OR (TABLE_NAME = 'fin_fee_source' AND COLUMN_NAME = 'source_hash'));
|
||||
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE finance_fee_hash_width_repair_20261023()
|
||||
BEGIN
|
||||
DECLARE checked_columns INT DEFAULT 0;
|
||||
DECLARE column_index INT DEFAULT 0;
|
||||
DECLARE target_table VARCHAR(64);
|
||||
DECLARE target_column VARCHAR(64);
|
||||
DECLARE current_length BIGINT;
|
||||
DECLARE nullable_value VARCHAR(3);
|
||||
DECLARE charset_value VARCHAR(64);
|
||||
DECLARE collation_value VARCHAR(64);
|
||||
DECLARE comment_value TEXT;
|
||||
|
||||
IF DATABASE() <> 'baiyue_finance' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '目标必须是 baiyue_finance';
|
||||
END IF;
|
||||
SELECT COUNT(*) INTO checked_columns
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'baiyue_finance' AND DATA_TYPE IN ('char', 'varchar')
|
||||
AND CHARACTER_MAXIMUM_LENGTH >= 64
|
||||
AND COLUMN_DEFAULT IS NULL AND EXTRA = ''
|
||||
AND ((TABLE_NAME = 'fin_inbox_event' AND COLUMN_NAME = 'payload_hash')
|
||||
OR (TABLE_NAME = 'fin_fee_source' AND COLUMN_NAME = 'source_hash'));
|
||||
IF checked_columns <> 2 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '摘要字段缺失或类型异常,停止修复';
|
||||
END IF;
|
||||
|
||||
WHILE column_index < 2 DO
|
||||
SET target_table = IF(column_index = 0, 'fin_inbox_event', 'fin_fee_source');
|
||||
SET target_column = IF(column_index = 0, 'payload_hash', 'source_hash');
|
||||
SELECT CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_COMMENT
|
||||
INTO current_length, nullable_value, charset_value, collation_value, comment_value
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'baiyue_finance' AND TABLE_NAME = target_table
|
||||
AND COLUMN_NAME = target_column;
|
||||
IF current_length < 71 THEN
|
||||
SET @finance_fee_hash_width_ddl = CONCAT(
|
||||
'ALTER TABLE baiyue_finance.`', target_table, '` MODIFY COLUMN `', target_column,
|
||||
'` VARCHAR(71) CHARACTER SET ', charset_value, ' COLLATE ', collation_value,
|
||||
IF(nullable_value = 'YES', ' NULL', ' NOT NULL'),
|
||||
' COMMENT ', QUOTE(comment_value));
|
||||
PREPARE finance_fee_hash_width_stmt FROM @finance_fee_hash_width_ddl;
|
||||
EXECUTE finance_fee_hash_width_stmt;
|
||||
DEALLOCATE PREPARE finance_fee_hash_width_stmt;
|
||||
END IF;
|
||||
SET column_index = column_index + 1;
|
||||
END WHILE;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL finance_fee_hash_width_repair_20261023();
|
||||
DROP PROCEDURE finance_fee_hash_width_repair_20261023;
|
||||
SET @finance_fee_hash_width_ddl = NULL;
|
||||
|
||||
-- 执行后两列长度均应至少为 71;结构已正确时不执行 ALTER。
|
||||
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE,
|
||||
CHARACTER_MAXIMUM_LENGTH >= 71 AS width_ok
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'baiyue_finance'
|
||||
AND ((TABLE_NAME = 'fin_inbox_event' AND COLUMN_NAME = 'payload_hash')
|
||||
OR (TABLE_NAME = 'fin_fee_source' AND COLUMN_NAME = 'source_hash'));
|
||||
@@ -1,11 +0,0 @@
|
||||
-- 仅用于单独授权的 TEST:修正作废应收仍占用原对账单的唯一约束。
|
||||
-- 不更新、删除或回填业务记录;作废单的原对账单关联与修订历史保持不变。
|
||||
-- 一条原子 ALTER 同时替换约束;有效应收重复、原索引缺失或目标列已存在均应报错停止。
|
||||
-- 使用独立连接并开启遇错停止;若结果不明确,先核对结构,不盲目重放。
|
||||
-- 前置:已部署 Finance 结算重开校验(fe89b8a2b875),目标为 MySQL 8 / InnoDB。
|
||||
ALTER TABLE baiyue_finance.fin_settlement
|
||||
ADD COLUMN active_receivable_statement_id BIGINT UNSIGNED
|
||||
GENERATED ALWAYS AS (CASE WHEN direction='RECEIVABLE' AND status<>'VOIDED' THEN reconciliation_statement_id ELSE NULL END)
|
||||
VIRTUAL COMMENT '有效应收占用的对账单;作废单不占用,历史关联仍保留',
|
||||
DROP INDEX uk_fin_settlement_receivable_statement,
|
||||
ADD UNIQUE KEY uk_fin_settlement_active_receivable (tenant_id, active_receivable_statement_id);
|
||||
@@ -1,7 +0,0 @@
|
||||
-- 排车新编号所需独立结构;仅新建序列表,不改写已有排车业务号或业务数据。
|
||||
USE baiyue_lastleg;
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_daily_sequence (
|
||||
business_date DATE NOT NULL COMMENT '排车编号业务日期(Asia/Shanghai)',
|
||||
last_sequence INT NOT NULL COMMENT '当日已分配排车流水号,范围0001至9999',
|
||||
PRIMARY KEY(business_date)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车单号每日独立原子流水';
|
||||
@@ -1,118 +0,0 @@
|
||||
-- MySQL 8 可重复执行增量:仓储转运到仓取货与本土卡车接入现有排车。
|
||||
-- 目标数据库固定为 baiyue_lastleg;仅新增运输类型、原单关联及请求账本,不回填或删除业务数据。
|
||||
-- 前置:已完成 Lastleg 现有整车排车结构升级;如部署为缺少每日流水表的旧库,也创建正式排车流水表。
|
||||
USE baiyue_lastleg;
|
||||
|
||||
-- 排车保存会同步异常快照;旧库必须先补齐该正式字段。
|
||||
SET @dispatch_exception_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_dispatch_order' AND column_name = 'exceptions_json'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_dispatch_order ADD COLUMN exceptions_json JSON NULL COMMENT ''派送异常登记记录及图片引用,不改变派送及库存状态'' AFTER review_basis_hash'
|
||||
);
|
||||
PREPARE dispatch_exception_stmt FROM @dispatch_exception_ddl;
|
||||
EXECUTE dispatch_exception_stmt;
|
||||
DEALLOCATE PREPARE dispatch_exception_stmt;
|
||||
|
||||
SET @dispatch_transport_column_ddl = IF(
|
||||
EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'll_dispatch_order' AND column_name = 'task_type'
|
||||
),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_dispatch_order ADD COLUMN task_type VARCHAR(32) NOT NULL DEFAULT ''DELIVERY'' COMMENT ''任务类型:仓库派送、到仓取货、本土卡车'' AFTER dispatch_no'
|
||||
);
|
||||
PREPARE dispatch_transport_column_stmt FROM @dispatch_transport_column_ddl;
|
||||
EXECUTE dispatch_transport_column_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_column_stmt;
|
||||
|
||||
-- 旧库兼容:整车主单跨客户,原来单客户排车头字段不再要求填写。
|
||||
-- 如目标库已删除旧字段则跳过;已有客户值保留,不置空、不修改。
|
||||
SET @dispatch_transport_legacy_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_dispatch_order' AND column_name = 'customer_id' AND is_nullable = 'NO'),
|
||||
'ALTER TABLE ll_dispatch_order MODIFY COLUMN customer_id VARCHAR(128) NULL COMMENT ''旧客户排车归属,整车主单不使用''',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE dispatch_transport_legacy_stmt FROM @dispatch_transport_legacy_ddl;
|
||||
EXECUTE dispatch_transport_legacy_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_legacy_stmt;
|
||||
|
||||
-- 旧本土卡车结构兼容:新单沿用已有的起终点联系人及pickup_at/delivery_at字段。
|
||||
-- 旧单字段保留原值,仅放宽空值约束,避免新单被已弃用字段阻断。
|
||||
SET @dispatch_transport_legacy_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_us_truck_order' AND column_name = 'contact_name' AND is_nullable = 'NO'),
|
||||
'ALTER TABLE ll_us_truck_order MODIFY COLUMN contact_name VARCHAR(128) NULL COMMENT ''旧本土卡车联系人,新单使用起终点联系人''',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE dispatch_transport_legacy_stmt FROM @dispatch_transport_legacy_ddl;
|
||||
EXECUTE dispatch_transport_legacy_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_legacy_stmt;
|
||||
|
||||
SET @dispatch_transport_legacy_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_us_truck_order' AND column_name = 'contact_info' AND is_nullable = 'NO'),
|
||||
'ALTER TABLE ll_us_truck_order MODIFY COLUMN contact_info VARCHAR(128) NULL COMMENT ''旧本土卡车联系方式,新单使用起终点联系方式''',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE dispatch_transport_legacy_stmt FROM @dispatch_transport_legacy_ddl;
|
||||
EXECUTE dispatch_transport_legacy_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_legacy_stmt;
|
||||
|
||||
SET @dispatch_transport_legacy_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_us_truck_order' AND column_name = 'requested_date' AND is_nullable = 'NO'),
|
||||
'ALTER TABLE ll_us_truck_order MODIFY COLUMN requested_date DATE NULL COMMENT ''旧本土卡车请求日期,新单使用取货和送货时间''',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE dispatch_transport_legacy_stmt FROM @dispatch_transport_legacy_ddl;
|
||||
EXECUTE dispatch_transport_legacy_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_legacy_stmt;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_daily_sequence (
|
||||
business_date DATE NOT NULL COMMENT '排车编号业务日期(Asia/Shanghai)',
|
||||
last_sequence INT NOT NULL COMMENT '当日已分配排车流水号,范围0001至9999',
|
||||
PRIMARY KEY (business_date)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车单号每日独立原子流水';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_truck_task (
|
||||
dispatch_no VARCHAR(64) NOT NULL COMMENT '排车业务号',
|
||||
trip_no VARCHAR(64) NOT NULL COMMENT '本次运输资源记录号',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '本土卡车原单客户标识',
|
||||
order_no VARCHAR(64) NOT NULL COMMENT '本土卡车原单业务号',
|
||||
active_order VARCHAR(193) NULL COMMENT '有效原单唯一键;取消置空,完成保留',
|
||||
PRIMARY KEY (dispatch_no),
|
||||
UNIQUE KEY uk_transport_trip (trip_no),
|
||||
UNIQUE KEY uk_transport_source (active_order),
|
||||
KEY idx_transport_order (customer_id, order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车与本土卡车原单关联';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_transport_create (
|
||||
trip_no VARCHAR(64) NOT NULL COMMENT '本次运输资源记录号',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '首次安排请求摘要',
|
||||
PRIMARY KEY (trip_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='本土卡车排车创建请求账本';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_transport_command (
|
||||
dispatch_no VARCHAR(64) NOT NULL COMMENT '排车业务号',
|
||||
request_key VARCHAR(128) NOT NULL COMMENT '客户端幂等请求键',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '执行命令请求摘要',
|
||||
evidence_json JSON NULL COMMENT '已确认运输完成凭证标识列表',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '业务命令提交时间',
|
||||
PRIMARY KEY (dispatch_no, request_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车运输执行命令与凭证账本';
|
||||
|
||||
-- 当前承运占用查询还依赖散板来源标识(与V33一致);仅补结构,不创建散板业务记录。
|
||||
SET @dispatch_transport_pool_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_fleet_external_booking' AND column_name = 'source_looseboard_order_id'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_fleet_external_booking ADD COLUMN source_looseboard_order_id BIGINT NULL COMMENT ''客户原始散板商业单ID,取消后保留来源'''
|
||||
);
|
||||
PREPARE dispatch_transport_pool_stmt FROM @dispatch_transport_pool_ddl;
|
||||
EXECUTE dispatch_transport_pool_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_pool_stmt;
|
||||
|
||||
SET @dispatch_transport_pool_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'll_fleet_external_booking' AND index_name = 'idx_booking_looseboard_source'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_fleet_external_booking ADD KEY idx_booking_looseboard_source (customer_id, source_looseboard_order_id, status)'
|
||||
);
|
||||
PREPARE dispatch_transport_pool_stmt FROM @dispatch_transport_pool_ddl;
|
||||
EXECUTE dispatch_transport_pool_stmt;
|
||||
DEALLOCATE PREPARE dispatch_transport_pool_stmt;
|
||||
@@ -1,16 +0,0 @@
|
||||
-- 仅新增车辆及司机档案照片版本表,可重复执行,不回填业务数据。
|
||||
USE baiyue_lastleg;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_fleet_resource_photo (
|
||||
resource_kind VARCHAR(16) NOT NULL COMMENT '档案类型:车辆或司机',
|
||||
resource_id BIGINT NOT NULL COMMENT '车辆或司机档案标识',
|
||||
record_version BIGINT NOT NULL COMMENT '照片版本,从一递增',
|
||||
file_id BIGINT NOT NULL COMMENT '文件服务照片标识',
|
||||
file_name VARCHAR(512) NOT NULL COMMENT '照片原始文件名',
|
||||
content_type VARCHAR(64) NOT NULL COMMENT '照片媒体类型',
|
||||
size_bytes BIGINT NOT NULL COMMENT '照片字节数',
|
||||
created_by VARCHAR(64) NOT NULL COMMENT '上传操作人标识',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '上传时间(UTC)',
|
||||
PRIMARY KEY (resource_kind, resource_id, record_version),
|
||||
UNIQUE KEY uk_fleet_resource_photo_file (resource_kind, resource_id, file_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆及司机档案照片版本记录';
|
||||
@@ -1,4 +0,0 @@
|
||||
-- 客户“确认计费重”统一确认 fl_inbound_fee 的当前推送费用版本。
|
||||
-- 先发布已移除旧重量确认接口及查询的 Firstleg 版本,再执行本脚本。
|
||||
-- 仅删除旧独立重量确认记录,不修改费用快照、订单或测量数据。
|
||||
DROP TABLE IF EXISTS baiyue_firstleg.fl_chargeable_weight_confirmation;
|
||||
@@ -1,28 +0,0 @@
|
||||
-- 采购节点动作独立授权;不新建岗位,不以通用编辑权限代替购买与取消。
|
||||
INSERT INTO iam_permission(id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted)
|
||||
VALUES
|
||||
(5117103,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:buy','采购购买及货款核定',NULL,'POST',803,'ACTIVE',1,0),
|
||||
(5117104,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:cancel','购买前取消采购订单',NULL,'POST',804,'ACTIVE',1,0),
|
||||
(5117105,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:receive-overseas','采购海外收货',NULL,'POST',805,'ACTIVE',1,0),
|
||||
(5117106,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:receive-domestic','采购国内收货',NULL,'POST',806,'ACTIVE',1,0),
|
||||
(5117107,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:pack','采购装箱与确认',NULL,'POST',807,'ACTIVE',1,0),
|
||||
(5117108,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:manage','采购差异处置与事实更正',NULL,'POST',808,'ACTIVE',1,0),
|
||||
(5117109,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:label','采购面单维护',NULL,'POST',809,'ACTIVE',1,0),
|
||||
(5117110,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:charge','采购国内核费',NULL,'POST',810,'ACTIVE',1,0),
|
||||
(5117111,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:finance-adjust','采购财务调整',NULL,'POST',811,'ACTIVE',1,0),
|
||||
(5117112,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:estimate','采购预估运费核对',NULL,'POST',812,'ACTIVE',1,0),
|
||||
(5117113,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:apply-label','采购逐箱贴单',NULL,'POST',813,'ACTIVE',1,0),
|
||||
(5117114,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:ship-overseas','采购海外整批交寄',NULL,'POST',814,'ACTIVE',1,0),
|
||||
(5117115,0,'PLATFORM','BUTTON',5107100,'platform:overseas-business:purchase:ship-customer','采购国内寄客户',NULL,'POST',815,'ACTIVE',1,0)
|
||||
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),status='ACTIVE',deleted=0;
|
||||
INSERT IGNORE INTO iam_role_permission(tenant_id,role_id,permission_id,created_at)
|
||||
SELECT 0,r.id,p.id,NOW(3) FROM iam_role r JOIN iam_permission p
|
||||
ON p.tenant_id=0 AND p.app_code='PLATFORM' AND p.permission_code IN
|
||||
('platform:overseas-business:purchase:buy','platform:overseas-business:purchase:cancel',
|
||||
'platform:overseas-business:purchase:receive-overseas','platform:overseas-business:purchase:receive-domestic',
|
||||
'platform:overseas-business:purchase:pack','platform:overseas-business:purchase:manage',
|
||||
'platform:overseas-business:purchase:label','platform:overseas-business:purchase:charge','platform:overseas-business:purchase:finance-adjust',
|
||||
'platform:overseas-business:purchase:estimate','platform:overseas-business:purchase:apply-label',
|
||||
'platform:overseas-business:purchase:ship-overseas','platform:overseas-business:purchase:ship-customer')
|
||||
WHERE r.tenant_id=0 AND r.app_code='PLATFORM' AND UPPER(r.role_code) IN('PLATFORM_ADMIN','PLATFORM_CUSTOM_ADMIN')
|
||||
AND r.status='ACTIVE' AND r.deleted=0;
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
-- 仅 baiyue_iam,新增客户废弃确认按钮权限并授权默认客户管理员。
|
||||
-- 自定义客户角色由管理员按需分配;不自动扩大其权限。
|
||||
-- 可重复执行;授权和持久化安全版本在同一事务提交。
|
||||
START TRANSACTION;
|
||||
INSERT INTO iam_permission(id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted)
|
||||
VALUES (5306183,0,'MERCHANT','BUTTON',5306180,'merchant:overseas-warehouse:discard:confirm','确认废弃完成',NULL,'POST',30,'ACTIVE',1,0)
|
||||
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),status='ACTIVE',deleted=0;
|
||||
INSERT IGNORE INTO iam_role_permission(tenant_id,role_id,permission_id,created_at)
|
||||
SELECT 0,r.id,p.id,NOW(3) FROM iam_role r JOIN iam_permission p
|
||||
ON p.tenant_id=0 AND p.app_code='MERCHANT' AND p.permission_code='merchant:overseas-warehouse:discard:confirm'
|
||||
WHERE r.tenant_id=0 AND r.app_code='MERCHANT' AND r.role_code='MERCHANT_OWNER' AND r.status='ACTIVE' AND r.deleted=0;
|
||||
INSERT INTO iam_security_subject_version(auth_user_id,permission_version)
|
||||
SELECT DISTINCT u.auth_user_id,1 FROM iam_user u
|
||||
JOIN iam_membership m ON m.user_id=u.id
|
||||
JOIN iam_membership_role mr ON mr.membership_id=m.id AND mr.tenant_id=m.tenant_id
|
||||
JOIN iam_role r ON r.id=mr.role_id
|
||||
WHERE u.auth_user_id IS NOT NULL AND u.status='ACTIVE' AND u.deleted=0
|
||||
AND m.status='ACTIVE' AND m.deleted=0 AND r.tenant_id=0 AND r.app_code='MERCHANT'
|
||||
AND r.role_code='MERCHANT_OWNER' AND r.status='ACTIVE' AND r.deleted=0
|
||||
ON DUPLICATE KEY UPDATE permission_version=permission_version+1;
|
||||
COMMIT;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- 采购实扣费用来源关联;仅补充结构,不回填历史费用,不修改资金或业务记录。
|
||||
-- 执行前核对指定测试环境、baiyue_lastleg schema 与该列尚不存在。
|
||||
ALTER TABLE ll_finance_fee_source
|
||||
ADD COLUMN wallet_settlement JSON NULL COMMENT '已实扣应收的Finance资金命令、冻结和消费流水引用'
|
||||
AFTER payment_voucher_file_ids;
|
||||
@@ -1,48 +0,0 @@
|
||||
-- 采购费用确认版本及资金尝试。仅变更结构,不回填、重扣或清理测试存量。
|
||||
ALTER TABLE ll_overseas_procurement_fee
|
||||
ADD COLUMN purpose VARCHAR(32) NULL COMMENT '费用业务用途;由履约节点确定',
|
||||
ADD COLUMN fee_version INT NULL COMMENT '同用途费用确认版本',
|
||||
ADD COLUMN active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否当前有效版本',
|
||||
ADD COLUMN determination VARCHAR(24) NULL COMMENT 'POSITIVE正额、ZERO零元、NOT_APPLICABLE不适用',
|
||||
ADD COLUMN original_currency CHAR(3) NULL COMMENT '核定原币CNY或USD',
|
||||
ADD COLUMN original_amount DECIMAL(20,2) NULL COMMENT '核定原币金额',
|
||||
ADD COLUMN exchange_rate DECIMAL(20,6) NULL COMMENT '已确认汇率快照',
|
||||
ADD COLUMN exchange_rate_month CHAR(7) NULL COMMENT '已确认汇率所属月份',
|
||||
ADD COLUMN business_date DATE NULL COMMENT '实际费用业务日期',
|
||||
ADD COLUMN wallet_business_id BIGINT NULL COMMENT '资金冻结对应采购费用记录',
|
||||
ADD COLUMN wallet_business_no VARCHAR(128) NULL COMMENT '资金冻结业务号;实际国际运费引用原预估',
|
||||
ADD COLUMN wallet_hold_id VARCHAR(64) NULL COMMENT 'Finance冻结引用',
|
||||
ADD COLUMN wallet_ledger_id VARCHAR(64) NULL COMMENT 'Finance实际处理流水引用',
|
||||
ADD COLUMN settled_command_event_id VARCHAR(64) NULL COMMENT '成功实扣或退款的资金命令事件',
|
||||
ADD COLUMN source_fee_id BIGINT NULL COMMENT '已实扣费用来源ID',
|
||||
ADD COLUMN parent_fee_id BIGINT NULL COMMENT '原费用或预估引用',
|
||||
ADD COLUMN request_hash CHAR(64) NULL COMMENT '确认请求摘要',
|
||||
MODIFY COLUMN voucher_file_id BIGINT NULL COMMENT '凭证文件ID;零元可空',
|
||||
MODIFY COLUMN voucher_file_name VARCHAR(255) NULL COMMENT '凭证文件名;零元可空',
|
||||
DROP CHECK chk_ll_procurement_fee_amount,
|
||||
ADD CONSTRAINT chk_ll_procurement_fee_amount CHECK(amount>=0),
|
||||
ADD UNIQUE KEY uk_ll_procurement_fee_version(order_id,purpose,fee_item_code,fee_version);
|
||||
|
||||
CREATE TABLE ll_procurement_wallet_attempt (
|
||||
id BIGINT NOT NULL COMMENT '请求尝试ID',
|
||||
order_id BIGINT NOT NULL COMMENT '采购订单ID',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
fee_id BIGINT NOT NULL COMMENT '不可变费用版本ID',
|
||||
attempt_no BIGINT NOT NULL COMMENT '费用版本内请求序号',
|
||||
operation VARCHAR(32) NOT NULL COMMENT '资金操作:FREEZE冻结、SETTLE结算、SETTLE_ACTUAL实际结算、RELEASE释放、REFUND退款',
|
||||
business_no VARCHAR(128) NOT NULL COMMENT 'Finance资金业务号',
|
||||
amount DECIMAL(20,2) NULL COMMENT '请求金额;全额结算或释放可空',
|
||||
command_event_id VARCHAR(64) NOT NULL COMMENT '资金指令事件唯一引用',
|
||||
status VARCHAR(16) NOT NULL COMMENT '资金请求结果:PENDING未决、SUCCEEDED成功、FAILED明确失败',
|
||||
result_hash CHAR(64) NULL COMMENT '原业务回执摘要',
|
||||
wallet_hold_id VARCHAR(64) NULL COMMENT 'Finance冻结引用',
|
||||
wallet_ledger_id VARCHAR(64) NULL COMMENT 'Finance处理流水引用',
|
||||
error_code VARCHAR(64) NULL COMMENT '业务失败码',
|
||||
error_message VARCHAR(500) NULL COMMENT '内部失败诊断,不直接对客展示',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '请求时间',
|
||||
completed_at DATETIME(3) NULL COMMENT '最终结果时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_attempt_event(command_event_id),
|
||||
UNIQUE KEY uk_procurement_attempt_number(fee_id,attempt_no),
|
||||
KEY idx_procurement_attempt_order(customer_id,order_id,status),
|
||||
CONSTRAINT chk_procurement_attempt_status CHECK(status IN('PENDING','SUCCEEDED','FAILED'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购费用资金命令尝试与不可变结果';
|
||||
@@ -1,57 +0,0 @@
|
||||
-- 采购节点事实与操作幂等;不补写历史订单的购买、授权或收货事实。
|
||||
CREATE TABLE ll_procurement_flow (
|
||||
order_id BIGINT NOT NULL COMMENT '采购订单ID,一单一个履约批次',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
purchased_at DATETIME(3) NULL COMMENT '真实购买时间',
|
||||
purchased_product_name VARCHAR(255) NULL COMMENT '实际购买商品',
|
||||
purchased_specification VARCHAR(500) NULL COMMENT '实际购买规格',
|
||||
purchased_quantity BIGINT NULL COMMENT '实际购买件数',
|
||||
purchase_amount DECIMAL(20,2) NULL COMMENT '供应商实付原币金额',
|
||||
purchase_currency CHAR(3) NULL COMMENT '供应商实付原币CNY或USD',
|
||||
purchase_voucher_id BIGINT NULL COMMENT '购买凭证引用',
|
||||
purchase_issue VARCHAR(500) NULL COMMENT '购买未核定或异常说明',
|
||||
purchase_confirmed_at DATETIME(3) NULL COMMENT '货款核定时间,不代表扣费成功',
|
||||
actual_warehouse_id BIGINT NULL COMMENT '首次实际收货冻结的仓库ID',
|
||||
actual_warehouse_code VARCHAR(128) NULL COMMENT '实际收货仓编码快照',
|
||||
actual_warehouse_name VARCHAR(255) NULL COMMENT '实际收货仓名称快照',
|
||||
overseas_received_at DATETIME(3) NULL COMMENT '海外整批收货完成时间',
|
||||
packing_version INT NULL COMMENT '当前确认装箱清单版本',
|
||||
overseas_shipped_at DATETIME(3) NULL COMMENT '国际段整批实际交寄时间',
|
||||
domestic_received_at DATETIME(3) NULL COMMENT '国内整批收货完成时间',
|
||||
charges_confirmed_at DATETIME(3) NULL COMMENT '国内整单费用核定时间',
|
||||
customer_shipped_at DATETIME(3) NULL COMMENT '国内寄客户实际交寄时间',
|
||||
domestic_receiver_name VARCHAR(128) NULL COMMENT '国际段国内收件人',
|
||||
domestic_receiver_phone VARCHAR(64) NULL COMMENT '国际段国内收件电话',
|
||||
domestic_receiver_address VARCHAR(1000) NULL COMMENT '国际段国内接收地址',
|
||||
cancelled_at DATETIME(3) NULL COMMENT '购买前取消时间',
|
||||
closed_at DATETIME(3) NULL COMMENT '异常关闭时间',
|
||||
control_reason VARCHAR(1000) NULL COMMENT '取消或关闭原因',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY(order_id), KEY idx_procurement_flow_customer(customer_id,order_id),
|
||||
CONSTRAINT chk_procurement_purchase_quantity CHECK(purchased_quantity IS NULL OR purchased_quantity>0),
|
||||
CONSTRAINT chk_procurement_purchase_amount CHECK(purchase_amount IS NULL OR purchase_amount>=0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购单一批次履约事实';
|
||||
|
||||
CREATE TABLE ll_procurement_command (
|
||||
id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '采购订单ID',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键', action VARCHAR(48) NOT NULL COMMENT '采购节点动作',
|
||||
idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求摘要',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '执行人', reason VARCHAR(1000) NOT NULL COMMENT '操作依据',
|
||||
detail_json JSON NOT NULL COMMENT '内部操作及更正依据快照,不直接对客展示',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '执行时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_command(order_id,action,idempotency_key),
|
||||
KEY idx_procurement_command_customer(customer_id,order_id,created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购节点幂等与不可变审计';
|
||||
|
||||
CREATE TABLE ll_procurement_budget_authorization (
|
||||
id BIGINT NOT NULL COMMENT '预算授权ID', order_id BIGINT NOT NULL COMMENT '采购订单ID',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
previous_amount DECIMAL(20,2) NULL COMMENT '原货款预算总上限;未授权保持空', previous_currency CHAR(3) NOT NULL COMMENT '原预算币种',
|
||||
authorized_amount DECIMAL(20,2) NOT NULL COMMENT '客户授权的新货款总上限', currency CHAR(3) NOT NULL COMMENT '客户授权币种',
|
||||
voucher_file_id BIGINT NOT NULL COMMENT '客户确认书面或聊天凭证', reason VARCHAR(1000) NOT NULL COMMENT '授权依据',
|
||||
reviewed_by VARCHAR(128) NOT NULL COMMENT '核验人员', reviewed_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '核验时间',
|
||||
PRIMARY KEY(id), KEY idx_procurement_budget_order(customer_id,order_id,id),
|
||||
CONSTRAINT chk_procurement_budget_amount CHECK(authorized_amount>=0 AND previous_amount>=0),
|
||||
CONSTRAINT chk_procurement_budget_currency CHECK(currency IN('CNY','USD') AND previous_currency IN('CNY','USD'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购货款预算授权核验历史';
|
||||
@@ -1,65 +0,0 @@
|
||||
-- 采购实收、差异、装箱和两段整批发运事实。不产生WMS库存流水,不回填历史采购数量。
|
||||
CREATE TABLE ll_procurement_receipt (
|
||||
id BIGINT NOT NULL COMMENT '实收明细ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
receipt_no VARCHAR(64) NOT NULL COMMENT '采购收货业务编号', leg VARCHAR(16) NOT NULL COMMENT 'OVERSEAS海外或DOMESTIC国内',
|
||||
source_carton_id BIGINT NULL COMMENT '国内实收关联原国际交寄箱,海外为空', warehouse_id BIGINT NULL COMMENT '海外实际收货仓',
|
||||
good_quantity BIGINT NOT NULL COMMENT '可发合格件数', damaged_quantity BIGINT NOT NULL COMMENT '破损待处置件数', extra_quantity BIGINT NOT NULL COMMENT '多到件数,不增加可发数量',
|
||||
received_at DATETIME(3) NOT NULL COMMENT '实际收货时间', active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '当前有效实收事实',
|
||||
supersedes_id BIGINT NULL COMMENT '受控更正所替代的原实收记录', created_by VARCHAR(128) NOT NULL COMMENT '登记人员',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '登记时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_receipt_no(receipt_no), KEY idx_procurement_receipt_source(order_id,leg,source_carton_id,active),
|
||||
CONSTRAINT chk_procurement_receipt_quantity CHECK(good_quantity>=0 AND damaged_quantity>=0 AND extra_quantity>=0 AND good_quantity+damaged_quantity+extra_quantity>0),
|
||||
CONSTRAINT chk_procurement_receipt_leg CHECK((leg='OVERSEAS' AND source_carton_id IS NULL) OR (leg='DOMESTIC' AND source_carton_id IS NOT NULL))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购分次实收与受控更正事实';
|
||||
|
||||
CREATE TABLE ll_procurement_disposition (
|
||||
id BIGINT NOT NULL COMMENT '差异处理ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
leg VARCHAR(16) NOT NULL COMMENT 'OVERSEAS海外或DOMESTIC国内', source_carton_id BIGINT NULL COMMENT '国内原交寄箱来源',
|
||||
receipt_id BIGINT NULL COMMENT '破损或多货对应实收记录,短少为空', kind VARCHAR(24) NOT NULL COMMENT 'SHORTAGE短少、DAMAGED破损、EXTRA多货',
|
||||
quantity BIGINT NOT NULL COMMENT '已批准处置件数', decision VARCHAR(32) NOT NULL COMMENT 'ACCEPT_SHORTAGE确认短少、DISPOSE_DAMAGED拒收或处置、RETURN_EXTRA退回多货',
|
||||
active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '当前有效处置;撤销只改变有效性并保留原事实',
|
||||
voucher_file_id BIGINT NOT NULL COMMENT '本单客户确认或实际处置凭证', reason VARCHAR(1000) NOT NULL COMMENT '处置依据',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '采购管理人员', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '确认时间',
|
||||
PRIMARY KEY(id), KEY idx_procurement_disposition_source(order_id,leg,source_carton_id,receipt_id,kind),
|
||||
CONSTRAINT chk_procurement_disposition_quantity CHECK(quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购单内差异处置,不自动退款';
|
||||
|
||||
CREATE TABLE ll_procurement_manifest (
|
||||
id BIGINT NOT NULL COMMENT '装箱清单ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
version INT NOT NULL COMMENT '订单内装箱版本', status VARCHAR(16) NOT NULL COMMENT 'DRAFT草稿、CONFIRMED已确认、SUPERSEDED已替代',
|
||||
confirmed_at DATETIME(3) NULL COMMENT '确认时间', created_by VARCHAR(128) NOT NULL COMMENT '制单人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '版本保存时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_manifest_version(order_id,version),
|
||||
CONSTRAINT chk_procurement_manifest_status CHECK(status IN('DRAFT','CONFIRMED','SUPERSEDED'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购装箱清单不可变版本';
|
||||
|
||||
CREATE TABLE ll_procurement_carton (
|
||||
id BIGINT NOT NULL COMMENT '版本内箱记录ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', manifest_id BIGINT NOT NULL COMMENT '装箱清单版本',
|
||||
carton_no VARCHAR(64) NOT NULL COMMENT '采购订单内业务箱号', length_cm DECIMAL(12,2) NOT NULL COMMENT '外箱长厘米',
|
||||
width_cm DECIMAL(12,2) NOT NULL COMMENT '外箱宽厘米', height_cm DECIMAL(12,2) NOT NULL COMMENT '外箱高厘米',
|
||||
gross_weight_kg DECIMAL(12,3) NOT NULL COMMENT '封箱毛重千克', quantity BIGINT NOT NULL COMMENT '本箱合格商品总件数',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_carton_version(manifest_id,carton_no), KEY idx_procurement_carton_order(order_id,manifest_id),
|
||||
CONSTRAINT chk_procurement_carton_measurement CHECK(length_cm>0 AND width_cm>0 AND height_cm>0 AND gross_weight_kg>0 AND quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购版本化逐箱实测与件数';
|
||||
|
||||
CREATE TABLE ll_procurement_carton_source (
|
||||
carton_id BIGINT NOT NULL COMMENT '版本内箱ID', receipt_id BIGINT NOT NULL COMMENT '海外实收明细来源', quantity BIGINT NOT NULL COMMENT '从该实收装入本箱的件数',
|
||||
PRIMARY KEY(carton_id,receipt_id), KEY idx_procurement_carton_receipt(receipt_id), CONSTRAINT chk_procurement_carton_source_quantity CHECK(quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购箱内货物的实收来源与数量';
|
||||
|
||||
CREATE TABLE ll_procurement_shipment (
|
||||
id BIGINT NOT NULL COMMENT '采购交寄ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
shipment_no VARCHAR(64) NOT NULL COMMENT '交寄业务编号', leg VARCHAR(16) NOT NULL COMMENT 'OVERSEAS国际交寄或DOMESTIC寄客户',
|
||||
manifest_id BIGINT NOT NULL COMMENT '原海外装箱清单版本', shipped_at DATETIME(3) NOT NULL COMMENT '整批真实交承运方时间',
|
||||
address_snapshot JSON NOT NULL COMMENT '本段交寄时的收寄姓名电话地址快照', created_by VARCHAR(128) NOT NULL COMMENT '交寄确认人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '确认时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_shipment_leg(order_id,leg), UNIQUE KEY uk_procurement_shipment_no(shipment_no),
|
||||
CONSTRAINT chk_procurement_shipment_leg CHECK(leg IN('OVERSEAS','DOMESTIC'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购两段各一次整批真实交寄';
|
||||
|
||||
CREATE TABLE ll_procurement_shipment_item (
|
||||
shipment_id BIGINT NOT NULL COMMENT '采购交寄ID', carton_id BIGINT NOT NULL COMMENT '原海外装箱版本内箱ID', quantity BIGINT NOT NULL COMMENT '本次实际交寄件数',
|
||||
carrier VARCHAR(128) NOT NULL COMMENT '承运商快照', tracking_no VARCHAR(128) NOT NULL COMMENT '运单号快照',
|
||||
label_snapshot JSON NOT NULL COMMENT '当次箱规、面单及货物来源快照',
|
||||
PRIMARY KEY(shipment_id,carton_id), CONSTRAINT chk_procurement_shipment_item_quantity CHECK(quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购整批交寄逐箱事实';
|
||||
@@ -1,40 +0,0 @@
|
||||
-- 采购面单、逐箱贴单、预估核对与国内一对一换包装;不重建历史发运事实。
|
||||
CREATE TABLE ll_procurement_label_set (
|
||||
id BIGINT NOT NULL COMMENT '面单批版本ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
leg VARCHAR(16) NOT NULL COMMENT 'OVERSEAS国际段或DOMESTIC寄客户段', version INT NOT NULL COMMENT '订单段内面单版本',
|
||||
manifest_id BIGINT NOT NULL COMMENT '原海外确认装箱版本', cargo_hash CHAR(64) NOT NULL COMMENT '箱规及有效货物来源摘要',
|
||||
sender_snapshot JSON NOT NULL COMMENT '寄件人姓名电话地址快照', receiver_snapshot JSON NOT NULL COMMENT '收件人姓名电话地址快照',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '制单操作人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '上传确认时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_label_version(order_id,leg,version),
|
||||
CONSTRAINT chk_procurement_label_leg CHECK(leg IN('OVERSEAS','DOMESTIC'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购两段面单不可变版本和地址快照';
|
||||
|
||||
CREATE TABLE ll_procurement_label_item (
|
||||
label_set_id BIGINT NOT NULL COMMENT '面单批版本ID', carton_id BIGINT NOT NULL COMMENT '原海外清单箱ID',
|
||||
file_id BIGINT NOT NULL COMMENT '本采购订单面单文件', page_no INT NOT NULL COMMENT '该箱对应文件页码,从1开始',
|
||||
carrier VARCHAR(128) NOT NULL COMMENT '承运商', tracking_no VARCHAR(128) NOT NULL COMMENT '箱主或子运单号',
|
||||
applied_at DATETIME(3) NULL COMMENT '真实贴单时间', applied_by VARCHAR(128) NULL COMMENT '贴单确认人',
|
||||
PRIMARY KEY(label_set_id,carton_id), CONSTRAINT chk_procurement_label_page CHECK(page_no>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购逐箱文件页关联及贴单事实';
|
||||
|
||||
CREATE TABLE ll_procurement_estimate_review (
|
||||
id BIGINT NOT NULL COMMENT '预估核对ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', label_set_id BIGINT NOT NULL COMMENT '已核对国际面单版本',
|
||||
fee_id BIGINT NOT NULL COMMENT '唯一有效预估费用版本', reviewed_by VARCHAR(128) NOT NULL COMMENT '核价人员',
|
||||
reviewed_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '核对时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_estimate_review(label_set_id,fee_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='面单清单与预估冻结的显式核对关联';
|
||||
|
||||
CREATE TABLE ll_procurement_repack (
|
||||
id BIGINT NOT NULL COMMENT '换包装版本ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', carton_id BIGINT NOT NULL COMMENT '原国际交寄箱ID,保持一对一来源',
|
||||
length_cm DECIMAL(12,2) NOT NULL COMMENT '新外箱长厘米', width_cm DECIMAL(12,2) NOT NULL COMMENT '新外箱宽厘米',
|
||||
height_cm DECIMAL(12,2) NOT NULL COMMENT '新外箱高厘米', gross_weight_kg DECIMAL(12,3) NOT NULL COMMENT '新封箱毛重千克',
|
||||
voucher_file_id BIGINT NOT NULL COMMENT '本单换包装证据', reason VARCHAR(1000) NOT NULL COMMENT '换包装依据',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '国内作业人员', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '登记时间',
|
||||
PRIMARY KEY(id), KEY idx_procurement_repack_carton(order_id,carton_id,id),
|
||||
CONSTRAINT chk_procurement_repack_measurement CHECK(length_cm>0 AND width_cm>0 AND height_cm>0 AND gross_weight_kg>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购国内原箱一对一换包装不可变历史';
|
||||
|
||||
ALTER TABLE ll_overseas_procurement_file
|
||||
DROP CHECK chk_ll_procurement_file_category,
|
||||
MODIFY COLUMN category VARCHAR(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'RECEIPT实收、VOUCHER费用、LABEL面单、PURCHASE采购、BUDGET预算、EXCEPTION异常凭证',
|
||||
ADD CONSTRAINT chk_ll_procurement_file_category CHECK(category IN ('RECEIPT','VOUCHER','LABEL','PURCHASE','BUDGET','EXCEPTION'));
|
||||
@@ -1,20 +0,0 @@
|
||||
-- 费用链目标更正快照与关联;资金流水仍唯一归Finance,不回填旧费用。
|
||||
CREATE TABLE ll_procurement_fee_correction (
|
||||
id BIGINT NOT NULL COMMENT '费用链更正ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
correction_no VARCHAR(64) NOT NULL COMMENT '财务更正业务号', root_fee_id BIGINT NOT NULL COMMENT '原实际费用链根',
|
||||
idempotency_key VARCHAR(128) NOT NULL COMMENT '本单更正请求幂等键', request_hash CHAR(64) NOT NULL COMMENT '更正目标及凭证请求摘要',
|
||||
target_original_amount DECIMAL(20,2) NOT NULL COMMENT '本次正确原币总额', original_currency CHAR(3) NOT NULL COMMENT '沿用原费用币种',
|
||||
exchange_rate DECIMAL(20,6) NOT NULL COMMENT '沿用原费用汇率快照', exchange_rate_month CHAR(7) NOT NULL COMMENT '原汇率月份,不取本次操作月份',
|
||||
target_amount DECIMAL(20,2) NOT NULL COMMENT '正确总额折算CNY', previous_net_amount DECIMAL(20,2) NOT NULL COMMENT '确认前整链净实扣CNY',
|
||||
difference_amount DECIMAL(20,2) NOT NULL COMMENT 'CNY正差额追加、负差额退款、零差额仅留核对记录',
|
||||
voucher_file_id BIGINT NOT NULL COMMENT '本订单财务更正凭证', reason VARCHAR(500) NOT NULL COMMENT '更正依据',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '授权财务操作人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '确认时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_correction_no(correction_no), UNIQUE KEY uk_procurement_correction_request(order_id,idempotency_key),
|
||||
KEY idx_procurement_correction_root(order_id,root_fee_id,id),
|
||||
CONSTRAINT chk_procurement_correction_amount CHECK(target_original_amount>=0 AND target_amount>=0 AND previous_net_amount>=0 AND exchange_rate>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购费用链更正目标与原汇率快照';
|
||||
|
||||
CREATE TABLE ll_procurement_fee_correction_item (
|
||||
correction_id BIGINT NOT NULL COMMENT '本次费用链更正ID', fee_id BIGINT NOT NULL COMMENT '本次产生的独立正差额或退款费用ID',
|
||||
PRIMARY KEY(correction_id,fee_id), UNIQUE KEY uk_procurement_correction_fee(fee_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购费用目标更正与逐笔资金事实关联';
|
||||
@@ -1,31 +0,0 @@
|
||||
-- 单采购订单内的更正说明、阻断异常与关闭证据。不生成WMS库存或退货运输任务。
|
||||
CREATE TABLE ll_procurement_control_note (
|
||||
id BIGINT NOT NULL COMMENT '采购更正说明ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
note_no VARCHAR(64) NOT NULL COMMENT '更正说明业务号', target_type VARCHAR(24) NOT NULL COMMENT '购买、仓库、实收或交寄事实类型',
|
||||
target_id BIGINT NULL COMMENT '本单事实对象引用,购买为空', blocking TINYINT(1) NOT NULL COMMENT '是否阻断后续计划履约',
|
||||
voucher_file_id BIGINT NOT NULL COMMENT '本单内部事实更正凭证', reason VARCHAR(1000) NOT NULL COMMENT '内部更正说明',
|
||||
client_summary VARCHAR(500) NULL COMMENT '人工确认的对客摘要,不复制内部原始内容',
|
||||
original_value_json JSON NULL COMMENT '服务端记录的原事实快照', corrected_value_json JSON NULL COMMENT '服务端记录的更正事实快照',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '采购管理操作人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '登记时间',
|
||||
resolved_by VARCHAR(128) NULL COMMENT '处理确认人', resolved_at DATETIME(3) NULL COMMENT '阻断解除时间',
|
||||
resolution_reason VARCHAR(1000) NULL COMMENT '内部处理结果', resolution_voucher_id BIGINT NULL COMMENT '本单处理凭证',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_note_no(note_no), KEY idx_procurement_note_block(order_id,blocking,resolved_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购不可覆盖事实的更正说明及阻断异常';
|
||||
|
||||
CREATE TABLE ll_procurement_closure (
|
||||
id BIGINT NOT NULL COMMENT '采购异常关闭ID', order_id BIGINT NOT NULL COMMENT '采购订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键',
|
||||
closure_no VARCHAR(64) NOT NULL COMMENT '异常关闭业务号', customer_voucher_file_id BIGINT NOT NULL COMMENT '客户同意停止履约凭证',
|
||||
financial_conclusion VARCHAR(1000) NOT NULL COMMENT '已知费用及后续无需收费的处理结论,不改变资金事实',
|
||||
reason VARCHAR(1000) NOT NULL COMMENT '内部关闭原因', client_summary VARCHAR(500) NOT NULL COMMENT '人工确认的对客关闭摘要',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '采购管理确认人', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '关闭确认时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_procurement_closure_order(order_id), UNIQUE KEY uk_procurement_closure_no(closure_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='采购实物资金收口后的异常关闭事实';
|
||||
|
||||
CREATE TABLE ll_procurement_closure_item (
|
||||
id BIGINT NOT NULL COMMENT '关闭货物处置ID', closure_id BIGINT NOT NULL COMMENT '采购关闭ID',
|
||||
source_kind VARCHAR(32) NOT NULL COMMENT '购买未达、在途未达、合格、破损或多货来源', source_id BIGINT NULL COMMENT '原实收或国际交寄箱,购买未达为空',
|
||||
quantity BIGINT NOT NULL COMMENT '本来源最终明确去向件数', decision VARCHAR(40) NOT NULL COMMENT '供应商保管、退还、报失、客户授权保管或处置',
|
||||
destination VARCHAR(500) NOT NULL COMMENT '实际去向及接收方说明', voucher_file_id BIGINT NOT NULL COMMENT '本单实物处置证明',
|
||||
PRIMARY KEY(id), KEY idx_procurement_closure_source(closure_id,source_kind,source_id),
|
||||
CONSTRAINT chk_procurement_closure_quantity CHECK(quantity>0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='异常关闭逐来源剩余货物最终去向,不产生新发运';
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
-- 采购费用核定入口。仅结构变更,不回填旧财务事实,不重试或补扣测试存量。
|
||||
ALTER TABLE ll_overseas_procurement_fee
|
||||
ADD COLUMN confirmation_origin VARCHAR(16) NOT NULL DEFAULT 'BUSINESS' COMMENT '核定入口:BUSINESS业务节点、FINANCIAL财务操作',
|
||||
ADD CONSTRAINT chk_procurement_confirmation_origin CHECK(confirmation_origin IN('BUSINESS','FINANCIAL'));
|
||||
@@ -1,21 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS ll_selfop_warehouse_daily_sales (
|
||||
sales_run_id BIGINT NOT NULL COMMENT '完整销量计算版本标识',
|
||||
source_account VARCHAR(64) NOT NULL COMMENT '受控来源账号别名,不保存密钥',
|
||||
warehouse_code VARCHAR(64) NOT NULL COMMENT '来源仓库原始编码',
|
||||
business_date DATE NOT NULL COMMENT '已核准业务日',
|
||||
observed_quantity DECIMAL(38,6) NULL COMMENT '该日PCS非负有效出库量之和,无有效行时为空',
|
||||
invalid_row_count BIGINT NOT NULL COMMENT '该日数量为空或负数或单位非PCS的日事实行数',
|
||||
source_row_count BIGINT NOT NULL COMMENT '该日参与仓库汇总的SKU日事实总行数',
|
||||
created_at DATETIME(3) NOT NULL COMMENT 'UTC创建时间',
|
||||
updated_at DATETIME(3) NOT NULL COMMENT 'UTC更新时间',
|
||||
PRIMARY KEY (sales_run_id,source_account,warehouse_code,business_date),
|
||||
CONSTRAINT chk_selfop_warehouse_daily_sales CHECK (source_row_count > 0 AND invalid_row_count >= 0 AND invalid_row_count <= source_row_count AND (observed_quantity IS NULL OR observed_quantity >= 0))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='完整销量版本按仓按日汇总,随SKU日事实批次原子构建';
|
||||
|
||||
SET @selfop_warehouse_daily_ready_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_selfop_sync_run' AND column_name='warehouse_daily_ready'),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_selfop_sync_run ADD COLUMN warehouse_daily_ready TINYINT NOT NULL DEFAULT 0 COMMENT ''仓库日汇总已完整构建并校验,含完整空版本''');
|
||||
PREPARE selfop_warehouse_daily_ready_stmt FROM @selfop_warehouse_daily_ready_ddl;
|
||||
EXECUTE selfop_warehouse_daily_ready_stmt;
|
||||
DEALLOCATE PREPARE selfop_warehouse_daily_ready_stmt;
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
-- Region: OVERSEAS
|
||||
-- Schema: baiyue_lastleg
|
||||
-- Purpose: 统一退货进销存 UNION 文本列排序规则,去除查询转换需求
|
||||
-- Preconditions: 八张退货表已存在;核对字段长度、可空性、默认值及唯一索引无目标规则冲突
|
||||
-- Postconditions: 指定文本字段及表默认规则统一为 utf8mb4_unicode_ci;不修改数量、状态或业务标识
|
||||
-- 不重放空库基线;本文件可重复执行。DDL 非事务,失败停止并核对后续执行范围。
|
||||
ALTER TABLE ll_return_order
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN customer_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户ID和隔离键',
|
||||
MODIFY COLUMN overseas_warehouse_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作海外仓ID';
|
||||
ALTER TABLE ll_return_order_item
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SKU编码',
|
||||
MODIFY COLUMN product_name_zh VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '中文品名';
|
||||
ALTER TABLE ll_return_receipt
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN receipt_no VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '签收单号';
|
||||
ALTER TABLE ll_return_receipt_item
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SKU编码';
|
||||
ALTER TABLE ll_return_inventory_carton
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN customer_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户ID和隔离键',
|
||||
MODIFY COLUMN overseas_warehouse_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '海外仓ID',
|
||||
MODIFY COLUMN carton_mark VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货箱号和箱唛编码';
|
||||
ALTER TABLE ll_return_inventory_carton_item
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SKU编码',
|
||||
MODIFY COLUMN product_name_zh VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '中文品名';
|
||||
ALTER TABLE ll_return_inventory_outbound_movement
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN customer_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '库存所属客户ID和隔离键',
|
||||
MODIFY COLUMN overseas_warehouse_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实际出库海外仓ID',
|
||||
MODIFY COLUMN sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '本次出库SKU编码快照',
|
||||
MODIFY COLUMN product_name_zh VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '中文品名快照',
|
||||
MODIFY COLUMN outbound_no VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '本次退货出库业务单号';
|
||||
ALTER TABLE ll_return_sku_conversion
|
||||
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
MODIFY COLUMN customer_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户隔离键',
|
||||
MODIFY COLUMN overseas_warehouse_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作海外仓ID',
|
||||
MODIFY COLUMN old_sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '换标前SKU',
|
||||
MODIFY COLUMN new_sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '换标后SKU',
|
||||
MODIFY COLUMN product_name_zh VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '中文品名快照',
|
||||
MODIFY COLUMN relabel_no VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '换标单号';
|
||||
@@ -1,16 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS ll_cargo_discard_photo (
|
||||
id BIGINT NOT NULL,
|
||||
customer_id VARCHAR(64) NOT NULL,
|
||||
application_id BIGINT NOT NULL,
|
||||
pallet_no VARCHAR(128) NOT NULL,
|
||||
file_id BIGINT NOT NULL,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
content_type VARCHAR(128) NOT NULL,
|
||||
size_bytes BIGINT NOT NULL,
|
||||
operator_id VARCHAR(64) NOT NULL,
|
||||
created_at DATETIME(6) NOT NULL,
|
||||
submitted_at DATETIME(6) NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_cargo_discard_photo_file (file_id),
|
||||
KEY idx_cargo_discard_photo_application (customer_id, application_id, pallet_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
-- 货物废弃支持所有入库来源及散箱全量作业;不回填或修改历史单据。
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_item' AND column_name='inventory_position_id'),
|
||||
'ALTER TABLE ll_cargo_discard_item ADD COLUMN inventory_position_id BIGINT NULL COMMENT ''废弃来源库存仓位ID''', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_item' AND column_name='carton_marks_json'),
|
||||
'ALTER TABLE ll_cargo_discard_item ADD COLUMN carton_marks_json TEXT NULL COMMENT ''本次废弃所选真实箱唛快照JSON数组''', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_item' AND index_name='uk_ll_discard_position_sku'),
|
||||
'ALTER TABLE ll_cargo_discard_item ADD UNIQUE KEY uk_ll_discard_position_sku(application_id,inventory_position_id,sku_code)', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE ll_cargo_discard_item MODIFY COLUMN source_type VARCHAR(32) NOT NULL DEFAULT 'DROPSHIP' COMMENT '库存来源:一件代发DROPSHIP、退货箱RETURN_CARTON、通用库存INVENTORY';
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_item' AND column_name='carton_scan_required'),
|
||||
'ALTER TABLE ll_cargo_discard_item ADD COLUMN carton_scan_required TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否需要逐箱核对本次所选箱子''', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
ALTER TABLE ll_cargo_discard_item MODIFY COLUMN carton_marks_json TEXT NULL COMMENT '本次废弃所选真实箱唛快照JSON数组';
|
||||
ALTER TABLE ll_inbound_plan_carton MODIFY COLUMN status VARCHAR(32) NOT NULL COMMENT '箱唛状态:未绑定UNASSIGNED、已绑托ON_PALLET、整票收货BULK_RECEIVED、可用AVAILABLE、待废弃DISCARD_PENDING、已废弃DISCARDED';
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_carton' AND column_name='source_type'),
|
||||
'ALTER TABLE ll_cargo_discard_carton ADD COLUMN source_type VARCHAR(32) NOT NULL DEFAULT ''DROPSHIP'' COMMENT ''箱子来源:一件代发DROPSHIP、入仓箱INBOUND、转运箱TRANSFER''', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
-- 整箱废弃后保留SKU明细,剩余数量允许归零,仍禁止负库存。
|
||||
-- 原子替换约束,可重复执行;不修改业务记录。
|
||||
SET @ddl = IF(EXISTS (
|
||||
SELECT 1 FROM information_schema.table_constraints
|
||||
WHERE constraint_schema=DATABASE() AND table_name='ll_return_inventory_carton_item'
|
||||
AND constraint_name='chk_ll_return_inventory_carton_item_quantity'
|
||||
),
|
||||
'ALTER TABLE ll_return_inventory_carton_item DROP CHECK chk_ll_return_inventory_carton_item_quantity, ADD CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK(quantity>=0)',
|
||||
'ALTER TABLE ll_return_inventory_carton_item ADD CONSTRAINT chk_ll_return_inventory_carton_item_quantity CHECK(quantity>=0)'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
-- 客户确认废弃完结时间,可重复执行;仅结构变更。
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_application' AND column_name='customer_confirmed_at'), 'ALTER TABLE ll_cargo_discard_application ADD COLUMN customer_confirmed_at DATETIME(3) NULL COMMENT ''客户确认废弃完结时间''', 'SELECT 1');
|
||||
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
-- 2026-10-16 拉取合并及本地恢复配套增量,MySQL 8。
|
||||
-- 目标:lastleg-service / baiyue_lastleg;前置:已有业务表及此前迁移。
|
||||
-- 只调整结构,不回填、删除或重算业务数据;执行失败应停止,修复后可重跑。
|
||||
SET NAMES utf8mb4;
|
||||
-- 由单 schema 执行器选择 baiyue_lastleg,不在迁移内部切库。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_compact_number_clock (
|
||||
number_key VARCHAR(16) NOT NULL COMMENT '业务前缀和客户名称缩写',
|
||||
last_second BIGINT NOT NULL COMMENT '最后分配的Unix逻辑秒',
|
||||
PRIMARY KEY (number_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='海外业务短单号分配时钟';
|
||||
|
||||
-- 仓储转运逐箱测量与清点;仅增加字段,不修改业务数据。
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='length_cm'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN length_cm DECIMAL(12,2) NULL COMMENT ''箱子实测长度厘米'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='width_cm'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN width_cm DECIMAL(12,2) NULL COMMENT ''箱子实测宽度厘米'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='height_cm'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN height_cm DECIMAL(12,2) NULL COMMENT ''箱子实测高度厘米'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='gross_weight_kg'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN gross_weight_kg DECIMAL(12,2) NULL COMMENT ''箱子实测重量千克'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='counted_quantity'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN counted_quantity BIGINT NULL COMMENT ''箱内SKU实点件数'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='count_idempotency_key'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN count_idempotency_key VARCHAR(255) NULL COMMENT ''箱内清点幂等键'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='count_request_hash'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN count_request_hash VARCHAR(64) NULL COMMENT ''箱内清点请求摘要'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='counted_by'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN counted_by VARCHAR(128) NULL COMMENT ''箱内清点操作人'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='counted_at'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN counted_at DATETIME(3) NULL COMMENT ''箱内清点完成时间'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='discrepancy_reason'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN discrepancy_reason VARCHAR(1000) NULL COMMENT ''实收与预报箱数差异原因'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='transfer_pallet_id'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN transfer_pallet_id BIGINT NULL COMMENT ''签收箱所属转运托盘事实ID'''));
|
||||
PREPARE transfer_count_stmt FROM @ddl; EXECUTE transfer_count_stmt; DEALLOCATE PREPARE transfer_count_stmt;
|
||||
|
||||
-- SKU 申报件数独立于预计箱数;历史未申报件数保持 NULL,实收以 PDA 清点为准。
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_item' AND column_name='declared_quantity'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_item ADD COLUMN declared_quantity BIGINT NULL COMMENT ''SKU申报件数,非预计或实收箱数'''));
|
||||
PREPARE transfer_quantity_stmt FROM @ddl; EXECUTE transfer_quantity_stmt; DEALLOCATE PREPARE transfer_quantity_stmt;
|
||||
|
||||
-- 仓储转运一箱多SKU清点;仅增加结构,不回填历史业务数据。
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='sku_items_json'), 'SELECT 1', 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN sku_items_json JSON NULL COMMENT ''实收箱内SKU及逐项件数明细'''));
|
||||
PREPARE transfer_sku_stmt FROM @ddl; EXECUTE transfer_sku_stmt; DEALLOCATE PREPARE transfer_sku_stmt;
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_carton' AND column_name='customer_carton_mark'), 'ALTER TABLE ll_warehouse_transfer_carton ADD COLUMN customer_carton_mark VARCHAR(255) NULL COMMENT ''客户原箱唛,用于换标现场绑定''', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_cargo_discard_item' AND index_name='idx_ll_cargo_discard_return_carton'), 'ALTER TABLE ll_cargo_discard_item ADD KEY idx_ll_cargo_discard_return_carton(customer_id,return_carton_id)', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
SET @ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_warehouse_transfer_order' AND column_name='estimated_arrival_at' AND is_nullable='NO'), 'ALTER TABLE ll_warehouse_transfer_order MODIFY COLUMN estimated_arrival_at DATETIME(3) NULL COMMENT ''预计入仓时间,库存转运不填写''', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
SET @ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_delivery_order' AND column_name='total_volume_cbm' AND is_nullable='NO'), 'ALTER TABLE ll_delivery_order MODIFY COLUMN total_volume_cbm DECIMAL(18,4) NULL COMMENT ''体积(立方米),来源未确认时为空''', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
SET @ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_order' AND column_name='volume_cbm' AND is_nullable='NO'), 'ALTER TABLE ll_outbound_order MODIFY COLUMN volume_cbm DECIMAL(18,4) NULL COMMENT ''体积(立方米),来源未确认时为空''', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
SET @ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_outbound_pallet_item' AND column_name='volume_cbm' AND is_nullable='NO'), 'ALTER TABLE ll_outbound_pallet_item MODIFY COLUMN volume_cbm DECIMAL(18,4) NULL COMMENT ''体积(立方米),来源未确认时为空''', 'SELECT 1');
|
||||
PREPARE merge_schema_stmt FROM @ddl; EXECUTE merge_schema_stmt; DEALLOCATE PREPARE merge_schema_stmt;
|
||||
|
||||
-- 执行后核对本次结构;这不是应用功能验收。
|
||||
SELECT table_name,column_name,column_type,is_nullable,column_comment FROM information_schema.columns
|
||||
WHERE table_schema=DATABASE() AND table_name IN ('ll_compact_number_clock','ll_warehouse_transfer_carton','ll_warehouse_transfer_item','ll_warehouse_transfer_order','ll_delivery_order','ll_outbound_order','ll_outbound_pallet_item')
|
||||
ORDER BY table_name,ordinal_position;
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
-- 对应数据库:baiyue_lastleg;可重复执行,不修改原箱号、SKU预报件数和实测数据。
|
||||
ALTER TABLE ll_warehouse_transfer_carton MODIFY COLUMN transfer_item_id BIGINT NULL COMMENT '实际箱内首项SKU明细ID,预报补箱可为空';
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
-- Region: OVERSEAS
|
||||
-- Schema: baiyue_lastleg
|
||||
-- Purpose: 补齐预约分批/合并后的替代预约业务号快照,供入仓计划查询过滤原预约。
|
||||
-- 可重复执行;不修改既有预约数据。
|
||||
SET @ddl = IF(
|
||||
EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'll_inbound_fba_appointment'
|
||||
AND column_name = 'replacement_nos_json'
|
||||
),
|
||||
'SELECT 1',
|
||||
'ALTER TABLE ll_inbound_fba_appointment ADD COLUMN replacement_nos_json LONGTEXT NULL COMMENT ''分批或合并后的新预约业务号列表,非空时原批次只读'' AFTER selected_count'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@@ -1,49 +0,0 @@
|
||||
-- Region: OVERSEAS
|
||||
-- Schema: baiyue_lastleg
|
||||
-- Purpose: 排车物理托盘串行点、物理占用及逻辑占用关联结构补齐。
|
||||
-- Preconditions: MySQL 8;已选中目标schema;ll_dispatch_pallet_lock已有业务基线存在。
|
||||
-- Postconditions: 两张实托表和physical_lock_id列/idx_dispatch_logical_physical索引存在。
|
||||
-- 只增加缺失结构,不删除/回填/重算历史数据。重复执行已存在对象时跳过。
|
||||
-- 与当前lastleg.sql最终定义一致;已有异构对象须人工核对,不能以跳过证明一致。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_physical_pallet_guard (
|
||||
warehouse_pallet_id BIGINT NOT NULL COMMENT '真实全局物理托盘ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次建立串行点时间',
|
||||
PRIMARY KEY (warehouse_pallet_id)
|
||||
) ENGINE=InnoDB COMMENT='排车冻结与仓内实托组成修改的共同串行点';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_dispatch_physical_pallet_lock (
|
||||
id BIGINT NOT NULL COMMENT '物理实托占用主键',
|
||||
warehouse_id VARCHAR(128) NOT NULL COMMENT '真实起运仓ID',
|
||||
warehouse_pallet_id BIGINT NOT NULL COMMENT '全局真实物理托盘ID',
|
||||
active_warehouse_pallet_id BIGINT NULL COMMENT '活动物理排他键,释放后为空',
|
||||
dispatch_order_id BIGINT NULL COMMENT '正式排车主单ID,与草稿归属互斥',
|
||||
draft_token VARCHAR(64) NULL COMMENT '草稿拥有者令牌,与正式排车归属互斥',
|
||||
draft_container_id BIGINT NULL COMMENT '草稿内唯一占用该实托的容器ID',
|
||||
operator_id VARCHAR(128) NULL COMMENT '占用操作人ID',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '物理占用状态',
|
||||
expires_at DATETIME(3) NULL COMMENT '草稿失效时间,正式占用为空',
|
||||
locked_at DATETIME(3) NOT NULL COMMENT '锁定时间',
|
||||
released_at DATETIME(3) NULL COMMENT '释放时间',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_dispatch_physical_active_pallet (active_warehouse_pallet_id),
|
||||
KEY idx_dispatch_physical_order (dispatch_order_id,status),
|
||||
KEY idx_dispatch_physical_draft (draft_token,draft_container_id,status),
|
||||
CONSTRAINT chk_dispatch_physical_active_key CHECK((status='ACTIVE' AND active_warehouse_pallet_id IS NOT NULL AND active_warehouse_pallet_id=warehouse_pallet_id) OR (status<>'ACTIVE' AND active_warehouse_pallet_id IS NULL)),
|
||||
CONSTRAINT chk_dispatch_physical_owner CHECK((dispatch_order_id IS NOT NULL AND draft_token IS NULL AND draft_container_id IS NULL) OR (dispatch_order_id IS NULL AND draft_token IS NOT NULL AND draft_container_id IS NOT NULL))
|
||||
) ENGINE=InnoDB COMMENT='同车共享且跨车排他的物理实托占用';
|
||||
|
||||
-- 已只读确认本地缺失:客户逻辑锁到物理锁的可空关联列及查询索引。
|
||||
-- 仅补结构,不根据历史单据推测或回填关联。
|
||||
SET @overseas_dimension_ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND column_name='physical_lock_id'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD COLUMN physical_lock_id BIGINT NULL COMMENT ''实际物理实托占用ID,非物理来源为空''');
|
||||
PREPARE overseas_dimension_stmt FROM @overseas_dimension_ddl;
|
||||
EXECUTE overseas_dimension_stmt;
|
||||
DEALLOCATE PREPARE overseas_dimension_stmt;
|
||||
SET @overseas_dimension_ddl = IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_dispatch_pallet_lock' AND index_name='idx_dispatch_logical_physical'), 'SELECT 1', 'ALTER TABLE ll_dispatch_pallet_lock ADD KEY idx_dispatch_logical_physical (physical_lock_id,status)');
|
||||
PREPARE overseas_dimension_stmt FROM @overseas_dimension_ddl;
|
||||
EXECUTE overseas_dimension_stmt;
|
||||
DEALLOCATE PREPARE overseas_dimension_stmt;
|
||||
SET @overseas_dimension_ddl = NULL;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
-- 仓储取货与本土卡车接入现有排车;保留旧排车用途默认值。
|
||||
ALTER TABLE ll_dispatch_order ADD COLUMN task_type VARCHAR(32) NOT NULL DEFAULT 'DELIVERY' COMMENT '任务类型:仓库派送、到仓取货、本土卡车' AFTER dispatch_no;
|
||||
CREATE TABLE ll_dispatch_truck_task (
|
||||
dispatch_no VARCHAR(64) NOT NULL COMMENT '排车业务号',
|
||||
trip_no VARCHAR(64) NOT NULL COMMENT '本次运输资源记录号',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '本土卡车原单客户标识',
|
||||
order_no VARCHAR(64) NOT NULL COMMENT '本土卡车原单业务号',
|
||||
active_order VARCHAR(193) NULL COMMENT '有效原单唯一键;取消置空,完成保留',
|
||||
PRIMARY KEY(dispatch_no), UNIQUE KEY uk_transport_trip(trip_no), UNIQUE KEY uk_transport_source(active_order),
|
||||
KEY idx_transport_order(customer_id,order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车与本土卡车原单关联';
|
||||
CREATE TABLE ll_dispatch_transport_create (
|
||||
trip_no VARCHAR(64) NOT NULL PRIMARY KEY COMMENT '本次运输资源记录号',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '首次安排请求摘要'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='本土卡车排车创建请求账本';
|
||||
CREATE TABLE ll_dispatch_transport_command (
|
||||
dispatch_no VARCHAR(64) NOT NULL COMMENT '排车业务号',
|
||||
request_key VARCHAR(128) NOT NULL COMMENT '客户端幂等请求键',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '执行命令请求摘要',
|
||||
evidence_json JSON NULL COMMENT '已确认运输完成凭证标识列表',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '业务命令提交时间',
|
||||
PRIMARY KEY(dispatch_no,request_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='排车运输执行命令与凭证账本';
|
||||
@@ -1,13 +0,0 @@
|
||||
-- Region: OVERSEAS
|
||||
-- Schema: baiyue_lastleg
|
||||
-- Purpose: 客户散板原单接入拼车需求池,未确认登记不占位。
|
||||
-- Preconditions: MySQL 8;已选择 baiyue_lastleg;预订表已存在。
|
||||
-- Postconditions: 预订原单来源列及客户来源索引存在,不回填历史来源。
|
||||
SET @looseboard_demand_ddl = IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_fleet_external_booking' AND column_name='source_looseboard_order_id'), 'SELECT 1', 'ALTER TABLE ll_fleet_external_booking ADD COLUMN source_looseboard_order_id BIGINT NULL COMMENT ''客户原始散板商业单ID,取消后保留来源''');
|
||||
PREPARE looseboard_demand_stmt FROM @looseboard_demand_ddl;
|
||||
EXECUTE looseboard_demand_stmt;
|
||||
DEALLOCATE PREPARE looseboard_demand_stmt;
|
||||
SET @looseboard_demand_ddl = IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_fleet_external_booking' AND index_name='idx_booking_looseboard_source'), 'SELECT 1', 'ALTER TABLE ll_fleet_external_booking ADD KEY idx_booking_looseboard_source (customer_id,source_looseboard_order_id,status)');
|
||||
PREPARE looseboard_demand_stmt FROM @looseboard_demand_ddl;
|
||||
EXECUTE looseboard_demand_stmt;
|
||||
DEALLOCATE PREPARE looseboard_demand_stmt;
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_fleet_resource_photo (
|
||||
resource_kind VARCHAR(16) NOT NULL COMMENT '档案类型:车辆或司机',
|
||||
resource_id BIGINT NOT NULL COMMENT '车辆或司机档案标识',
|
||||
record_version BIGINT NOT NULL COMMENT '照片版本,从一递增',
|
||||
file_id BIGINT NOT NULL COMMENT '文件服务照片标识',
|
||||
file_name VARCHAR(512) NOT NULL COMMENT '照片原始文件名',
|
||||
content_type VARCHAR(64) NOT NULL COMMENT '照片媒体类型',
|
||||
size_bytes BIGINT NOT NULL COMMENT '照片字节数',
|
||||
created_by VARCHAR(64) NOT NULL COMMENT '上传操作人标识',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '上传时间(UTC)',
|
||||
PRIMARY KEY (resource_kind, resource_id, record_version),
|
||||
UNIQUE KEY uk_fleet_resource_photo_file (resource_kind, resource_id, file_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆及司机档案照片版本记录';
|
||||
@@ -1,9 +0,0 @@
|
||||
-- 先于新版本 Lastleg 上线执行。历史订单保持海外采购回国内,不改数量、资金或交寄事实。
|
||||
SET @procurement_direction_ddl = IF(
|
||||
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'll_overseas_procurement_order' AND COLUMN_NAME = 'procurement_direction') = 0,
|
||||
'ALTER TABLE ll_overseas_procurement_order ADD COLUMN procurement_direction VARCHAR(32) NOT NULL DEFAULT ''OVERSEAS_TO_DOMESTIC'' COMMENT ''采购方向:海外采购回国内/国内采购发海外''',
|
||||
'SELECT 1');
|
||||
PREPARE procurement_direction_stmt FROM @procurement_direction_ddl;
|
||||
EXECUTE procurement_direction_stmt;
|
||||
DEALLOCATE PREPARE procurement_direction_stmt;
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
-- 海外费用资金重试动作长度修复:兼容 MANUAL_FUNDING_RETRY 等费用幂等动作。
|
||||
ALTER TABLE baiyue_lastleg.ll_finance_fee_command
|
||||
MODIFY COLUMN action VARCHAR(32) NOT NULL COMMENT '费用写操作动作:CREATE、SUBMIT、REVIEW、ADJUST、VOID或资金重试';
|
||||
@@ -1,121 +0,0 @@
|
||||
-- 海外费用既有写按钮最小修复;MySQL 8,目标只能是 baiyue_iam。
|
||||
-- 仅恢复基线 5105024/5105025 及既有 4000001 PLATFORM_ADMIN 缺失授权。
|
||||
-- 不创建角色/成员,不授予其他角色,不新增 overseas-fee:edit/review 别名。
|
||||
-- 在支持 DELIMITER、遇错停止的客户端同连接整份执行;执行期间暂停相关角色权限维护。
|
||||
-- 不在其他未提交事务中调用。所有业务DML及subject版本变更同事务,任何异常回滚。
|
||||
USE baiyue_iam;
|
||||
SET NAMES utf8mb4;
|
||||
SELECT DATABASE() AS target_database;
|
||||
|
||||
DROP PROCEDURE IF EXISTS repair_overseas_fee_canonical_write;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE repair_overseas_fee_canonical_write()
|
||||
BEGIN
|
||||
DECLARE locked_role BIGINT;
|
||||
DECLARE changed_rows BIGINT DEFAULT 0;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
START TRANSACTION;
|
||||
IF DATABASE()<>'baiyue_iam' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Wrong schema: expected baiyue_iam';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM iam_role WHERE id=4000001 AND tenant_id=0 AND app_code='PLATFORM'
|
||||
AND role_code='PLATFORM_ADMIN' AND role_type='SYSTEM' AND status='ACTIVE' AND deleted=0)<>1
|
||||
OR EXISTS(SELECT 1 FROM iam_role WHERE role_code='PLATFORM_ADMIN' AND id<>4000001) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Existing PLATFORM_ADMIN identity/status mismatch; no role will be created';
|
||||
END IF;
|
||||
SELECT id INTO locked_role FROM iam_role WHERE id=4000001 FOR UPDATE;
|
||||
|
||||
-- 新建缺失按钮使用当前客户应收父菜单;只接受已核对的既有财务菜单,不修复其他菜单。
|
||||
IF (SELECT COUNT(*) FROM iam_permission WHERE id=5105041 AND tenant_id=0 AND app_code='PLATFORM'
|
||||
AND permission_type='MENU' AND permission_code='platform:finance:customer-arap:list'
|
||||
AND status='ACTIVE' AND deleted=0)<>1
|
||||
OR EXISTS(SELECT 1 FROM iam_permission WHERE permission_code='platform:finance:customer-arap:list' AND id<>5105041) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Existing customer AR/AP parent menu is missing or mismatched';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM iam_permission WHERE
|
||||
(id=5105024 AND NOT(permission_code<=>'platform:finance:fee-source:review'))
|
||||
OR (id=5105025 AND NOT(permission_code<=>'platform:finance:fee-source:edit'))
|
||||
OR (permission_code='platform:finance:fee-source:review' AND id<>5105024)
|
||||
OR (permission_code='platform:finance:fee-source:edit' AND id<>5105025)
|
||||
OR (id IN(5105024,5105025) AND (tenant_id<>0 OR app_code<>'PLATFORM'
|
||||
OR permission_type<>'BUTTON' OR built_in<>1 OR parent_id NOT IN(5105000,5105041)
|
||||
OR route_path IS NOT NULL
|
||||
OR NOT(http_method<=>IF(id=5105024,'POST','PUT'))))) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Canonical fee button identity/type/metadata conflict';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM iam_permission child LEFT JOIN iam_permission parent ON parent.id=child.parent_id
|
||||
WHERE child.id IN(5105024,5105025) AND (parent.id IS NULL OR parent.tenant_id<>0
|
||||
OR parent.app_code<>'PLATFORM' OR parent.permission_type<>'MENU' OR parent.status<>'ACTIVE' OR parent.deleted<>0
|
||||
OR NOT(parent.permission_code<=>IF(child.parent_id=5105000,'platform:finance','platform:finance:customer-arap:list')))) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Existing fee button parent is invalid';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM iam_role_permission WHERE permission_id IN(5105024,5105025) AND tenant_id<>0)
|
||||
OR EXISTS(SELECT 1 FROM iam_membership_role mr LEFT JOIN iam_membership m ON m.id=mr.membership_id
|
||||
WHERE mr.role_id=4000001 AND (mr.tenant_id<>0 OR m.id IS NULL OR m.tenant_id<>0)) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Existing canonical permission or administrator membership scope mismatch';
|
||||
END IF;
|
||||
-- 恢复停用/缺失资源也会恢复其他角色的旧授权;这种情况必须单独核对,不能随本补丁扩权。
|
||||
IF EXISTS(SELECT 1 FROM iam_role_permission rp LEFT JOIN iam_permission p ON p.id=rp.permission_id
|
||||
WHERE rp.permission_id IN(5105024,5105025) AND rp.role_id<>4000001
|
||||
AND (p.id IS NULL OR p.status<>'ACTIVE' OR p.deleted<>0)) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Restoring fee button would affect another role; review separately';
|
||||
END IF;
|
||||
|
||||
INSERT INTO iam_permission
|
||||
(id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted)
|
||||
SELECT 5105024,0,'PLATFORM','BUTTON',5105041,'platform:finance:fee-source:review','审核财务费用来源',NULL,'POST',150,'ACTIVE',1,0
|
||||
WHERE NOT EXISTS(SELECT 1 FROM iam_permission WHERE id=5105024);
|
||||
SET changed_rows=changed_rows+ROW_COUNT();
|
||||
INSERT INTO iam_permission
|
||||
(id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,deleted)
|
||||
SELECT 5105025,0,'PLATFORM','BUTTON',5105041,'platform:finance:fee-source:edit','编辑财务费用来源',NULL,'PUT',160,'ACTIVE',1,0
|
||||
WHERE NOT EXISTS(SELECT 1 FROM iam_permission WHERE id=5105025);
|
||||
SET changed_rows=changed_rows+ROW_COUNT();
|
||||
UPDATE iam_permission SET status='ACTIVE',deleted=0
|
||||
WHERE id IN(5105024,5105025) AND (status<>'ACTIVE' OR deleted<>0);
|
||||
SET changed_rows=changed_rows+ROW_COUNT();
|
||||
INSERT INTO iam_role_permission(tenant_id,role_id,permission_id,created_at)
|
||||
SELECT 0,4000001,p.id,CURRENT_TIMESTAMP(3) FROM iam_permission p WHERE p.id IN(5105024,5105025)
|
||||
AND NOT EXISTS(SELECT 1 FROM iam_role_permission rp WHERE rp.role_id=4000001 AND rp.permission_id=p.id);
|
||||
SET changed_rows=changed_rows+ROW_COUNT();
|
||||
|
||||
-- 只有真实变更才推进版本;枚举所有既有管理员成员,不依赖当前登录用户,也不遗漏停用成员。
|
||||
IF changed_rows>0 THEN
|
||||
INSERT INTO iam_security_subject_version(auth_user_id,permission_version)
|
||||
SELECT DISTINCT u.auth_user_id,1 FROM iam_user u
|
||||
JOIN iam_membership m ON m.user_id=u.id AND m.tenant_id=0
|
||||
JOIN iam_membership_role mr ON mr.membership_id=m.id AND mr.tenant_id=m.tenant_id AND mr.role_id=4000001
|
||||
WHERE u.auth_user_id IS NOT NULL
|
||||
ON DUPLICATE KEY UPDATE permission_version=permission_version+1;
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM iam_role_permission rp JOIN iam_permission p ON p.id=rp.permission_id
|
||||
WHERE rp.role_id=4000001 AND rp.tenant_id=0 AND p.id IN(5105024,5105025)
|
||||
AND p.tenant_id=0 AND p.app_code='PLATFORM' AND p.permission_type='BUTTON'
|
||||
AND p.status='ACTIVE' AND p.deleted=0)<>2 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Canonical fee write grants incomplete; repair rolled back';
|
||||
END IF;
|
||||
COMMIT;
|
||||
SELECT changed_rows AS repaired_catalog_or_grant_rows;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL repair_overseas_fee_canonical_write();
|
||||
DROP PROCEDURE repair_overseas_fee_canonical_write;
|
||||
|
||||
-- 核验1:必须恰好两行,角色4000001、tenant=0、BUTTON、ACTIVE、deleted=0。
|
||||
SELECT r.id AS role_id,r.role_code,rp.tenant_id,p.id AS permission_id,p.permission_code,
|
||||
p.permission_type,p.status,p.deleted
|
||||
FROM iam_role r JOIN iam_role_permission rp ON rp.role_id=r.id
|
||||
JOIN iam_permission p ON p.id=rp.permission_id
|
||||
WHERE r.id=4000001 AND p.id IN(5105024,5105025) ORDER BY p.id;
|
||||
-- 核验2:仅查看既有管理员主体与当前版本,不创建或切换任何成员角色。
|
||||
SELECT DISTINCT u.auth_user_id,m.id AS membership_id,u.status AS user_status,m.status AS membership_status,
|
||||
COALESCE(sv.permission_version,0) AS permission_version
|
||||
FROM iam_user u JOIN iam_membership m ON m.user_id=u.id AND m.tenant_id=0
|
||||
JOIN iam_membership_role mr ON mr.membership_id=m.id AND mr.tenant_id=m.tenant_id AND mr.role_id=4000001
|
||||
LEFT JOIN iam_security_subject_version sv ON sv.auth_user_id=u.auth_user_id
|
||||
ORDER BY u.auth_user_id,m.id;
|
||||
@@ -1,83 +0,0 @@
|
||||
-- 海外费用菜单定向修复,MySQL 8.0+,目标只能 baiyue_iam。
|
||||
-- 将“海外费用管理”改为“海外费用明细”,并挂到“财务管理”下。
|
||||
-- 权限码、路由和角色授权保持不变;可重复执行。
|
||||
USE baiyue_iam;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
DROP PROCEDURE IF EXISTS repair_overseas_fee_menu_parent;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE repair_overseas_fee_menu_parent()
|
||||
BEGIN
|
||||
DECLARE v_menu_changed INT DEFAULT 0;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
IF (SELECT COUNT(*) FROM iam_permission
|
||||
WHERE id=5105000 AND tenant_id=0 AND app_code='PLATFORM'
|
||||
AND permission_type='MENU' AND permission_code='platform:finance'
|
||||
AND status='ACTIVE' AND deleted=0)<>1 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT='Finance parent menu platform:finance is missing or inactive';
|
||||
END IF;
|
||||
|
||||
IF EXISTS (SELECT 1 FROM iam_permission
|
||||
WHERE (id=5117200 AND (permission_code<>'platform:overseas-fee:list'
|
||||
OR tenant_id<>0 OR app_code<>'PLATFORM' OR permission_type<>'MENU'))
|
||||
OR (permission_code='platform:overseas-fee:list'
|
||||
AND (id<>5117200 OR tenant_id<>0 OR app_code<>'PLATFORM'
|
||||
OR permission_type<>'MENU'))) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT='Overseas fee menu permission identity conflict';
|
||||
END IF;
|
||||
|
||||
IF (SELECT COUNT(*) FROM iam_permission
|
||||
WHERE id=5117200 AND tenant_id=0 AND app_code='PLATFORM'
|
||||
AND permission_type='MENU' AND permission_code='platform:overseas-fee:list')<>1 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT='Overseas fee menu platform:overseas-fee:list is missing';
|
||||
END IF;
|
||||
|
||||
START TRANSACTION;
|
||||
UPDATE iam_permission
|
||||
SET parent_id=5105000,
|
||||
permission_name='海外费用明细',
|
||||
route_path='/overseas-business/fees',
|
||||
http_method='GET',
|
||||
sort_no=60,
|
||||
status='ACTIVE',
|
||||
deleted=0,
|
||||
updated_at=CURRENT_TIMESTAMP(3)
|
||||
WHERE id=5117200 AND tenant_id=0 AND app_code='PLATFORM'
|
||||
AND permission_type='MENU' AND permission_code='platform:overseas-fee:list'
|
||||
AND (parent_id<>5105000 OR permission_name<>'海外费用明细'
|
||||
OR route_path<>'/overseas-business/fees' OR http_method<>'GET'
|
||||
OR sort_no<>60 OR status<>'ACTIVE' OR deleted<>0);
|
||||
SET v_menu_changed=ROW_COUNT();
|
||||
|
||||
-- 菜单实际变化时递增已获该菜单权限用户的安全版本,刷新旧授权快照。
|
||||
IF v_menu_changed>0 THEN
|
||||
INSERT INTO iam_security_subject_version(auth_user_id,permission_version)
|
||||
SELECT DISTINCT u.auth_user_id,1
|
||||
FROM iam_user u
|
||||
JOIN iam_membership m ON m.user_id=u.id AND m.tenant_id=0
|
||||
JOIN iam_membership_role mr ON mr.membership_id=m.id AND mr.tenant_id=0
|
||||
JOIN iam_role r ON r.id=mr.role_id AND r.tenant_id=0
|
||||
JOIN iam_role_permission rp ON rp.role_id=r.id
|
||||
AND rp.permission_id=5117200 AND rp.tenant_id=0
|
||||
WHERE u.auth_user_id IS NOT NULL AND u.status='ACTIVE' AND u.deleted=0
|
||||
AND m.status='ACTIVE' AND m.deleted=0
|
||||
AND r.app_code='PLATFORM' AND r.status='ACTIVE' AND r.deleted=0
|
||||
ON DUPLICATE KEY UPDATE permission_version=permission_version+1;
|
||||
END IF;
|
||||
|
||||
COMMIT;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL repair_overseas_fee_menu_parent();
|
||||
DROP PROCEDURE repair_overseas_fee_menu_parent;
|
||||
|
||||
SELECT id,parent_id,permission_code,permission_name,route_path,sort_no
|
||||
FROM iam_permission WHERE id IN (5105000,5117200) ORDER BY id;
|
||||
@@ -1,19 +0,0 @@
|
||||
-- 海外人工费用说明字段。仅修改 baiyue_lastleg.ll_finance_fee_source 的结构。
|
||||
-- 执行需单独授权;使用独立连接、遇错停止。先执行本脚本,再加载配套 Lastleg 代码。
|
||||
-- 无业务数据回填、费用重建、资金操作或菜单变更。已有字段时跳过新增。
|
||||
USE baiyue_lastleg;
|
||||
|
||||
SET @overseas_fee_remark_ddl = (
|
||||
SELECT IF(EXISTS(
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'll_finance_fee_source' AND column_name = 'fee_remark'
|
||||
), 'SELECT ''fee_remark already exists'' AS result',
|
||||
'ALTER TABLE ll_finance_fee_source ADD COLUMN fee_remark VARCHAR(500) NULL COMMENT ''费用说明,补收或重复作业原因'' AFTER fee_item_name')
|
||||
);
|
||||
PREPARE overseas_fee_remark_stmt FROM @overseas_fee_remark_ddl;
|
||||
EXECUTE overseas_fee_remark_stmt;
|
||||
DEALLOCATE PREPARE overseas_fee_remark_stmt;
|
||||
|
||||
SELECT table_schema, table_name, column_name, column_type, is_nullable, column_comment
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_lastleg' AND table_name = 'll_finance_fee_source' AND column_name = 'fee_remark';
|
||||
@@ -1,97 +0,0 @@
|
||||
-- 指定 TEST 的海外费用/仓租结构补齐;实例必须由执行者另行核对并获准。
|
||||
-- 仅新增 ll_storage_rent_inbound 和 ll_finance_fee_source.reviewer_name。
|
||||
-- 使用独立连接,支持 DELIMITER,遇错停止;禁止 mysql --force。
|
||||
-- 不更新费用、库存、钱包或历史计租数据,不重放空库初始化。
|
||||
-- DDL 隐式提交;失败先回查结构,禁止删除已建表/字段来重跑。
|
||||
USE baiyue_lastleg;
|
||||
|
||||
-- 仅清理本脚本可能遗留的专用校验过程,不删除业务对象。
|
||||
DROP PROCEDURE IF EXISTS overseas_fee_rent_structure_add_20261026;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE overseas_fee_rent_structure_add_20261026()
|
||||
BEGIN
|
||||
DECLARE inbound_exists INT DEFAULT 0;
|
||||
DECLARE reviewer_exists INT DEFAULT 0;
|
||||
|
||||
IF DATABASE()<>'baiyue_lastleg' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='目标必须为 baiyue_lastleg';
|
||||
END IF;
|
||||
-- 在首个业务 DDL 前核对两张依赖表及新增字段的定位列。
|
||||
IF (SELECT COUNT(*) FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME IN ('ll_finance_fee_source','ll_storage_rent_lot')
|
||||
AND TABLE_TYPE='BASE TABLE' AND ENGINE='InnoDB')<>2
|
||||
OR (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source'
|
||||
AND COLUMN_NAME='reviewer_id' AND DATA_TYPE='varchar' AND CHARACTER_MAXIMUM_LENGTH=128)<>1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='费用来源或计租批次基础结构不匹配,停止补齐';
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*) INTO reviewer_exists FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source' AND COLUMN_NAME='reviewer_name';
|
||||
IF reviewer_exists>0 AND (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source' AND COLUMN_NAME='reviewer_name'
|
||||
AND DATA_TYPE='varchar' AND CHARACTER_MAXIMUM_LENGTH=255 AND IS_NULLABLE='YES'
|
||||
AND COLUMN_DEFAULT IS NULL AND EXTRA='')<>1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='已存在的审核人名称字段与正式定义不同,停止且不覆盖';
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*) INTO inbound_exists FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound';
|
||||
-- 已存在的同名表必须完整匹配;不以 IF NOT EXISTS 掩盖半成品或异构表。
|
||||
IF inbound_exists>0 THEN
|
||||
IF (SELECT COUNT(*) FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound'
|
||||
AND TABLE_TYPE='BASE TABLE' AND ENGINE='InnoDB' AND TABLE_COLLATION='utf8mb4_unicode_ci')<>1
|
||||
OR (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound')<>4
|
||||
OR (SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound'
|
||||
AND IS_NULLABLE='NO' AND COLUMN_DEFAULT IS NULL AND EXTRA=''
|
||||
AND ((COLUMN_NAME IN ('receipt_id','lot_id') AND COLUMN_TYPE='bigint')
|
||||
OR (COLUMN_NAME='quantity' AND COLUMN_TYPE='decimal(24,12)')
|
||||
OR (COLUMN_NAME='created_at' AND COLUMN_TYPE='datetime(3)')))<>4 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='已存在的计租实收表字段与正式定义不同,停止且不覆盖';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound' AND INDEX_NAME='PRIMARY')<>1
|
||||
OR (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound' AND INDEX_NAME='PRIMARY'
|
||||
AND COLUMN_NAME='receipt_id' AND SEQ_IN_INDEX=1 AND NON_UNIQUE=0 AND SUB_PART IS NULL)<>1
|
||||
OR (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound'
|
||||
AND INDEX_NAME='idx_storage_rent_inbound_lot')<>1
|
||||
OR (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_storage_rent_inbound'
|
||||
AND INDEX_NAME='idx_storage_rent_inbound_lot' AND COLUMN_NAME='lot_id'
|
||||
AND SEQ_IN_INDEX=1 AND NON_UNIQUE=1 AND SUB_PART IS NULL)<>1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='计租实收表主键或批次索引不匹配,停止且不覆盖';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- 全部前置检查通过后才补缺项;重跑时保持已存在的业务结构和数据。
|
||||
IF reviewer_exists=0 THEN
|
||||
ALTER TABLE ll_finance_fee_source
|
||||
ADD COLUMN reviewer_name VARCHAR(255) NULL COMMENT '审核人名称快照' AFTER reviewer_id;
|
||||
END IF;
|
||||
IF inbound_exists=0 THEN
|
||||
CREATE TABLE ll_storage_rent_inbound (
|
||||
receipt_id bigint NOT NULL COMMENT '实际入库凭证主键,防止重复累计计租数量',
|
||||
lot_id bigint NOT NULL COMMENT '头程同单同仓计租批次主键',
|
||||
quantity decimal(24,12) NOT NULL COMMENT '本次实收追加计租箱数',
|
||||
created_at datetime(3) NOT NULL COMMENT '计租登记时间,采用协调世界时',
|
||||
PRIMARY KEY (receipt_id),
|
||||
KEY idx_storage_rent_inbound_lot (lot_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='头程实收计租幂等登记';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL overseas_fee_rent_structure_add_20261026();
|
||||
DROP PROCEDURE overseas_fee_rent_structure_add_20261026;
|
||||
|
||||
SHOW CREATE TABLE ll_storage_rent_inbound;
|
||||
SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source' AND COLUMN_NAME='reviewer_name';
|
||||
SELECT 'TABLE_COLUMN_READY' AS structure_status;
|
||||
-- TABLE_COLUMN_READY 只表示上述表/字段补齐;免费仓租另执行已审阅的
|
||||
-- overseas-storage-rent-zero-fee-repair.sql,不能据此宣称完整功能上线。
|
||||
@@ -1,29 +0,0 @@
|
||||
-- 2026-10-29:采购驳回照片返工及客户下单预估冻结;仅在Lastleg所属库执行。
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='customer_rejection_reason'), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN customer_rejection_reason VARCHAR(1000) NULL COMMENT ''客户采购结果驳回原因'''));
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='rejected_photo_ids'), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN rejected_photo_ids TEXT NULL COMMENT ''本轮客户驳回的收货照片主键快照'''));
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
CREATE TABLE IF NOT EXISTS ll_order_budget_reservation (
|
||||
id BIGINT NOT NULL COMMENT '预算冻结记录主键',
|
||||
customer_id VARCHAR(64) NOT NULL COMMENT '客户隔离标识',
|
||||
kind VARCHAR(32) NOT NULL COMMENT '客户下单业务类型',
|
||||
request_key VARCHAR(128) NOT NULL COMMENT '下单幂等键',
|
||||
order_no VARCHAR(64) NULL COMMENT '成功创建的业务单号',
|
||||
original_amount DECIMAL(18,2) NOT NULL COMMENT '客户预估原币金额',
|
||||
currency VARCHAR(3) NOT NULL COMMENT '预估金额币种',
|
||||
amount_cny DECIMAL(18,2) NOT NULL COMMENT '按下单月份汇率折算的人民币冻结金额',
|
||||
status VARCHAR(32) NOT NULL COMMENT '资金冻结或释放回执状态',
|
||||
error_message VARCHAR(1000) NULL COMMENT '资金失败原因',
|
||||
command_event_id VARCHAR(64) NULL COMMENT '当前资金指令事件标识',
|
||||
command_version BIGINT NOT NULL DEFAULT 0 COMMENT '资金指令单调版本',
|
||||
release_requested TINYINT NOT NULL DEFAULT 0 COMMENT '是否已请求释放预占',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '首次预占时间',
|
||||
updated_at DATETIME(3) NOT NULL COMMENT '最近资金状态更新时间',
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_order_budget_request(customer_id,kind,request_key),
|
||||
KEY idx_order_budget_release(status,release_requested,created_at),
|
||||
KEY idx_order_budget_order(customer_id,kind,order_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='海外客户下单预估资金冻结投影';
|
||||
@@ -1,102 +0,0 @@
|
||||
-- 海外采购旧流程专属表退役,MySQL 8.0+,目标仅 baiyue_lastleg。
|
||||
-- 必须先停止旧版 Lastleg 写入并部署本次分离版本,验证新流程后在维护窗口执行。
|
||||
-- 永久删除下面明确列出的 21 张旧采购表及其记录,DDL 隐式提交;禁止 mysql --force。
|
||||
-- 保留主单、审核流水、采购附件、分批收货、出库及幂等六表;不改任何共用财务、资金、文件或仓储表。
|
||||
-- 旧资金表有记录或旧状态采购未处理时拒绝,不自动清除、回填或伪造资金完成。
|
||||
-- 运行者须在同一连接显式 SET @procurement_retirement_release='procurement-six-tables-20261027';
|
||||
-- 文件准备不表示数据库已执行。先审核备份及运行版本,按清单整份执行,遇错停止。
|
||||
USE baiyue_lastleg;
|
||||
DELIMITER $$
|
||||
DROP PROCEDURE IF EXISTS retire_procurement_legacy_tables$$
|
||||
CREATE PROCEDURE retire_procurement_legacy_tables()
|
||||
BEGIN
|
||||
IF DATABASE()<>'baiyue_lastleg' OR COALESCE(@procurement_retirement_release,'')<>'procurement-six-tables-20261027' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Confirm the six-table procurement release and target schema first';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name IN (
|
||||
'll_overseas_procurement_order','ll_overseas_procurement_status_history','ll_overseas_procurement_file',
|
||||
'll_procurement_workflow_receipt','ll_procurement_workflow_outbound','ll_procurement_workflow_command'))<>6 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Six active procurement tables must exist before retiring legacy tables';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM ll_overseas_procurement_order WHERE status NOT IN
|
||||
('PENDING_REVIEW','RECEIVING','WAIT_CUSTOMER_CONFIRM','CONFIRMED','IN_TRANSIT','DELIVERING','COMPLETED','REJECTED','CANCELLED')) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Legacy procurement orders remain; resolve them before retirement';
|
||||
END IF;
|
||||
-- 仅只读核对共用资金记录;不删除资金命令或回执,不把已投递当作已结清。
|
||||
IF EXISTS(SELECT 1 FROM ll_event_outbox WHERE aggregate_type='PROCUREMENT_FEE')
|
||||
OR EXISTS(SELECT 1 FROM ll_wallet_event_inbox
|
||||
WHERE JSON_UNQUOTE(JSON_EXTRACT(payload_json,'$.payload.businessType'))='PROCUREMENT_FEE') THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Legacy procurement wallet events exist; financial review is required';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_fee') THEN
|
||||
SET @procurement_retirement_financial_rows=0;
|
||||
SET @procurement_retirement_check_sql='SELECT COUNT(*) INTO @procurement_retirement_financial_rows FROM baiyue_lastleg.ll_overseas_procurement_fee';
|
||||
PREPARE procurement_retirement_check FROM @procurement_retirement_check_sql;
|
||||
EXECUTE procurement_retirement_check;
|
||||
DEALLOCATE PREPARE procurement_retirement_check;
|
||||
IF @procurement_retirement_financial_rows<>0 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Legacy procurement financial records remain; do not delete financial evidence';
|
||||
END IF;
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='ll_procurement_wallet_attempt') THEN
|
||||
SET @procurement_retirement_financial_rows=0;
|
||||
SET @procurement_retirement_check_sql='SELECT COUNT(*) INTO @procurement_retirement_financial_rows FROM baiyue_lastleg.ll_procurement_wallet_attempt';
|
||||
PREPARE procurement_retirement_check FROM @procurement_retirement_check_sql;
|
||||
EXECUTE procurement_retirement_check;
|
||||
DEALLOCATE PREPARE procurement_retirement_check;
|
||||
IF @procurement_retirement_financial_rows<>0 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Legacy procurement financial records remain; do not delete financial evidence';
|
||||
END IF;
|
||||
END IF;
|
||||
-- 不关闭外键校验;来自其他业务表的外键也会使这条精确删除失败。
|
||||
DROP TABLE IF EXISTS
|
||||
ll_procurement_closure_item,
|
||||
ll_procurement_closure,
|
||||
ll_procurement_control_note,
|
||||
ll_procurement_fee_correction_item,
|
||||
ll_procurement_fee_correction,
|
||||
ll_procurement_repack,
|
||||
ll_procurement_estimate_review,
|
||||
ll_procurement_label_item,
|
||||
ll_procurement_label_set,
|
||||
ll_procurement_shipment_item,
|
||||
ll_procurement_shipment,
|
||||
ll_procurement_carton_source,
|
||||
ll_procurement_carton,
|
||||
ll_procurement_manifest,
|
||||
ll_procurement_disposition,
|
||||
ll_procurement_receipt,
|
||||
ll_procurement_budget_authorization,
|
||||
ll_procurement_command,
|
||||
ll_procurement_flow,
|
||||
ll_procurement_wallet_attempt,
|
||||
ll_overseas_procurement_fee;
|
||||
END$$
|
||||
CALL retire_procurement_legacy_tables()$$
|
||||
DROP PROCEDURE retire_procurement_legacy_tables$$
|
||||
DELIMITER ;
|
||||
|
||||
-- 若上面任一步失败必须停止。剩余旧表数应为 0;此 SELECT 不代替客户端退出码核对。
|
||||
SELECT COUNT(*) AS remaining_legacy_procurement_tables
|
||||
FROM information_schema.tables WHERE table_schema='baiyue_lastleg' AND table_name IN (
|
||||
'll_overseas_procurement_fee',
|
||||
'll_procurement_wallet_attempt',
|
||||
'll_procurement_flow',
|
||||
'll_procurement_command',
|
||||
'll_procurement_budget_authorization',
|
||||
'll_procurement_receipt',
|
||||
'll_procurement_disposition',
|
||||
'll_procurement_manifest',
|
||||
'll_procurement_carton',
|
||||
'll_procurement_carton_source',
|
||||
'll_procurement_shipment',
|
||||
'll_procurement_shipment_item',
|
||||
'll_procurement_label_set',
|
||||
'll_procurement_label_item',
|
||||
'll_procurement_estimate_review',
|
||||
'll_procurement_repack',
|
||||
'll_procurement_fee_correction',
|
||||
'll_procurement_fee_correction_item',
|
||||
'll_procurement_control_note',
|
||||
'll_procurement_closure',
|
||||
'll_procurement_closure_item');
|
||||
@@ -1,38 +0,0 @@
|
||||
-- 海外采购退役表只读核查;2026-10-27 分离版本。MySQL 8.0+,仅查询,不自动执行删除。
|
||||
-- 6 张当前业务表保留;21 张旧采购专属表已从生产代码和初始化基线移除。
|
||||
-- 只有先部署分离版本并通过 legacy-tables-retire.sql 前置校验后,才可执行精确删表清单。
|
||||
-- 元数据行数是估算;actual_count_sql 供逐表只读核对,不自动执行。
|
||||
WITH inventory AS (
|
||||
SELECT 'll_overseas_procurement_order' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_overseas_procurement_status_history' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_overseas_procurement_file' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_workflow_receipt' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_workflow_outbound' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_workflow_command' AS table_name, 'KEEP' AS disposition
|
||||
UNION ALL SELECT 'll_overseas_procurement_fee' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_wallet_attempt' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_flow' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_command' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_budget_authorization' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_receipt' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_disposition' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_manifest' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_carton' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_carton_source' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_shipment' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_shipment_item' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_label_set' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_label_item' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_estimate_review' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_repack' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_fee_correction' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_fee_correction_item' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_control_note' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_closure' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
UNION ALL SELECT 'll_procurement_closure_item' AS table_name, 'RETIRED_RELEASE_REQUIRED' AS disposition
|
||||
)
|
||||
SELECT i.table_name,i.disposition,CASE WHEN t.table_name IS NULL THEN 'MISSING' ELSE 'EXISTS' END AS database_state,
|
||||
t.table_rows AS table_rows_estimate,
|
||||
CASE WHEN t.table_name IS NOT NULL THEN CONCAT('SELECT COUNT(*) AS actual_rows FROM baiyue_lastleg.',i.table_name,';') END AS actual_count_sql
|
||||
FROM inventory i LEFT JOIN information_schema.tables t ON t.table_schema='baiyue_lastleg' AND t.table_name=i.table_name
|
||||
ORDER BY i.disposition,i.table_name;
|
||||
@@ -1,65 +0,0 @@
|
||||
-- 仅用于用户确认可丢弃数据的海外采购测试环境,MySQL 8.0+。
|
||||
-- 清空六张当前采购表的数据,删除二十一张旧采购表及其数据。
|
||||
-- 仅作用于 baiyue_lastleg 的采购专属表;不修改共用费用、余额、文件对象及库存。
|
||||
-- 共用表中已有的采购关联记录不会自动删除或退款;本脚本不用于财务结算。
|
||||
-- 先更新分离后的后端并停止采购写入,整份执行,遇错停止,不使用 --force。
|
||||
-- 无存储过程、无 DELIMITER、无需设置会话确认变量;DDL 隐式提交。
|
||||
USE baiyue_lastleg;
|
||||
START TRANSACTION;
|
||||
DELETE FROM ll_procurement_workflow_command;
|
||||
DELETE FROM ll_procurement_workflow_outbound;
|
||||
DELETE FROM ll_procurement_workflow_receipt;
|
||||
DELETE FROM ll_overseas_procurement_file;
|
||||
DELETE FROM ll_overseas_procurement_status_history;
|
||||
DELETE FROM ll_overseas_procurement_order;
|
||||
COMMIT;
|
||||
|
||||
DROP TABLE IF EXISTS
|
||||
ll_procurement_closure_item,
|
||||
ll_procurement_closure,
|
||||
ll_procurement_control_note,
|
||||
ll_procurement_fee_correction_item,
|
||||
ll_procurement_fee_correction,
|
||||
ll_procurement_repack,
|
||||
ll_procurement_estimate_review,
|
||||
ll_procurement_label_item,
|
||||
ll_procurement_label_set,
|
||||
ll_procurement_shipment_item,
|
||||
ll_procurement_shipment,
|
||||
ll_procurement_carton_source,
|
||||
ll_procurement_carton,
|
||||
ll_procurement_manifest,
|
||||
ll_procurement_disposition,
|
||||
ll_procurement_receipt,
|
||||
ll_procurement_budget_authorization,
|
||||
ll_procurement_command,
|
||||
ll_procurement_flow,
|
||||
ll_procurement_wallet_attempt,
|
||||
ll_overseas_procurement_fee;
|
||||
|
||||
SELECT 'procurement_test_reset_complete' AS result,
|
||||
(SELECT COUNT(*) FROM ll_overseas_procurement_order) AS procurement_orders,
|
||||
(SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema='baiyue_lastleg' AND table_name IN (
|
||||
'll_overseas_procurement_fee',
|
||||
'll_procurement_wallet_attempt',
|
||||
'll_procurement_flow',
|
||||
'll_procurement_command',
|
||||
'll_procurement_budget_authorization',
|
||||
'll_procurement_receipt',
|
||||
'll_procurement_disposition',
|
||||
'll_procurement_manifest',
|
||||
'll_procurement_carton',
|
||||
'll_procurement_carton_source',
|
||||
'll_procurement_shipment',
|
||||
'll_procurement_shipment_item',
|
||||
'll_procurement_label_set',
|
||||
'll_procurement_label_item',
|
||||
'll_procurement_estimate_review',
|
||||
'll_procurement_repack',
|
||||
'll_procurement_fee_correction',
|
||||
'll_procurement_fee_correction_item',
|
||||
'll_procurement_control_note',
|
||||
'll_procurement_closure',
|
||||
'll_procurement_closure_item'
|
||||
)) AS remaining_legacy_procurement_tables;
|
||||
@@ -1,36 +0,0 @@
|
||||
-- 简化采购独立批次表;只增加结构,不回填旧采购记录,执行需另行授权。
|
||||
USE baiyue_lastleg;
|
||||
-- 简化采购:独立采购库存,收货、占用和签收扣减均由订单锁串行控制。
|
||||
CREATE TABLE IF NOT EXISTS ll_procurement_workflow_receipt (
|
||||
id BIGINT NOT NULL PRIMARY KEY COMMENT '批次主键',
|
||||
order_id BIGINT NOT NULL COMMENT '采购单主键',
|
||||
quantity BIGINT NOT NULL COMMENT '本批次数量',
|
||||
file_ids TEXT NOT NULL COMMENT '本批次关联凭证文件主键列表',
|
||||
received_at DATETIME(3) NOT NULL COMMENT '本批次实收时间',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '作业人标识',
|
||||
KEY idx_procurement_workflow_receipt (order_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购分批收货照片与实收数量';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_procurement_workflow_outbound (
|
||||
id BIGINT NOT NULL PRIMARY KEY COMMENT '批次主键',
|
||||
order_id BIGINT NOT NULL COMMENT '采购单主键',
|
||||
outbound_no VARCHAR(64) NOT NULL COMMENT '采购出库单号',
|
||||
quantity BIGINT NOT NULL COMMENT '本批次数量',
|
||||
tracking_no VARCHAR(255) NOT NULL COMMENT '物流跟踪号',
|
||||
status VARCHAR(32) NOT NULL COMMENT '批次运输派送及签收状态',
|
||||
file_ids TEXT NOT NULL COMMENT '本批次关联凭证文件主键列表',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '记录创建时间',
|
||||
completed_at DATETIME(3) NULL COMMENT '本批次签收完成时间',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '作业人标识',
|
||||
UNIQUE KEY uk_procurement_workflow_outbound_no (outbound_no),
|
||||
KEY idx_procurement_workflow_outbound (order_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购分批出库物流与签收凭证';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_procurement_workflow_command (
|
||||
order_id BIGINT NOT NULL COMMENT '采购单主键',
|
||||
command_key VARCHAR(128) NOT NULL COMMENT '本单操作幂等键',
|
||||
request_hash VARCHAR(64) NOT NULL COMMENT '动作及请求参数哈希',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '作业人标识',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录创建时间',
|
||||
PRIMARY KEY (order_id,command_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购操作幂等及审计';
|
||||
@@ -1,73 +0,0 @@
|
||||
-- 固定目标经单独授权的 TEST 或本机开发 baiyue_lastleg,只修复自动免费仓租结构,不更新业务数据。
|
||||
-- 使用独立连接、遇错停止;先核对既有表结构,不能重放空库初始化。
|
||||
USE baiyue_lastleg;
|
||||
SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source'
|
||||
AND COLUMN_NAME IN ('amount','original_amount','exchange_rate','created_by','fee_item_code','direction');
|
||||
|
||||
-- 上次 CALL 前置检查失败可能遗留本专用过程,仅清理本脚本自己的过程后重建。
|
||||
DROP PROCEDURE IF EXISTS storage_rent_zero_fee_repair_20261023;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE storage_rent_zero_fee_repair_20261023()
|
||||
BEGIN
|
||||
DECLARE checked_columns INT DEFAULT 0;
|
||||
DECLARE checked_constraints INT DEFAULT 0;
|
||||
DECLARE rate_type VARCHAR(64);
|
||||
DECLARE rate_comment TEXT;
|
||||
DECLARE rate_default TEXT;
|
||||
DECLARE rate_default_sql TEXT;
|
||||
IF DATABASE()<>'baiyue_lastleg' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='目标必须为 baiyue_lastleg';
|
||||
END IF;
|
||||
SELECT COUNT(*) INTO checked_columns FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source'
|
||||
AND ((COLUMN_NAME IN ('amount','original_amount') AND DATA_TYPE='decimal' AND IS_NULLABLE='NO')
|
||||
OR (COLUMN_NAME='exchange_rate' AND DATA_TYPE='decimal' AND EXTRA='')
|
||||
OR (COLUMN_NAME IN ('created_by','fee_item_code','direction') AND DATA_TYPE='varchar' AND IS_NULLABLE='NO'));
|
||||
SELECT COUNT(*) INTO checked_constraints FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source'
|
||||
AND CONSTRAINT_NAME='chk_ll_finance_fee_amount' AND CONSTRAINT_TYPE='CHECK';
|
||||
IF checked_columns<>6 OR checked_constraints<>1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='费用源表字段或金额约束异常,停止修复';
|
||||
END IF;
|
||||
-- 增加新约束前只读检查;人工费用仍须正额且有效汇率,防止意外放宽。
|
||||
IF EXISTS (SELECT 1 FROM ll_finance_fee_source
|
||||
WHERE NOT ((amount>0 OR (amount=0 AND original_amount=0 AND created_by='STORAGE_RENT' AND fee_item_code='FEE_TYPE_077' AND direction='RECEIVABLE'))
|
||||
AND ((exchange_rate IS NOT NULL AND exchange_rate>0) OR (exchange_rate IS NULL AND amount=0 AND original_amount=0 AND created_by='STORAGE_RENT' AND fee_item_code='FEE_TYPE_077' AND direction='RECEIVABLE')))) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='存在不满足新约束的费用,停止且不改数据';
|
||||
END IF;
|
||||
SELECT COUNT(*) INTO checked_constraints FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source'
|
||||
AND CONSTRAINT_NAME='chk_ll_finance_fee_exchange_rate' AND CONSTRAINT_TYPE='CHECK';
|
||||
IF checked_constraints=0 THEN
|
||||
-- 保留真实已有列的精度和备注,不把存量 DECIMAL(18,8) 收窄到基线精度。
|
||||
SELECT COLUMN_TYPE,COLUMN_COMMENT,COLUMN_DEFAULT INTO rate_type,rate_comment,rate_default
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='ll_finance_fee_source' AND COLUMN_NAME='exchange_rate';
|
||||
IF rate_type NOT REGEXP '^decimal[(][0-9]+,[0-9]+[)]$' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='汇率列不是预期定点数类型,停止修复';
|
||||
END IF;
|
||||
IF LOCATE('自动零元仓租可空',rate_comment)=0 THEN
|
||||
SET rate_comment=CONCAT(rate_comment,',自动零元仓租可空');
|
||||
END IF;
|
||||
-- 保留既有数值默认值(例如1.00000000);拒绝表达式或非数值默认值。
|
||||
IF rate_default IS NOT NULL AND rate_default NOT REGEXP '^-?[0-9]+([.][0-9]+)?$' THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='汇率默认值不是预期数值,停止修复';
|
||||
END IF;
|
||||
SET rate_default_sql=IF(rate_default IS NULL,' DEFAULT NULL',CONCAT(' DEFAULT ',rate_default));
|
||||
-- 单次原子 ALTER 同步调整可空性与两项约束,原币及结算列完全不改。
|
||||
SET @storage_rent_zero_fee_ddl=CONCAT(
|
||||
'ALTER TABLE baiyue_lastleg.ll_finance_fee_source DROP CHECK chk_ll_finance_fee_amount, ',
|
||||
'MODIFY COLUMN exchange_rate ',rate_type,' NULL',rate_default_sql,' COMMENT ',QUOTE(rate_comment),', ',
|
||||
'ADD CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0 OR (amount=0 AND original_amount=0 AND created_by=''STORAGE_RENT'' AND fee_item_code=''FEE_TYPE_077'' AND direction=''RECEIVABLE'')), ',
|
||||
'ADD CONSTRAINT chk_ll_finance_fee_exchange_rate CHECK((exchange_rate IS NOT NULL AND exchange_rate>0) OR (exchange_rate IS NULL AND amount=0 AND original_amount=0 AND created_by=''STORAGE_RENT'' AND fee_item_code=''FEE_TYPE_077'' AND direction=''RECEIVABLE''))');
|
||||
PREPARE storage_rent_zero_fee_stmt FROM @storage_rent_zero_fee_ddl;
|
||||
EXECUTE storage_rent_zero_fee_stmt;
|
||||
DEALLOCATE PREPARE storage_rent_zero_fee_stmt;
|
||||
SET @storage_rent_zero_fee_ddl=NULL;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL storage_rent_zero_fee_repair_20261023();
|
||||
DROP PROCEDURE storage_rent_zero_fee_repair_20261023;
|
||||
SHOW CREATE TABLE ll_finance_fee_source;
|
||||
@@ -1,112 +0,0 @@
|
||||
-- TEST ONLY. Rebuild the explicitly authorized appointment header and item tables.
|
||||
-- The command-history and cargo-verification tables MUST NOT already exist; check both before any DROP.
|
||||
-- If either exists, stop and inspect the prior outcome. Do not clear history or blindly retry.
|
||||
-- Requires explicit approval; never run against production or as automatic startup SQL.
|
||||
-- Caller must verify the TEST connection before executing.
|
||||
USE baiyue_lastleg;
|
||||
DROP PROCEDURE IF EXISTS assert_test_appointment_reset_preconditions;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_test_appointment_reset_preconditions()
|
||||
BEGIN
|
||||
IF EXISTS(SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE()
|
||||
AND table_name IN ('ll_fba_appointment_command','ll_appointment_cargo_verification',
|
||||
'll_appointment_work','ll_dispatch_appointment_allocation','ll_fba_receiving_agreement',
|
||||
'll_fba_receiving_member','ll_fba_receiving_change','ll_fba_receiving_revision','ll_fba_receiving_plan')) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Stop: appointment history or work/allocation schema already exists; inspect before any reset';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE()
|
||||
AND table_name IN ('ll_inbound_fba_appointment','ll_inbound_fba_appointment_item')) <> 2 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Stop: expected both legacy appointment tables; inspect partial or new schema';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_test_appointment_reset_preconditions();
|
||||
DROP PROCEDURE assert_test_appointment_reset_preconditions;
|
||||
DROP TABLE ll_inbound_fba_appointment_item;
|
||||
DROP TABLE ll_inbound_fba_appointment;
|
||||
CREATE TABLE ll_inbound_fba_appointment (
|
||||
id BIGINT NOT NULL COMMENT '主键ID',
|
||||
appointment_no VARCHAR(64) NOT NULL COMMENT '系统预约业务单号,不是外部约号',
|
||||
confirmation_no VARCHAR(128) NULL COMMENT '收货方正式外部确认号',
|
||||
planned_date DATE NULL COMMENT '计划当地日期,可只有日期而无时段',
|
||||
planned_at DATETIME(3) NULL COMMENT '计划开始当地时间,待定可空',
|
||||
planned_end_at DATETIME(3) NULL COMMENT '计划结束当地时间',
|
||||
appointment_at DATETIME(3) NULL COMMENT '对方确认开始当地时间',
|
||||
appointment_end_at DATETIME(3) NULL COMMENT '对方确认结束当地时间',
|
||||
appointment_start_utc DATETIME(3) NULL COMMENT '确认开始UTC时间点',
|
||||
appointment_end_utc DATETIME(3) NULL COMMENT '确认结束UTC时间点',
|
||||
timezone VARCHAR(64) NULL COMMENT '目的仓权威IANA时区,未维护不得确认',
|
||||
origin_warehouse_id VARCHAR(64) NOT NULL COMMENT '实际起运仓',
|
||||
version INT NOT NULL DEFAULT 0 COMMENT '并发版本',
|
||||
appointment_status VARCHAR(32) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING安排/SUCCESS对方确认/FAILED/CANCELLED',
|
||||
appointment_remark VARCHAR(1000) NULL COMMENT '备注或取消原因',
|
||||
fba_warehouse_code VARCHAR(128) NOT NULL COMMENT 'FBA目的仓编码',
|
||||
selected_count INT NOT NULL DEFAULT 0 COMMENT '真实货源票数',
|
||||
replacement_nos_json LONGTEXT NULL COMMENT '分批或合并后的新预约业务号列表,非空时原批次只读',
|
||||
replacement_keys_json LONGTEXT NULL COMMENT '替代批次不可变键列表,只用于内部业务关联',
|
||||
repartition_reason VARCHAR(1000) NULL COMMENT '分批或合并原因,原安排及来源明细保留',
|
||||
created_by VARCHAR(128) NOT NULL COMMENT '登录操作人',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建UTC时间',
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '更新UTC时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_ll_fba_appointment_no (appointment_no),
|
||||
KEY idx_ll_fba_appointment_list (appointment_at,appointment_status,fba_warehouse_code),
|
||||
KEY idx_ll_fba_appointment_planned (planned_at,appointment_status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='FBA预约安排与正式确认唯一主记录';
|
||||
|
||||
CREATE TABLE ll_inbound_fba_appointment_item (
|
||||
id BIGINT NOT NULL COMMENT '记录主键',
|
||||
appointment_id BIGINT NOT NULL COMMENT '预约主记录标识',
|
||||
source_key VARCHAR(160) NOT NULL COMMENT '稳定ORDER或BOOKING货源键',
|
||||
source_version VARCHAR(160) NULL COMMENT '保存时核实的来源版本',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '本票所属客户',
|
||||
order_id BIGINT NULL COMMENT '尚未形成尾程订单时为空',
|
||||
inbound_code VARCHAR(128) NULL COMMENT '真实入仓码,不伪造',
|
||||
fba_warehouse_code VARCHAR(128) NOT NULL COMMENT '目的FBA仓编码',
|
||||
package_count INT NULL COMMENT '本批分配箱数,未知保持空;同一原来源总量守恒',
|
||||
cargo_verification_version INT NULL COMMENT '采用的预约货物核实版本,未核实时为空',
|
||||
shipment_references_json LONGTEXT NULL COMMENT '本次采用的货件或追踪号核实快照',
|
||||
active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '当前批次数量分配有效;取消、未约成和完成均保留,仅替代时释放',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建UTC时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_ll_fba_item_source (appointment_id,source_key),
|
||||
KEY idx_ll_fba_active_source (customer_id,source_key,active),
|
||||
KEY idx_ll_fba_active_order (customer_id,order_id,active),
|
||||
KEY idx_ll_fba_item_source_lookup (source_key,customer_id),
|
||||
KEY idx_ll_fba_item_customer_order (customer_id,order_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='入仓前后共用的预约真实货源';
|
||||
|
||||
CREATE TABLE ll_appointment_cargo_verification (
|
||||
id BIGINT NOT NULL COMMENT '核实记录主键',
|
||||
customer_id VARCHAR(128) NOT NULL COMMENT '原货源所属客户',
|
||||
source_key VARCHAR(160) NOT NULL COMMENT '稳定ORDER或BOOKING原来源键',
|
||||
destination_key VARCHAR(160) NOT NULL COMMENT '核实时的原目的地',
|
||||
source_version VARCHAR(160) NULL COMMENT '核实时的原来源版本',
|
||||
source_packages INT NULL COMMENT '核实时的原来源箱数,未知为空',
|
||||
version INT NOT NULL COMMENT '同一来源的核实版本,从一递增',
|
||||
package_count INT NULL COMMENT '独立核实箱数,不回写原订单',
|
||||
shipment_references_json LONGTEXT NOT NULL COMMENT '本票货件号或追踪号列表,不回写原订单',
|
||||
remark VARCHAR(1000) NULL COMMENT '核实说明',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '登录操作人',
|
||||
operator_name VARCHAR(200) NULL COMMENT '操作人名称快照',
|
||||
command_key VARCHAR(64) NOT NULL COMMENT '来源内幂等命令键',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '来源、操作人及请求摘要',
|
||||
created_at DATETIME(3) NOT NULL COMMENT '核实UTC时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_ll_cargo_verification_version (customer_id,source_key,version),
|
||||
UNIQUE KEY uk_ll_cargo_verification_command (customer_id,source_key,command_key),
|
||||
CONSTRAINT chk_ll_cargo_verification_quantity CHECK (package_count IS NULL OR package_count > 0),
|
||||
CONSTRAINT chk_ll_cargo_verification_version CHECK (version > 0)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约货物核实资料及不可覆盖的版本历史';
|
||||
|
||||
CREATE TABLE ll_fba_appointment_command (
|
||||
command_key VARCHAR(128) NOT NULL COMMENT '持久化幂等键',
|
||||
request_hash CHAR(64) NOT NULL COMMENT '操作、操作者和请求摘要',
|
||||
operation VARCHAR(96) NOT NULL COMMENT '操作类型及目标业务号',
|
||||
operator_id VARCHAR(128) NOT NULL COMMENT '登录操作人',
|
||||
appointment_no VARCHAR(64) NULL COMMENT '系统预约业务单号',
|
||||
response_json LONGTEXT NULL COMMENT '原命令返回快照,与业务写入同事务',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建UTC时间',
|
||||
PRIMARY KEY(command_key),
|
||||
KEY idx_ll_fba_command_appointment(appointment_no,created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='预约命令与变更历史';
|
||||
@@ -1,11 +0,0 @@
|
||||
-- 自营库存周转后端导出权限;不建表,不修改销量、库存或采集任务。
|
||||
USE baiyue_iam;
|
||||
SET NAMES utf8mb4;
|
||||
START TRANSACTION;
|
||||
INSERT INTO iam_permission (id,tenant_id,app_code,permission_type,parent_id,permission_code,permission_name,route_path,http_method,sort_no,status,built_in,created_at,updated_at,deleted) VALUES
|
||||
(5118002,0,'PLATFORM','API',5118120,'platform:self-operated-analytics:export','导出平台自营库存周转','/api/platform/v1/files/export-tasks','POST',20,'ACTIVE',1,CURRENT_TIMESTAMP(3),CURRENT_TIMESTAMP(3),0)
|
||||
ON DUPLICATE KEY UPDATE permission_name=VALUES(permission_name),route_path=VALUES(route_path),http_method=VALUES(http_method),status='ACTIVE',deleted=0,updated_at=CURRENT_TIMESTAMP(3);
|
||||
INSERT INTO iam_role_permission (role_id,permission_id,tenant_id,created_at)
|
||||
SELECT 4000001,5118002,0,CURRENT_TIMESTAMP(3)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM iam_role_permission WHERE role_id=4000001 AND permission_id=5118002 AND tenant_id=0);
|
||||
COMMIT;
|
||||
@@ -1,40 +0,0 @@
|
||||
-- 供应商查询缺失结构修复。MySQL 8;仅用于本次明确授权的本机开发库。
|
||||
-- 固定目标 baiyue_warehouse;不修改供应商、费用、余额或授信数据。
|
||||
-- 已有结构安全跳过;不推断历史拖车供应商的国内/海外类别。
|
||||
-- DDL 会隐式提交,请在独立连接以遇错停止模式整份执行。
|
||||
USE baiyue_warehouse;
|
||||
SET NAMES utf8mb4;
|
||||
SELECT DATABASE() AS target_database;
|
||||
|
||||
-- 先确认正式供应商主表存在;不存在时 ALTER 会报错并停止,不创建第二份主档。
|
||||
SET @supplier_query_column_ddl = IF(
|
||||
EXISTS (SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_warehouse'
|
||||
AND table_name = 'wh_supplier' AND column_name = 'trucking_scope'),
|
||||
'SELECT ''trucking_scope 已存在,跳过'' AS structure_result',
|
||||
'ALTER TABLE baiyue_warehouse.wh_supplier ADD COLUMN trucking_scope VARCHAR(16) NULL COMMENT ''拖车类型:DOMESTIC国内拖车、OVERSEAS海外车队;非拖车为空'' AFTER category'
|
||||
);
|
||||
PREPARE supplier_query_statement FROM @supplier_query_column_ddl;
|
||||
EXECUTE supplier_query_statement;
|
||||
DEALLOCATE PREPARE supplier_query_statement;
|
||||
|
||||
-- 正式列表还会读取船司关联;若未初始化,仅按当前模块基线建立空表。
|
||||
CREATE TABLE IF NOT EXISTS wh_supplier_carrier (
|
||||
supplier_id BIGINT UNSIGNED NOT NULL COMMENT 'BOOKING供应商ID',
|
||||
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '平台公共作用域,固定为0',
|
||||
carrier_code VARCHAR(16) NOT NULL COMMENT '船司标准编码',
|
||||
created_by BIGINT UNSIGNED NULL COMMENT '创建人ID',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||
PRIMARY KEY (supplier_id,carrier_code),
|
||||
KEY idx_wh_supplier_carrier_code (tenant_id,carrier_code,supplier_id),
|
||||
CONSTRAINT chk_wh_supplier_carrier_tenant CHECK (tenant_id = 0),
|
||||
CONSTRAINT chk_wh_supplier_carrier_code CHECK (carrier_code IN ('MATSON','SML','ZIM','COSCO','EMC','HEDE','OTHER'))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='BOOKING供应商与标准船司编码多对多关联';
|
||||
|
||||
-- 执行后只核对结构,不读取供应商联系信息。
|
||||
SELECT table_name, column_name, column_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_warehouse'
|
||||
AND ((table_name = 'wh_supplier' AND column_name = 'trucking_scope')
|
||||
OR table_name = 'wh_supplier_carrier')
|
||||
ORDER BY table_name, ordinal_position;
|
||||
+324
-518
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
# 排车运输接入数据库变更汇总
|
||||
|
||||
执行文件:[lastleg-dispatch-transport-tasks.sql](lastleg-dispatch-transport-tasks.sql)。目标为 **MySQL 8 / baiyue_lastleg**,文件内已有 `USE baiyue_lastleg`。可整份重复执行;按 information_schema 判断字段及索引,按 IF NOT EXISTS 创建表。已在本机既有业务数据环境连续执行两次通过;未在远端环境执行。
|
||||
|
||||
| 对象 | 新增或调整 | 用途 |
|
||||
|---|---|---|
|
||||
| ll_dispatch_order.task_type | 新增 VARCHAR(32) NOT NULL DEFAULT DELIVERY | 区分仓库派送、到仓取货、本土卡车;旧单保留派送类型 |
|
||||
| ll_dispatch_truck_task | 新表;dispatch_no、trip_no、customer_id、order_no、active_order | 真实排车关联原单;运输记录唯一、有效原单唯一;取消释放有效键,完成保留 |
|
||||
| ll_dispatch_transport_create | 新表;trip_no、request_hash | 原安排请求摘要,避免重复建单及同键更换原单 |
|
||||
| ll_dispatch_transport_command | 新表;dispatch_no、request_key、request_hash、evidence_json、created_at | 执行命令幂等、已确认完成凭证持久化 |
|
||||
| ll_dispatch_daily_sequence | 既有正式日流水表,缺失时补建 | 统一 PC 日期与四位流水;不修改历史单号 |
|
||||
| ll_dispatch_order.customer_id | 仅旧库存在且为 NOT NULL 时改为允许 NULL | 兼容整车跨客户主单;保留原值,不回填或置空 |
|
||||
| ll_us_truck_order.contact_name / contact_info / requested_date | 仅旧库仍为 NOT NULL 时改为允许 NULL | 兼容现有原单起终点联系人及取送时间模型,保留历史字段和数据 |
|
||||
| ll_fleet_external_booking.source_looseboard_order_id | 缺失时补 BIGINT NULL | 当前承运占用查询依赖,等同 V33;不创建散板业务 |
|
||||
| ll_fleet_external_booking.idx_booking_looseboard_source | 缺失时补客户、原散板ID、状态联合索引 | 原单承运占用查询 |
|
||||
|
||||
所有新增表、字段均有中文注释。SQL不创建账号、不改角色权限、不删除表或记录、不改库存及历史单号,也不回填旧任务。
|
||||
|
||||
前置:目标库已具备当前整车排车、FleetTrip、仓储转运取货及本土卡车业务结构;本文件是本次运输接入增量,不替代这些模块的完整升级。执行完成后配套发布 Lastleg 和 Admin。迁移系统记录为 V32,承运占用依赖结构为 V33;直接交付执行时使用本份汇总 SQL 即可,不再重复手动执行两个版本文件。
|
||||
|
||||
本机验收中发现的旧字段约束与缺少日流水表已一并纳入。业务数据由正式 Gateway HTTP 创建,结构验证未写业务SQL。
|
||||
+849
-1585
File diff suppressed because it is too large
Load Diff
@@ -56,5 +56,3 @@
|
||||
| PDF 标签、审计、跨区双向事件 | `print/`、`audit-service/`、`event-bridge-service/` | 事件模型先读 `common-event-contract/AGENTS.md`;国内真实生产验收 `firstleg/.../TaillegRealProducerAcceptanceTest.java`、海外真实消费验收 `lastleg-service/.../TaillegRealConsumerAcceptanceTest.java`;可靠投递与 CN/OVERSEAS 目标路由读 `event-bridge-service/AGENTS.md` |
|
||||
|
||||
散货托盘码与跨区传递:`firstleg/` 的 `LoadingPalletLabelService.java` 生成冻结标签并调用 Print 输出 PDF,`LoadingCompletedOutboxService.java` 传递装柜快照;`lastleg-service/` 通过 `LastlegSourcePalletMapper.java` 保存来源托盘,`InboundPlanService.java` 和 `ContainerInboundPlanConversionCoordinator.java` 消费。标签与资源预留的细节继续读对应服务指引。
|
||||
|
||||
平台自营销量、产品库存与采集:正式入口为 ../docs/自营业务/README.md;适配从 integration-service/AGENTS.md 进入,持久化、指标和平台运行查询从 lastleg-service/AGENTS.md 进入 selfoperated/analytics/,权限源为 iam/src/main/resources/db/selfoperated-analytics-permissions.sql。Admin 从 ../apps/admin-web/src/modules/self-operated/AGENTS.md 进入;与客户物流订单和仓储作业库存分开。
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 236 KiB |
@@ -1,90 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="1280" viewBox="0 0 1800 1280">
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><path d="M0,0 L10,3 L0,6 Z" fill="#335c81"/></marker>
|
||||
<marker id="greenArrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><path d="M0,0 L10,3 L0,6 Z" fill="#18865b"/></marker>
|
||||
<marker id="redArrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto"><path d="M0,0 L10,3 L0,6 Z" fill="#c94d4d"/></marker>
|
||||
<style>
|
||||
.title{font:700 34px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#17324d}
|
||||
.sub{font:400 17px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#547086}
|
||||
.lane{font:700 20px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#17324d}
|
||||
.boxTitle{font:700 19px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#17324d}
|
||||
.boxText{font:400 16px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#36566d}
|
||||
.small{font:400 14px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#547086}
|
||||
.assert{font:500 16px 'Microsoft YaHei','Noto Sans SC',sans-serif;fill:#23445a}
|
||||
.line{stroke:#335c81;stroke-width:3;fill:none;marker-end:url(#arrow)}
|
||||
.gline{stroke:#18865b;stroke-width:3;fill:none;marker-end:url(#greenArrow)}
|
||||
.rline{stroke:#c94d4d;stroke-width:3;fill:none;marker-end:url(#redArrow)}
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="1800" height="1280" fill="#f6f9fc"/>
|
||||
<text x="70" y="62" class="title">海外业务|库存变动测试总流程图</text>
|
||||
<text x="70" y="94" class="sub">测试看库存:先看库存状态,再看数量、位置、流水和幂等;灰色节点只改状态/资源,不直接改可用库存。</text>
|
||||
|
||||
<g transform="translate(70,125)">
|
||||
<rect width="1660" height="58" rx="12" fill="#e9f1f8"/>
|
||||
<circle cx="28" cy="29" r="10" fill="#18865b"/><text x="50" y="35" class="small">绿色:库存增加/恢复</text>
|
||||
<circle cx="250" cy="29" r="10" fill="#c94d4d"/><text x="272" y="35" class="small">红色:库存扣减</text>
|
||||
<circle cx="450" cy="29" r="10" fill="#e19a28"/><text x="472" y="35" class="small">橙色:冻结/释放</text>
|
||||
<circle cx="690" cy="29" r="10" fill="#7657a8"/><text x="712" y="35" class="small">紫色:SKU/箱唛变化</text>
|
||||
<circle cx="960" cy="29" r="10" fill="#78909c"/><text x="982" y="35" class="small">灰色:状态/资源变化</text>
|
||||
<text x="1260" y="35" class="small">所有写操作:租户隔离 + 版本/锁 + 幂等键</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(70,220)">
|
||||
<rect width="1660" height="196" rx="16" fill="#edf5ee" stroke="#b7d9c2" stroke-width="2"/>
|
||||
<text x="24" y="34" class="lane">A. 库存来源与入仓</text>
|
||||
<rect x="24" y="58" width="240" height="96" rx="12" fill="#fff" stroke="#6ea984" stroke-width="2"/>
|
||||
<text x="44" y="88" class="boxTitle">头程装柜完成事件</text><text x="44" y="116" class="boxText">生成尾程单 / 冻结明细</text><text x="44" y="140" class="small">在途:不可用库存</text>
|
||||
<path d="M264 106 H330" class="line"/>
|
||||
<rect x="330" y="58" width="250" height="96" rx="12" fill="#fff" stroke="#6ea984" stroke-width="2"/>
|
||||
<text x="350" y="88" class="boxTitle">平台转换入仓计划</text><text x="350" y="116" class="boxText">按入仓单 / 推荐托数建计划</text><text x="350" y="140" class="small">仍未形成可用库存</text>
|
||||
<path d="M580 106 H646" class="line"/>
|
||||
<rect x="646" y="58" width="290" height="96" rx="12" fill="#fff" stroke="#18865b" stroke-width="3"/>
|
||||
<text x="666" y="88" class="boxTitle">PDA 签收 → 实收 → 上架</text><text x="666" y="116" class="boxText">完成后入仓库存入账</text><text x="666" y="140" class="small">AVAILABLE + 位置 + 库存流水</text>
|
||||
<path d="M936 106 H1002" class="gline"/>
|
||||
<rect x="1002" y="58" width="280" height="96" rx="12" fill="#e6f6ed" stroke="#18865b" stroke-width="2"/>
|
||||
<text x="1022" y="88" class="boxTitle">可用库存池</text><text x="1022" y="116" class="boxText">客户 × 海外仓 × 目的仓</text><text x="1022" y="140" class="small">入仓单汇总;托盘只做作业维度</text>
|
||||
<rect x="1316" y="58" width="310" height="96" rx="12" fill="#f0f2f4" stroke="#9baab4" stroke-width="2"/>
|
||||
<text x="1336" y="88" class="boxTitle">门禁与失败</text><text x="1336" y="116" class="boxText">照片、仓绑定、客户/柜号</text><text x="1336" y="140" class="small">任一失败:库存与状态整体回滚</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(70,450)">
|
||||
<rect width="1660" height="222" rx="16" fill="#fff8ec" stroke="#efd39a" stroke-width="2"/>
|
||||
<text x="24" y="34" class="lane">B. 从可用库存出发的四类作业</text>
|
||||
<rect x="24" y="60" width="360" height="126" rx="12" fill="#fff" stroke="#dfa43c" stroke-width="2"/>
|
||||
<text x="44" y="88" class="boxTitle">排车 / 一件代发拣货</text><text x="44" y="116" class="boxText">AVAILABLE → 冻结 → PICKED</text><text x="44" y="144" class="boxText">发车/出库 → 扣减</text><text x="44" y="170" class="small">整托扫描也按入仓单组成核平</text>
|
||||
<rect x="430" y="60" width="360" height="126" rx="12" fill="#fff" stroke="#7657a8" stroke-width="2"/>
|
||||
<text x="450" y="88" class="boxTitle">换标</text><text x="450" y="116" class="boxText">冻结 hold_packages</text><text x="450" y="144" class="boxText">旧 SKU 转出 → 新 SKU 转入</text><text x="450" y="170" class="small">箱唛/托盘绑定变化,箱数守恒</text>
|
||||
<rect x="836" y="60" width="360" height="126" rx="12" fill="#fff" stroke="#dfa43c" stroke-width="2"/>
|
||||
<text x="856" y="88" class="boxTitle">仓储转运</text><text x="856" y="116" class="boxText">来源仓冻结/扣减</text><text x="856" y="144" class="boxText">目标仓收货 → 增加</text><text x="856" y="170" class="small">可联动换标;来源/目标核对</text>
|
||||
<rect x="1242" y="60" width="384" height="126" rx="12" fill="#fff" stroke="#c94d4d" stroke-width="2"/>
|
||||
<text x="1262" y="88" class="boxTitle">废弃</text><text x="1262" y="116" class="boxText">申请仅锁箱:DISCARD_PENDING</text><text x="1262" y="144" class="boxText">PDA 实际确认 → 扣减 → DISCARDED</text><text x="1262" y="170" class="small">驳回释放;平台结案不再扣一次</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(70,706)">
|
||||
<rect width="1660" height="222" rx="16" fill="#eef3fa" stroke="#b7cae2" stroke-width="2"/>
|
||||
<text x="24" y="34" class="lane">C. 出库后的结果与恢复</text>
|
||||
<rect x="24" y="60" width="350" height="126" rx="12" fill="#fff" stroke="#c94d4d" stroke-width="2"/>
|
||||
<text x="44" y="88" class="boxTitle">OUTBOUNDED / 派送中</text><text x="44" y="116" class="boxText">库存已扣减,保留出库事实</text><text x="44" y="144" class="boxText">签收:不再二次扣库存</text><text x="44" y="170" class="small">派送费用与库存动作分开核对</text>
|
||||
<path d="M374 123 H446" class="line"/>
|
||||
<rect x="446" y="60" width="380" height="126" rx="12" fill="#fff" stroke="#18865b" stroke-width="3"/>
|
||||
<text x="466" y="88" class="boxTitle">异常退回入仓</text><text x="466" y="116" class="boxText">只能选原出库拣货事实</text><text x="466" y="144" class="boxText">RETURN_STOCK_IN → 目标托盘/库位</text><text x="466" y="170" class="small">库存恢复 + 异常完成 + 派送 RETURNED</text>
|
||||
<rect x="900" y="60" width="330" height="126" rx="12" fill="#fff" stroke="#78909c" stroke-width="2"/>
|
||||
<text x="920" y="88" class="boxTitle">盘点调整</text><text x="920" y="116" class="boxText">实盘数量 − 账面数量 = 差异</text><text x="920" y="144" class="boxText">按正/负生成调整流水</text><text x="920" y="170" class="small">无差异不造流水;需 adjust 权限</text>
|
||||
<rect x="1270" y="60" width="356" height="126" rx="12" fill="#fff" stroke="#78909c" stroke-width="2"/>
|
||||
<text x="1290" y="88" class="boxTitle">移库 / 拆合托 / 换绑</text><text x="1290" y="116" class="boxText">同仓位置或托盘组成变化</text><text x="1290" y="144" class="boxText">数量净额 = 0</text><text x="1290" y="170" class="small">记录位置流水;资源锁防并发</text>
|
||||
</g>
|
||||
|
||||
<path d="M1142 416 V450" class="gline"/><path d="M120 638 V706" class="rline"/><path d="M610 638 V706" class="gline"/>
|
||||
<path d="M1020 638 V706" class="line"/><path d="M1435 638 V706" class="rline"/>
|
||||
|
||||
<g transform="translate(70,965)">
|
||||
<rect width="1660" height="250" rx="16" fill="#ffffff" stroke="#d5e0e8" stroke-width="2"/>
|
||||
<text x="24" y="36" class="lane">D. 测试统一断言(每个库存场景都要检查)</text>
|
||||
<text x="42" y="78" class="assert">① 数量守恒:客户 / 海外仓 / 目的仓 / 入仓单 / 托盘组成逐层核平</text>
|
||||
<text x="42" y="114" class="assert">② 三账一致:库存余额 = 位置明细汇总 = 库存流水结果</text>
|
||||
<text x="42" y="150" class="assert">③ 幂等并发:重复事件、重复请求、并发锁定不得产生第二笔变动</text>
|
||||
<text x="42" y="186" class="assert">④ 原子回滚:权限、门禁、资源锁、跨服务失败时,库存/单据/流水一起回滚</text>
|
||||
<text x="42" y="222" class="assert">⑤ 隔离校验:客户、仓、来源入仓单、原出库事实不可伪造或串用</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.2 KiB |
@@ -1,40 +0,0 @@
|
||||
# 海外业务库存变动测试整理
|
||||
|
||||
范围依据:`lastleg-service/AGENTS.md`、`docs/backend-business-index.md` 及当前海外仓库存、入仓、出库、换标、转运、废弃、异常退回和 PDA 作业入口。
|
||||
|
||||
## 先统一库存口径
|
||||
|
||||
- **可用库存**:按客户、海外仓、目的仓、入仓单汇总箱数;SKU、箱唛和托盘是明细快照/作业维度。
|
||||
- **冻结库存**:拣货、换标、废弃、转运等处理中暂时不可重复使用;冻结不等于已经扣减。
|
||||
- **库存流水**:每一次入账、冻结、释放、扣减、恢复、SKU 转换和位置变化都应能按业务单号、幂等键追溯。
|
||||
- **托盘不是库存归属**:合托后一个物理托盘可以包含多个入仓单,出库、换标和退回必须按托盘组成明细核平。
|
||||
|
||||
## 测试场景矩阵
|
||||
|
||||
| 场景 | 触发与前置 | 库存变动 | 测试重点 |
|
||||
|---|---|---|---|
|
||||
| 头程接柜/海外入仓 | 装柜完成事件 → 生成尾程单/入仓计划;PDA 签收、实收、上架、完成 | 在途冻结 → 入仓后 `AVAILABLE` 增加;写库存位置和流水 | 柜号/客户/入仓单隔离;卸柜照片门禁;重复事件不重复入账;失败整事务回滚 |
|
||||
| 普通排车出库/派送 | 计划已入仓;排车审核、拣货、箱数核平、发车 | `AVAILABLE` → 冻结/已拣;原子出库后可用库存扣减 | 整托/部分托按组成明细核平;未审核、数量不平、车辆门禁时不得出库;同键重放幂等 |
|
||||
| 一件代发 | 已完成入库且有可用箱唛/SKU;创建 `WAIT_PICK` 出库单 | SKU/箱唛库存冻结 → PDA 拣货 → `OUTBOUNDED` 扣减 | 候选只能来自真实可用库存;一单不得跨客户/跨仓;整托扫描任一明细失败必须整体回滚 |
|
||||
| 客户换标 | 历史入仓库存可用;客户申请、PDA 扫旧 SKU/箱唛、完工、客户确认 | 旧 SKU/箱唛冻结;换标完成后旧库存转出、新 SKU/箱唛转入;库存总箱数守恒 | 同箱多 SKU 不重复冻结;只移动本单 `hold_packages`;已生成出库单禁止再次拆托;照片/复核/客户确认门禁 |
|
||||
| 仓储转运 | 来源库存可用;创建转运、测量、换标(可选)、出库、目标仓收货 | 来源仓冻结/扣减 → 目标仓入账;换标时 SKU 转换 | 来源客户、入仓单和箱数核对;部分转运数量守恒;目标仓与来源仓不能串;重复完成不重复入账 |
|
||||
| 货物废弃 | 一件代发/库存货物申请废弃;审批后由绑定海外 PDA 实际确认 | `AVAILABLE` → `DISCARD_PENDING`;实际确认后 SKU、余额、位置扣减并记 `DISCARDED` | 申请阶段只锁箱不扣库存;驳回释放;批准不是实际扣减;实际数量与逐箱流水一致;失败整批回滚 |
|
||||
| 异常退回入仓 | 只能选择原出库拣货事实;异常单受理并完成退回 | 原出库来源核验 → `RETURN_STOCK_IN` 恢复到真实目标托盘/库位 | 不能伪造出库来源、借用其他客户主单;退回数量与原实发核平;异常单完成与派送 `RETURNED` 同事务 |
|
||||
| PDA 盘点调整 | 绑定海外仓;盘点锁定库存位置并提交实盘数量 | 按差异产生增加/减少调整流水;无差异不产生虚假变动 | 需要 `inventory:adjust`;并发版本校验;差异正负方向正确;盘点重复提交幂等 |
|
||||
| PDA 移库/托盘拆合/换绑 | 同仓有效托盘/库位;资源锁成功 | 数量净额不变,仅位置/托盘组成变化,写位置流水 | 不跨仓;托盘组成明细保留;资源锁释放;出库/换标占用时禁止绕过协调单独移动 |
|
||||
|
||||
## 不应误判为库存变动
|
||||
|
||||
- 目的仓修改、暂扣/解除、报价、排车预排、外接预约、车辆/司机资料:只改变状态、资格、资源占用或费用快照。
|
||||
- 海外采购样品履约:按当前契约走 Admin 台账,**不接入 PDA,也不写 WMS 可用库存**。
|
||||
- 退货申请/废弃申请/转派送建单:申请或建单阶段只形成冻结/候选/出库单,必须到实际收货、实际扣减或实际出库节点才确认数量变化。
|
||||
|
||||
## 每条库存用例的统一断言
|
||||
|
||||
1. 变动前后按客户、海外仓、目的仓、入仓单、托盘组成核对数量守恒。
|
||||
2. 查询余额、位置明细和库存流水三处结果一致,且业务单号/幂等键可追溯。
|
||||
3. 重复请求、重复事件、并发操作不得新增第二笔库存变动。
|
||||
4. 任一校验、权限、资源锁或跨服务依赖失败时,库存、单据状态和流水一起回滚。
|
||||
5. 客户越权、跨仓、跨客户、伪造来源入仓单/出库单均应拒绝。
|
||||
|
||||
流程图:`overseas-inventory-mutation-flow.svg` / `overseas-inventory-mutation-flow.png`
|
||||
@@ -1,9 +1,5 @@
|
||||
# File Service 模块指引
|
||||
|
||||
## 数据库访问与中文注释约束
|
||||
|
||||
- 强制继承 `../AGENTS.md` 的“数据库访问与中文代码注释”全部规则;该节是分层、SQL 执行和方法/核心逻辑中文注释的唯一维护处,本模块不另设例外。
|
||||
|
||||
## 职责与边界
|
||||
|
||||
- Mapper 只由 `FileServiceApplication.java` 对 `com.baiyue.file` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
|
||||
|
||||
@@ -21,14 +21,13 @@ public class ExportProviderClient {
|
||||
@Resource private WarehouseExportProviderClient warehouse;
|
||||
@Resource private FirstlegExportProviderClient firstleg;
|
||||
@Resource private FinanceExportProviderClient finance;
|
||||
@Resource private LastlegExportProviderClient lastleg;
|
||||
@Resource
|
||||
private MeterRegistry meters;
|
||||
@PostConstruct
|
||||
void initializeClients() {
|
||||
this.clients = Map.of("iam-service", iam, "order-service", order,
|
||||
"warehouse-service", warehouse, "firstleg-service", firstleg,
|
||||
"finance-service", finance, "lastleg-service", lastleg);
|
||||
"finance-service", finance);
|
||||
}
|
||||
|
||||
public ApiResponse<ExportBatchResponse> batch(String internalToken, String exportType,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.baiyue.file.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
@FeignClient(name="lastleg-service", contextId="lastlegExportProviderClient",
|
||||
url="${baiyue.clients.lastleg.url:}", configuration=ExportProviderFeignConfiguration.class)
|
||||
interface LastlegExportProviderClient extends ExportProviderFeignClient { }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user