文件
hyb-oa/server/tests/unit/routes/assets.erp.test.js
T

149 行
3.7 KiB
JavaScript

const assetsRoutes = require('../../../src/routes/assets');
const { resolveAssetLedgerSummaryChange } = require('../../../src/services/integrations/erpAsset');
describe('asset ERP helper', () => {
const { handleAssetLedgerSummaryErpSync } = assetsRoutes.__testables;
function createRequest() {
return {
id: 'req-1',
ip: '127.0.0.1',
headers: {},
employee: {
id: 'actor-1',
permissionCodes: ['asset.manage'],
},
};
}
function createTx() {
return {
auditLog: {
create: vi.fn().mockResolvedValue({ id: 'audit-1' }),
},
};
}
function createAsset(overrides = {}) {
return {
id: 'asset-1',
asset_no: 'ZC-001',
legal_entity_id: 'le-1',
cost_center_id: 'cc-1',
status: 'in_use',
...overrides,
};
}
it('auto enqueues asset export when gate is enabled', async () => {
const tx = createTx();
const evaluateGate = vi.fn().mockResolvedValue({
enabled: true,
reason: 'department_deferred',
});
const enqueueExport = vi.fn().mockResolvedValue({
id: 'outbox-1',
status: 'pending',
duplicated: false,
requeued: false,
eventType: 'erp.asset.export',
});
const result = await handleAssetLedgerSummaryErpSync({
tx,
config: {},
request: createRequest(),
actorId: 'actor-1',
asset: createAsset(),
sourceEventName: 'asset.card.created',
changeType: 'created',
changedFields: [],
evaluateGate,
enqueueExport,
});
expect(enqueueExport).toHaveBeenCalledWith(
tx,
{},
expect.objectContaining({
actorId: 'actor-1',
requeueOnFailure: false,
}),
);
expect(tx.auditLog.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
action: 'ERP_SYNC_ENQUEUED',
target_type: 'asset_card',
target_id: 'asset-1',
}),
}),
);
expect(result.skipped).toBe(false);
});
it('writes skip audit when asset ERP gate is disabled', async () => {
const tx = createTx();
const evaluateGate = vi.fn().mockResolvedValue({ enabled: false, reason: 'flag_force_off' });
const enqueueExport = vi.fn();
const result = await handleAssetLedgerSummaryErpSync({
tx,
config: {},
request: createRequest(),
actorId: 'actor-1',
asset: createAsset(),
sourceEventName: 'asset.card.created',
changeType: 'created',
changedFields: [],
evaluateGate,
enqueueExport,
});
expect(enqueueExport).not.toHaveBeenCalled();
expect(tx.auditLog.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
action: 'ERP_SYNC_SKIPPED_BY_FEATURE_FLAG',
target_type: 'asset_card',
target_id: 'asset-1',
}),
}),
);
expect(result.skipped).toBe(true);
});
it('only marks financial field and retired status changes as ERP-relevant', () => {
const current = createAsset();
expect(
resolveAssetLedgerSummaryChange(current, {
...current,
name: '新资产名称',
}),
).toBeNull();
expect(
resolveAssetLedgerSummaryChange(current, {
...current,
legal_entity_id: 'le-2',
}),
).toEqual({
sourceEventName: 'asset.ledger.summary.updated',
changeType: 'financial_dimensions_changed',
changedFields: ['legalEntityId'],
});
expect(
resolveAssetLedgerSummaryChange(current, {
...current,
status: 'retired',
}),
).toEqual({
sourceEventName: 'asset.ledger.summary.updated',
changeType: 'retired',
changedFields: ['status'],
});
});
});