234 lines
7.0 KiB
JavaScript
234 lines
7.0 KiB
JavaScript
const { GraphQLClient } = require("graphql-request");
|
|
const queries = require("../graphql-client/queries");
|
|
const CreateRRLogEvent = require("./rr-logger-event");
|
|
const { extractRRXmlPair } = require("./rr-log-xml");
|
|
|
|
/** Get bearer token from the socket (same approach used elsewhere) */
|
|
const getAuthToken = (socket) =>
|
|
(socket?.data && socket.data.authToken) || (socket?.handshake?.auth && socket.handshake.auth.token) || null;
|
|
|
|
/** Compact metadata for RR */
|
|
const buildRRExportMeta = ({ result, extra = {} }) => {
|
|
const tx = result?.statusBlocks?.transaction;
|
|
const rawRoStatus = result?.roStatus || result?.data?.roStatus || null;
|
|
|
|
const roStatus =
|
|
rawRoStatus ||
|
|
(tx
|
|
? {
|
|
status: tx.status ?? tx.Status,
|
|
statusCode: tx.statusCode ?? tx.StatusCode,
|
|
message: tx.message ?? tx.Message
|
|
}
|
|
: null);
|
|
|
|
return {
|
|
provider: "rr",
|
|
success: Boolean(
|
|
result?.success || (roStatus && String(roStatus.status || roStatus.Status).toUpperCase() === "SUCCESS")
|
|
),
|
|
customerNo: result?.customerNo,
|
|
svId: result?.svId,
|
|
roStatus: roStatus && {
|
|
status: roStatus.status ?? roStatus.Status,
|
|
statusCode: roStatus.statusCode ?? roStatus.StatusCode,
|
|
message: roStatus.message ?? roStatus.Message
|
|
},
|
|
statusBlocks: result?.statusBlocks || undefined,
|
|
xml: result?.xml,
|
|
parsed: result?.parsed,
|
|
...extra
|
|
};
|
|
};
|
|
|
|
/** Build a stringified JSON array for the `message` text column */
|
|
const buildMessageJSONString = ({ error, classification, result, fallback }) => {
|
|
const msgs = [];
|
|
|
|
const clean = (v) => {
|
|
if (v == null) return null;
|
|
try {
|
|
const s = String(v).replace(/\s+/g, " ").trim();
|
|
return s.length ? s : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const push = (v) => {
|
|
const s = clean(v);
|
|
if (s && !msgs.includes(s)) msgs.push(s);
|
|
};
|
|
|
|
// Friendly first
|
|
push(classification?.friendlyMessage);
|
|
push(classification?.title);
|
|
|
|
// Error text
|
|
if (error instanceof Error) push(error.message);
|
|
else if (typeof error === "string") push(error);
|
|
else if (error?.message) push(error.message);
|
|
|
|
// RR status message
|
|
push(
|
|
result?.roStatus?.message ??
|
|
result?.roStatus?.Message ??
|
|
result?.statusBlocks?.transaction?.message ??
|
|
result?.statusBlocks?.transaction?.Message
|
|
);
|
|
|
|
// Fallback
|
|
push(fallback || "RR export failed");
|
|
|
|
const arr = msgs.length ? msgs : ["RR export failed"];
|
|
return JSON.stringify(arr);
|
|
};
|
|
|
|
/**
|
|
* Success: mark job exported + (optionally) insert a success log.
|
|
* Uses queries.MARK_JOB_EXPORTED (same shape as Fortellis/PBS).
|
|
* @param {boolean} isEarlyRo - If true, only logs success but does NOT change job status (for early RO creation)
|
|
*/
|
|
const markRRExportSuccess = async ({ socket, jobId, job, bodyshop, result, metaExtra = {}, isEarlyRo = false }) => {
|
|
const endpoint = process.env.GRAPHQL_ENDPOINT;
|
|
if (!endpoint) throw new Error("GRAPHQL_ENDPOINT not configured");
|
|
const token = getAuthToken(socket);
|
|
if (!token) throw new Error("Auth token missing on socket");
|
|
|
|
const client = new GraphQLClient(endpoint, {});
|
|
client.setHeaders({ Authorization: `Bearer ${token}` });
|
|
|
|
const meta = buildRRExportMeta({ result, extra: metaExtra });
|
|
|
|
// For early RO, we only insert a log but do NOT change job status or mark as exported
|
|
if (isEarlyRo) {
|
|
try {
|
|
await client.request(queries.INSERT_EXPORT_LOG, {
|
|
logs: [
|
|
{
|
|
bodyshopid: bodyshop?.id || job?.bodyshop?.id,
|
|
jobid: jobId,
|
|
successful: true,
|
|
useremail: socket?.user?.email || null,
|
|
metadata: meta,
|
|
message: buildMessageJSONString({ result, fallback: "RR early RO created" })
|
|
}
|
|
]
|
|
});
|
|
|
|
CreateRRLogEvent(socket, "INFO", "RR early RO: success log inserted (job status unchanged)", {
|
|
jobId
|
|
});
|
|
} catch (e) {
|
|
CreateRRLogEvent(socket, "ERROR", "RR early RO: failed to insert success log", {
|
|
jobId,
|
|
error: e?.message
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Full export: mark job as exported and insert success log
|
|
const exportedStatus =
|
|
job?.bodyshop?.md_ro_statuses?.default_exported || bodyshop?.md_ro_statuses?.default_exported || "Exported*";
|
|
|
|
try {
|
|
await client.request(queries.MARK_JOB_EXPORTED, {
|
|
jobId,
|
|
job: {
|
|
status: exportedStatus,
|
|
date_exported: new Date()
|
|
},
|
|
log: {
|
|
bodyshopid: bodyshop?.id || job?.bodyshop?.id,
|
|
jobid: jobId,
|
|
successful: true,
|
|
useremail: socket?.user?.email || null,
|
|
metadata: meta,
|
|
message: buildMessageJSONString({ result, fallback: "RR export succeeded" })
|
|
},
|
|
bill: {
|
|
exported: true,
|
|
exported_at: new Date()
|
|
}
|
|
});
|
|
|
|
CreateRRLogEvent(socket, "INFO", "RR export: job marked exported + success log inserted", {
|
|
jobId,
|
|
exportedStatus
|
|
});
|
|
} catch (e) {
|
|
CreateRRLogEvent(socket, "ERROR", "RR export: failed to persist success markers/log", {
|
|
jobId,
|
|
error: e?.message
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Failure: insert failure ExportsLog with `message` as JSON **string** (text column).
|
|
* Uses queries.INSERT_EXPORT_LOG($logs: [exportlog_insert_input!]!).
|
|
*/
|
|
const insertRRFailedExportLog = async ({ socket, jobId, job, bodyshop, error, classification, result }) => {
|
|
const endpoint = process.env.GRAPHQL_ENDPOINT;
|
|
if (!endpoint) throw new Error("GRAPHQL_ENDPOINT not configured");
|
|
|
|
const token = getAuthToken(socket);
|
|
if (!token) throw new Error("Auth token missing on socket");
|
|
|
|
const client = new GraphQLClient(endpoint, {});
|
|
client.setHeaders({ Authorization: `Bearer ${token}` });
|
|
|
|
const { requestXml, responseXml } = extractRRXmlPair(error);
|
|
const xmlFromError =
|
|
requestXml || responseXml
|
|
? {
|
|
...(requestXml ? { request: requestXml } : {}),
|
|
...(responseXml ? { response: responseXml } : {})
|
|
}
|
|
: undefined;
|
|
|
|
const meta = buildRRExportMeta({
|
|
result,
|
|
extra: {
|
|
error: error?.message || String(error),
|
|
classification: classification || undefined,
|
|
...(requestXml ? { requestXml } : {}),
|
|
...(responseXml ? { responseXml } : {}),
|
|
...(xmlFromError && !result?.xml ? { xml: xmlFromError } : {})
|
|
}
|
|
});
|
|
|
|
const message = buildMessageJSONString({
|
|
error,
|
|
classification,
|
|
result,
|
|
fallback: "RR export failed"
|
|
});
|
|
|
|
const entry = {
|
|
bodyshopid: bodyshop?.id || job?.bodyshop?.id,
|
|
jobid: jobId,
|
|
successful: false,
|
|
message, // stringified JSON array
|
|
useremail: socket?.user?.email || null,
|
|
metadata: meta
|
|
};
|
|
|
|
try {
|
|
// Your mutation expects $logs (array). Keep to that signature.
|
|
await client.request(queries.INSERT_EXPORT_LOG, { logs: [entry] });
|
|
CreateRRLogEvent(socket, "INFO", "RR export: failure log inserted", { jobId });
|
|
} catch (e) {
|
|
CreateRRLogEvent(socket, "ERROR", "RR export: failed to insert failure log", {
|
|
jobId,
|
|
error: e?.message
|
|
});
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
markRRExportSuccess,
|
|
insertRRFailedExportLog
|
|
};
|