feat(P19ERP3-1,P19ERP3-2): 实现资产ERP摘要服务与建卡/流转出站联动

这个提交包含在:
2026-03-09 11:15:21 +08:00
父节点 7613d7d912
当前提交 0168ebfe2e
共修改 10 个文件,包含 1128 行新增和 4 行删除
+120
查看文件
@@ -4,6 +4,12 @@ const { AppError } = require("../utils/AppError");
const { buildAuditLogData } = require("../utils/audit");
const { parseDateOnlyString } = require("../utils/date");
const { issueDocumentNumber } = require("../services/documentSequence");
const { FEATURE_FLAG_KEYS, evaluateFeatureFlag } = require('../services/featureFlags');
const {
ASSET_ERP_TARGET,
enqueueAssetLedgerSummaryExport,
resolveAssetLedgerSummaryChange,
} = require('../services/integrations/erpAsset');
const { sendData } = require("../utils/reply");
const UUID_SCHEMA = z.string().uuid();
@@ -557,6 +563,92 @@ async function ensureApprovedPurchaseRequest(tx, purchaseRequestId) {
return record;
}
async function handleAssetLedgerSummaryErpSync({
tx,
config,
request,
actorId,
asset,
sourceEventName,
changeType,
changedFields,
evaluateGate = evaluateFeatureFlag,
enqueueExport = enqueueAssetLedgerSummaryExport,
}) {
const gate = await evaluateGate({
prisma: tx,
config,
flagKey: FEATURE_FLAG_KEYS.erpSync,
departmentId: null,
strictDepartment: false,
});
if (!gate.enabled) {
await tx.auditLog.create({
data: buildAuditLogData(request, {
actorId,
action: 'ERP_SYNC_SKIPPED_BY_FEATURE_FLAG',
targetType: 'asset_card',
targetId: asset.id,
extra: {
erpTarget: ASSET_ERP_TARGET,
eventType: 'erp.asset.export',
assetId: asset.id,
assetNo: asset.asset_no,
changeType,
gateReason: gate.reason,
featureFlag: FEATURE_FLAG_KEYS.erpSync,
},
}),
});
return {
skipped: true,
gate,
asset,
};
}
const enqueued = await enqueueExport(tx, config, {
asset,
sourceEventName,
changeType,
changedFields,
occurredAt: new Date(),
actorId,
requeueOnFailure: false,
});
await tx.auditLog.create({
data: buildAuditLogData(request, {
actorId,
action: 'ERP_SYNC_ENQUEUED',
targetType: 'asset_card',
targetId: asset.id,
extra: {
erpTarget: ASSET_ERP_TARGET,
eventType: enqueued.eventType,
assetId: asset.id,
assetNo: asset.asset_no,
outboxId: enqueued.id,
duplicated: enqueued.duplicated,
requeued: enqueued.requeued,
changeType,
changedFields: Array.isArray(changedFields) ? changedFields : [],
gateReason: gate.reason,
featureFlag: FEATURE_FLAG_KEYS.erpSync,
},
}),
});
return {
skipped: false,
gate,
asset,
enqueued,
};
}
async function assetsRoutes(fastify) {
fastify.get(
"/asset-categories",
@@ -843,6 +935,17 @@ async function assetsRoutes(fastify) {
}),
});
await handleAssetLedgerSummaryErpSync({
tx,
config: fastify.config,
request,
actorId: request.employee.id,
asset: created,
sourceEventName: 'asset.card.created',
changeType: 'created',
changedFields: [],
});
return created;
});
@@ -953,6 +1056,20 @@ async function assetsRoutes(fastify) {
}),
});
const assetLedgerSummaryChange = resolveAssetLedgerSummaryChange(current, updated);
if (assetLedgerSummaryChange) {
await handleAssetLedgerSummaryErpSync({
tx,
config: fastify.config,
request,
actorId: request.employee.id,
asset: updated,
sourceEventName: assetLedgerSummaryChange.sourceEventName,
changeType: assetLedgerSummaryChange.changeType,
changedFields: assetLedgerSummaryChange.changedFields,
});
}
return updated;
});
@@ -962,3 +1079,6 @@ async function assetsRoutes(fastify) {
}
module.exports = assetsRoutes;
module.exports.__testables = {
handleAssetLedgerSummaryErpSync,
};