fix: allow manual FBA quote when rate is missing
This commit is contained in:
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ApiResponseError, http } from '@/shared/api/http'
|
||||
import {
|
||||
adjustPublishedInboundFee,
|
||||
createManualInboundQuote,
|
||||
confirmInboundFee,
|
||||
createFeeActionIdempotencyKey,
|
||||
createFeeAdjustmentIdempotencyKey,
|
||||
@@ -69,6 +70,17 @@ describe('inbound fee API', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a manual FBA quote through the dedicated fallback endpoint', async () => {
|
||||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: { ...snapshot, rateCode: 'MANUAL_QUOTE' } })
|
||||
const payload = { selectedWeightKg: 62.5, selectedVolumeCbm: 0.384, unitPrice: 12.2, reason: 'FBA价格未维护' }
|
||||
|
||||
await expect(createManualInboundQuote('10001', '88', payload, 'fee-manual-1'))
|
||||
.resolves.toMatchObject({ rateCode: 'MANUAL_QUOTE' })
|
||||
expect(http.post).toHaveBeenCalledWith('/platform/v1/inbounds/88/fees/manual-quote', payload, {
|
||||
params: { tenantId: '10001' }, headers: { 'Idempotency-Key': 'fee-manual-1' },
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves backend conflict metadata for stale-version recovery', async () => {
|
||||
vi.mocked(http.put).mockResolvedValue({
|
||||
code: 'A0409', message: '费用已被其他操作员修改,请刷新后重试', data: null,
|
||||
|
||||
@@ -23,6 +23,16 @@ export async function calculateInboundFee(tenantId: string, inboundId: string, p
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function createManualInboundQuote(tenantId: string, inboundId: string, payload: {
|
||||
selectedWeightKg: number; selectedVolumeCbm: number; unitPrice: number; reason: string
|
||||
}, idempotencyKey: string) {
|
||||
const response = await http.post<unknown, ApiEnvelope<InboundFeeSnapshot>>(
|
||||
`${feeBasePath(inboundId)}/manual-quote`, payload,
|
||||
{ params: { tenantId }, headers: { 'Idempotency-Key': idempotencyKey } },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
async function transitionInboundFee(
|
||||
tenantId: string,
|
||||
inboundId: string,
|
||||
@@ -63,7 +73,7 @@ export function createFeeAdjustmentIdempotencyKey() {
|
||||
return createFeeActionIdempotencyKey('adjust')
|
||||
}
|
||||
|
||||
export function createFeeActionIdempotencyKey(action: 'adjust' | 'calculate' | 'confirm' | 'send') {
|
||||
export function createFeeActionIdempotencyKey(action: 'adjust' | 'calculate' | 'manual' | 'confirm' | 'send') {
|
||||
const uuid = globalThis.crypto?.randomUUID?.()
|
||||
if (uuid) return `fee-${action}-${uuid}`
|
||||
return `fee-${action}-${Date.now()}-${Math.random().toString(36).slice(2, 12)}`
|
||||
|
||||
@@ -13,9 +13,9 @@ export interface InboundFeeSnapshot {
|
||||
chargeRuleId: string
|
||||
ruleCode: string
|
||||
chargeRuleVersion: number
|
||||
carrierRateId: string
|
||||
carrierRateId: string | null
|
||||
rateCode: string
|
||||
carrierRateVersion: number
|
||||
carrierRateVersion: number | null
|
||||
customerId: string
|
||||
customerName: string
|
||||
originWarehouseId: string
|
||||
@@ -45,7 +45,7 @@ export interface InboundFeeSnapshot {
|
||||
additionalAmount: number
|
||||
totalAmount: number
|
||||
currency: string
|
||||
rateEffectiveFrom: string
|
||||
rateEffectiveFrom: string | null
|
||||
rateEffectiveTo: string | null
|
||||
calculatedAt: string
|
||||
confirmedAt: string | null
|
||||
|
||||
@@ -8,6 +8,7 @@ export { default as InboundFeePanel } from './fee/InboundFeePanel.vue'
|
||||
export {
|
||||
adjustPublishedInboundFee,
|
||||
calculateInboundFee,
|
||||
createManualInboundQuote,
|
||||
confirmInboundFee,
|
||||
createFeeAdjustmentIdempotencyKey,
|
||||
createFeeActionIdempotencyKey,
|
||||
|
||||
Reference in New Issue
Block a user