FL6 完善财务台账与导出审计
这个提交包含在:
@@ -308,7 +308,7 @@ async function listOpenRiskFlagsForBatch(tx, batch) {
|
||||
return items.map(buildPersistedRiskFlag);
|
||||
}
|
||||
|
||||
async function executeReimbursementPayment(tx, { batch, item, actorId, index }) {
|
||||
async function executeReimbursementPayment(tx, { batch, item, actorId, index, request }) {
|
||||
const current = await tx.reimbursementForm.findUnique({
|
||||
where: { id: item.entity_id },
|
||||
select: {
|
||||
@@ -348,11 +348,31 @@ async function executeReimbursementPayment(tx, { batch, item, actorId, index })
|
||||
if (conflict) {
|
||||
throw buildValidationError({ payment: "already_paid_conflict" }, 409);
|
||||
}
|
||||
await tx.auditLog.create({
|
||||
data: buildAuditLogData(request, {
|
||||
actorId,
|
||||
action: "REIMBURSEMENT_PAYMENT_MARKED",
|
||||
targetType: "reimbursement_form",
|
||||
targetId: current.id,
|
||||
extra: {
|
||||
formNumber: current.form_number ?? null,
|
||||
paymentVoucherNo: current.payment_voucher_no ?? null,
|
||||
paymentDate: existingPaymentDate,
|
||||
paymentChannel: current.payment_channel ?? null,
|
||||
paymentNote: null,
|
||||
idempotent: true,
|
||||
archivedInvoiceCount: 0,
|
||||
source: "payment_batch",
|
||||
paymentBatchId: batch.id,
|
||||
paymentBatchItemId: item.id,
|
||||
},
|
||||
}),
|
||||
});
|
||||
return { idempotent: true };
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
await tx.invoicePool.updateMany({
|
||||
const archivedResult = await tx.invoicePool.updateMany({
|
||||
where: { linked_reimbursement_id: item.entity_id, status: "bound" },
|
||||
data: {
|
||||
status: "archived",
|
||||
@@ -373,6 +393,26 @@ async function executeReimbursementPayment(tx, { batch, item, actorId, index })
|
||||
updated_by: actorId,
|
||||
},
|
||||
});
|
||||
await tx.auditLog.create({
|
||||
data: buildAuditLogData(request, {
|
||||
actorId,
|
||||
action: "REIMBURSEMENT_PAYMENT_MARKED",
|
||||
targetType: "reimbursement_form",
|
||||
targetId: current.id,
|
||||
extra: {
|
||||
formNumber: current.form_number ?? null,
|
||||
paymentVoucherNo: voucher,
|
||||
paymentDate,
|
||||
paymentChannel,
|
||||
paymentNote: null,
|
||||
idempotent: false,
|
||||
archivedInvoiceCount: archivedResult.count,
|
||||
source: "payment_batch",
|
||||
paymentBatchId: batch.id,
|
||||
paymentBatchItemId: item.id,
|
||||
},
|
||||
}),
|
||||
});
|
||||
return { idempotent: false };
|
||||
}
|
||||
|
||||
@@ -842,7 +882,13 @@ async function paymentBatchesRoutes(fastify) {
|
||||
|
||||
try {
|
||||
if (batch.entity_type === "reimbursement") {
|
||||
const paymentResult = await executeReimbursementPayment(tx, { batch, item, actorId: request.employee.id, index });
|
||||
const paymentResult = await executeReimbursementPayment(tx, {
|
||||
batch,
|
||||
item,
|
||||
actorId: request.employee.id,
|
||||
index,
|
||||
request,
|
||||
});
|
||||
if (!paymentResult.idempotent) {
|
||||
successfulReimbursementIds.push(item.entity_id);
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户