You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chajia/__tests__/modules/quote/quote-serializer-priority1....

159 lines
5.0 KiB

import { describe, expect, it } from "vitest";
import type { QuoteRecord } from "@prisma/client";
import { PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE } from "@/modules/priority1/constants";
import { isPriority1ManualFollowupDetail } from "@/modules/priority1/quote-outcome";
import { serializeQuoteDetail } from "@/modules/quote/quote-serializer";
import { PRIORITY1_MANUAL_FOLLOWUP_MESSAGE } from "@/workers/rpa/priority1/quote-extract";
function baseRecord(overrides: Partial<QuoteRecord> = {}): QuoteRecord {
return {
id: 1,
quoteId: "Q-TEST-001",
requestId: "req-1",
customerId: "cust-1",
cargoHash: "hash",
status: "done",
sourceType: "rpa",
isRealtime: true,
confidenceScore: 0.95,
currency: "USD",
pickupJson: {},
deliveryJson: {},
weightLb: 100,
dimLIn: 48,
dimWIn: 40,
dimHIn: 48,
palletCount: 1,
cargoType: "general_freight",
quotesJson: null,
markupPercent: 0,
validUntil: null,
errorCode: PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE,
errorMessage: PRIORITY1_MANUAL_FOLLOWUP_MESSAGE,
isDeleted: false,
createdAt: new Date("2026-06-01T00:00:00Z"),
updatedAt: new Date("2026-06-01T00:00:00Z"),
...overrides,
} as QuoteRecord;
}
describe("Priority1 manual_followup quote detail", () => {
it("serializes done + PRIORITY1_MANUAL_FOLLOWUP as informational outcome", () => {
const detail = serializeQuoteDetail(baseRecord());
expect(detail.status).toBe("done");
expect(detail.error_code).toBe(PRIORITY1_MANUAL_FOLLOWUP_ERROR_CODE);
expect(detail.error_message).toBe(PRIORITY1_MANUAL_FOLLOWUP_MESSAGE);
expect(detail.quotes).toEqual([]);
expect(isPriority1ManualFollowupDetail(detail)).toBe(true);
});
it("serializes priority1 stored quotes without mothership tiers", () => {
const detail = serializeQuoteDetail(
baseRecord({
errorCode: null,
errorMessage: null,
quotesJson: {
provider: "priority1",
display_mode: "ltl_cards",
lines: [
{
rank: 1,
carrier: "Forward Air",
totalUsd: 557,
markup_amount: 0,
final_total_usd: 557,
serviceLevel: "STANDARD LTL",
source: "visible-dom",
},
],
},
pickupJson: {
zip: "32801",
priority1_shipment_type: "ltl",
priority1_pickup_date: "2026-07-14",
},
deliveryJson: { zip: "28202" },
}),
);
expect(detail.priority1?.display_mode).toBe("ltl_cards");
expect(detail.priority1?.lines).toHaveLength(1);
expect(detail.priority1?.shipment_meta?.origin_zip).toBe("32801");
expect(detail.quotes).toBeUndefined();
});
it("serializes legacy tier quotesJson as priority1 payload", () => {
const detail = serializeQuoteDetail(
baseRecord({
errorCode: null,
errorMessage: null,
quotesJson: [
{
service_level: "standard",
rate_option: "lowest",
carrier: "Forward Air",
transit_days: "3",
raw_total: 428.5,
final_total: 428.5,
markup_amount: 0,
},
],
pickupJson: { zip: "32801", priority1_shipment_type: "ltl" },
deliveryJson: { zip: "28202" },
}),
);
expect(detail.priority1?.lines).toHaveLength(1);
expect(detail.priority1?.lines[0]?.carrier).toBe("Forward Air");
});
it("MotherShip tier 数组在无 Priority1 上下文时序列化为 quotes 而非 priority1", () => {
const detail = serializeQuoteDetail(
baseRecord({
errorCode: null,
errorMessage: null,
quotesJson: [
{
service_level: "standard",
rate_option: "lowest",
carrier: "Frontline Freight",
transit_days: "3",
raw_freight: 300,
surcharges: 32.6,
raw_total: 332.6,
markup_percent: 0,
markup_amount: 0,
final_total: 332.6,
breakdown: [
{ item: "运费", amount: 300 },
{ item: "附加费", amount: 32.6 },
],
},
],
pickupJson: { zip: "90001" },
deliveryJson: { zip: "75201" },
}),
);
expect(detail.priority1).toBeUndefined();
expect(detail.quotes).toHaveLength(1);
expect(detail.quotes?.[0]).toMatchObject({
service_level: "standard",
rate_option: "lowest",
carrier: "Frontline Freight",
});
});
it("Priority1 询价无 priority1 数据时返回 failed 而非空结果", () => {
const detail = serializeQuoteDetail(
baseRecord({
errorCode: null,
errorMessage: null,
quotesJson: null,
pickupJson: { zip: "32801", priority1_shipment_type: "ltl" },
deliveryJson: { zip: "28202" },
}),
);
expect(detail.status).toBe("failed");
expect(detail.priority1).toBeUndefined();
expect(detail.quotes).toBeUndefined();
});
});