test: use active suppliers for finance fixtures
This commit is contained in:
@@ -27,6 +27,15 @@ export function normalizeFinanceFixtureSources(sources, orders, allocations, cus
|
||||
})
|
||||
}
|
||||
|
||||
export function supplierCategoryForFeeItem(item) {
|
||||
const value = `${item?.feeCode ?? item?.code ?? ''} ${item?.feeName ?? item?.name ?? ''}`.toUpperCase()
|
||||
if (['TRUCK', 'TRAILER', 'DRAYAGE', '拖车', '卡车'].some((candidate) => value.includes(candidate))) return 'TRUCKING'
|
||||
if (['CUSTOMS', 'CLEARANCE', 'DECLARATION', '报关', '清关'].some((candidate) => value.includes(candidate))) return 'CUSTOMS'
|
||||
if (['CERTIFICATE', 'CERTIFICATION', 'CERT_', '认证', '证书'].some((candidate) => value.includes(candidate))) return 'CERTIFICATE'
|
||||
if (['BOOKING', 'FREIGHT', 'OCEAN', 'SHIPPING', '订舱', '海运', '运费'].some((candidate) => value.includes(candidate))) return 'BOOKING'
|
||||
return null
|
||||
}
|
||||
|
||||
async function createOrder(context, suffix, pricingProfile = null) {
|
||||
if (context.financeFixtureHooks?.createOrder) return context.financeFixtureHooks.createOrder(context, suffix, pricingProfile)
|
||||
const originalMarker = context.marker
|
||||
@@ -124,7 +133,7 @@ async function loadFeeItem(context, direction) {
|
||||
const list = context.apiSuccess(MODULE, `查询${direction}人工费用项目`, response, '', OPTIONS)
|
||||
return rows(list).find((item) => item?.status === 'ACTIVE' && (direction === 'RECEIVABLE'
|
||||
? item.warehouseReceivable === true
|
||||
: item.warehousePayable === true)) || null
|
||||
: item.warehousePayable === true && Boolean(supplierCategoryForFeeItem(item)))) || null
|
||||
}
|
||||
|
||||
async function createManualFee(context, resource, feeItem, direction, amount, basis, businessDate, partner = null) {
|
||||
@@ -218,11 +227,13 @@ async function loadPublishedAutomaticFee(context, resource) {
|
||||
actualWeightKg: responseWeightKg, actualVolumeCbm: responseVolumeCbm }
|
||||
}
|
||||
|
||||
async function loadSupplier(context) {
|
||||
if (context.financeFixtureHooks?.loadSupplier) return context.financeFixtureHooks.loadSupplier(context)
|
||||
const response = await context.request('GET', '/api/platform/v1/suppliers?page=1&size=200&status=ACTIVE&category=BOOKING')
|
||||
const page = context.apiSuccess(MODULE, '查询 Warehouse ACTIVE 订舱供应商', response, 'category=BOOKING', OPTIONS)
|
||||
return rows(page).find((item) => item?.status === 'ACTIVE' && item?.category === 'BOOKING') || null
|
||||
async function loadSupplier(context, category) {
|
||||
if (context.financeFixtureHooks?.loadSupplier) return context.financeFixtureHooks.loadSupplier(context, category)
|
||||
if (!category) return null
|
||||
const path = `/api/platform/v1/suppliers?page=1&size=200&status=ACTIVE&category=${encodeURIComponent(category)}`
|
||||
const response = await context.request('GET', path)
|
||||
const page = context.apiSuccess(MODULE, '查询 Warehouse ACTIVE 费用类别供应商', response, `category=${category}`, OPTIONS)
|
||||
return rows(page).find((item) => item?.status === 'ACTIVE' && item?.category === category && item?.id && item?.name) || null
|
||||
}
|
||||
|
||||
async function uploadVoucher(context, customerId) {
|
||||
@@ -370,8 +381,10 @@ export async function run(context) {
|
||||
RECEIVABLE: await loadFeeItem(context, 'RECEIVABLE'),
|
||||
PAYABLE: await loadFeeItem(context, 'PAYABLE'),
|
||||
}
|
||||
const supplier = await loadSupplier(context)
|
||||
if (!supplier?.id) blocker(context, '取得 Warehouse PAYABLE 供应商', '未找到 ACTIVE BOOKING 供应商;不能伪造 supplierId/partnerId')
|
||||
const payableSupplierCategory = supplierCategoryForFeeItem(feeItems.PAYABLE)
|
||||
const supplier = await loadSupplier(context, payableSupplierCategory)
|
||||
if (!supplier?.id) blocker(context, '取得 Warehouse PAYABLE 供应商',
|
||||
`未找到 ACTIVE ${payableSupplierCategory || 'SUPPORTED'} 供应商或匹配正式类别的 PAYABLE 费用项;不能伪造 supplierId/partnerId`)
|
||||
for (const direction of ['RECEIVABLE', 'PAYABLE']) {
|
||||
if (!feeItems[direction]) context.addCoverageGap(MODULE, `missing-${direction.toLowerCase()}-fee-item`, `${direction} 人工费用 fixture`,
|
||||
`没有找到带 warehouse${direction === 'RECEIVABLE' ? 'Receivable' : 'Payable'}=true 的 ACTIVE 费用项目,禁止猜测费用项目 ID`, 'missing-deployed-fee-item')
|
||||
@@ -400,7 +413,8 @@ export async function run(context) {
|
||||
for (const [index, manualResource] of manualResources.entries()) {
|
||||
const fee = await createManualFee(context, manualResource, feeItems.PAYABLE, 'PAYABLE', 80 + index * 10,
|
||||
'MANUAL_ORDER_FEE', dateOffset(-3 - index), supplier)
|
||||
if (fee) fixtures.push({ ...fee, supplierId: id(supplier.id), partnerId: id(supplier.id), supplierName: supplier.name || null })
|
||||
if (fee) fixtures.push({ ...fee, supplierId: id(supplier.id), partnerId: id(supplier.id),
|
||||
supplierName: supplier.name || null, supplierCategory: supplier.category || payableSupplierCategory })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +440,7 @@ export async function run(context) {
|
||||
containerFixture = { feeSourceId: feeId || null, sourceType: 'MANUAL', direction: 'PAYABLE', amount: 300,
|
||||
businessDate: body.businessDate, currency: 'CNY', billingBasis: 'CONTAINER_SHARED',
|
||||
supplierId: supplier?.id ? id(supplier.id) : null, partnerId: supplier?.id ? id(supplier.id) : null,
|
||||
supplierName: supplier?.name || null, supplierCategory: supplier?.category || payableSupplierCategory,
|
||||
containerBookingId: id(container.containerBookingId), containerNo: container.containerNo || null,
|
||||
loadingPlanId: id(container.loadingPlanId) }
|
||||
} else {
|
||||
@@ -463,7 +478,9 @@ export async function run(context) {
|
||||
businessDate: fixtures.find((fee) => fee.orderId === id(item.orderId))?.businessDate || null }))
|
||||
const fixtureSources = normalizeFinanceFixtureSources(fixtures, fixtureOrders, allocations, customerId, context.marker)
|
||||
const invalidFixtureSources = fixtureSources.filter((source) => !source.feeSourceId || !source.customerId
|
||||
|| !source.businessDate || !(source.waybillId || source.shipmentId || source.orderNo) || source.marker !== context.marker)
|
||||
|| !source.businessDate || !(source.waybillId || source.shipmentId || source.orderNo) || source.marker !== context.marker
|
||||
|| (source.direction === 'PAYABLE' && (!source.supplierId || !source.supplierName
|
||||
|| source.supplierCategory !== payableSupplierCategory)))
|
||||
context.assert(MODULE, '输出完整 Finance 来源契约', null, invalidFixtureSources.length === 0,
|
||||
`sources=${fixtureSources.length}, invalid=${invalidFixtureSources.length};字段必须来自本轮费用来源、客户、订单/运单和真实柜次分摊`, OPTIONS)
|
||||
context.createdResources.financeFullFixtures = {
|
||||
@@ -480,7 +497,8 @@ export async function run(context) {
|
||||
feeSources: fixtureSources,
|
||||
container: containerFixture ? { containerBookingId: containerFixture.containerBookingId,
|
||||
containerNo: containerFixture.containerNo } : { containerBookingId: null, containerNo: null },
|
||||
allocations, supplier: supplier?.id ? { supplierId: id(supplier.id), partnerId: id(supplier.id), supplierName: supplier.name || null } : null,
|
||||
allocations, supplier: supplier?.id ? { supplierId: id(supplier.id), partnerId: id(supplier.id),
|
||||
supplierName: supplier.name || null, category: supplier.category || payableSupplierCategory } : null,
|
||||
voucherFileId, pricingEvidence,
|
||||
deploymentBlocker: context.steps.slice(start).filter((step) => step.deploymentBlocker).map((step) => step.evidence),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user