feat(P20T2-1,P20T2-2,P20T2-3): 卡授权/交易/支付标记/发票绑定/ERP出站后端
这个提交包含在:
@@ -0,0 +1,121 @@
|
||||
const {
|
||||
buildTravelOrderPaymentJournalPayload,
|
||||
buildTravelOrderPaymentJournalDedupeKey,
|
||||
buildTravelOrderPaymentJournalPreview,
|
||||
} = require("../../../src/services/integrations/erpJournal");
|
||||
|
||||
describe("erpJournal travel helpers", () => {
|
||||
it("builds payment journal payload with travel dimensions", () => {
|
||||
const payload = buildTravelOrderPaymentJournalPayload({
|
||||
travelOrder: {
|
||||
id: "order-1",
|
||||
source: "ctrip",
|
||||
external_order_no: "EXT-001",
|
||||
employee_id: "employee-1",
|
||||
department_id: "dept-1",
|
||||
travel_request_id: "travel-1",
|
||||
amount: "500.00",
|
||||
currency: "CNY",
|
||||
payment_voucher_no: "BANK-001",
|
||||
payment_date: new Date("2026-03-10T00:00:00.000Z"),
|
||||
payment_channel: "bank_transfer",
|
||||
paid_at: new Date("2026-03-10T09:00:00.000Z"),
|
||||
created_at: new Date("2026-03-10T08:00:00.000Z"),
|
||||
updated_at: new Date("2026-03-10T09:00:00.000Z"),
|
||||
travel_request: {
|
||||
id: "travel-1",
|
||||
request_no: "CL-20260310-0001",
|
||||
applicant_employee_id: "employee-1",
|
||||
submitter_id: null,
|
||||
legal_entity: { code: "HY" },
|
||||
cost_center: { code: "CC001" },
|
||||
budget_pool: { code: "POOL-1" },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(payload).toEqual(
|
||||
expect.objectContaining({
|
||||
journalType: "travel_order_payment",
|
||||
sourceEventName: "travel_order.paid",
|
||||
entityType: "travel_order",
|
||||
entityId: "order-1",
|
||||
documentNo: "EXT-001",
|
||||
paymentVoucherNo: "BANK-001",
|
||||
paymentDate: "2026-03-10",
|
||||
paymentChannel: "bank_transfer",
|
||||
dimensions: expect.objectContaining({
|
||||
legalEntityCode: "HY",
|
||||
costCenterCode: "CC001",
|
||||
budgetPoolCode: "POOL-1",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("builds stable travel-order dedupe key", () => {
|
||||
expect(buildTravelOrderPaymentJournalDedupeKey("order-1")).toBe("travel_order:order-1:paid");
|
||||
});
|
||||
|
||||
it("builds preview with current binding and outbox state", async () => {
|
||||
const prisma = {
|
||||
integrationBinding: {
|
||||
findUnique: vi.fn().mockResolvedValue({
|
||||
id: "binding-1",
|
||||
provider: "erp",
|
||||
entity_type: "travel_order_payment_journal",
|
||||
local_id: "order-1",
|
||||
external_id: "erp-1",
|
||||
external_code: "EXT-001",
|
||||
last_synced_at: new Date("2026-03-10T10:00:00.000Z"),
|
||||
}),
|
||||
},
|
||||
integrationOutbox: {
|
||||
findFirst: vi.fn().mockResolvedValue({
|
||||
id: "outbox-1",
|
||||
event_type: "erp.journal.export",
|
||||
status: "succeeded",
|
||||
last_error: null,
|
||||
processed_at: new Date("2026-03-10T10:00:00.000Z"),
|
||||
updated_at: new Date("2026-03-10T10:00:00.000Z"),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const preview = await buildTravelOrderPaymentJournalPreview(prisma, {
|
||||
id: "order-1",
|
||||
source: "ctrip",
|
||||
external_order_no: "EXT-001",
|
||||
employee_id: "employee-1",
|
||||
department_id: "dept-1",
|
||||
linked_reimbursement_id: null,
|
||||
travel_request_id: "travel-1",
|
||||
amount: "500.00",
|
||||
currency: "CNY",
|
||||
payment_voucher_no: "BANK-001",
|
||||
payment_date: new Date("2026-03-10T00:00:00.000Z"),
|
||||
payment_channel: "bank_transfer",
|
||||
paid_at: new Date("2026-03-10T09:00:00.000Z"),
|
||||
created_at: new Date("2026-03-10T08:00:00.000Z"),
|
||||
updated_at: new Date("2026-03-10T09:00:00.000Z"),
|
||||
travel_request: {
|
||||
id: "travel-1",
|
||||
request_no: "CL-20260310-0001",
|
||||
applicant_employee_id: "employee-1",
|
||||
submitter_id: null,
|
||||
legal_entity: { code: "HY" },
|
||||
cost_center: { code: "CC001" },
|
||||
budget_pool: { code: "POOL-1" },
|
||||
},
|
||||
});
|
||||
|
||||
expect(preview.exportState).toEqual(
|
||||
expect.objectContaining({
|
||||
externalId: "erp-1",
|
||||
lastOutboxId: "outbox-1",
|
||||
lastOutboxStatus: "succeeded",
|
||||
}),
|
||||
);
|
||||
expect(preview.binding).toEqual(expect.objectContaining({ localId: "order-1" }));
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户