sendmaterialscosting
false
diff --git a/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx b/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx
index 966cadf13..3445c88c1 100644
--- a/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx
+++ b/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx
@@ -92,6 +92,7 @@ export function DmsAllocationsSummary({ socket, bodyshop, jobId, title }) {
rowKey="center"
dataSource={allocationsSummary}
locale={{ emptyText: t("dms.labels.refreshallocations") }}
+ scroll={{ x: true }}
summary={() => {
const totals =
allocationsSummary &&
diff --git a/client/src/components/job-detail-cards/job-detail-cards.parts.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.parts.component.jsx
index 9f3c32820..949d42eae 100644
--- a/client/src/components/job-detail-cards/job-detail-cards.parts.component.jsx
+++ b/client/src/components/job-detail-cards/job-detail-cards.parts.component.jsx
@@ -90,7 +90,7 @@ export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})) ||
@@ -103,7 +103,7 @@ export function JobDetailCardsPartsComponent({ loading, data, jobRO }) {
);
diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx
index 2cadcf4e8..02dd2cda6 100644
--- a/client/src/components/job-detail-lines/job-lines.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines.component.jsx
@@ -318,7 +318,7 @@ export function JobLinesComponent({
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})) ||
diff --git a/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
index 8fbee411c..c7cc3a115 100644
--- a/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
+++ b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
@@ -1,8 +1,9 @@
import { useMemo } from "react";
-import { Col, Row, Tag, Tooltip } from "antd";
+import { Tag, Tooltip } from "antd";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
+import { useTranslation } from "react-i18next";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -11,65 +12,67 @@ const mapDispatchToProps = () => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
-export const DEFAULT_COL_LAYOUT = { xs: 24, sm: 24, md: 8, lg: 4, xl: 4, xxl: 4 };
-
export default connect(mapStateToProps, mapDispatchToProps)(JobPartsQueueCount);
-export function JobPartsQueueCount({ bodyshop, parts, defaultColLayout = DEFAULT_COL_LAYOUT }) {
+export function JobPartsQueueCount({ bodyshop, parts }) {
+ const { t } = useTranslation();
const partsStatus = useMemo(() => {
if (!parts) return null;
+ const statusKeys = ["default_bo", "default_ordered", "default_received", "default_returned"];
return parts.reduce(
(acc, val) => {
if (val.part_type === "PAS" || val.part_type === "PASL") return acc;
acc.total = acc.total + val.count;
acc[val.status] = acc[val.status] + val.count;
-
return acc;
},
{
total: 0,
null: 0,
- [bodyshop.md_order_statuses.default_bo]: 0,
- [bodyshop.md_order_statuses.default_ordered]: 0,
- [bodyshop.md_order_statuses.default_received]: 0,
- [bodyshop.md_order_statuses.default_returned]: 0
+ ...Object.fromEntries(statusKeys.map((key) => [bodyshop.md_order_statuses[key], 0]))
}
);
}, [bodyshop, parts]);
if (!parts) return null;
return (
-
-
-
- {partsStatus.total}
-
-
-
-
- {partsStatus["null"]}
-
-
-
-
- {partsStatus[bodyshop.md_order_statuses.default_ordered]}
-
-
-
-
- {partsStatus[bodyshop.md_order_statuses.default_received]}
-
-
-
-
- {partsStatus[bodyshop.md_order_statuses.default_returned]}
-
-
-
-
- {partsStatus[bodyshop.md_order_statuses.default_bo]}
-
-
-
+
+
+ {partsStatus.total}
+
+
+
+ {partsStatus["null"]}
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_bo]}
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_ordered]}
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_received]}
+
+
+
+
+ {partsStatus[bodyshop.md_order_statuses.default_returned]}
+
+
+
);
}
diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx
index 49439fa00..bde88d161 100644
--- a/client/src/components/jobs-list/jobs-list.component.jsx
+++ b/client/src/components/jobs-list/jobs-list.component.jsx
@@ -166,7 +166,7 @@ export function JobsList({ bodyshop }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})
diff --git a/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx b/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
index b88b713c2..b218b46f4 100644
--- a/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
+++ b/client/src/components/jobs-ready-list/jobs-ready-list.component.jsx
@@ -165,7 +165,7 @@ export function JobsReadyList({ bodyshop }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})
diff --git a/client/src/components/parts-queue-card/parts-queue-job-lines.component.jsx b/client/src/components/parts-queue-card/parts-queue-job-lines.component.jsx
index 7d108954c..066e937e8 100644
--- a/client/src/components/parts-queue-card/parts-queue-job-lines.component.jsx
+++ b/client/src/components/parts-queue-card/parts-queue-job-lines.component.jsx
@@ -145,7 +145,7 @@ export function PartsQueueJobLinesComponent({ loading, jobLines }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})) ||
diff --git a/client/src/components/parts-queue-list/parts-queue.list.component.jsx b/client/src/components/parts-queue-list/parts-queue.list.component.jsx
index bb4b72b79..a947eaefa 100644
--- a/client/src/components/parts-queue-list/parts-queue.list.component.jsx
+++ b/client/src/components/parts-queue-list/parts-queue.list.component.jsx
@@ -171,7 +171,7 @@ export function PartsQueueListComponent({ bodyshop }) {
filters:
bodyshop.md_ro_statuses.active_statuses.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
}) || [],
diff --git a/client/src/components/production-list-columns/production-list-columns.data.jsx b/client/src/components/production-list-columns/production-list-columns.data.jsx
index f26733c36..165e15c1d 100644
--- a/client/src/components/production-list-columns/production-list-columns.data.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.data.jsx
@@ -34,8 +34,9 @@ const getEmployeeName = (employeeId, employees) => {
return employee ? `${employee.first_name} ${employee.last_name}` : "";
};
-const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatments }) => {
+const productionListColumnsData = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatments }) => {
const { Enhanced_Payroll } = treatments;
+
return [
{
title: i18n.t("jobs.actions.viewdetail"),
@@ -313,7 +314,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
activeStatuses
?.map((s) => {
return {
- text: s || "No Status*",
+ text: s || i18n.t("dashboard.errors.status"),
value: [s]
};
})
@@ -584,4 +585,4 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
}
];
};
-export default r;
+export default productionListColumnsData;
diff --git a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
index ccae00d4f..6e7a4edfd 100644
--- a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
+++ b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
@@ -138,6 +138,15 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
)}
+ {bodyshop.pbs_serialnumber && (
+
+
+
+ )}
{bodyshop.pbs_serialnumber && (
{
+ filters: bodyshop?.md_ro_statuses?.parts_statuses?.map((s) => {
return { text: s, value: [s] };
}),
onFilter: (value, record) => value.includes(record.status)
diff --git a/client/src/components/tech-lookup-jobs-list/tech-lookup-jobs-list.component.jsx b/client/src/components/tech-lookup-jobs-list/tech-lookup-jobs-list.component.jsx
index 0febbb24d..dfba5a133 100644
--- a/client/src/components/tech-lookup-jobs-list/tech-lookup-jobs-list.component.jsx
+++ b/client/src/components/tech-lookup-jobs-list/tech-lookup-jobs-list.component.jsx
@@ -111,7 +111,7 @@ export function TechLookupJobsList({ bodyshop }) {
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})) ||
diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx
index 78f86a0c6..afc67a4a7 100644
--- a/client/src/pages/dms/dms.container.jsx
+++ b/client/src/pages/dms/dms.container.jsx
@@ -48,7 +48,7 @@ export const socket = SocketIO(
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
const { t } = useTranslation();
- const [logLevel, setLogLevel] = useState("DEBUG");
+ const [logLevel, setLogLevel] = useState(determineDmsType(bodyshop) === "pbs" ? "INFO" : "DEBUG");
const history = useNavigate();
const [logs, setLogs] = useState([]);
const search = queryString.parse(useLocation().search);
diff --git a/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx b/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx
index 1849b9b63..5cc1f308d 100644
--- a/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx
+++ b/client/src/pages/tech-assigned-prod-jobs/tech-assigned-prod-jobs.component.jsx
@@ -97,7 +97,7 @@ export function TechAssignedProdJobs({ setTimeTicketTaskContext, technician, bod
.filter(onlyUnique)
.map((s) => {
return {
- text: s || "No Status*",
+ text: s || t("dashboard.errors.status"),
value: [s]
};
})) ||
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index aca3da3e2..342843b64 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -321,6 +321,7 @@
"itc_local": "Local Tax is ITC?",
"itc_state": "State Tax is ITC?",
"mappingname": "DMS Mapping Name",
+ "ro_posting": "Create $0 RO?",
"sendmaterialscosting": "Materials Cost as % of Sale",
"srcco": "Source Company #/Dealer #"
},
@@ -996,6 +997,7 @@
"insco": "No Ins. Co.*",
"refreshrequired": "You must refresh the dashboard data to see this component.",
"status": "No Status*",
+ "status_normal": "No Status",
"updatinglayout": "Error saving updated layout {{message}}"
},
"labels": {
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 345712670..124f78f36 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -321,6 +321,7 @@
"itc_local": "",
"itc_state": "",
"mappingname": "",
+ "ro_posting": "",
"sendmaterialscosting": "",
"srcco": ""
},
@@ -996,6 +997,7 @@
"insco": "",
"refreshrequired": "",
"status": "",
+ "status_normal": "",
"updatinglayout": ""
},
"labels": {
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index c3f680059..726fa4740 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -321,6 +321,7 @@
"itc_local": "",
"itc_state": "",
"mappingname": "",
+ "ro_posting": "",
"sendmaterialscosting": "",
"srcco": ""
},
@@ -996,6 +997,7 @@
"insco": "",
"refreshrequired": "",
"status": "",
+ "status_normal": "",
"updatinglayout": ""
},
"labels": {
diff --git a/server/accounting/pbs/pbs-constants.js b/server/accounting/pbs/pbs-constants.js
index c8a6d54f3..7c54f4d0e 100644
--- a/server/accounting/pbs/pbs-constants.js
+++ b/server/accounting/pbs/pbs-constants.js
@@ -6,10 +6,6 @@ const PBS_CREDENTIALS = {
};
exports.PBS_CREDENTIALS = PBS_CREDENTIALS;
-// const cdkDomain =
-// process.env.NODE_ENV === "production"
-// ? "https://3pa.dmotorworks.com"
-// : "https://uat-3pa.dmotorworks.com";
const pbsDomain = `https://partnerhub.pbsdealers.com/json/reply`;
exports.PBS_ENDPOINTS = {
@@ -18,5 +14,9 @@ exports.PBS_ENDPOINTS = {
VehicleGet: `${pbsDomain}/VehicleGet`,
AccountingPostingChange: `${pbsDomain}/AccountingPostingChange`,
ContactChange: `${pbsDomain}/ContactChange`,
- VehicleChange: `${pbsDomain}/VehicleChange`
+ VehicleChange: `${pbsDomain}/VehicleChange`,
+ RepairOrderChange: `${pbsDomain}/RepairOrderChange`, //TODO: Verify that this is correct. Docs have /reply/ in path.
+ RepairOrderGet: `${pbsDomain}/RepairOrderGet`,
+ RepairOrderContactVehicleGet: `${pbsDomain}/RepairOrderContactVehicleGet`,
+ RepairOrderContactVehicleChange: `${pbsDomain}/RepairOrderContactVehicleChange`,
};
diff --git a/server/accounting/pbs/pbs-job-export.js b/server/accounting/pbs/pbs-job-export.js
index 127c9d5e2..feb3dc064 100644
--- a/server/accounting/pbs/pbs-job-export.js
+++ b/server/accounting/pbs/pbs-job-export.js
@@ -19,12 +19,11 @@ axios.interceptors.request.use((x) => {
...x.headers[x.method],
...x.headers
};
- const printable = `${new Date()} | Request: ${x.method.toUpperCase()} | ${
- x.url
- } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
- //console.log(printable);
+ const printable = `${new Date()} | Request: ${x.method.toUpperCase()} | ${x.url
+ } | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
+ //logRequestToFile(printable);
- CdkBase.createJsonEvent(socket, "SILLY", `Raw Request: ${printable}`, x.data);
+ CdkBase.createJsonEvent(socket, "DEBUG", `Raw Request: ${printable}`, x.data);
return x;
});
@@ -32,23 +31,39 @@ axios.interceptors.request.use((x) => {
axios.interceptors.response.use((x) => {
const socket = x.config.socket;
- const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`;
- //console.log(printable);
- CdkBase.createJsonEvent(socket, "SILLY", `Raw Response: ${printable}`, x.data);
+ const printable = `${new Date()} | Response: ${x.status} ${x.statusText} |${JSON.stringify(x.data)}`;
+ //logRequestToFile(printable);
+ CdkBase.createJsonEvent(socket, "DEBUG", `Raw Response: ${printable}`, x.data);
return x;
});
+const fs = require('fs');
+const path = require("path");
+function logRequestToFile(printable) {
+ try {
+ const logDir = path.join(process.cwd(), "logs");
+ if (!fs.existsSync(logDir)) {
+ fs.mkdirSync(logDir, { recursive: true });
+ }
+ const logFile = path.join(logDir, "pbs-http.log");
+ fs.appendFileSync(logFile, `${printable}\n`);
+ } catch (err) {
+ console.error("Unexpected error in logRequestToFile:", err);
+ }
+}
+
+
exports.default = async function (socket, { txEnvelope, jobid }) {
socket.logEvents = [];
socket.recordid = jobid;
socket.txEnvelope = txEnvelope;
try {
- CdkBase.createLogEvent(socket, "DEBUG", `Received Job export request for id ${jobid}`);
+ CdkBase.createLogEvent(socket, "INFO", `Received Job export request for id ${jobid}`);
const JobData = await QueryJobData(socket, jobid);
socket.JobData = JobData;
- CdkBase.createLogEvent(socket, "DEBUG", `Querying the DMS for the Vehicle Record.`);
+ CdkBase.createLogEvent(socket, "INFO", `Querying the DMS for the Vehicle Record.`);
//Query for the Vehicle record to get the associated customer.
socket.DmsVeh = await QueryVehicleFromDms(socket);
//Todo: Need to validate the lines and methods below.
@@ -69,42 +84,52 @@ exports.default = async function (socket, { txEnvelope, jobid }) {
exports.PbsSelectedCustomer = async function PbsSelectedCustomer(socket, selectedCustomerId) {
try {
- if (socket.JobData.bodyshop.pbs_configuration.disablecontactvehicle === false) {
- CdkBase.createLogEvent(socket, "DEBUG", `User selected customer ${selectedCustomerId || "NEW"}`);
+ socket.selectedCustomerId = selectedCustomerId;
+ if (socket.JobData.bodyshop.pbs_configuration.disablecontactvehicle !== true) {
+ CdkBase.createLogEvent(socket, "INFO", `User selected customer ${selectedCustomerId || "NEW"}`);
//Upsert the contact information as per Wafaa's Email.
CdkBase.createLogEvent(
socket,
- "DEBUG",
- `Upserting contact information to DMS for ${
- socket.JobData.ownr_fn || ""
+ "INFO",
+ `Upserting contact information to DMS for ${socket.JobData.ownr_fn || ""
} ${socket.JobData.ownr_ln || ""} ${socket.JobData.ownr_co_nm || ""}`
);
const ownerRef = await UpsertContactData(socket, selectedCustomerId);
-
- CdkBase.createLogEvent(socket, "DEBUG", `Upserting vehicle information to DMS for ${socket.JobData.v_vin}`);
- await UpsertVehicleData(socket, ownerRef.ReferenceId);
+ socket.ownerRef = ownerRef;
+ CdkBase.createLogEvent(socket, "INFO", `Upserting vehicle information to DMS for ${socket.JobData.v_vin}`);
+ const vehicleRef = await UpsertVehicleData(socket, ownerRef.ReferenceId);
+ socket.vehicleRef = vehicleRef;
} else {
CdkBase.createLogEvent(
socket,
- "DEBUG",
- `Contact and Vehicle updates disabled. Skipping to accounting data insert.`
+ "INFO",
+ `Contact and Vehicle updates disabled. Querying data and skipping to accounting data insert.`
);
+ //Must query for records to insert $0 RO.
+ if (!socket.ownerRef) {
+ const ownerRef = (await QueryCustomerBycodeFromDms(socket, selectedCustomerId))?.[0];
+ socket.ownerRef = ownerRef;
+ }
+ const vehicleRef = await GetVehicleData(socket, socket.ownerRef?.ReferenceId || socket.selectedCustomerId);
+ socket.vehicleRef = vehicleRef;
}
- CdkBase.createLogEvent(socket, "DEBUG", `Inserting account data.`);
- CdkBase.createLogEvent(socket, "DEBUG", `Inserting accounting posting data..`);
+ CdkBase.createLogEvent(socket, "INFO", `Inserting accounting posting data..`);
const insertResponse = await InsertAccountPostingData(socket);
if (insertResponse.WasSuccessful) {
- CdkBase.createLogEvent(socket, "DEBUG", `Marking job as exported.`);
- await MarkJobExported(socket, socket.JobData.id);
+ if (socket.JobData.bodyshop.pbs_configuration.ro_posting) {
+ await CreateRepairOrderInPBS(socket, socket.ownerRef, socket.vehicleRef)
+ }
+ CdkBase.createLogEvent(socket, "INFO", `Marking job as exported.`);
+ await MarkJobExported(socket, socket.JobData.id);
socket.emit("export-success", socket.JobData.id);
} else {
CdkBase.createLogEvent(socket, "ERROR", `Export was not successful.`);
}
} catch (error) {
- CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkSelectedCustomer. ${error}`);
+ CdkBase.createLogEvent(socket, "ERROR", `Error encountered in PbsSelectedCustomer. ${error}`);
await InsertFailedExportLog(socket, error);
}
};
@@ -112,22 +137,22 @@ exports.PbsSelectedCustomer = async function PbsSelectedCustomer(socket, selecte
// Was Successful
async function CheckForErrors(socket, response) {
if (response.WasSuccessful === undefined || response.WasSuccessful === true) {
- CdkBase.createLogEvent(socket, "DEBUG", `Successful response from DMS. ${response.Message || ""}`);
+ CdkBase.createLogEvent(socket, "INFO", `Successful response from DMS. ${response.Message || ""}`);
} else {
CdkBase.createLogEvent(socket, "ERROR", `Error received from DMS: ${response.Message}`);
- CdkBase.createLogEvent(socket, "SILLY", `Error received from DMS: ${JSON.stringify(response)}`);
+ CdkBase.createLogEvent(socket, "DEBUG", `Error received from DMS: ${JSON.stringify(response)}`);
}
}
exports.CheckForErrors = CheckForErrors;
async function QueryJobData(socket, jobid) {
- CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`);
+ CdkBase.createLogEvent(socket, "INFO", `Querying job data for id ${jobid}`);
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
const result = await client
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
.request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid });
- CdkBase.createLogEvent(socket, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`);
+ CdkBase.createLogEvent(socket, "DEBUG", `Job data query result ${JSON.stringify(result, null, 2)}`);
return result.jobs_by_pk;
}
@@ -247,15 +272,15 @@ async function UpsertContactData(socket, selectedCustomerId) {
Code: socket.JobData.owner.accountingid,
...(socket.JobData.ownr_co_nm
? {
- //LastName: socket.JobData.ownr_ln,
- FirstName: socket.JobData.ownr_co_nm,
- IsBusiness: true
- }
+ //LastName: socket.JobData.ownr_ln,
+ FirstName: socket.JobData.ownr_co_nm,
+ IsBusiness: true
+ }
: {
- LastName: socket.JobData.ownr_ln,
- FirstName: socket.JobData.ownr_fn,
- IsBusiness: false
- }),
+ LastName: socket.JobData.ownr_ln,
+ FirstName: socket.JobData.ownr_fn,
+ IsBusiness: false
+ }),
//Salutation: "String",
//MiddleName: "String",
@@ -332,7 +357,7 @@ async function UpsertVehicleData(socket, ownerRef) {
//FleetNumber: "String",
//Status: "String",
OwnerRef: ownerRef, // "00000000000000000000000000000000",
- ModelNumber: socket.JobData.vehicle && socket.JobData.vehicle.v_makecode,
+ // ModelNumber: socket.JobData.vehicle && socket.JobData.vehicle.v_makecode,
Make: socket.JobData.v_make_desc,
Model: socket.JobData.v_model_desc,
Trim: socket.JobData.vehicle && socket.JobData.vehicle.v_trimcode,
@@ -340,7 +365,7 @@ async function UpsertVehicleData(socket, ownerRef) {
Year: socket.JobData.v_model_yr,
Odometer: socket.JobData.kmout,
ExteriorColor: {
- Code: socket.JobData.v_color,
+ // Code: socket.JobData.v_color,
Description: socket.JobData.v_color
}
// InteriorColor: { Code: "String", Description: "String" },
@@ -470,6 +495,57 @@ async function UpsertVehicleData(socket, ownerRef) {
}
}
+async function GetVehicleData(socket, ownerRef) {
+ try {
+ const { data: { Vehicles } } = await axios.post(
+ PBS_ENDPOINTS.VehicleGet,
+ {
+ SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
+ // "VehicleId": "00000000000000000000000000000000",
+ // "Year": "String",
+ // "YearFrom": "String",
+ // "YearTo": "String",
+ // "Make": "String",
+ // "Model": "String",
+ // "Trim": "String",
+ // "ModelNumber": "String",
+ // "StockNumber": "String",
+ VIN: socket.JobData.v_vin,
+ // "LicenseNumber": "String",
+ // "Lot": "String",
+ // "Status": "String",
+ // "StatusList": ["String"],
+ // "OwnerRef": "00000000000000000000000000000000",
+ // "ModifiedSince": "0001-01-01T00:00:00.0000000Z",
+ // "ModifiedUntil": "0001-01-01T00:00:00.0000000Z",
+ // "LastSaleSince": "0001-01-01T00:00:00.0000000Z",
+ // "VehicleIDList": ["00000000000000000000000000000000"],
+ // "IncludeInactive": false,
+ // "IncludeBuildVehicles": false,
+ // "IncludeBlankLot": false,
+ // "ShortVIN": "String",
+ // "ResultLimit": 0,
+ // "LotAccessDivisions": [0],
+ // "OdometerTo": 0,
+ // "OdometerFrom": 0
+ }
+ ,
+ { auth: PBS_CREDENTIALS, socket }
+ );
+ CheckForErrors(socket, Vehicles);
+ if (Vehicles.length === 1) {
+ return Vehicles[0];
+
+ } else {
+ CdkBase.createLogEvent(socket, "ERROR", `Error in Getting Vehicle Data - ${Vehicles.length} vehicle(s) found`);
+ }
+ } catch (error) {
+ CdkBase.createLogEvent(socket, "ERROR", `Error in UpsertVehicleData - ${error}`);
+ throw new Error(error);
+ }
+}
+
+
async function InsertAccountPostingData(socket) {
try {
const allocations = await CalculateAllocations(socket, socket.JobData.id);
@@ -572,7 +648,7 @@ async function InsertAccountPostingData(socket) {
}
async function MarkJobExported(socket, jobid) {
- CdkBase.createLogEvent(socket, "DEBUG", `Marking job as exported for id ${jobid}`);
+ CdkBase.createLogEvent(socket, "INFO", `Marking job as exported for id ${jobid}`);
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
const result = await client
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
@@ -618,3 +694,158 @@ async function InsertFailedExportLog(socket, error) {
CdkBase.createLogEvent(socket, "ERROR", `Error in InsertFailedExportLog - ${error} - ${JSON.stringify(error2)}`);
}
}
+
+
+async function CreateRepairOrderInPBS(socket) {
+ try {
+ const { RepairOrders } = await RepairOrderGet(socket);
+ if (RepairOrders.length === 0) {
+ const InsertedRepairOrder = await RepairOrderChange(socket)
+ socket.InsertedRepairOrder = InsertedRepairOrder;
+ CdkBase.createLogEvent(socket, "INFO", `No repair orders found for vehicle. Inserting record.`);
+
+ } else if (RepairOrders.length > 0) {
+ //Find out if it's a matching RO.
+ //This logic is used because the integration will simply add another line to an open RO if it exists.
+ const matchingRo = RepairOrders.find(ro => ro.Memo?.toLowerCase()?.includes(socket.JobData.ro_number.toLowerCase()))
+ if (!matchingRo) {
+ CdkBase.createLogEvent(socket, "INFO", `ROs found for vehicle, but none match. Inserting record.`);
+ const InsertedRepairOrder = await RepairOrderChange(socket)
+ socket.InsertedRepairOrder = InsertedRepairOrder;
+ } else {
+ CdkBase.createLogEvent(socket, "WARN", `Repair order appears to already exist in PBS. ${matchingRo.RepairOrderNumber}`);
+ }
+ }
+ } catch (error) {
+ CdkBase.createLogEvent(socket, "ERROR", `Error in CreateRepairOrderInPBS - ${error} - ${JSON.stringify(error)}`);
+ }
+}
+
+async function RepairOrderGet(socket) {
+ try {
+ const { data: RepairOrderGet } = await axios.post(
+ PBS_ENDPOINTS.RepairOrderGet,
+ {
+ SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
+ //"RepairOrderId": "374728766",
+ //"RepairOrderNumber": "4" || socket.JobData.ro_number,
+ //"RawRepairOrderNumber": socket.JobData.ro_number,
+ // "Tag": "String",
+ //"ContactRef": socket.contactRef,
+ // "ContactRefList": ["00000000000000000000000000000000"],
+ "VehicleRef": socket.vehicleRef?.ReferenceId || socket.vehicleRef?.VehicleId,
+ // "VehicleRefList": ["00000000000000000000000000000000"],
+ // "Status": "String",
+ // "CashieredSince": "0001-01-01T00:00:00.0000000Z",
+ // "CashieredUntil": "0001-01-01T00:00:00.0000000Z",
+ // "OpenDateSince": "0001-01-01T00:00:00.0000000Z",
+ // "OpenDateUntil": "0001-01-01T00:00:00.0000000Z",
+ //"ModifiedSince": "2025-01-01T00:00:00.0000000Z",
+ // "ModifiedUntil": "0001-01-01T00:00:00.0000000Z",
+ // "Shop": "String"
+ },
+ { auth: PBS_CREDENTIALS, socket }
+ );
+ CheckForErrors(socket, RepairOrderGet);
+ return RepairOrderGet;
+ } catch (error) {
+ CdkBase.createLogEvent(socket, "ERROR", `Error in RepairOrderChange - ${error}`);
+ throw new Error(error);
+ }
+}
+
+async function RepairOrderChange(socket) {
+ try {
+ const { data: RepairOrderChangeResponse } = await axios.post(
+ PBS_ENDPOINTS.RepairOrderChange,
+ { //Additional details at https://partnerhub.pbsdealers.com/json/metadata?op=RepairOrderChange
+ "RepairOrderInfo": {
+ //"Id": "string/00000000-0000-0000-0000-000000000000",
+ //"RepairOrderId": "00000000000000000000000000000000",
+ SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
+ "RepairOrderNumber": "00000000000000000000000000000000", //This helps force a new RO.
+ "RawRepairOrderNumber": "00000000000000000000000000000000",
+ // "RepairOrderNumber": socket.JobData.ro_number, //These 2 values are ignored as confirmed by PBS.
+ // "RawRepairOrderNumber": socket.JobData.ro_number,
+ "DateOpened": moment(),
+ // "DateOpenedUTC": "0001-01-01T00:00:00.0000000Z",
+ // "DateCashiered": "0001-01-01T00:00:00.0000000Z",
+ // "DateCashieredUTC": "0001-01-01T00:00:00.0000000Z",
+ "DatePromised": socket.JobData.scheduled_completion,
+ // "DatePromisedUTC": "0001-01-01T00:00:00.0000000Z",
+ "DateVehicleCompleted": socket.JobData.actual_completion,
+ // "DateCustomerNotified": "0001-01-01T00:00:00.0000000Z",
+ // "CSR": "String",
+ // "CSRRef": "00000000000000000000000000000000",
+ // "BookingUser": "String",
+ // "BookingUserRef": "00000000000000000000000000000000",
+ "ContactRef": socket.ownerRef?.ReferenceId || socket.ownerRef?.ContactId,
+ "VehicleRef": socket.vehicleRef?.ReferenceId || socket.vehicleRef?.VehicleId,
+ "MileageIn": socket.JobData.km_in,
+ "Tag": "BODYSHOP",
+ //"Status": "CLOSED", //Values here do not impact the status. Confirmed by PBS support.
+ Requests: [
+ {
+ // "RepairOrderRequestRef": "b1842ecad62c4279bbc2fef4f6bf6cde",
+ // "RepairOrderRequestId": 1,
+ // "CSR": "PBS",
+ // "CSRRef": "1ce12ac692564e94bda955d529ee911a",
+ // "Skill": "GEN",
+ "RequestCode": "MISC",
+ "RequestDescription": `VEHICLE REPAIRED AT BODYSHOP. PLEASE REFERENCE IMEX SHOP MANAGEMENT SYSTEM. ${socket.txEnvelope.story}`,
+ "Status": "Completed",
+ // "TechRef": "00000000000000000000000000000000",
+ "AllowedHours": 0,
+ "EstimateLabour": 0,
+ "EstimateParts": 0,
+ "ComeBack": false,
+ "AddedOperation": true,
+ "PartLines": [],
+ "PartRequestLines": [],
+ "LabourLines": [],
+ "SubletLines": [],
+ "TimePunches": [],
+ "Summary": {
+ "Labour": 0,
+ "Parts": 0,
+ "OilGas": 0,
+ "SubletTow": 0,
+ "Misc": 0,
+ "Environment": 0,
+ "ShopSupplies": 0,
+ "Freight": 0,
+ "WarrantyDeductible": 0,
+ "Discount": 0,
+ "SubTotal": 0,
+ "Tax1": 0,
+ "Tax2": 0,
+ "InvoiceTotal": 0,
+ "CustomerDeductible": 0,
+ "GrandTotal": 0,
+ "LabourDiscount": 0,
+ "PartDiscount": 0,
+ "ServiceFeeTotal": 0,
+ "OEMDiscount": 0
+ },
+ "LineType": "RequestLine",
+ },
+ ],
+
+ "Memo": socket.txEnvelope.story,
+
+ },
+ "IsAsynchronous": false,
+ // "UserRequest": "String",
+ // "UserRef": "00000000000000000000000000000000"
+ }
+
+ ,
+ { auth: PBS_CREDENTIALS, socket }
+ );
+ CheckForErrors(socket, RepairOrderChangeResponse);
+ return RepairOrderChangeResponse;
+ } catch (error) {
+ CdkBase.createLogEvent(socket, "ERROR", `Error in RepairOrderChange - ${error}`);
+ throw new Error(error);
+ }
+}
\ No newline at end of file
diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js
index d6ebfce64..3e29387bb 100644
--- a/server/graphql-client/queries.js
+++ b/server/graphql-client/queries.js
@@ -420,6 +420,8 @@ query QUERY_JOBS_FOR_PBS_EXPORT($id: uuid!) {
v_make_desc
v_color
ca_customer_gst
+ scheduled_completion
+ actual_completion
vehicle {
v_trimcode
v_makecode
@@ -2201,18 +2203,16 @@ exports.UPDATE_OLD_TRANSITION = `mutation UPDATE_OLD_TRANSITION($jobid: uuid!, $
exports.INSERT_NEW_TRANSITION = (
includeOldTransition
-) => `mutation INSERT_NEW_TRANSITION($newTransition: transitions_insert_input!, ${
- includeOldTransition ? `$oldTransitionId: uuid!, $duration: numeric` : ""
-}) {
+) => `mutation INSERT_NEW_TRANSITION($newTransition: transitions_insert_input!, ${includeOldTransition ? `$oldTransitionId: uuid!, $duration: numeric` : ""
+ }) {
insert_transitions_one(object: $newTransition) {
id
}
- ${
- includeOldTransition
- ? `update_transitions(where: {id: {_eq: $oldTransitionId}}, _set: {duration: $duration}) {
+ ${includeOldTransition
+ ? `update_transitions(where: {id: {_eq: $oldTransitionId}}, _set: {duration: $duration}) {
affected_rows
}`
- : ""
+ : ""
}
}`;