149 行
3.7 KiB
JavaScript
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'],
|
|
});
|
|
});
|
|
});
|