fix(detail-page-structure-progress-actions): 收敛操作面板定位并补充制单诊断
这个提交包含在:
@@ -1675,6 +1675,12 @@ async function paymentBatchesRoutes(fastify) {
|
||||
const resultCode = error instanceof PaymentOrderXlsError
|
||||
? error.code
|
||||
: error?.details?.status ?? error?.code ?? "export_failed";
|
||||
if (error instanceof PaymentOrderXlsError && error.diagnostic) {
|
||||
fastify.log.error(
|
||||
{ diagnostic: error.diagnostic, requestId: request.id },
|
||||
"payment order generator unavailable",
|
||||
);
|
||||
}
|
||||
await fastify.prisma.auditLog.create({
|
||||
data: buildAuditLogData(request, {
|
||||
actorId: request.employee.id,
|
||||
|
||||
@@ -4,14 +4,23 @@ const { spawnSync } = require("node:child_process");
|
||||
const { decryptStringOrThrow } = require("./crypto");
|
||||
|
||||
class PaymentOrderXlsError extends Error {
|
||||
constructor(code, details = {}) {
|
||||
constructor(code, details = {}, diagnostic = null) {
|
||||
super(code);
|
||||
this.name = "PaymentOrderXlsError";
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
if (diagnostic) {
|
||||
Object.defineProperty(this, "diagnostic", {
|
||||
value: diagnostic,
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PAYMENT_ORDER_RUNTIME_DIAGNOSTIC =
|
||||
"BIFF8 运行时不可用:请安装 server/requirements/payment-order-biff8.txt 中的固定依赖,并通过 PAYMENT_ORDER_PYTHON_BIN 指定 Python 可执行文件。";
|
||||
|
||||
function buildCustomerSerial(batchNo, rowNumber) {
|
||||
const serial = `${String(batchNo).trim()}-R${String(rowNumber).padStart(3, "0")}`;
|
||||
if (serial.length > 32) {
|
||||
@@ -177,10 +186,13 @@ function mapTemplateProcessError(result) {
|
||||
const matched = stderr.match(/^\[payment-order-template\]\[ERROR\] ([a-z_]+)\s*$/);
|
||||
const internalCode = matched && PYTHON_ERROR_CODES.has(matched[1]) ? matched[1] : "process_failed";
|
||||
if (internalCode === "runtime_dependency_unavailable" || result?.error?.code === "ENOENT") {
|
||||
return "payment_order_generator_unavailable";
|
||||
return {
|
||||
code: "payment_order_generator_unavailable",
|
||||
diagnostic: PAYMENT_ORDER_RUNTIME_DIAGNOSTIC,
|
||||
};
|
||||
}
|
||||
if (internalCode.startsWith("template_")) return "payment_order_template_unavailable";
|
||||
return "payment_order_generation_failed";
|
||||
if (internalCode.startsWith("template_")) return { code: "payment_order_template_unavailable" };
|
||||
return { code: "payment_order_generation_failed" };
|
||||
}
|
||||
|
||||
function generatePaymentOrderXls(config, batch, options = {}) {
|
||||
@@ -201,7 +213,8 @@ function generatePaymentOrderXls(config, batch, options = {}) {
|
||||
},
|
||||
});
|
||||
if (result.status !== 0 || result.error || !Buffer.isBuffer(result.stdout)) {
|
||||
throw new PaymentOrderXlsError(mapTemplateProcessError(result));
|
||||
const mappedError = mapTemplateProcessError(result);
|
||||
throw new PaymentOrderXlsError(mappedError.code, {}, mappedError.diagnostic);
|
||||
}
|
||||
const buffer = result.stdout;
|
||||
if (buffer.length > maxBuffer || buffer.subarray(0, 8).toString("hex") !== "d0cf11e0a1b11ae1") {
|
||||
|
||||
在新工单中引用
屏蔽一个用户