openapi: 3.0.3 info: title: 柏悦二期 FBA 计费 API version: 2.0.0 description: 业务成功和失败均使用 HTTP 200;仅响应体 code 为字符串 "200" 时表示成功。 security: - bearerAuth: [] paths: /api/platform/v1/fba-pricing/customer-rules: get: summary: 查询客户计费规则版本 description: 需要 firstleg:fba-pricing:rule:view 权限 parameters: - {$ref: '#/components/parameters/OptionalTenantId'} - {name: ruleCode, in: query, schema: {type: string, maxLength: 50}} responses: '200': description: 成功或业务失败 content: application/json: schema: {$ref: '#/components/schemas/CustomerRuleVersionSummary'} '403': {description: 无权限} /api/platform/v1/fba-pricing/customer-rules/versions: post: summary: 新建客户计费规则版本 description: 版本内容不可原地修改;有效期使用 [effectiveFrom,effectiveTo) 半开区间。 parameters: [{$ref: '#/components/parameters/TenantId'}] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CustomerRuleVersionRequest'}}}} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/customer-rules/{id}: get: summary: 查询客户计费规则版本详情 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/Id'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} delete: summary: 停用客户计费规则版本 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/Id'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates: get: summary: 查询平台公共船司 FBA 价格版本 description: 需要 firstleg:fba-pricing:rate:view 权限 parameters: - {name: rateCode, in: query, schema: {type: string, maxLength: 50}} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates/versions: post: summary: 新建平台公共船司 FBA 价格版本 requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CarrierRateVersionRequest'}}}} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates/{id}: get: summary: 查询船司 FBA 价格版本详情 parameters: [{$ref: '#/components/parameters/Id'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} delete: summary: 停用船司 FBA 价格版本 parameters: [{$ref: '#/components/parameters/Id'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates/price-books: get: summary: 查询船期价格表版本 description: 需要 firstleg:fba-pricing:rate:view 权限;返回待确认上传、当前生效和历史替换版本。 parameters: - {name: status, in: query, schema: {$ref: '#/components/schemas/PriceBookStatus'}} responses: '200': description: 成功或业务失败 content: application/json: schema: type: array items: {$ref: '#/components/schemas/PriceBookVersionSummary'} '403': {description: 无权限} post: summary: 上传船期价格表并生成待确认记录 description: 仅上传和解析,生成待确认上传记录,不改变当前生效版本;需要 firstleg:fba-pricing:rate:edit 权限。 requestBody: required: true content: multipart/form-data: schema: {$ref: '#/components/schemas/PriceBookUploadRequest'} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates/price-books/{versionId}: get: summary: 查询船期价格表版本详情和解析结果 parameters: [{$ref: '#/components/parameters/VersionId'}] responses: '200': description: 成功或业务失败 content: application/json: schema: {$ref: '#/components/schemas/PriceBookVersionDetail'} '403': {description: 无权限} /api/platform/v1/fba-pricing/carrier-rates/price-books/{versionId}/publish: post: summary: 确认并立即生效船期价格表版本 description: 只确认上传表中的仓库映射,不允许在线改价;阻断错误必须为零。发布事务将上一 ACTIVE 版本标记为 SUPERSEDED,始终只保留一份 ACTIVE。 parameters: [{$ref: '#/components/parameters/VersionId'}] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/PriceBookConfirmationRequest'}}}} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/fba-pricing/carrier-rates/price-books/{versionId}/source: get: summary: 下载船期价格表原始文件 description: 需要 firstleg:fba-pricing:rate:view 权限;由 Firstleg 代理 File 服务内部下载。 parameters: [{$ref: '#/components/parameters/VersionId'}] responses: '200': {description: 原始 XLSX 附件, content: {application/octet-stream: {schema: {type: string, format: binary}}}} '403': {description: 无权限} /api/merchant/v1/first-leg/pricing/channels: get: summary: 查询当前起运仓可选船期渠道 description: 客户只看到当前 ACTIVE 版本;不存在于当前版本的渠道不可选择。pricingTaxModes 来自当前起运仓下的生效价格行,前端不得写死包税选项。 parameters: - {name: originWarehouseId, in: query, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} responses: '200': description: 成功或业务失败 content: application/json: schema: type: array items: {$ref: '#/components/schemas/MerchantPricingChannel'} /api/merchant/v1/first-leg/pricing/estimate: post: summary: 计算头程参考费用 description: 只返回基础参考费用,不包含复杂附加费和最终结算调整;pricingTaxMode 不复用订单 taxMode。 requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/PriceEstimateRequest'}}}} responses: {'200': {description: 成功或业务失败}} /api/platform/v1/inbounds/{inboundId}/fees/calculate: post: summary: 按审核通过测量快照试算 FBA 费用 description: 仅匹配当前唯一 ACTIVE 船期价格表中的 ACTIVE 价格行,按起运仓、渠道、目的仓、pricingTaxMode 和计费单位估价;不再以 carrierId、业务 customerId 或客户计费规则作为前置。区域阶梯渠道可按平台 FBA 仓或海外中转仓的邮编区域和重量阶梯匹配;测量审核后即使主流程已到 WAIT_SPLIT,也可独立试算且不回退主流程状态;需要 firstleg:fba-pricing:calculate 权限。 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}, {$ref: '#/components/parameters/IdempotencyKey'}] requestBody: {content: {application/json: {schema: {$ref: '#/components/schemas/CalculateRequest'}}}} responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/inbounds/{inboundId}/fees/confirm: post: summary: 确认最新费用快照 description: 确认费用只更新费用状态;主流程已到 WAIT_SPLIT 时保持不变。 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}, {$ref: '#/components/parameters/IdempotencyKey'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/inbounds/{inboundId}/fees/send: post: summary: 发送已确认费用快照 description: 该动作涉及后续仓储流程,本轮二期验收不调用。 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}, {$ref: '#/components/parameters/IdempotencyKey'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/inbounds/{inboundId}/fees/latest: get: summary: 查询最新费用快照 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}] responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}} /api/platform/v1/inbounds/{inboundId}/fees/published: put: summary: 调整初算或已发布费用 description: 需要 firstleg:fba-pricing:adjust 权限;人工修改计费量、单价和附加费,小计与总额由服务端重算并生成新版本,不回退 WAIT_SPLIT 状态。调整 CALCULATED/CONFIRMED 时生成新的 CALCULATED 版本;调整 SENT 时生成新的 SENT 版本并发布调整事件。 parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}, {$ref: '#/components/parameters/IdempotencyKey'}] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AdjustFeeRequest'} responses: {'200': {description: 成功或业务失败}, '403': {description: 无调整权限}} components: securitySchemes: bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT} parameters: OptionalTenantId: {name: tenantId, in: query, required: false, description: 可选目标客户 ID;参数名为历史兼容,不传时查询全部企业, schema: {type: string, pattern: '^[1-9][0-9]*$'}} TenantId: {name: tenantId, in: query, required: true, description: 目标客户 ID;参数名为历史兼容, schema: {type: string, pattern: '^[1-9][0-9]*$'}} Id: {name: id, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} InboundId: {name: inboundId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} VersionId: {name: versionId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} IdempotencyKey: {name: Idempotency-Key, in: header, required: true, schema: {type: string, maxLength: 128}} schemas: AdjustFeeRequest: type: object required: [expectedFeeVersion, chargeableQuantity, unitPrice, additionalAmount, reason] properties: expectedFeeVersion: {type: integer, minimum: 1} chargeableQuantity: {type: number, exclusiveMinimum: 0, description: 计费量,单位沿用当前费用快照的 chargeUnit} unitPrice: {type: number, minimum: 0, description: 人工确认单价} additionalAmount: {type: number, minimum: 0, multipleOf: 0.01} reason: {type: string, minLength: 1, maxLength: 500} CalculateRequest: type: object properties: {pricingAt: {type: string, format: date-time, description: 缺省为服务端当前时间}} CustomerRuleVersionRequest: type: object required: [ruleCode, customerId, customerName, businessType, chargeMode, taxMode, conversionFactor, roundingScale, roundingMode, currency, effectiveFrom] properties: ruleCode: {type: string, maxLength: 50} customerId: {type: string, pattern: '^[1-9][0-9]*$'} customerName: {type: string, maxLength: 128} businessType: {type: string, maxLength: 32} chargeMode: {type: string, enum: [KG, CBM]} taxMode: {type: string, enum: [TAX_INCLUDED, TAX_EXCLUDED]} conversionFactor: {type: number, exclusiveMinimum: 0, example: 167} roundingScale: {type: integer, minimum: 0, maximum: 4} roundingMode: {type: string, enum: [UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN]} currency: {type: string, pattern: '^[A-Z]{3}$'} effectiveFrom: {type: string, format: date-time} effectiveTo: {type: string, format: date-time, nullable: true} CarrierRateVersionRequest: type: object required: [rateCode, originWarehouseId, originWarehouseName, businessType, channelCode, carrierId, carrierName, destinationType, chargeUnit, unitPrice, currency, additionalFee, effectiveFrom] properties: rateCode: {type: string, maxLength: 50} originWarehouseId: {type: string, pattern: '^[1-9][0-9]*$'} originWarehouseName: {type: string} businessType: {type: string} channelCode: {type: string} carrierId: {type: string, pattern: '^[1-9][0-9]*$'} carrierName: {type: string} destinationType: {$ref: '#/components/schemas/PricingDestinationType'} destinationCode: {type: string, nullable: true} destinationWarehouseId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true} destinationName: {type: string, maxLength: 128, nullable: true} chargeUnit: {type: string, enum: [KG, CBM]} unitPrice: {type: number, exclusiveMinimum: 0} currency: {type: string, pattern: '^[A-Z]{3}$'} additionalFee: {type: number, minimum: 0} effectiveFrom: {type: string, format: date-time} effectiveTo: {type: string, format: date-time, nullable: true} PriceBookStatus: type: string enum: [PENDING_CONFIRMATION, ACTIVE, SUPERSEDED, FAILED] PriceModel: type: string enum: [FBA_WAREHOUSE_RATE, REGION_WEIGHT_TIER] PricingTaxMode: type: string enum: [TAX_INCLUDED, TAX_EXCLUDED] PricingDestinationType: type: string description: 价格明细支持的目的地类型;PRIVATE 本期不参与自动估价 enum: [FBA, OVERSEAS] PriceBookUploadRequest: type: object required: [file] properties: file: {type: string, format: binary, description: 原始 XLSX 文件} PriceBookVersionSummary: type: object properties: id: {type: string, pattern: '^[1-9][0-9]*$'} versionNo: {type: integer} originalFileName: {type: string, maxLength: 255} sourceFileId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true} sourceSha256: {type: string, maxLength: 64, nullable: true} status: {$ref: '#/components/schemas/PriceBookStatus'} channelCount: {type: integer, minimum: 0} rateCount: {type: integer, minimum: 0} blockingErrorCount: {type: integer, minimum: 0} warningCount: {type: integer, minimum: 0} parseIssuesJson: {type: string, nullable: true, description: 上传解析问题及待确认重新校验结果JSON} createdBy: {type: string, pattern: '^[1-9][0-9]*$'} createdAt: {type: string, format: date-time} publishedBy: {type: string, pattern: '^[1-9][0-9]*$', nullable: true} publishedAt: {type: string, format: date-time, nullable: true} supersededAt: {type: string, format: date-time, nullable: true} PriceBookVersionDetail: type: object required: [version, channels, rates, issues] properties: version: {$ref: '#/components/schemas/PriceBookVersionSummary'} channels: type: array items: {$ref: '#/components/schemas/PriceBookParsedChannel'} rates: type: array items: {$ref: '#/components/schemas/PriceBookParsedRate'} issues: type: array items: {$ref: '#/components/schemas/PriceBookParseIssue'} PriceBookParseIssue: type: object properties: severity: {type: string} issueCode: {type: string} message: {type: string} sourceSheetName: {type: string, nullable: true} sourceRowNumber: {type: integer, minimum: 1, nullable: true} sourceCell: {type: string, nullable: true} PriceBookConfirmationRequest: type: object required: [originMappings] properties: originMappings: type: array minItems: 1 maxItems: 2 items: {$ref: '#/components/schemas/PriceBookOriginMapping'} overseasMappings: type: array maxItems: 2 items: {$ref: '#/components/schemas/PriceBookOverseasMapping'} PriceBookOriginMapping: type: object required: [originWarehouseCode, warehouseId] properties: originWarehouseCode: {type: string, maxLength: 64, description: 上传表识别出的起运仓稳定编码} warehouseId: {type: string, pattern: '^[1-9][0-9]*$', description: 平台公共国内仓稳定ID} PriceBookOverseasMapping: type: object required: [sourceDestinationName, warehouseId] properties: sourceDestinationName: {type: string, maxLength: 128, description: 上传表中的海外仓名称} warehouseId: {type: string, pattern: '^[1-9][0-9]*$', description: 平台公共海外仓稳定ID} PriceBookParsedChannel: type: object required: [channelCode, channelName, priceModel, sourceSheetName] properties: channelCode: {type: string, maxLength: 64} channelName: {type: string, maxLength: 128} priceModel: {$ref: '#/components/schemas/PriceModel'} sourceSheetName: {type: string, maxLength: 128} estimatedDepartureDate: {type: string, format: date} estimatedDepartureText: {type: string, maxLength: 128} latestWarehouseEntry: {type: string, maxLength: 128} vesselName: {type: string, maxLength: 128} voyageNo: {type: string, maxLength: 64} referenceTransit: {type: string, maxLength: 128} surchargeDescription: {type: string, maxLength: 2000} remark: {type: string, maxLength: 2000} PriceBookParsedRate: type: object required: [channelCode, priceModel, originWarehouseCode, originWarehouseName, chargeUnit, unitPrice, currency, sourceSheetName, sourceRowNumber] properties: id: {type: string, pattern: '^[1-9][0-9]*$'} channelCode: {type: string, maxLength: 64} priceModel: {$ref: '#/components/schemas/PriceModel'} originWarehouseId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 确认时绑定的平台公共国内仓稳定ID} originWarehouseCode: {type: string, maxLength: 64} originWarehouseName: {type: string, maxLength: 128} destinationType: {$ref: '#/components/schemas/PricingDestinationType', nullable: true, description: FBA_WAREHOUSE_RATE 必填;REGION_WEIGHT_TIER 为空} destinationCode: {type: string, maxLength: 32, nullable: true} destinationWarehouseId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true, description: 确认时绑定的平台海外仓稳定ID} destinationName: {type: string, maxLength: 128, nullable: true, description: 目的仓名称快照} regionCode: {type: string, maxLength: 16, nullable: true} pricingTaxMode: {$ref: '#/components/schemas/PricingTaxMode'} chargeUnit: {type: string, enum: [KG, CBM]} weightFromKg: {type: number, minimum: 0, nullable: true} unitPrice: {type: number, exclusiveMinimum: 0} currency: {type: string, pattern: '^[A-Z]{3}$'} sourceSheetName: {type: string, maxLength: 128} sourceRowNumber: {type: integer, minimum: 1} sourceDestinationText: {type: string, maxLength: 1000} remark: {type: string, maxLength: 500} MerchantPricingChannel: type: object required: [priceBookVersionId, channelCode, channelName, priceModel, pricingTaxModes] properties: priceBookVersionId: {type: string, pattern: '^[1-9][0-9]*$'} channelCode: {type: string, maxLength: 64} channelName: {type: string, maxLength: 128} priceModel: {$ref: '#/components/schemas/PriceModel'} pricingTaxModes: type: array description: 当前起运仓、当前渠道的生效价格行支持的报价税模式;可能只包含包税或不包税其中一种。 items: {$ref: '#/components/schemas/PricingTaxMode'} estimatedDepartureDate: {type: string, format: date, nullable: true} estimatedDepartureText: {type: string, maxLength: 128, nullable: true} latestWarehouseEntry: {type: string, maxLength: 128, nullable: true} referenceTransit: {type: string, maxLength: 128, nullable: true} surchargeDescription: {type: string, maxLength: 2000, nullable: true} remark: {type: string, maxLength: 2000, nullable: true} PriceEstimateRequest: type: object required: [originWarehouseId, channelCode, destinationType] properties: originWarehouseId: {type: string, pattern: '^[1-9][0-9]*$'} channelCode: {type: string, maxLength: 64} destinationType: {$ref: '#/components/schemas/PricingDestinationType'} destinationCode: {type: string, maxLength: 32} destinationWarehouseId: {type: string, pattern: '^[1-9][0-9]*$', nullable: true} destinationName: {type: string, maxLength: 128, nullable: true} destinationRegion: {type: string, enum: [WEST, CENTRAL, EAST]} pricingTaxMode: {$ref: '#/components/schemas/PricingTaxMode'} actualWeightKg: {type: number, minimum: 0} actualVolumeCbm: {type: number, minimum: 0}