feat(fleet): integrate costs quotes operations and in-transit handovers

This commit is contained in:
2026-10-03 12:38:04 +08:00
parent 274ecac474
commit cb6c54ffe5
107 changed files with 7304 additions and 42 deletions
+1
View File
@@ -16,6 +16,7 @@
| 平台订单商品图片读取 | `controller/PlatformProductImageController.java` 的 `/api/platform/v1/files/product-images/{tenantId}/{fileId}`、`service/ProductImageService.java`;仅平台 `platform:order:list` 可按明确客户与文件 ID 内联读取,响应 `no-store` |
| 装柜与业务文件证据 | `controller/PlatformLoadingEvidenceController.java`、`InternalLoadingEvidenceController.java`、`service/LoadingEvidenceService.java`、`src/main/resources/openapi/loading-evidence-v1.yaml`;五类装柜证据固定为平台所有、`tenantId=0`、`businessId=containerBookingId`,不得绑定客户或入仓单。其他业务文件进入 `InternalBusinessFileController.java`、`service/InternalBusinessFileService.java` |
| 财务付款凭证、海外卸柜照片 | 通用业务文件入口 `InternalBusinessFileController.java`、`InternalBusinessFileService.java`;`FINANCE_VOUCHER` 按客户与业务 ID 精确校验;`OVERSEAS_UNLOAD_PHOTO` 是允许同柜多客户的柜级物理证据,固定平台范围 `tenantId=0` 并按接柜会话 ID 精确校验 |
| 公司车辆付款凭证 | `src/main/resources/openapi/finance-vehicle-voucher-v1.yaml`;类型`FINANCE_VEHICLE_VOUCHER`,固定平台0和Finance费用ID,仅非空JPG/PNG、10MiB及签名校验;不复用客户凭证或维修照片 |
| 海外异常订单证据 | 通用内部业务文件入口;固定 `businessType=OVERSEAS_EXCEPTION_EVIDENCE`、`tenantId=异常订单所属客户ID`、`businessId=异常订单ID`,File 只校验文件复合归属,异常状态、完成门禁和证据引用归 Lastleg |
| 平台司机驾驶证 | 通用内部业务文件入口,契约 `src/main/resources/openapi/fleet-driver-license-v1.yaml`;`FLEET_DRIVER_LICENSE` 固定平台 `tenantId=0`、`businessId=driverId`,仅非空 PDF/JPG/PNG、最大 10MiB并校验签名;Lastleg维护审核、当前/历史附件关联及读取权限 |
| 车辆保养加油照片 | 通用内部业务文件入口,契约 `src/main/resources/openapi/fleet-vehicle-record-photo-v1.yaml`;`FLEET_VEHICLE_RECORD_PHOTO` 固定平台0及运维记录ID,仅非空JPG/PNG、最大10MiB并校验签名;Lastleg校验车辆/记录/附件关联与权限,不使用车牌作为文件归属键 |
@@ -17,6 +17,7 @@ enum BusinessFileCategory {
CUSTOMS_DOCUMENT(false, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
CUSTOMS_RECEIPT(false, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
FINANCE_VOUCHER(false, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
FINANCE_VEHICLE_VOUCHER(false, FormatPolicy.IMAGE, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
INBOUND_HOLD_EVIDENCE(true, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
OVERSEAS_PROCUREMENT_RECEIPT(true, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
OVERSEAS_PROCUREMENT_VOUCHER(true, FormatPolicy.STANDARD, Limits.STANDARD, BusinessIdPolicy.POSITIVE_LONG),
@@ -61,6 +62,9 @@ enum BusinessFileCategory {
}
void validateOwner(long tenantId) {
if (this == FINANCE_VEHICLE_VOUCHER && tenantId != 0) {
throw new BizException(ResultCode.BAD_REQUEST, "公司车辆付款凭证必须归属平台");
}
if (this == FLEET_VEHICLE_RECORD_PHOTO && tenantId != 0) {
throw new BizException(ResultCode.BAD_REQUEST, "车辆运维照片必须归属平台");
}
@@ -65,7 +65,7 @@ public class BusinessFileStorage {
extension = ".xlsx";
} else {
if (formatPolicy == BusinessFileCategory.FormatPolicy.IMAGE && !java.util.Set.of("image/jpeg", "image/png").contains(type))
throw bad("运维照片仅支持JPG、PNG");
throw bad("图片附件仅支持JPG、PNG");
if (formatPolicy == BusinessFileCategory.FormatPolicy.LICENSE && !java.util.Set.of("application/pdf", "image/jpeg", "image/png").contains(type))
throw bad("驾驶证附件仅支持PDF、JPG、PNG");
extension = TYPES.get(type);
@@ -0,0 +1,10 @@
openapi: 3.0.3
info:
title: 公司车辆付款凭证归属
version: 1.0.0
description: >-
复用InternalBusinessFileController内部上传、元数据及内容接口,不增加公网路径。
businessType为FINANCE_VEHICLE_VOUCHER,tenantId必须为0,businessId为Finance公司费用内部主键。
仅非空JPG/PNG,最多10MiB,同时校验MIME及文件签名;File按平台、业务类型、费用ID及文件ID复合校验。
Finance校验list/upload/pay权限及费用归属;上传不是付款,不复用客户FINANCE_VOUCHER或车辆维修照片。
paths: {}
@@ -9,8 +9,10 @@ import static org.assertj.core.api.Assertions.*;
class VehicleCarePhotoTest {
@TempDir Path root;
@Test void recordPhotosArePlatformOwnedAndRequireRealImageBytes() throws Exception {
var category = BusinessFileCategory.require("FLEET_VEHICLE_RECORD_PHOTO");
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource(strings = {"FLEET_VEHICLE_RECORD_PHOTO", "FINANCE_VEHICLE_VOUCHER"})
void recordPhotosAndCompanyVouchersArePlatformOwnedAndRequireRealImageBytes(String type) throws Exception {
var category = BusinessFileCategory.require(type);
category.validateOwner(0);
assertThatThrownBy(() -> category.validateOwner(7)).hasMessageContaining("平台");
assertThatThrownBy(() -> category.validateOwner(-1)).hasMessageContaining("平台");