feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration Translations / Export Logs
This commit is contained in:
@@ -192,25 +192,31 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
|
|
||||||
{dms === "rr" && (
|
{dms === "rr" && (
|
||||||
<>
|
<>
|
||||||
{/* Advisor + inline Refresh (restores original behavior with better UX) */}
|
{/* Advisor + inline Refresh (binding fixed via inner noStyle Form.Item) */}
|
||||||
<Col xs={24} sm={24} md={12} lg={8}>
|
<Col xs={24} sm={24} md={12} lg={8}>
|
||||||
<Form.Item name="advisorNo" label={t("jobs.fields.dms.advisor")} rules={[{ required: true }]}>
|
<Form.Item label={t("jobs.fields.dms.advisor")} required>
|
||||||
<Space.Compact block>
|
<Space.Compact block>
|
||||||
<Select
|
<Form.Item
|
||||||
style={{ flex: 1 }}
|
name="advisorNo"
|
||||||
loading={advLoading}
|
noStyle
|
||||||
allowClear
|
rules={[{ required: true, message: t("general.validation.required") }]}
|
||||||
placeholder={t("general.actions.select", "Select...")}
|
>
|
||||||
popupMatchSelectWidth
|
<Select
|
||||||
options={advisors
|
style={{ flex: 1 }}
|
||||||
.map((a) => {
|
loading={advLoading}
|
||||||
const value = getAdvisorNumber(a);
|
allowClear
|
||||||
if (value == null) return null;
|
placeholder={t("general.actions.select", "Select...")}
|
||||||
return { value: String(value), label: getAdvisorLabel(a) || String(value) };
|
popupMatchSelectWidth
|
||||||
})
|
options={advisors
|
||||||
.filter(Boolean)}
|
.map((a) => {
|
||||||
notFoundContent={advLoading ? t("general.loading") : t("general.none")}
|
const value = getAdvisorNumber(a);
|
||||||
/>
|
if (value == null) return null;
|
||||||
|
return { value: String(value), label: getAdvisorLabel(a) || String(value) };
|
||||||
|
})
|
||||||
|
.filter(Boolean)}
|
||||||
|
notFoundContent={advLoading ? t("general.labels.loading") : t("general.labels.none")}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
<Tooltip title={t("general.actions.refresh")}>
|
<Tooltip title={t("general.actions.refresh")}>
|
||||||
<Button
|
<Button
|
||||||
aria-label={t("general.actions.refresh")}
|
aria-label={t("general.actions.refresh")}
|
||||||
@@ -336,12 +342,12 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
style={{ marginBottom: 12 }}
|
style={{ marginBottom: 12 }}
|
||||||
title={`${t("jobs.fields.dms.payer.payer_type")} #${index + 1}`}
|
title={`${t("jobs.fields.dms.payer.payer_type")} #${index + 1}`}
|
||||||
extra={
|
extra={
|
||||||
<Tooltip title={t("jobs.actions.remove", "Remove")}>
|
<Tooltip title={t("general.actions.remove", "Remove")}>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteFilled />}
|
icon={<DeleteFilled />}
|
||||||
aria-label={t("jobs.actions.remove", "Remove")}
|
aria-label={t("general.actions.remove", "Remove")}
|
||||||
onClick={() => remove(field.name)}
|
onClick={() => remove(field.name)}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -405,7 +411,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
})) ?? []
|
})) ?? []
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Anchor trigger restored (was missing) */}
|
{/* Anchor trigger */}
|
||||||
<a href="#" onClick={(e) => e.preventDefault()}>
|
<a href="#" onClick={(e) => e.preventDefault()}>
|
||||||
<DownOutlined />
|
<DownOutlined />
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1035,7 +1035,7 @@
|
|||||||
"alreadyexported": "This job has already been sent to the DMS. If you need to resend it, please use admin permissions to mark the job for re-export."
|
"alreadyexported": "This job has already been sent to the DMS. If you need to resend it, please use admin permissions to mark the job for re-export."
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"refreshallocations": "Refresh to see DMS Allocataions."
|
"refreshallocations": "Refresh to see DMS Allocations."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"documents": {
|
"documents": {
|
||||||
@@ -1212,6 +1212,7 @@
|
|||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"select": "Select",
|
||||||
"optional": "Optional",
|
"optional": "Optional",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"autoupdate": "{{app}} will automatically update in {{time}} seconds. Please save all changes.",
|
"autoupdate": "{{app}} will automatically update in {{time}} seconds. Please save all changes.",
|
||||||
@@ -1855,7 +1856,7 @@
|
|||||||
"loss_of_use": "Loss of Use",
|
"loss_of_use": "Loss of Use",
|
||||||
"lost_sale_reason": "Lost Sale Reason",
|
"lost_sale_reason": "Lost Sale Reason",
|
||||||
"ma2s": "2 Stage Paint",
|
"ma2s": "2 Stage Paint",
|
||||||
"ma3s": "3 Stage Pain",
|
"ma3s": "3 Stage Paint",
|
||||||
"mabl": "MABL?",
|
"mabl": "MABL?",
|
||||||
"macs": "MACS?",
|
"macs": "MACS?",
|
||||||
"mahw": "Hazardous Waste",
|
"mahw": "Hazardous Waste",
|
||||||
|
|||||||
@@ -1772,6 +1772,8 @@
|
|||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
"dms_model_override": "",
|
"dms_model_override": "",
|
||||||
|
"make_override": "",
|
||||||
|
"advisor": "",
|
||||||
"dms_unsold": "",
|
"dms_unsold": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
|
|||||||
@@ -1772,6 +1772,8 @@
|
|||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
"dms_model_override": "",
|
"dms_model_override": "",
|
||||||
|
"make_override": "",
|
||||||
|
"advisor": "",
|
||||||
"dms_unsold": "",
|
"dms_unsold": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// File: server/rr/rr-export-logs.js
|
|
||||||
// Mark job exported + insert export logs (success/failure) for Reynolds, mirroring Fortellis/PBS.
|
|
||||||
|
|
||||||
const { GraphQLClient } = require("graphql-request");
|
const { GraphQLClient } = require("graphql-request");
|
||||||
const queries = require("../graphql-client/queries");
|
const queries = require("../graphql-client/queries");
|
||||||
const CreateRRLogEvent = require("./rr-logger-event");
|
const CreateRRLogEvent = require("./rr-logger-event");
|
||||||
@@ -10,11 +7,9 @@ function getAuthToken(socket) {
|
|||||||
return (socket?.data && socket.data.authToken) || (socket?.handshake?.auth && socket.handshake.auth.token) || null;
|
return (socket?.data && socket.data.authToken) || (socket?.handshake?.auth && socket.handshake.auth.token) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a compact ExportsLog metadata object for RR */
|
/** Compact metadata for RR */
|
||||||
function buildRRExportMeta({ result, extra = {} }) {
|
function buildRRExportMeta({ result, extra = {} }) {
|
||||||
// Avoid gigantic payloads; keep the useful bits
|
|
||||||
const roStatus = result?.roStatus || result?.data?.roStatus || null;
|
const roStatus = result?.roStatus || result?.data?.roStatus || null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
provider: "rr",
|
provider: "rr",
|
||||||
success: Boolean(result?.success || roStatus?.status === "Success"),
|
success: Boolean(result?.success || roStatus?.status === "Success"),
|
||||||
@@ -32,8 +27,46 @@ function buildRRExportMeta({ result, extra = {} }) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Build a stringified JSON array for the `message` text column */
|
||||||
|
function 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);
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
push(fallback || "RR export failed");
|
||||||
|
|
||||||
|
const arr = msgs.length ? msgs : ["RR export failed"];
|
||||||
|
return JSON.stringify(arr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Success path: mark job exported + insert success ExportsLog w/ metadata.
|
* Success: mark job exported + (optionally) insert a success log.
|
||||||
* Uses queries.MARK_JOB_EXPORTED (same shape as Fortellis/PBS).
|
* Uses queries.MARK_JOB_EXPORTED (same shape as Fortellis/PBS).
|
||||||
*/
|
*/
|
||||||
async function markRRExportSuccess({ socket, jobId, job, bodyshop, result, metaExtra = {} }) {
|
async function markRRExportSuccess({ socket, jobId, job, bodyshop, result, metaExtra = {} }) {
|
||||||
@@ -62,7 +95,8 @@ async function markRRExportSuccess({ socket, jobId, job, bodyshop, result, metaE
|
|||||||
jobid: jobId,
|
jobid: jobId,
|
||||||
successful: true,
|
successful: true,
|
||||||
useremail: socket?.user?.email || null,
|
useremail: socket?.user?.email || null,
|
||||||
metadata: meta
|
metadata: meta,
|
||||||
|
message: buildMessageJSONString({ result, fallback: "RR export succeeded" })
|
||||||
},
|
},
|
||||||
bill: {
|
bill: {
|
||||||
exported: true,
|
exported: true,
|
||||||
@@ -75,7 +109,6 @@ async function markRRExportSuccess({ socket, jobId, job, bodyshop, result, metaE
|
|||||||
exportedStatus
|
exportedStatus
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Non-fatal: export already succeeded; just surface the DB log failure
|
|
||||||
CreateRRLogEvent(socket, "ERROR", "RR export: failed to persist success markers/log", {
|
CreateRRLogEvent(socket, "ERROR", "RR export: failed to persist success markers/log", {
|
||||||
jobId,
|
jobId,
|
||||||
error: e?.message
|
error: e?.message
|
||||||
@@ -84,8 +117,8 @@ async function markRRExportSuccess({ socket, jobId, job, bodyshop, result, metaE
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Failure path: insert failure ExportsLog (no job status flip).
|
* Failure: insert failure ExportsLog with `message` as JSON **string** (text column).
|
||||||
* Uses queries.INSERT_EXPORT_LOG (same shape as Fortellis/PBS).
|
* Uses queries.INSERT_EXPORT_LOG($logs: [exportlog_insert_input!]!).
|
||||||
*/
|
*/
|
||||||
async function insertRRFailedExportLog({ socket, jobId, job, bodyshop, error, classification, result }) {
|
async function insertRRFailedExportLog({ socket, jobId, job, bodyshop, error, classification, result }) {
|
||||||
const endpoint = process.env.GRAPHQL_ENDPOINT;
|
const endpoint = process.env.GRAPHQL_ENDPOINT;
|
||||||
@@ -104,21 +137,27 @@ async function insertRRFailedExportLog({ socket, jobId, job, bodyshop, error, cl
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
const message = buildMessageJSONString({
|
||||||
await client.request(queries.INSERT_EXPORT_LOG, {
|
error,
|
||||||
log: {
|
classification,
|
||||||
bodyshopid: bodyshop?.id || job?.bodyshop?.id,
|
result,
|
||||||
jobid: jobId,
|
fallback: "RR export failed"
|
||||||
successful: false,
|
});
|
||||||
message: error?.message || String(error),
|
|
||||||
useremail: socket?.user?.email || null,
|
|
||||||
metadata: meta
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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 });
|
CreateRRLogEvent(socket, "INFO", "RR export: failure log inserted", { jobId });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Best-effort; don't throw
|
|
||||||
CreateRRLogEvent(socket, "ERROR", "RR export: failed to insert failure log", {
|
CreateRRLogEvent(socket, "ERROR", "RR export: failed to insert failure log", {
|
||||||
jobId,
|
jobId,
|
||||||
error: e?.message
|
error: e?.message
|
||||||
|
|||||||
Reference in New Issue
Block a user