Test #1

Merged
admin merged 1726 commits from test into main 2026-09-17 11:52:45 +08:00
107 changed files with 465 additions and 271 deletions
Showing only changes of commit da32a67d7f - Show all commits
+3
View File
@@ -25,6 +25,7 @@
| 订单、货物、快照、状态、幂等、Outbox | `order/` | `order/AGENTS.md` |
| 履约分配、入库、测量、审核、FBA 计费 | `firstleg/` | `firstleg/AGENTS.md` |
| Firstleg 内部模块化与依赖基线 | `firstleg/` | `firstleg/docs/firstleg-internal-modularization-baseline.md`、`firstleg/scripts/analyze-firstleg-dependencies.mjs`;价格簿查询和客户统计按端口/适配器切片,不改变服务与数据库边界 |
| Mapper 新增、移动、Bean 缺失与扫描遗漏 | 目标持久化服务 | 所有 Mapper 显式 `@Mapper`,启动类按服务根包注解过滤扫描;先运行 `node scripts/mapper-scan-contract.mjs`,再按目标模块执行 `test-compile/test`,不得等部署启动发现 |
| 分柜、柜次、智能排柜、预装/装柜清单、PDA | `firstleg/` | `firstleg/AGENTS.md`,再按 `split/`、`loading/`、`outbound/` 定位 |
| 智能装柜入仓码候选与箱数分配 | `firstleg/` | `controller/PlatformSmartLoadingController.java` 的 `/inbound-candidates`、`/plans/{planId}/inbound-assignments`,业务编排 `service/SmartLoadingService.java` |
| 订舱、船期、拖车、报关 | `firstleg/` | `oceanbooking/`、`portschedule/`、`outbound/dispatch/`、`customs/` |
@@ -78,6 +79,7 @@
- 跨服务修改先检查调用方 `client/`、被调用方 Controller/DTO、`src/main/resources/openapi/` 和双方契约测试;禁止共享领域 Entity。
- 修改 Java 方法、构造器、Controller、Client、DTO 或 Mapper 参数签名时,先用 `rg` 定向查找符号及旧参数形态,并同步更新 `src/main/`、`src/test/`、Mock、Fixture、契约测试和脚本中的全部调用点。新增可选参数也必须补齐旧测试调用,不能因生产调用已更新就视为完成。
- 所有生产 MyBatis Mapper 接口必须显式标记 `@Mapper`;每个持久化服务只允许在启动类使用一次服务根包 `@MapperScan(..., annotationClass = Mapper.class)`,不得新增子域包白名单或分散的 `*MapperConfiguration`。新增或移动 Mapper 后先运行 `node scripts/mapper-scan-contract.mjs`,全量后端回归也会在 Maven 前执行该门禁。
- 平台后台存在正式列表页时,`*:list` 同时授权列表、详情及只读辅助接口;`create`、`edit`、`delete`、`status`、`approve`、`review`、`export`、`upload`、`complete` 等操作保持独立。当前未上线,不兼容旧独立 `*:view`,Controller 不得使用 `hasAnyAuthority(list, view)`,OpenAPI 和角色初始化只保留 `*:list`。
- 供应商查询接口固定只使用 `platform:supplier:list`;IAM 中 `platform:supplier:list` 是正式菜单资源,`platform:supplier:view` 必须停用/移除,不得重新提升或兼容。
- 权限语义变更必须同步 Controller `@PreAuthorize`、OpenAPI、模块权限 SQL、IAM 菜单资源、统一增量脚本和契约测试。并行模块任务不得覆盖菜单与权限总控已写入共享 SQL 或权限契约的改动。
@@ -86,6 +88,7 @@
- 通用配置在 `config/nacos/{local,cn}/`;服务日志、上传文件、`target/`、`reports/` 不属于源码。
- 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`;脚本只读源码目录和指定指引,验证根快速表唯一性、部署单元、Client active 路由、四期范围漂移、仓库主档唯一权威、订舱关联候选与柜量语义、整柜出仓与船节点单调性、海外 Gateway 覆盖、PDA 运行配置/独立更新/语言预留、人工分段验收链、Lastleg 海外安全投影、同步 Trace、模块覆盖、关键入口与排除目录,不访问 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`。实际部署仍须当前对话明确授权。
## 全量 HTTP 验收脚本路由
+1
View File
@@ -2,6 +2,7 @@
## 职责边界
- Mapper 只由 `BaiyueAuditApplication.java` 对 `com.baiyue.audit` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责接收 `common-audit` 产生的审计事件并持久化到 `baiyue_audit`。
- 审计注解、切面、脱敏和发送策略在 `common-audit/`;本服务不复制业务服务的审计采集逻辑。
@@ -1,6 +1,7 @@
package com.baiyue.audit;
import com.baiyue.common.core.mybatis.MybatisPlusConfiguration;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -10,7 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 审计微服务启动入口,初始化 Spring Boot 应用并扫描审计日志 Mapper。
*/
@MapperScan("com.baiyue.audit.mapper")
@MapperScan(basePackages = "com.baiyue.audit", annotationClass = Mapper.class)
@EnableScheduling
@Import(MybatisPlusConfiguration.class)
@SpringBootApplication
@@ -1,10 +1,13 @@
package com.baiyue.audit.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.audit.entity.AuditLogEntity;
/**
* 审计日志 MyBatis-Plus Mapper,提供 {@code sys_audit_log} 表的单表写入和查询能力。
*/
@Mapper
public interface AuditLogMapper extends BaseMapper<AuditLogEntity> {
}
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `BaiyueAuthApplication.java` 对 `com.baiyue.auth` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责登录、注册、账号凭据、Access/Refresh Token、退出、密码和账号归属范围。
- 客户主档、成员、角色权限归 `iam/`;Auth 通过 IAM 客户端获取授权快照,不跨库写 IAM。
- 修改国内/海外 Token、Audience、JWKS 或跨区域身份边界前,先读 `../../docs/跨区域认证与服务通信契约.md`。
@@ -1,5 +1,6 @@
package com.baiyue.auth;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -8,7 +9,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 认证服务启动入口,负责装配统一登录、令牌签发与会话管理相关组件。
*/
@MapperScan("com.baiyue.auth.mapper")
@MapperScan(basePackages = "com.baiyue.auth", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.auth.client")
@SpringBootApplication(scanBasePackages = "com.baiyue")
public class BaiyueAuthApplication {
@@ -1,9 +1,12 @@
package com.baiyue.auth.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.auth.entity.AuthAccount;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 认证账号 MyBatis-Plus 数据访问接口,负责 {@code auth_account} 表的基础持久化操作。
*/
@Mapper
public interface AuthAccountMapper extends BaseMapper<AuthAccount> { }
@@ -1,9 +1,12 @@
package com.baiyue.auth.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.auth.entity.AuthRefreshToken;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 刷新令牌 MyBatis-Plus 数据访问接口,负责 {@code auth_refresh_token} 表的基础持久化操作。
*/
@Mapper
public interface AuthRefreshTokenMapper extends BaseMapper<AuthRefreshToken> { }
+1
View File
@@ -2,6 +2,7 @@
## 职责边界
- Mapper 只由 `EventBridgeApplication.java` 对 `com.baiyue.eventbridge` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责跨区事件接收、Inbox 持久化、按目标区域向海外尾程或国内头程投递、失败重试、投递记录和人工补投。
- 只承载可靠传输,不执行尾程建单逻辑,不查询头程或尾程业务表。
- 事件结构和 Payload 哈希以 `common-event-contract` 为准。
@@ -1,6 +1,7 @@
package com.baiyue.eventbridge;
import com.baiyue.eventbridge.config.EventDispatcherProperties;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -10,7 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 跨区域事件桥启动入口。
*/
@MapperScan("com.baiyue.eventbridge.mapper")
@MapperScan(basePackages = "com.baiyue.eventbridge", annotationClass = Mapper.class)
@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties(EventDispatcherProperties.class)
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `FileServiceApplication.java` 对 `com.baiyue.file` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责企业资质文件、公共导出、二期入库测量图片的上传、存储、读取和鉴权。
- 资质审核元数据归 `iam/`,入库状态归 `firstleg/`,OCR 适配归 `integration-service/`;不跨库读取业务表。
@@ -1,5 +1,7 @@
package com.baiyue.file;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@@ -9,6 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* 文件中心服务启动入口。
*/
@SpringBootApplication(scanBasePackages = "com.baiyue")
@MapperScan(basePackages = "com.baiyue.file", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.file.client")
@EnableScheduling
public class FileServiceApplication {
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 统一显式使用 `@Mapper`,仅由 `BaiyueFirstlegApplication.java` 对 `com.baiyue.firstleg` 根包按 `annotationClass = Mapper.class` 扫描;禁止恢复业务子域 Mapper 包白名单。静态门禁见根 `scripts/mapper-scan-contract.mjs`,模块内编译门禁见 `MapperRegistrationArchitectureTest.java`、`BaiyueFirstlegApplicationContractTest.java`。
- 负责履约任务/分配、入库单、测量/OCR、审核后初始计价、FBA 计费、客户在途柜量统计、国内出仓履约链路,以及四期国内出仓后的船节点查询任务和节点事实。
- 订单主数据归 `order/`,托盘/库位归 `warehouse/`,文件对象归 `file/`,OCR 供应商归 `integration-service/`;通过客户端 DTO 和内部令牌协作。
- 入库、分柜、装柜、PDA 和出仓能力均在本模块按对应服务端契约协作;`WAIT_SPLIT + APPROVED + CONFIRMED` 是入库链路状态节点,不是全量验收的范围终点。财务状态仍归 `finance`,本模块只生产不可变费用来源和柜次成本快照。
@@ -1,5 +1,6 @@
package com.baiyue.firstleg;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,18 +10,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 头程履约微服务启动入口,负责装配履约任务组件并扫描 MyBatis-Plus Mapper。
*/
@MapperScan(basePackages = {
"com.baiyue.firstleg.mapper",
"com.baiyue.firstleg.split.mapper",
"com.baiyue.firstleg.loading.mapper",
"com.baiyue.firstleg.loading.bridge.mapper",
"com.baiyue.firstleg.oceanbooking.mapper",
"com.baiyue.firstleg.outbound.dispatch.mapper",
"com.baiyue.firstleg.portschedule.mapper",
"com.baiyue.firstleg.customs.container.mapper",
"com.baiyue.firstleg.customerstatistics.adapter.out.persistence",
"com.baiyue.firstleg.pricebookquery.adapter.out.persistence"
})
@MapperScan(basePackages = "com.baiyue.firstleg", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.firstleg")
@EnableScheduling
@SpringBootApplication(scanBasePackages = "com.baiyue")
@@ -1,4 +1,10 @@
package com.baiyue.firstleg.mapper; import com.baiyue.firstleg.entity.AssignmentHistoryEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.firstleg.entity.AssignmentHistoryEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 头程任务指派历史 Mapper,提供 {@code fl_assignment_history} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface AssignmentHistoryMapper extends BaseMapper<AssignmentHistoryEntity>{}
@@ -1,9 +1,12 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface CarrierFbaRateMapper extends BaseMapper<CarrierFbaRateEntity> {
@Delete("DELETE FROM fl_carrier_fba_rate WHERE price_book_version_id = #{versionId} AND status = 'PENDING_CONFIRMATION'")
int physicallyDeletePendingByPriceBookVersionId(@Param("versionId") long versionId);
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.CustomerChargeRuleEntity;
@Mapper
public interface CustomerChargeRuleMapper extends BaseMapper<CustomerChargeRuleEntity> {}
@@ -1,5 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.CustomerDimensionConfigEntity;
import org.apache.ibatis.annotations.Delete;
@@ -9,6 +11,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface CustomerDimensionConfigMapper extends BaseMapper<CustomerDimensionConfigEntity> {
@Insert("""
<script>
@@ -1,4 +1,10 @@
package com.baiyue.firstleg.mapper; import com.baiyue.firstleg.entity.FulfillmentTaskEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.firstleg.entity.FulfillmentTaskEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 头程履约任务 Mapper,提供 {@code fl_fulfillment_task} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface FulfillmentTaskMapper extends BaseMapper<FulfillmentTaskEntity>{}
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.InboundFeeItemEntity;
@Mapper
public interface InboundFeeItemMapper extends BaseMapper<InboundFeeItemEntity> {}
@@ -1,8 +1,11 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.InboundOrderLookupEntity;
/** 入库单只读 Mapper,开放接口不得在此增加 update 方法。 */
@Mapper
public interface InboundOrderLookupMapper extends BaseMapper<InboundOrderLookupEntity> {
}
@@ -1,7 +1,10 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.firstleg.entity.InboundPickupSnapshotEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@Mapper
public interface InboundPickupSnapshotMapper extends BaseMapper<InboundPickupSnapshotEntity> {
}
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.InboundPricingIdempotencyEntity;
@Mapper
public interface InboundPricingIdempotencyMapper extends BaseMapper<InboundPricingIdempotencyEntity> {}
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.InboundPricingEntity;
@Mapper
public interface InboundPricingMapper extends BaseMapper<InboundPricingEntity> {}
@@ -1,9 +1,12 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.PriceBookChannelEntity;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface PriceBookChannelMapper extends BaseMapper<PriceBookChannelEntity> {
@Delete("DELETE FROM fl_price_book_channel WHERE price_book_version_id = #{versionId}")
int physicallyDeleteByPriceBookVersionId(@Param("versionId") long versionId);
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.PriceBookVersionEntity;
@Mapper
public interface PriceBookVersionMapper extends BaseMapper<PriceBookVersionEntity> {}
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.PriceChannelCatalogEntity;
@Mapper
public interface PriceChannelCatalogMapper extends BaseMapper<PriceChannelCatalogEntity> {}
@@ -1,4 +1,7 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.PriceOriginAliasEntity;
@Mapper
public interface PriceOriginAliasMapper extends BaseMapper<PriceOriginAliasEntity> {}
@@ -1,6 +1,9 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.PriceWarehouseMappingEntity;
@Mapper
public interface PriceWarehouseMappingMapper extends BaseMapper<PriceWarehouseMappingEntity> {}
@@ -1,7 +1,10 @@
package com.baiyue.firstleg.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.firstleg.entity.ThirdPartyCallLogEntity;
@Mapper
public interface ThirdPartyCallLogMapper extends BaseMapper<ThirdPartyCallLogEntity> {
}
@@ -1,5 +1,6 @@
package com.baiyue.firstleg;
import org.apache.ibatis.annotations.Mapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
@@ -8,22 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat;
class BaiyueFirstlegApplicationContractTest {
@Test
void scansAllFirstlegMapperPackagesIncludingCustoms() {
void scansAnnotatedMappersFromTheStableServiceRoot() {
MapperScan scan = BaiyueFirstlegApplication.class.getAnnotation(MapperScan.class);
assertThat(scan.basePackages())
.contains("com.baiyue.firstleg.mapper")
.contains("com.baiyue.firstleg.split.mapper")
.contains("com.baiyue.firstleg.loading.mapper")
.contains("com.baiyue.firstleg.loading.bridge.mapper")
.contains("com.baiyue.firstleg.oceanbooking.mapper")
.contains("com.baiyue.firstleg.outbound.dispatch.mapper")
.contains("com.baiyue.firstleg.portschedule.mapper")
.contains("com.baiyue.firstleg.customs.container.mapper")
.contains("com.baiyue.firstleg.customerstatistics.adapter.out.persistence")
.contains("com.baiyue.firstleg.pricebookquery.adapter.out.persistence")
.doesNotContain("com.baiyue.firstleg.customerstatistics.mapper")
.doesNotContain("com.baiyue.firstleg.customs.mapper");
assertThat(scan.basePackages()).containsExactly("com.baiyue.firstleg");
assertThat(scan.annotationClass()).isEqualTo(Mapper.class);
}
@Test
@@ -0,0 +1,21 @@
package com.baiyue.firstleg;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.apache.ibatis.annotations.Mapper;
import org.junit.jupiter.api.Test;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
class MapperRegistrationArchitectureTest {
private static final JavaClasses PRODUCTION_CLASSES = new ClassFileImporter()
.importPackages("com.baiyue.firstleg");
@Test
void everyMapperInterfaceDeclaresItsRegistrationMarker() {
classes().that().areInterfaces().and().haveSimpleNameEndingWith("Mapper")
.should().beAnnotatedWith(Mapper.class)
.because("Mapper registration must fail during tests instead of service startup")
.check(PRODUCTION_CLASSES);
}
}
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `BaiyueIamApplication.java` 对 `com.baiyue.iam` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责客户主档、成员、企业资料/审核、平台用户、角色权限、数据范围和授权快照。
- 账号凭据/Token 属于 `auth/`,文件内容属于 `file/`;资质登记只接收 File 的内部元数据调用。
- 修改用户可见层级、菜单权限、列表/详情只读语义或权限资源前,先读 `../../docs/平台客户层级与权限契约.md`。
@@ -1,5 +1,6 @@
package com.baiyue.iam;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +10,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 身份与权限服务启动入口,负责装配租户、成员、双端 RBAC 和授权快照相关组件。
*/
@MapperScan({"com.baiyue.iam.mapper", "com.baiyue.iam.notification.mapper"})
@MapperScan(basePackages = "com.baiyue.iam", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.iam.client")
@EnableScheduling
@SpringBootApplication(scanBasePackages = "com.baiyue")
@@ -1,5 +1,6 @@
package com.baiyue.iam;
import org.apache.ibatis.annotations.Mapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
@@ -7,12 +8,11 @@ import static org.assertj.core.api.Assertions.assertThat;
class BaiyueIamApplicationContractTest {
@Test
void scansCoreAndNotificationMappers() {
void scansAnnotatedMappersFromTheStableServiceRoot() {
MapperScan mapperScan = BaiyueIamApplication.class.getAnnotation(MapperScan.class);
assertThat(mapperScan).isNotNull();
assertThat(mapperScan.value()).containsExactlyInAnyOrder(
"com.baiyue.iam.mapper",
"com.baiyue.iam.notification.mapper");
assertThat(mapperScan.basePackages()).containsExactly("com.baiyue.iam");
assertThat(mapperScan.annotationClass()).isEqualTo(Mapper.class);
}
}
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 统一显式使用 `@Mapper`,仅由 `BaiyueLastlegApplication.java` 对 `com.baiyue.lastleg` 根包按 `annotationClass = Mapper.class` 扫描;各业务切片不得新增 `*MapperConfiguration` 或维护包白名单。静态门禁见根 `scripts/mapper-scan-contract.mjs`,模块内门禁见 `MapperRegistrationArchitectureTest.java`。
- 负责消费头程装柜完成事件,保存业务 Inbox,并按最终实装入仓单建立待分配尾程订单、明细冻结快照和初始状态历史;事件不得自动创建入仓计划,平台人工调用 `/api/platform/v1/last-leg/inbound-plans/convert` 后才生成计划并推进订单。
- 负责尾程订单列表、详情、导出和目的仓调整,以及海外入仓计划、托盘分配与 PDA 入仓作业;PDA 卸柜完成后通过本地 Outbox 向国内头程回传货柜报空事实。
- 不查询头程数据库,不调用头程接口补齐建单字段;事件快照缺失时应拒绝消费并保留可诊断错误。
@@ -1,5 +1,6 @@
package com.baiyue.lastleg;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +10,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 尾程微服务预留模块启动入口,初始化 Spring Boot 应用并扫描尾程 Mapper。
*/
@MapperScan("com.baiyue.lastleg.mapper")
@MapperScan(basePackages = "com.baiyue.lastleg", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.lastleg")
@EnableScheduling
@SpringBootApplication(scanBasePackages = "com.baiyue")
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.delivery;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.delivery.mapper")
public class DeliveryMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.discard;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.discard.mapper")
public class DiscardMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.dispatch;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.dispatch.mapper")
public class DispatchMapperConfiguration {
}
@@ -1,8 +0,0 @@
package com.baiyue.lastleg.dispatch.pda;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.dispatch.pda.mapper")
public class DispatchPdaMapperConfiguration {}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.dropship;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.dropship.mapper")
public class DropshipMapperConfiguration {
}
@@ -1,7 +1,10 @@
package com.baiyue.lastleg.dropship.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.dropship.entity.DropshipCartonLedger;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.*;
@Mapper
public interface DropshipCartonLedgerMapper extends BaseMapper<DropshipCartonLedger> {
@Select("SELECT * FROM ll_dropship_carton_ledger WHERE customer_id=#{customerId} AND idempotency_key=#{key} LIMIT 1")
DropshipCartonLedger findIdempotency(@Param("customerId") String customerId, @Param("key") String key);
@@ -1,8 +1,11 @@
package com.baiyue.lastleg.dropship.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface DropshipCartonMapper extends BaseMapper<DropshipCarton> {
@Select("SELECT * FROM ll_dropship_carton WHERE customer_id=#{customerId} AND order_id=#{orderId} AND carton_mark=#{cartonMark} LIMIT 1")
DropshipCarton find(@Param("customerId") String customerId, @Param("orderId") Long orderId, @Param("cartonMark") String cartonMark);
@@ -1,8 +1,11 @@
package com.baiyue.lastleg.dropship.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.dropship.entity.DropshipOrderProfile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface DropshipOrderProfileMapper extends BaseMapper<DropshipOrderProfile> {
@Select("SELECT * FROM ll_dropship_order_profile WHERE customer_id=#{customerId} AND order_id=#{orderId} ORDER BY source_pallet_no")
List<DropshipOrderProfile> listOrder(@Param("customerId") String customerId, @Param("orderId") Long orderId);
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.dropship.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.dropship.entity.DropshipSkuInventory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -7,6 +9,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface DropshipSkuInventoryMapper extends BaseMapper<DropshipSkuInventory> {
@Select("SELECT * FROM ll_dropship_sku_inventory WHERE customer_id=#{customerId} AND order_id=#{orderId} ORDER BY profile_id,sku_code")
List<DropshipSkuInventory> listOrder(@Param("customerId") String customerId, @Param("orderId") Long orderId);
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.inboundplan;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan({"com.baiyue.lastleg.inboundplan.mapper", "com.baiyue.lastleg.inboundplan.pda.mapper"})
public class InboundPlanMapperConfiguration {
}
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.inboundplan.pda.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inboundplan.pda.entity.InboundStockReceipt;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -7,6 +9,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface InboundStockReceiptMapper extends BaseMapper<InboundStockReceipt> {
@Select("SELECT * FROM ll_inbound_stock_receipt WHERE customer_id=#{customerId} AND task_id=#{taskId} " +
"ORDER BY allocation_id")
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.inventory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.inventory.mapper")
public class InventoryMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.inventory.command;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.inventory.command.mapper")
public class InventoryCommandMapperConfiguration {
}
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.inventory.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inventory.entity.InventoryBalance;
import com.baiyue.lastleg.inventory.model.InventorySummary;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
@@ -10,6 +12,7 @@ import org.apache.ibatis.annotations.Update;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface InventoryBalanceMapper extends BaseMapper<InventoryBalance> {
@Select("SELECT * FROM ll_inventory_balance WHERE customer_id=#{customerId} " +
"AND overseas_warehouse_id=#{overseasWarehouseId} " +
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.inventory.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inventory.entity.InventoryLedger;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -8,6 +10,7 @@ import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface InventoryLedgerMapper extends BaseMapper<InventoryLedger> {
@Select("SELECT * FROM ll_inventory_ledger WHERE customer_id=#{customerId} AND idempotency_key=#{idempotencyKey} LIMIT 1")
InventoryLedger findIdempotency(@Param("customerId") String customerId,
@@ -1,10 +1,13 @@
package com.baiyue.lastleg.inventory.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inventory.entity.InventoryOperation;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface InventoryOperationMapper extends BaseMapper<InventoryOperation> {
@Select("SELECT * FROM ll_inventory_operation WHERE customer_id=#{customerId} AND idempotency_key=#{idempotencyKey} LIMIT 1")
InventoryOperation findIdempotency(@Param("customerId") String customerId,
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.inventory.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -7,6 +9,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface InventoryPositionMapper extends BaseMapper<InventoryPosition> {
@Select("SELECT p.* FROM ll_inventory_position p JOIN ll_inventory_balance b ON b.id=p.balance_id " +
"WHERE b.customer_id=#{customerId} AND p.balance_id=#{balanceId} ORDER BY p.pallet_no,p.batch_no")
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.inventory.query;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.inventory.query.mapper")
public class InventoryQueryMapperConfiguration {
}
@@ -1,5 +1,7 @@
package com.baiyue.lastleg.inventory.query.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.lastleg.inventory.entity.InventoryBalance;
import com.baiyue.lastleg.inventory.entity.InventoryLedger;
import com.baiyue.lastleg.inventory.entity.InventoryPosition;
@@ -10,6 +12,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface InventoryQueryMapper {
String BALANCE_FILTER = " WHERE 1=1" +
"<if test='customerId != null and customerId != \"\"'> AND customer_id=#{customerId}</if>" +
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.looseboard;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.looseboard.mapper")
public class LooseboardMapperConfiguration {
}
@@ -1,10 +0,0 @@
package com.baiyue.lastleg.masterdata;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(basePackages = "com.baiyue.lastleg.masterdata", annotationClass = Mapper.class)
public class MasterDataMapperConfiguration {
}
@@ -1,15 +0,0 @@
package com.baiyue.lastleg.pda;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
/** Registers mapper packages used by the overseas PDA warehouse operation workflows. */
@Configuration
@MapperScan(basePackages = {
"com.baiyue.lastleg.palletops.mapper",
"com.baiyue.lastleg.pda.move.mapper",
"com.baiyue.lastleg.pda.stocktake.mapper",
"com.baiyue.lastleg.pda.warehouse.mapper"
})
public class PdaOperationsMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.procurement;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.procurement.mapper")
public class ProcurementMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.relabel;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.relabel.mapper")
public class RelabelMapperConfiguration {
}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.relabel.pda;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.relabel.pda.mapper")
public class PdaRelabelMapperConfiguration {
}
@@ -1,10 +0,0 @@
package com.baiyue.lastleg.shipping;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
/** Registers the shipping gate persistence mapper used during event and receiving workflows. */
@Configuration
@MapperScan(basePackages = "com.baiyue.lastleg.shipping.mapper")
public class ShippingMapperConfiguration {
}
@@ -1,4 +0,0 @@
package com.baiyue.lastleg.transfer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration @MapperScan("com.baiyue.lastleg.transfer.mapper") public class TransferMapperConfiguration {}
@@ -1,9 +0,0 @@
package com.baiyue.lastleg.trucking;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.baiyue.lastleg.trucking.mapper")
public class TruckingMapperConfiguration {
}
@@ -0,0 +1,30 @@
package com.baiyue.lastleg;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.apache.ibatis.annotations.Mapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static org.assertj.core.api.Assertions.assertThat;
class MapperRegistrationArchitectureTest {
private static final JavaClasses PRODUCTION_CLASSES = new ClassFileImporter()
.importPackages("com.baiyue.lastleg");
@Test
void everyMapperInterfaceDeclaresItsRegistrationMarker() {
classes().that().areInterfaces().and().haveSimpleNameEndingWith("Mapper")
.should().beAnnotatedWith(Mapper.class)
.because("Mapper registration must fail during tests instead of service startup")
.check(PRODUCTION_CLASSES);
}
@Test
void applicationUsesOneAnnotationFilteredRootScan() {
MapperScan scan = BaiyueLastlegApplication.class.getAnnotation(MapperScan.class);
assertThat(scan.basePackages()).containsExactly("com.baiyue.lastleg");
assertThat(scan.annotationClass()).isEqualTo(Mapper.class);
}
}
@@ -1,25 +0,0 @@
package com.baiyue.lastleg.masterdata;
import org.apache.ibatis.annotations.Mapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class MasterDataMapperConfigurationTest {
@Test
void scansOnlyAnnotatedMasterDataMappers() {
MapperScan mapperScan = MasterDataMapperConfiguration.class.getAnnotation(MapperScan.class);
assertThat(mapperScan.basePackages()).containsExactly("com.baiyue.lastleg.masterdata");
assertThat(mapperScan.annotationClass()).isEqualTo(Mapper.class);
}
@Test
void broadExchangeMapperScanMustNotBeReintroduced() {
assertThatThrownBy(() -> Class.forName(
"com.baiyue.lastleg.masterdata.exchange.ExchangeMapperConfiguration"))
.isInstanceOf(ClassNotFoundException.class);
}
}
@@ -1,20 +0,0 @@
package com.baiyue.lastleg.pda;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import static org.assertj.core.api.Assertions.assertThat;
class PdaOperationsMapperConfigurationTest {
@Test
void scansEveryPdaWarehouseOperationMapperPackage() {
MapperScan mapperScan = PdaOperationsMapperConfiguration.class.getAnnotation(MapperScan.class);
assertThat(mapperScan.basePackages()).containsExactlyInAnyOrder(
"com.baiyue.lastleg.palletops.mapper",
"com.baiyue.lastleg.pda.move.mapper",
"com.baiyue.lastleg.pda.stocktake.mapper",
"com.baiyue.lastleg.pda.warehouse.mapper"
);
}
}
@@ -1,15 +0,0 @@
package com.baiyue.lastleg.shipping;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import static org.assertj.core.api.Assertions.assertThat;
class ShippingMapperConfigurationTest {
@Test
void scansShippingMappers() {
MapperScan mapperScan = ShippingMapperConfiguration.class.getAnnotation(MapperScan.class);
assertThat(mapperScan.basePackages()).containsExactly("com.baiyue.lastleg.shipping.mapper");
}
}
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `BaiyueOrderApplication.java` 对 `com.baiyue.order` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责头程订单主数据、货物明细、快照、状态编排、幂等、Outbox 和内部货物查询。
- 订单交易状态归本模块;履约/入库状态归 `firstleg/`,仓储资源归 `warehouse/`,不得跨库读取。
- `tenant_id` 是客户隔离键;`customer_id` 是客户/企业账号 ID,商户下单时固定来自认证上下文,不得指向 Warehouse 往来单位。发货单位、收货单位只保存为订单 Party 引用与业务快照。
@@ -1,5 +1,6 @@
package com.baiyue.order;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +10,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 订单微服务启动入口,负责装配订单领域组件并扫描 MyBatis-Plus Mapper。
*/
@MapperScan("com.baiyue.order.mapper")
@MapperScan(basePackages = "com.baiyue.order", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.order.client")
@EnableScheduling
@SpringBootApplication(scanBasePackages = "com.baiyue")
@@ -1,4 +1,10 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OrderCargoEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderCargoEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 订单货物明细 Mapper,提供 {@code ord_order_cargo} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface OrderCargoMapper extends BaseMapper<OrderCargoEntity>{}
@@ -1,8 +1,11 @@
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Param;
/**
* 订单子表清理 Mapper,在租户边界内删除订单货物和参与方数据,供草稿整体更新时重建明细。
*/
@Mapper
public interface OrderChildPurgeMapper {
@Delete("DELETE FROM ord_order_cargo WHERE tenant_id=#{tenantId} AND order_id=#{orderId}") int purgeCargo(@Param("tenantId") long tenantId,@Param("orderId") long orderId);
@Delete("DELETE FROM ord_order_party WHERE tenant_id=#{tenantId} AND order_id=#{orderId}") int purgeParties(@Param("tenantId") long tenantId,@Param("orderId") long orderId);
@@ -1,8 +1,11 @@
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderIdempotencyRecordEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/** 订单写入幂等记录 Mapper。 */
@Mapper
public interface OrderIdempotencyRecordMapper extends BaseMapper<OrderIdempotencyRecordEntity> {
}
@@ -1,4 +1,10 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OrderInternalNoteEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderInternalNoteEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 订单内部备注 Mapper,提供 {@code ord_order_internal_note} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface OrderInternalNoteMapper extends BaseMapper<OrderInternalNoteEntity>{}
@@ -1,11 +1,16 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OrderEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 订单主表 Mapper,提供 {@code ord_order} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface OrderMapper extends BaseMapper<OrderEntity>{
@Select("""
SELECT COUNT(*) AS total_submitted_orders,
@@ -1,4 +1,10 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OrderPartyEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderPartyEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 订单参与方 Mapper,提供 {@code ord_order_party} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface OrderPartyMapper extends BaseMapper<OrderPartyEntity>{}
@@ -1,4 +1,10 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OrderStatusHistoryEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OrderStatusHistoryEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 订单状态历史 Mapper,提供 {@code ord_order_status_history} 的 MyBatis-Plus 基础数据访问能力。
*/
@Mapper
public interface OrderStatusHistoryMapper extends BaseMapper<OrderStatusHistoryEntity>{}
@@ -1,4 +1,10 @@
package com.baiyue.order.mapper; import com.baiyue.order.entity.OutboxEventEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /**
package com.baiyue.order.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.order.entity.OutboxEventEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 订单事务 Outbox Mapper,提供 {@code ord_outbox_event} 待发布领域事件的持久化访问能力。
*/
@Mapper
public interface OutboxEventMapper extends BaseMapper<OutboxEventEntity>{}
+1
View File
@@ -33,6 +33,7 @@ node scripts/create-pending-review-orders.mjs
| PDA 本地页面和状态测试 | `../apps/pda-uniapp/tests/*.test.mjs` |
| 本地数据库 SQL 静态/受控验收 | `scripts/local-db-full-acceptance.ps1` |
| AGENTS 快速索引一致性 | `scripts/agents-index-contract.ps1`;只读核对根快速表唯一性、部署单元、业务模块、Client active 路由、四期范围漂移、仓库主档唯一权威、订舱候选与柜量语义、整柜出仓与船节点单调性、海外 Gateway 覆盖、PDA 页面/运行配置/独立更新/语言预留/能力开关、人工分段验收链、Maven 模块、Lastleg 海外安全投影、同步 Trace、关键入口与排除目录 |
| Mapper 注册静态合同 | `node scripts/mapper-scan-contract.mjs`、`node --test scripts/mapper-scan-contract.test.mjs`;自动核对全部持久化模块的 `@Mapper`、服务根包注解过滤扫描和唯一扫描入口,不启动 Spring、不连接数据库;`backend-full-regression.ps1` 在 Maven 前强制执行 |
| Java 质量聚合摘要 | `node --test scripts/java-quality-summary.test.mjs`、`node scripts/java-quality-summary.mjs --output target/java-quality-summary.json`;聚合 Maven/服务拓扑、OpenAPI 覆盖、JaCoCo 和 SpotBugs 报告,默认只报告存量缺口,CI 用显式 `--require-jacoco --require-spotbugs` 检查报告完整性且当前允许失败 |
| 单服务部署失败回滚合同 | `scripts/deploy-built-service-rollback.test.mjs`;模拟成功、健康失败和启动失败,确认仅恢复同服务先前健康镜像且部署任务仍失败 |
+28
View File
@@ -93,13 +93,37 @@ $pdaAgents = Read-RequiredText $pdaAgentsPath
$overseasPdaAgents = Read-RequiredText $overseasPdaAgentsPath
$backendAgents = Read-RequiredText $backendAgentsPath
$engineeringConstraints = Read-RequiredText (Join-Path $workspaceRoot 'docs/AI工程执行与协作约束.md')
$mapperScanContract = Read-RequiredText (Join-Path $backendRoot 'scripts/mapper-scan-contract.mjs')
# 当前未上线阶段的无兼容原则必须覆盖全部实现与运行状态,不能再次缩窄为文件或数据库专项规则。
Assert-Contains $rootAgents '源码结构、接口与 DTO、字段、状态机、权限、配置键、数据库结构与初始化 SQL、事件、路由、页面、Mock/Fixture、测试和脚本' '根无兼容收敛范围'
Assert-Contains $rootAgents '数据库记录、上传文件、缓存、会话、消息、搜索索引和其他运行状态均视为可丢弃' '根开发运行状态范围'
Assert-Contains $rootAgents '后端 MyBatis Mapper 新增、移动或扫描遗漏' '根 Mapper 快速入口'
Assert-Contains $rootAgents 'node scripts/mapper-scan-contract.mjs' '根 Mapper 静态门禁'
Assert-Contains $engineeringConstraints '禁止为旧代码、旧调用或开发环境存量保留旧接口/旧字段别名' '工程无兼容执行规则'
Assert-Contains $engineeringConstraints '不授权自动重置数据库、删除数据/文件、执行 SQL、部署或修改环境' '无兼容安全边界'
Assert-Contains $clientAgents '不得继续扩展 `LEGACY_MANUAL`、旧系统入仓码、C02 不可用回退旧 API' 'Client 头程无兼容边界'
Assert-Contains $backendAgents '所有生产 MyBatis Mapper 接口必须显式标记 `@Mapper`' '后端 Mapper 注册规则'
Assert-Contains $backendAgents 'Mapper 新增、移动、Bean 缺失与扫描遗漏' '后端 Mapper 快速路由'
Assert-Contains $mapperScanContract 'annotationClass = Mapper.class' 'Mapper 根包注解过滤合同'
Assert-Contains $mapperScanContract '禁止分散维护 MapperScan' 'Mapper 单一扫描入口合同'
$mapperModuleAgents = @(
@{ Module = 'audit-service'; Application = 'BaiyueAuditApplication.java' },
@{ Module = 'auth'; Application = 'BaiyueAuthApplication.java' },
@{ Module = 'event-bridge-service'; Application = 'EventBridgeApplication.java' },
@{ Module = 'file'; Application = 'FileServiceApplication.java' },
@{ Module = 'firstleg'; Application = 'BaiyueFirstlegApplication.java' },
@{ Module = 'iam'; Application = 'BaiyueIamApplication.java' },
@{ Module = 'lastleg-service'; Application = 'BaiyueLastlegApplication.java' },
@{ Module = 'order'; Application = 'BaiyueOrderApplication.java' },
@{ Module = 'warehouse'; Application = 'BaiyueWarehouseApplication.java' },
@{ Module = 'warehouse-overseas-service'; Application = 'BaiyueWarehouseOverseasApplication.java' }
)
foreach ($entry in $mapperModuleAgents) {
$moduleAgents = Read-RequiredText (Join-Path $backendRoot "$($entry.Module)/AGENTS.md")
Assert-Contains $moduleAgents $entry.Application "$($entry.Module) Mapper 启动入口"
Assert-Contains $moduleAgents 'scripts/mapper-scan-contract.mjs' "$($entry.Module) Mapper 静态门禁"
}
# 部署单元必须能从根索引进入。
Get-ChildItem -LiteralPath (Join-Path $workspaceRoot 'apps') -Directory |
@@ -439,6 +463,10 @@ $criticalPaths = @(
'apps/pda-overseas-uniapp/src/i18n/locales/en.js',
'apps/pda-overseas-uniapp/src/i18n/locales/es.js',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/FeePaymentSnapshotValidator.java',
'baiyue-firstleg/scripts/mapper-scan-contract.mjs',
'baiyue-firstleg/scripts/mapper-scan-contract.test.mjs',
'baiyue-firstleg/firstleg/src/test/java/com/baiyue/firstleg/MapperRegistrationArchitectureTest.java',
'baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/MapperRegistrationArchitectureTest.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/client/FeePaymentVoucherFileClient.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java',
+8
View File
@@ -7,7 +7,9 @@ param(
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$pom = Join-Path $repoRoot "pom.xml"
$mapperScanContract = Join-Path $repoRoot "scripts/mapper-scan-contract.mjs"
$requiredTests = @(
"scripts/mapper-scan-contract.test.mjs",
"firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/controller/PlatformOceanBookingControllerContractTest.java",
"firstleg/src/test/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingServiceTest.java",
"firstleg/src/test/java/com/baiyue/firstleg/repository/TruckAppointmentMapperContractTest.java",
@@ -45,6 +47,10 @@ if (-not (Test-Path -LiteralPath $pom)) {
Write-Error "Missing Maven pom: $pom"
exit 2
}
if (-not (Test-Path -LiteralPath $mapperScanContract)) {
Write-Error "Missing Mapper scan contract: $mapperScanContract"
exit 2
}
$missing = @($requiredTests | Where-Object { -not (Test-Path -LiteralPath (Join-Path $repoRoot $_)) })
if ($missing.Count -gt 0) {
@@ -60,6 +66,8 @@ if ($DryRun) {
Push-Location $repoRoot
try {
& node $mapperScanContract
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& $MavenCommand @mavenArgs
$code = $LASTEXITCODE
} finally {
@@ -23,6 +23,11 @@ test('backend full regression includes file reactor and critical file/container
]) assert.match(backendScript, new RegExp(required.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')))
})
test('backend full regression rejects Mapper registration drift before Maven', () => {
assert.match(backendScript, /scripts\/mapper-scan-contract\.mjs/)
assert.match(backendScript, /& node \$mapperScanContract[\s\S]*& \$MavenCommand @mavenArgs/)
})
test('test-environment full acceptance registers container overview module', () => {
const modulePath = resolve(scriptsDir, 'admin-test-env-modules', 'phase3-container-overview.mjs')
if (!adminAcceptance.includes('phase3-container-overview') || !existsSync(modulePath)) {
+122
View File
@@ -0,0 +1,122 @@
import { readFileSync, readdirSync, statSync } from 'node:fs'
import { dirname, join, relative, resolve, sep } from 'node:path'
import { fileURLToPath } from 'node:url'
const scriptDir = dirname(fileURLToPath(import.meta.url))
export const repositoryRoot = resolve(scriptDir, '..')
function filesBelow(root, predicate) {
if (!statSafe(root)?.isDirectory()) return []
const result = []
for (const entry of readdirSync(root, { withFileTypes: true })) {
if (entry.name === 'target' || entry.name === '.git') continue
const path = join(root, entry.name)
if (entry.isDirectory()) result.push(...filesBelow(path, predicate))
else if (predicate(path)) result.push(path)
}
return result
}
function statSafe(path) {
try { return statSync(path) } catch { return null }
}
function packageName(source) {
return source.match(/\bpackage\s+([\w.]+)\s*;/)?.[1] || ''
}
function mapperInterfaces(javaFiles) {
return javaFiles.flatMap((path) => {
const source = readFileSync(path, 'utf8')
const names = [...source.matchAll(/\b(?:public\s+)?interface\s+(\w*Mapper)\b/g)].map((match) => match[1])
return names.map((name) => ({ path, source, packageName: packageName(source), name }))
})
}
function mapperScanAnnotation(source) {
const start = source.indexOf('@MapperScan')
if (start < 0) return ''
const end = source.indexOf('\n', start)
if (source[start + '@MapperScan'.length] !== '(') return source.slice(start, end < 0 ? undefined : end)
let depth = 0
for (let index = start + '@MapperScan'.length; index < source.length; index += 1) {
if (source[index] === '(') depth += 1
else if (source[index] === ')' && --depth === 0) return source.slice(start, index + 1)
}
return source.slice(start)
}
function moduleNames(root) {
const pom = readFileSync(join(root, 'pom.xml'), 'utf8')
return [...pom.matchAll(/<module>([^<]+)<\/module>/g)].map((match) => match[1].trim())
}
export function auditMapperScanning(root = repositoryRoot) {
const failures = []
let mapperCount = 0
let persistenceModuleCount = 0
for (const moduleName of moduleNames(root)) {
const moduleRoot = join(root, moduleName)
const javaRoot = join(moduleRoot, 'src', 'main', 'java')
const javaFiles = filesBelow(javaRoot, (path) => path.endsWith('.java'))
const mappers = mapperInterfaces(javaFiles)
if (!mappers.length) continue
persistenceModuleCount += 1
mapperCount += mappers.length
const mapperNames = new Map()
for (const mapper of mappers) {
const previous = mapperNames.get(mapper.name)
if (previous) {
failures.push(`${moduleName}: 根包扫描下 Mapper Bean 名称重复 ${mapper.name}(${relative(root, previous)}、${relative(root, mapper.path)})`)
} else mapperNames.set(mapper.name, mapper.path)
if (!/@Mapper\b/.test(mapper.source)) {
failures.push(`${moduleName}: ${mapper.packageName}.${mapper.name} 缺少 @Mapper(${relative(root, mapper.path)})`)
}
}
const applications = javaFiles.filter((path) => /@SpringBootApplication\b/.test(readFileSync(path, 'utf8')))
if (applications.length !== 1) {
failures.push(`${moduleName}: 期望且只能有一个 @SpringBootApplication,实际 ${applications.length} 个`)
continue
}
const applicationPath = applications[0]
const applicationSource = readFileSync(applicationPath, 'utf8')
const rootPackage = packageName(applicationSource)
const scan = mapperScanAnnotation(applicationSource)
if (!scan) failures.push(`${moduleName}: 启动类缺少统一 @MapperScan`)
else {
if (!scan.includes(`"${rootPackage}"`)) failures.push(`${moduleName}: @MapperScan 必须覆盖服务根包 ${rootPackage}`)
if (!/annotationClass\s*=\s*Mapper\.class/.test(scan)) failures.push(`${moduleName}: @MapperScan 必须使用 annotationClass = Mapper.class`)
}
for (const path of javaFiles) {
if (path === applicationPath) continue
if (/@MapperScan\b/.test(readFileSync(path, 'utf8'))) {
failures.push(`${moduleName}: 禁止分散维护 MapperScan(${relative(root, path)})`)
}
}
for (const mapper of mappers) {
if (!(mapper.packageName === rootPackage || mapper.packageName.startsWith(`${rootPackage}.`))) {
failures.push(`${moduleName}: ${mapper.packageName}.${mapper.name} 不在服务扫描根包 ${rootPackage} 内`)
}
}
}
return { failures, mapperCount, persistenceModuleCount }
}
function main() {
const result = auditMapperScanning(repositoryRoot)
if (result.failures.length) {
console.error(`Mapper 扫描合同失败,共 ${result.failures.length} 项:`)
result.failures.forEach((failure) => console.error(`- ${failure}`))
process.exitCode = 1
return
}
console.log(`Mapper 扫描合同通过:${result.persistenceModuleCount} 个持久化模块、${result.mapperCount} 个 Mapper 均使用 @Mapper,并由服务根包注解过滤扫描。`)
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main()
+10
View File
@@ -0,0 +1,10 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { auditMapperScanning, repositoryRoot } from './mapper-scan-contract.mjs'
test('every production MyBatis mapper is annotated and covered by one root scan', () => {
const result = auditMapperScanning(repositoryRoot)
assert.deepEqual(result.failures, [])
assert.ok(result.persistenceModuleCount >= 10)
assert.ok(result.mapperCount >= 200)
})
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `BaiyueWarehouseOverseasApplication.java` 对 `com.baiyue.warehouse` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责海外库位、托盘及业务资源锁定/释放;只保存国内仓库 ID 引用,不保存仓库、地址或能力主档。
- 国内 `warehouse-service` 是仓库 ID、类型、状态、地址和能力的唯一权威;本服务通过内部目录校验平台共享 `OVERSEAS + ACTIVE + RECEIVING` 仓。尾程入仓计划通过内部网关请求资源;本模块不读取尾程订单库或头程数据库。
@@ -1,5 +1,6 @@
package com.baiyue.warehouse;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -8,7 +9,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 仓库微服务启动入口,启用 Spring Boot 自动配置并扫描仓库服务的 MyBatis Mapper。
*/
@MapperScan("com.baiyue.warehouse.mapper")
@MapperScan(basePackages = "com.baiyue.warehouse", annotationClass = Mapper.class)
@EnableFeignClients(basePackages = "com.baiyue.warehouse.client")
@SpringBootApplication(scanBasePackages = "com.baiyue")
public class BaiyueWarehouseOverseasApplication {
@@ -1,10 +1,13 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.WarehouseLocationEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface WarehouseLocationMapper extends BaseMapper<WarehouseLocationEntity> {
/**
* The unique location-code index makes this safe for concurrent first use of an older warehouse.
@@ -1,10 +1,13 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baiyue.warehouse.entity.WarehousePalletBindingEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface WarehousePalletBindingMapper extends BaseMapper<WarehousePalletBindingEntity> {
@Select("SELECT * FROM wh_pallet_business_binding WHERE customer_id=#{customerId} AND warehouse_id=#{warehouseId} " +
"AND business_type=#{businessType} AND business_id=#{businessId} LIMIT 1")
@@ -1,6 +1,9 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.WarehousePalletEntity;
@Mapper
public interface WarehousePalletMapper extends BaseMapper<WarehousePalletEntity> { }
@@ -1,5 +1,7 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.WarehousePalletEntity;
import com.baiyue.warehouse.entity.WarehousePalletOperationEntity;
@@ -7,6 +9,7 @@ import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface WarehousePalletTransitionMapper extends BaseMapper<WarehousePalletOperationEntity> {
@Select("SELECT * FROM wh_pallet_operation WHERE operation_key=#{operationKey} LIMIT 1")
WarehousePalletOperationEntity findOperation(@Param("operationKey") String operationKey);
@@ -1,11 +1,14 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.WarehouseResourceLockEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface WarehouseResourceLockMapper extends BaseMapper<WarehouseResourceLockEntity> {
@Select("""
SELECT * FROM wh_resource_lock
+1
View File
@@ -2,6 +2,7 @@
## 职责与边界
- Mapper 只由 `BaiyueWarehouseApplication.java` 对 `com.baiyue.warehouse` 根包按 `@Mapper` 过滤扫描;新增或移动 Mapper 后从后端根运行 `node scripts/mapper-scan-contract.mjs`,不得增加子域扫描配置。
- 负责国内收货仓及现有平台仓库主数据、地址/能力、往来单位、快递公司、平台公共供应商、国内整柜库存/出入库,以及托盘主数据、库位预占和占用。四期只在本模块扩展“海外仓合作仓”仓库类型及其公共主数据契约。
- 入库单、测量和入库状态归 `firstleg/`;订单只通过内部接口校验并保存快照。
- 四期海外接柜、卸货、海外入库、换标、产品、箱号、库存和库内作业属于海外区域服务,不得落入本国内 Warehouse Service;范围先读 `../../docs/四期/README.md`。
@@ -1,5 +1,6 @@
package com.baiyue.warehouse;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -7,7 +8,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 仓库微服务启动入口,启用 Spring Boot 自动配置并扫描仓库服务的 MyBatis Mapper。
*/
@MapperScan({"com.baiyue.warehouse.mapper", "com.baiyue.warehouse.domesticcontainer.mapper"})
@MapperScan(basePackages = "com.baiyue.warehouse", annotationClass = Mapper.class)
@SpringBootApplication(scanBasePackages = "com.baiyue")
public class BaiyueWarehouseApplication {
public static void main(String[] args) { SpringApplication.run(BaiyueWarehouseApplication.class, args); }
@@ -1,5 +1,7 @@
package com.baiyue.warehouse.domesticcontainer.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.domesticcontainer.entity.DomesticContainerIdempotencyEntity;
import org.apache.ibatis.annotations.Insert;
@@ -7,6 +9,7 @@ import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface DomesticContainerIdempotencyMapper extends BaseMapper<DomesticContainerIdempotencyEntity> {
@Insert("INSERT IGNORE INTO wh_domestic_container_idempotency (id,tenant_id,operation_type,idempotency_key,request_hash,operation_status,created_at) VALUES (#{id},0,#{operationType},#{idempotencyKey},#{requestHash},'PROCESSING',CURRENT_TIMESTAMP(3))")
int claim(@Param("id") long id, @Param("operationType") String operationType,
@@ -1,10 +1,13 @@
package com.baiyue.warehouse.domesticcontainer.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.domesticcontainer.entity.DomesticContainerInventoryEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface DomesticContainerInventoryMapper extends BaseMapper<DomesticContainerInventoryEntity> {
@Select("SELECT id FROM wh_warehouse WHERE tenant_id=0 AND id=#{warehouseId} AND warehouse_type='DOMESTIC' AND status='ACTIVE' AND deleted=0 FOR UPDATE")
Long lockWarehouse(@Param("warehouseId") long warehouseId);
@@ -1,7 +1,10 @@
package com.baiyue.warehouse.domesticcontainer.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.domesticcontainer.entity.DomesticContainerOrderEntity;
@Mapper
public interface DomesticContainerOrderMapper extends BaseMapper<DomesticContainerOrderEntity> {
}
@@ -1,7 +1,10 @@
package com.baiyue.warehouse.domesticcontainer.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.domesticcontainer.entity.DomesticContainerTransactionEntity;
@Mapper
public interface DomesticContainerTransactionMapper extends BaseMapper<DomesticContainerTransactionEntity> {
}
@@ -1,8 +1,11 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.ExpressCompanyEntity;
/** 快递公司持久化映射。 */
@Mapper
public interface ExpressCompanyMapper extends BaseMapper<ExpressCompanyEntity> {
}
@@ -1,8 +1,11 @@
package com.baiyue.warehouse.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baiyue.warehouse.entity.OverseasStorageFeeRuleEntity;
/** 海外仓阶梯费用主记录 Mapper。 */
@Mapper
public interface OverseasStorageFeeRuleMapper extends BaseMapper<OverseasStorageFeeRuleEntity> {
}

Some files were not shown because too many files have changed in this diff Show More