22 KiB
Lastleg 业务详细索引
本文件是同服务 AGENTS.md 的按需补充;命中业务后读取相应行/段,不默认全文加载。路径保持以 lastleg-service/ 为根;Java 简写包路径从 src/main/java/com/baiyue/lastleg/ 起算,不相对于本文件的 docs/ 目录。
快速索引
退货预报、签收、库存、合箱与退货出库:
- 客户预报
returnreceipt/controller/MerchantReturnOrderController.java→returnreceipt/service/ReturnReceiptService.java,路径/api/merchant/v1/last-leg/return-orders;客户范围取认证身份,预报按 SKU 保存期望数量。状态PENDING_RECEIPT → PARTIALLY_RECEIVED → COMPLETED表示签收进度,不等于换标或出库完成。 - PDA 后端签收
returnreceipt/controller/PdaReturnReceiptController.java,前缀/api/pda/v1/last-leg/return-receipts,依次start/sku-candidates/confirm;按冻结仓和退货单校验实收,不允许未预报 SKU 或超量,幂等重放不得重复入账。确认同时生成签收箱与 SKU 库存;设备页面是否接通另查 PDA 工作台,不能以 Controller 存在代替前端接入。 - 库存/箱号
returnreceipt/controller/PlatformReturnInventoryController.java、MerchantReturnInventoryController.java→returnreceipt/service/ReturnInventoryService.java,前缀分别为/api/platform/v1/last-leg/return-inventory、/api/merchant/v1/last-leg/return-inventory;PDA 合箱入口PdaReturnInventoryController.java的/packing/orders、/cartons/merge、/cartons/{cartonMark}/label。同仓同客户选取退货单及可用 SKU,合箱扣减来源箱数量并生成目标箱,空来源箱标为MERGED,不得跨客户或超出可用量。 - 退货出库继续进入
delivery/service/DeliveryTransferService.java的RETURN_OUTBOUND,按退货库存可用箱唛创建与拣货;不能与exceptionorder/的派送退回恢复库存混用。契约见src/main/resources/openapi/overseas-business-v1.yaml,表入口src/main/resources/db/lastleg.sql的ll_return_*。 - 客户箱号管理使用
GET /api/merchant/v1/last-leg/return-inventory/cartons按实物箱分页,库存箱内 SKU 明细仍使用根查询;两者均按登录客户精确隔离。合箱sourceBatchNo/sourceReturnNo保存实际消耗来源的去重业务编号(多个以逗号分隔),不得写状态或包含未取货订单。ReturnCartonBarcode按箱号生成 Code 128 SVG,打印内容不得使用内部客户/仓库 ID。
人工计划自动生成托盘与资源重试:inboundplan/controller/InboundPlanController.java → inboundplan/service/ContainerInboundPlanConversionCoordinator.java 的 convertManualAndAutoMaterialize;保存单票后重读全柜预览,全员为 PLANNED/RESOURCE_PENDING、预览就绪且存在待绑定资源时自动调用柜级 confirm。一票柜立即触发,多票柜在最后一票齐全后触发;资源异常沿 resourcePendingPlanCount 和原柜级预览/确认入口重试,不新增独立正常人工步骤。回归入口为 src/test/java/com/baiyue/lastleg/inboundplan/service/ContainerInboundPlanConversionCoordinatorTest.java。
柜级预览同时返回 sourcePalletCount/supplementPalletCount/targetPalletCount:头程冻结托盘码原样保留,海外仓最终托数较多时按同柜同 FBA 编码序列补足差额,不因头尾装托密度不同阻断;页面必须分别展示头程已有、海外补充和最终托数,不能把最终总数误称为“本次新增”。
头程来源托盘快照:service/LoadingCompletedConsumer.java、mapper/LastlegSourcePalletMapper.java;来源标签随装柜完成事件落入 ll_order_source_pallet,后续由 inboundplan/service/InboundPlanService.java 与 ContainerInboundPlanConversionCoordinator.java 传递给海外资源批量预留。排查标签跨区丢失时沿此链路核对,不能在尾程页面重新生成头程托盘码。
| 功能 | 入口 |
|---|---|
| 内部模块化基线与依赖分析 | docs/lastleg-internal-modularization-baseline.md、scripts/analyze-lastleg-dependencies.mjs、scripts/analyze-lastleg-dependencies.test.mjs、src/test/resources/architecture/lastleg-slice-dependencies.json;只约束本服务内部包依赖,不改变部署单元或数据库边界 |
| 事件接收、平台订单列表/详情、柜级进度、目的仓调整 | src/main/java/com/baiyue/lastleg/controller/LastlegOrderController.java;/api/platform/v1/last-leg/orders/container-summaries 按 sourceContainerBookingId 服务端聚合全柜订单、入仓码、有效计划及托盘资源异常并分页返回全部稳定来源柜,已完成计划转换的柜仍保留用于接柜仓查询与修改;单票手工计划保存后,整柜最后一票齐全时自动生成并绑定全柜托盘码,一票柜立即生成,resourcePendingPlanCount 只作为失败重试事实;/{sourceContainerBookingId} 返回柜内全部订单/入仓码/计划状态且不受订单分页截断;plannedArrivalAt 只取装柜完成事件 estimatedWarehouseArrivalAt 冻结到 ll_order.estimated_warehouse_at 的正式事实,按其升序、null 最后、稳定柜 ID 排序;目的仓调整仅接受国内 Warehouse Service 平台公共 ACTIVE + FBA 主档,写入前由 service/FbaWarehouseValidator.java 经内部只读目录校验 ID/编码/名称一致 |
| 尾程订单完整计划、柜级到仓时间、暂扣与人工节点 | controller/LastlegOrderController.java、service/LastlegOrderCommandService.java、inboundplan/service/InboundPlanService.java、dto/LastlegOrderCommandDtos.java;Admin 清关提柜列表通过 /orders/container-arrival-times/query 批量读取整柜预计/实际到仓,预计时间在任何入库计划生成前按柜级版本与幂等键人工维护并原子同步全柜 ll_order.estimated_warehouse_at,实际时间只取海外 PDA 会话首次 receiving_at。单票计划写入校验订单版本、客户范围、订单冻结入仓码、稳定接柜仓 ID、当前仓库主档与幂等键;预计到仓日期不接受计划请求输入,必须锁定来源柜全部订单的 estimated_warehouse_at,缺失或同柜不一致时阻断,人工与自动计划统一写其日期;一件代发人工计划必须逐托沿用不可变头程封托的 DP 托盘码和箱数,托数及各托箱数均不得重新分配,禁止保存无法绑定真实资源的半成品计划;接柜仓编码/名称以该 ID 当前目录快照为准,不要求订单残留旧展示快照。暂扣/解除写不可变历史并发布 InboundOrderDetainedOutboxService;新增暂扣只允许完成入库且尚未进入出库流程的订单,解除暂扣不受该状态限制;暂扣只阻断排车和出库,不阻断入库计划或入库作业。人工节点必须一次提交固定八行完整快照且至少一个时间,首次保存后永久使用 MANUAL 来源,不得回退柜级节点或反向修改头程船节点 |
| 客户尾程订单列表与详情 | controller/MerchantLastlegOrderController.java;客户范围只取认证身份,稳定类型/状态见 model/LastlegOrderType.java、LastlegOrderStatus.java |
| 装柜完成事件消费 | service/LoadingCompletedConsumer.java;当前生产信封为 FIRST_LEG_LOADING_PLAN_COMPLETED V3,消费端除冻结 V2 货物事实外,按 sourceContainerBookingId 幂等投影物理柜五类国内装柜照片;FBA 可按箱数且不生成逐箱作业账,OVERSEAS 必须逐箱校验并生成箱级事实;V1/V2 仅用于历史事件读取 |
| 尾程单号生成 | service/LastlegOrderNoGenerator.java |
| 订单查询与更新 | service/LastlegOrderService.java |
| 业务 Inbox | entity/LastlegEventInbox.java、mapper/LastlegEventInboxMapper.java |
| 尾程订单、明细、状态历史 | entity/LastlegOrder.java、LastlegOrderDetail.java、LastlegOrderStatusHistory.java 及对应 Mapper |
| 独立尾程入仓单快照 | entity/LastlegInboundOrder.java、mapper/LastlegInboundOrderMapper.java;按客户与来源入仓标识冻结 inboundCode、来源/根订单及目的仓,不以尾程订单行代替入仓单聚合 |
| 内部令牌保护 | security/InternalServiceTokenGuard.java |
| 统一认证与撤销 | 复用 common-security 的Redis会话及Auth/IAM权威指纹校验,故障拒绝访问;Lastleg不保存独立授权投影 |
| 入仓计划分页、柜级预览、转换与详情 | 平台 inboundplan/controller/InboundPlanController.java,客户只读 inboundplan/controller/MerchantInboundPlanController.java;共用 inboundplan/dto/InboundPlanRequests.java、InboundPlanListResponse.java、ContainerInboundPlanPreviewResponse.java、inboundplan/mapper/InboundPlanQueryMapper.java、inboundplan/service/InboundPlanService.java;客户入口固定 /api/merchant/v1/last-leg/inbound-plans,范围只取 Token。/container-preview 按全柜返回 FBA/一件代发/私人地址分组、托数、就绪、阻断项及 snapshotVersion/snapshotHash;ContainerInboundPlanConversionCoordinator.java 用唯一柜级 Saga 锁柜重算,先经 WarehouseResourceGateway 批量预留真实托盘,再本地原子生成剩余独立计划并确认资源,本地失败只补偿未确认资源,远端确认失败的重放只重试确认,同柜不同幂等键也不得产生第二批资源 |
| 托盘分配算法 | inboundplan/service/PalletAllocator.java |
| FBA 预约创建、详情与编辑 | InboundPlanController.java 的 /fba-appointments/**、inboundplan/service/InboundFbaAppointmentService.java、BatchFbaAppointmentRequest.java、UpdateFbaAppointmentRequest.java |
| PDA 入仓、实收、上架与完成 | inboundplan/pda/controller/ReceivingContainerController.java、inboundplan/pda/service/ReceivingContainerService.java、内部编排 InboundPdaWorkflowService.java;公网入口固定为 /api/pda/v1/last-leg/receiving-containers/**,/warehouse-profile 只按 Token 绑定仓解析共享仓库中文名称与编码,旧 planNo/allocationId Controller 已移除。多计划同柜返回计划级 assigned/mergeAllowed/urgent/mergeHint;普通 FBA/OVERSEAS 分别使用 bulk/carton 收货,一件代发只允许 /current/receipts/pallet 按国内冻结来源托盘整托收货。合托只作现场可选提示;全部计划完整绑定真实 pallet/location/lock 前不得查看、准备或签收该柜,首扫只确认已预留绑定,不得重新分配计划资源 |
| PDA 卸柜照片上传、归属校验与预览 | ReceivingContainerController.java 的 /current/unload-photos/files、/current/unload-photos/files/{fileId}/download,网关 inboundplan/pda/gateway/UnloadPhotoFileGateway.java、HttpUnloadPhotoFileGateway.java;File 类型固定 OVERSEAS_UNLOAD_PHOTO,下载只允许当前会话已签收的 fileId 并返回 no-store |
| PDA 国内装柜照片对照 | ReceivingContainerController.java 的 /current/domestic-loading-photos/{evidenceType}/content、ContainerLoadingEvidenceMapper.java、DomesticLoadingEvidenceGateway.java;元数据按物理柜投影,不保存客户,下载必须经当前 PDA 会话鉴权并复用 FILE_SERVICE_URL 只读访问 File 服务,单图不可用不改变拆柜状态 |
| 卸柜照片与海外卸柜完成 Outbox | ReceivingContainerController.java、ReceivingContainerService.java、inboundplan/pda/service/InboundUnloadCompletedOutboxService.java、entity/LastlegEventOutbox.java、mapper/LastlegEventOutboxMapper.java;多计划同柜只能在全柜完成后调用 publishContainerCompleted,按来源柜预订 ID 幂等发布一次,完成时刻与拍照时刻分离;事件模型见 ../common-event-contract/AGENTS.md |
| 拆柜打托成本与客户应收分摊 | inboundplan/service/DestuffingPalletCostJob.java、DestuffingPalletCostService.java;仅全柜所有 PDA 入仓任务完成后执行,按实物托盘单价汇总并按客户实收 CBM 分摊,尾差落最后一位客户;每份分摊发布 OVERSEAS_CONTAINER_FEE/DESTUFF_PALLET 应收费用来源,不直接改国内钱包 |
| 尾程暂扣状态回传 | service/InboundOrderDetainedOutboxService.java;暂扣与解除暂扣在订单更新事务内按 sourceInboundId 写入海外到国内 Outbox,国内按来源入仓单绑定更新 |
| 派送完成回传 | delivery/service/DeliveryCompletedOutboxService.java;签收资料保存并自动完成时在业务事务内按关联 sourceInboundId 分别写 OVERSEAS_DELIVERY_COMPLETED Outbox,同车不同 FBA 派送单互不代完成;不保留人工完成入口 |
| 入仓后 SKU 库存余额、库位和流水 | inventory/;平台只读查询与非出库库存命令分别从 inventory/query/controller/InventoryQueryController.java、inventory/command/controller/InventoryCommandController.java 进入 |
| 海外PDA盘点、同仓整托移库、托盘组拆换绑与换标现场作业 | pda/stocktake/、pda/move/、palletops/、relabel/pda/;版本化契约 src/main/resources/openapi/overseas-pda-operations-v1.yaml;全部范围取自PDA Token,排车和出库使用独立 PDA Controller |
| 贴标申请、箱唛/SKU/组合换标与 PDA 完工 | relabel/、relabel/pda/;一条 ll_relabel_item 对应一个客户填写的我方箱唛任务,CARTON_LABEL、SKU_LABEL、CARTON_AND_SKU 分别保存箱唛、SKU 或组合需求,SKU 子项 JSON 数量按件;涉及箱唛换标时整张申请只能有一个 FBA 目的仓,服务端拒绝明细目的仓不一致的请求。普通尾程入库没有箱唛到实物托盘的精确快照,历史入仓库存仓位只能作为冻结记账锚点和现场大概位置,禁止把该仓位解释为箱唛已绑定具体托盘。库存只按箱任务冻结一次。涉及箱唛换标时申请必须选择 TRUCK/EXPRESS/TRUCK_PICKUP/EXPRESS_PICKUP,两种快递方式可要求打印并上传面单;PDA 扫我方箱唛完成逐箱事实和照片,仓库复核后等待客户查看照片确认。对外换标状态只投影为 PENDING_PROCESSING/COMPLETED(待处理/换标完成),PROCESSING、CUSTOMER_CONFIRM_PENDING、READY_FOR_OUTBOUND 只属于内部作业节点且不得直接出现在业务列表;客户确认后仅卡车派送进入 WAIT_PRE_DISPATCH,快递派送和两种自提直接创建换标出库单。客户确认前不得进入出库 |
| PDA 仓内通用扫码与操作历史 | pda/warehouse/controller/PdaWarehouseController.java、pda/warehouse/service/PdaWarehouseService.java;解析库存、库位和托盘码并查询操作历史,固定要求 lastleg:pda:operate 与 ROLE_WAREHOUSE_PICKER,仓库范围只能取自 PDA Token |
| 船节点接收与海外 PDA 可收货门禁 | shipping/service/ContainerShippingNodeConsumer.java、shipping/entity/ContainerShippingGate.java、shipping/mapper/ContainerShippingGateMapper.java;按 containerBookingId 柜级接收,信封使用 tenantId=0 且门禁不存客户;只单调接受实际标准节点,PICKUP_READY 及以后才允许对应柜进入 PDA 收货候选 |
| 平台排车列表/详情与智能预排 | dispatch/controller/DispatchQueryController.java、SmartDispatchController.java、dispatch/mapper/DispatchCandidateMapper.java、dispatch/service/DispatchService.java;草稿柜 entity/DispatchDraftContainer.java、mapper/DispatchDraftContainerMapper.java,托盘锁 DispatchPalletLock.java;入口 /api/platform/v1/last-leg/dispatches,路线由当前已排托盘的 FBA 仓编码去重后按稳定顺序以英文逗号连接,预排与普通编辑请求均不接收路线;查询、预排与执行边界见“海外仓全流程开发路由” |
| 排车编辑、PDA 出库、派送与交接 | dispatch/controller/DispatchController.java、dispatch/pda/controller/DispatchPdaController.java、delivery/controller/DeliveryTransferController.java、MerchantDeliveryController.java、OutboundPdaController.java |
| 仓储资源调用 | inboundplan/pda/gateway/WarehouseResourceGateway.java、HttpWarehouseResourceGateway.java |
| 仓储转运、历史订单/入仓绑定、可选换标联动 | transfer/controller/WarehouseTransferController.java、transfer/service/WarehouseTransferService.java |
| 一件代发接收、SKU/箱唛库存 | 内部接收入口 dropship/controller/DropshipOrderController.java 的 /internal/v1/lastleg/dropship/receive,必须经 InternalServiceTokenGuard;版本化契约 src/main/resources/openapi/lastleg-internal-dropship-v1.yaml;处理 dropship/service/DropshipOrderService.java、dropship/entity/、dropship/mapper/ |
| 货物废弃、待审锁箱、审批扣减 | discard/controller/CargoDiscardController.java、discard/service/CargoDiscardService.java |
| 客户拜访、派送状态与签收附件 | customervisit/controller/CustomerVisitController.java、customervisit/service/CustomerVisitService.java、delivery/model/DeliveryStatusPolicy.java;派送单返回服务端 allowedActions/version,状态只允许单调迁移,同状态幂等;人工动作不再提供完成派送,签收资料保存后自动完成当前目的FBA仓派送单 |
| 派送三类资料、摘要与历史证据 | delivery/controller/DeliveryDocumentController.java、delivery/service/DeliveryDocumentService.java、delivery/gateway/DeliveryDocumentFileGateway.java、src/main/resources/openapi/delivery-documents-v1.yaml;固定装车照片 LOADING_PHOTO、BOL文件(含签名)BOL、签收文件(POD签收/快递签收)RECEIPT,按已保存类别计数 x/3。每类0至20文件,文件精确绑定客户、按目的FBA仓拆分的派送单和类别;全量保存共用派送版本并记录不可变历史,替换删除仅解绑,未保存上传不计数、不授权下载。RECEIPT 成功保存进权威快照时事务内自动完成当前派送单,单纯上传不触发完成 |
| 异常订单与派送退回入仓 | exceptionorder/controller/ExceptionOrderController.java、exceptionorder/service/ExceptionOrderService.java、exceptionorder/gateway/ExceptionEvidenceFileGateway.java、inventory/command/service/InventoryCommandService.java;证据固定按客户、异常单 ID 和 OVERSEAS_EXCEPTION_EVIDENCE 校验。退回候选按原出库拣货事实冻结,不接受自由 SKU 或数量;异常按 PENDING→PROCESSING→COMPLETED(待处理可取消)、版本与幂等键流转。退回海外仓须把实收按原出库来源恢复到服务端校验的真实托盘/库位并写 RETURN_STOCK_IN 流水,库存恢复、异常完成与派送 RETURNED 在同一事务完成 |
| 海外采购、客户下单、采购审核、客户/采购仓候选与操作流水 | procurement/controller/、procurement/service/OverseasProcurementService.java;客户入口按 merchant:cross-border:procurement:list/create 拆分且只取 Token 客户范围;OpenAPI src/main/resources/openapi/overseas-business-v1.yaml |
| 海外业务资金指令与结果 | wallet/WalletCommandOutboxService.java、WalletCommandCompletedConsumer.java、WalletResultHandler.java;采购和换标通过 WALLET_COMMAND_REQUESTED 请求国内 Finance 冻结、结算或释放,并以 WALLET_COMMAND_COMPLETED 幂等回写业务资金状态;不得跨区同步调用 Finance 钱包或在 Lastleg 自建余额账本 |
| 海外业务费用来源 | financefee/controller/PlatformOverseasFeeSourceController.java、financefee/service/OverseasFeeSourceService.java、OverseasFeeBusinessGuard.java、OverseasFeeOutboxService.java、OverseasFeeOutboxRelay.java;海外入仓、采购、美国卡车、本土散板和海外仓服务费必须匹配当前客户的真实业务,入仓记录和入仓码按事实选填;当前 V1 审核通过、调整或作废后以版本化完整快照经 Outbox/Event Bridge 进入独立 Finance,OpenAPI src/main/resources/openapi/overseas-finance-fees-v1.yaml。阶段 0A—0E 开发目标另读 ../../docs/财务管理/海外仓费用统一接入阶段0技术契约.md,收费身份、候选版本、Finance 结果事件与资金计划 V2 尚须以实际代码落地验证,不能因文档存在宣称已实现 |
| 美国/本土卡车订单 | trucking/controller/PlatformUsTruckOrderController.java、MerchantUsTruckOrderController.java 及同子域 Service/DTO;客户入口按 merchant:cross-border:domestic-trucking:list/create/edit 拆分 |
| 本土散板订单 | looseboard/controller/PlatformLocalLooseboardController.java、MerchantLocalLooseboardController.java 及同子域 Service/DTO/Entity/Mapper;客户入口按 merchant:cross-border:pallet-shipping:list/create/edit 拆分;OpenAPI src/main/resources/openapi/overseas-business-v1.yaml |
| 海外仓报价、月度汇率、车辆主数据 | 报价 masterdata/quote/、汇率 masterdata/exchange/;车辆入口 masterdata/vehicle/adapter/in/web/PlatformVehicleController.java,应用服务 application/VehicleApplicationService.java,持久化端口与适配器 application/port/out/VehicleRepository.java、adapter/out/persistence/;OpenAPI src/main/resources/openapi/overseas-master-data-v1.yaml,车辆档案不含派送履约历史 |
| 跨服务 HTTP 客户端装配 | config/LastlegRestClientFactory.java、config/LastlegRestClientProperties.java;目标地址与内部服务令牌只来自配置,不在业务子域手工创建客户端 |
| 数据库基线、表索引与中文注释契约 | src/main/resources/db/lastleg.sql、src/test/java/com/baiyue/lastleg/schema/SchemaChineseCommentContractTest.java |
| 测试 | src/test/java/com/baiyue/lastleg/ |
| 真实事件消费验收 | src/test/java/com/baiyue/lastleg/service/TaillegRealConsumerAcceptanceTest.java;覆盖真实 V2 建单、独立入仓单快照及下游转运/换标可消费性 |