Compare commits

...

13 Commits

Author SHA1 Message Date
Allan Carr
6cac0f9594 IO-3010 Task Table UI refactor
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-30 17:38:09 -07:00
Dave Richer
9b67148522 Merged in release/2024-11-01 (pull request #1866)
Release/2024-11-01 into master-AIO - IO-2979 - Misc Logger related fixes
2024-10-29 20:10:02 +00:00
Dave Richer
6b501e4619 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 11:02:08 -07:00
Dave Richer
42f1d6fa13 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 10:53:09 -07:00
Dave Richer
3f247a9227 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 09:54:45 -07:00
Dave Richer
63b914731b release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 08:25:54 -07:00
Dave Richer
23f8f69bbe release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 08:19:58 -07:00
Dave Richer
fc3ea2bdf8 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 07:37:40 -07:00
Dave Richer
96e970faf7 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 18:16:48 -07:00
Dave Richer
c133195607 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 17:48:43 -07:00
Dave Richer
d75ea2b1a6 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 17:38:46 -07:00
Dave Richer
ec0fd840e4 Merged in feature/IO-2979-DST (pull request #1856)
IO-2979-DST into release/2024-11-01 - DST Related Fixes
2024-10-28 21:05:57 +00:00
Dave Richer
19050d31f7 Merged in release/2024-11-01 (pull request #1853)
Release/2024-11-01 into master-AIO  - Fix Logging Issues
2024-10-28 20:39:28 +00:00
28 changed files with 249 additions and 168 deletions

View File

@@ -116,18 +116,15 @@ function Header({
const { t } = useTranslation(); const { t } = useTranslation();
const deleteBetaCookie = () => { // const deleteBetaCookie = () => {
const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`)); // const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
if (cookieExists) { // if (cookieExists) {
const domain = window.location.hostname.split(".").slice(-2).join("."); // const domain = window.location.hostname.split(".").slice(-2).join(".");
document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`; // document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
console.log(`betaSwitchImex cookie deleted`); // }
} else { // };
console.log(`betaSwitchImex cookie does not exist`); //
} // deleteBetaCookie();
};
deleteBetaCookie();
const accountingChildren = []; const accountingChildren = [];

View File

@@ -144,7 +144,7 @@ function TaskListComponent({
title: t("tasks.fields.created_by"), title: t("tasks.fields.created_by"),
dataIndex: "created_by", dataIndex: "created_by",
key: "created_by", key: "created_by",
width: "10%", width: "8%",
defaultSortOrder: "descend", defaultSortOrder: "descend",
sorter: true, sorter: true,
sortOrder: sortcolumn === "created_by" && sortorder, sortOrder: sortcolumn === "created_by" && sortorder,
@@ -166,65 +166,70 @@ function TaskListComponent({
}); });
} }
if (showRo) { columns.push({
columns.push({ title: t("tasks.fields.related_items"),
title: t("tasks.fields.job.ro_number"), key: "related_items",
dataIndex: ["job", "ro_number"], width: "12%",
key: "job.ro_number", render: (text, record) => {
width: "8%", const items = [];
render: (text, record) =>
record.job ? ( // Job
<Link to={`/manage/jobs/${record.job.id}?tab=tasks`}>{record.job.ro_number || t("general.labels.na")}</Link> if (showRo && record.job) {
) : ( items.push(
t("general.labels.na") <Link key="job" to={`/manage/jobs/${record.job.id}?tab=tasks`}>
) {t("tasks.fields.job.ro_number")}: {record.job.ro_number}
}); </Link>
} );
}
if (showRo && !record.job) {
items.push(`${t("tasks.fields.job.ro_number")}: ${t("general.labels.na")}`);
}
// Jobline
if (record.jobline?.line_desc) {
items.push(
<span key="jobline">
{t("tasks.fields.jobline")}: {record.jobline.line_desc}
</span>
);
}
// Parts Order
if (record.parts_order) {
const { order_number, vendor } = record.parts_order;
const partsOrderText =
order_number && vendor?.name ? `${order_number} - ${vendor.name}` : t("general.labels.na");
items.push(
<Link
key="parts_order"
to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}
>
{t("tasks.fields.parts_order")}: {partsOrderText}
</Link>
);
}
// Bill
if (record.bill) {
const { invoice_number, vendor } = record.bill;
const billText = invoice_number && vendor?.name ? `${invoice_number} - ${vendor.name}` : t("general.labels.na");
items.push(
<Link key="bill" to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
{t("tasks.fields.bill")}: {billText}
</Link>
);
}
return items.length > 0 ? <Space direction="vertical">{items}</Space> : null;
}
});
columns.push( columns.push(
{
title: t("tasks.fields.jobline"),
dataIndex: ["jobline", "id"],
key: "jobline.id",
width: "8%",
render: (text, record) => record?.jobline?.line_desc || ""
},
{
title: t("tasks.fields.parts_order"),
dataIndex: ["parts_order", "id"],
key: "part_order.id",
width: "8%",
render: (text, record) =>
record.parts_order ? (
<Link to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}>
{record.parts_order.order_number && record.parts_order.vendor && record.parts_order.vendor.name
? `${record.parts_order.order_number} - ${record.parts_order.vendor.name}`
: t("general.labels.na")}
</Link>
) : (
""
)
},
{
title: t("tasks.fields.bill"),
dataIndex: ["bill", "id"],
key: "bill.id",
width: "10%",
render: (text, record) =>
record.bill ? (
<Link to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
{record.bill.invoice_number && record.bill.vendor && record.bill.vendor.name
? `${record.bill.invoice_number} - ${record.bill.vendor.name}`
: t("general.labels.na")}
</Link>
) : (
""
)
},
{ {
title: t("tasks.fields.title"), title: t("tasks.fields.title"),
dataIndex: "title", dataIndex: "title",
key: "title", key: "title",
minWidth: "20%",
sorter: true, sorter: true,
sortOrder: sortcolumn === "title" && sortorder sortOrder: sortcolumn === "title" && sortorder
}, },
@@ -258,7 +263,7 @@ function TaskListComponent({
{ {
title: t("tasks.fields.actions"), title: t("tasks.fields.actions"),
key: "toggleCompleted", key: "toggleCompleted",
width: "5%", width: "8%",
render: (text, record) => ( render: (text, record) => (
<Space direction="horizontal"> <Space direction="horizontal">
<Button <Button

View File

@@ -3204,6 +3204,7 @@
"medium": "Medium" "medium": "Medium"
}, },
"priority": "Priority", "priority": "Priority",
"related_items": "Related Items",
"remind_at": "Remind At", "remind_at": "Remind At",
"title": "Title" "title": "Title"
}, },

View File

@@ -3204,6 +3204,7 @@
"medium": "" "medium": ""
}, },
"priority": "", "priority": "",
"related_items": "",
"remind_at": "", "remind_at": "",
"title": "" "title": ""
}, },

View File

@@ -3204,6 +3204,7 @@
"medium": "" "medium": ""
}, },
"priority": "", "priority": "",
"related_items": "",
"remind_at": "", "remind_at": "",
"title": "" "title": ""
}, },

View File

@@ -63,7 +63,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
); );
if (!account) { if (!account) {
logger.log("qbxml-receivables-no-account", "warn", null, jobline.id, null); logger.log("qbxml-receivables-no-account", "warn", null, jobline.id);
throw new Error( throw new Error(
`A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}` `A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}`
); );

View File

@@ -45,7 +45,7 @@ exports.default = async (req, res) => {
const BearerToken = req.BearerToken; const BearerToken = req.BearerToken;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("qbo-payable-create", "DEBUG", req.user.email, billsToQuery); logger.log("qbo-payable-create", "DEBUG", req.user.email, null, { billsToQuery });
const result = await client const result = await client
.setHeaders({ Authorization: BearerToken }) .setHeaders({ Authorization: BearerToken })
@@ -91,6 +91,12 @@ exports.default = async (req, res) => {
ret.push({ billid: bill.id, success: true }); ret.push({ billid: bill.id, success: true });
} catch (error) { } catch (error) {
logger.log("qbo-paybles-create-error", "ERROR", req.user.email, null, {
error:
(error && error.authResponse && error.authResponse.body) ||
error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") ||
(error && error.message)
});
ret.push({ ret.push({
billid: bill.id, billid: bill.id,
success: false, success: false,
@@ -122,7 +128,7 @@ exports.default = async (req, res) => {
res.status(200).json(ret); res.status(200).json(ret);
} catch (error) { } catch (error) {
//console.log(error); //console.log(error);
logger.log("qbo-payable-create-error", "ERROR", req.user.email, { logger.log("qbo-payable-create-error", "ERROR", req.user.email, null, {
error: error.message, error: error.message,
stack: error.stack stack: error.stack
}); });

View File

@@ -49,7 +49,7 @@ exports.default = async (req, res) => {
const BearerToken = req.BearerToken; const BearerToken = req.BearerToken;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("qbo-payment-create", "DEBUG", req.user.email, paymentsToQuery); logger.log("qbo-payment-create", "DEBUG", req.user.email, null, { paymentsToQuery });
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, { const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
payments: paymentsToQuery payments: paymentsToQuery
@@ -152,7 +152,7 @@ exports.default = async (req, res) => {
ret.push({ paymentid: payment.id, success: true }); ret.push({ paymentid: payment.id, success: true });
} catch (error) { } catch (error) {
logger.log("qbo-payment-create-error", "ERROR", req.user.email, { logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, {
error: (error && error.authResponse && error.authResponse.body) || (error && error.message) error: (error && error.authResponse && error.authResponse.body) || (error && error.message)
}); });
//Add the export log error. //Add the export log error.
@@ -183,7 +183,7 @@ exports.default = async (req, res) => {
res.status(200).json(ret); res.status(200).json(ret);
} catch (error) { } catch (error) {
//console.log(error); //console.log(error);
logger.log("qbo-payment-create-error", "ERROR", req.user.email, { logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, {
error: error.message, error: error.message,
stack: error.stack stack: error.stack
}); });

View File

@@ -42,9 +42,10 @@ exports.default = async (req, res) => {
//For each invoice. //For each invoice.
res.status(200).json(QbXmlToExecute); res.status(200).json(QbXmlToExecute);
} catch (error) { } catch (error) {
logger.log("qbxml-payable-error", "ERROR", req.user.email, req.body.billsToQuery, { logger.log("qbxml-payable-error", "ERROR", req?.user?.email, null, {
error: error.message, billsToQuery: req?.body?.billsToQuery,
stack: error.stack error: error?.message,
stack: error?.stack
}); });
res.status(400).send(JSON.stringify(error)); res.status(400).send(JSON.stringify(error));
} }

View File

@@ -21,7 +21,9 @@ exports.default = async (req, res) => {
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
try { try {
logger.log("qbxml-payments-create", "DEBUG", req.user.email, req.body.paymentsToQuery, null); logger.log("qbxml-payments-create", "DEBUG", req?.user?.email, null, {
paymentsToQuery: req.body?.paymentsToQuery
});
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, { const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
payments: paymentsToQuery payments: paymentsToQuery
@@ -62,7 +64,8 @@ exports.default = async (req, res) => {
res.status(200).json(QbXmlToExecute); res.status(200).json(QbXmlToExecute);
} catch (error) { } catch (error) {
logger.log("qbxml-payments-error", "error", req.user.email, req.body.paymentsToQuery, { logger.log("qbxml-payments-error", "error", req?.user?.email, null, {
paymentsToQuery: req.body?.paymentsToQuery,
error: error.message, error: error.message,
stack: error.stack stack: error.stack
}); });

View File

@@ -23,7 +23,9 @@ exports.default = async (req, res) => {
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
try { try {
logger.log("qbxml-receivables-create", "DEBUG", req.user.email, req.body.jobIds, null); logger.log("qbxml-receivables-create", "DEBUG", req?.user?.email, null, {
jobIds: req?.body?.jobIds
});
const result = await client const result = await client
.setHeaders({ Authorization: BearerToken }) .setHeaders({ Authorization: BearerToken })
@@ -74,7 +76,8 @@ exports.default = async (req, res) => {
res.status(200).json(QbXmlToExecute); res.status(200).json(QbXmlToExecute);
} catch (error) { } catch (error) {
logger.log("qbxml-receivables-error", "error", req.user.email, req.body.jobIds, { logger.log("qbxml-receivables-error", "error", req?.user?.email, null, {
jobIds: req.body?.jobIds,
error: error.message, error: error.message,
stack: error.stack stack: error.stack
}); });

View File

@@ -39,8 +39,8 @@ exports.default = async function ReloadCdkMakes(req, res) {
const deleteResult = await client const deleteResult = await client
.setHeaders({ Authorization: BearerToken }) .setHeaders({ Authorization: BearerToken })
.request(queries.DELETE_ALL_DMS_VEHICLES, {}); .request(queries.DELETE_ALL_DMS_VEHICLES, {});
console.log("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", deleteResult);
// logger.logger.debug("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", { deleteResult });
//Insert the new ones. //Insert the new ones.
const insertResult = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_DMS_VEHICLES, { const insertResult = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_DMS_VEHICLES, {
@@ -59,6 +59,7 @@ exports.default = async function ReloadCdkMakes(req, res) {
cdk_dealerid, cdk_dealerid,
count: newList.length count: newList.length
}); });
res.sendStatus(200); res.sendStatus(200);
} catch (error) { } catch (error) {
logger.log("cdk-replace-makes-models-error", "ERROR", req.user.email, null, { logger.log("cdk-replace-makes-models-error", "ERROR", req.user.email, null, {

View File

@@ -3,6 +3,7 @@ const { defaultProvider } = require("@aws-sdk/credential-provider-node");
const { default: InstanceManager } = require("../utils/instanceMgr"); const { default: InstanceManager } = require("../utils/instanceMgr");
const aws = require("@aws-sdk/client-ses"); const aws = require("@aws-sdk/client-ses");
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
const logger = require("../utils/logger");
const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME); const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME);
@@ -19,7 +20,7 @@ const sesConfig = {
if (isLocal) { if (isLocal) {
sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
console.log(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`); logger.logger.debug(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`);
} }
const ses = new aws.SES(sesConfig); const ses = new aws.SES(sesConfig);

View File

@@ -21,7 +21,7 @@ const getImage = async (imageUrl) => {
// Log the email in the database // Log the email in the database
const logEmail = async (req, email) => { const logEmail = async (req, email) => {
try { try {
const insertresult = await client.request(queries.INSERT_EMAIL_AUDIT, { await client.request(queries.INSERT_EMAIL_AUDIT, {
email: { email: {
to: email.to, to: email.to,
cc: email.cc, cc: email.cc,
@@ -34,13 +34,13 @@ const logEmail = async (req, email) => {
status: "Sent" status: "Sent"
} }
}); });
console.log(insertresult);
} catch (error) { } catch (error) {
logger.log("email-log-error", "error", req.user.email, null, { logger.log("email-log-error", "error", req?.user?.email, null, {
from: `${req.body.from.name} <${req.body.from.address}>`, from: `${req.body.from.name} <${req.body.from.address}>`,
to: req.body.to, to: req?.body?.to,
cc: req.body.cc, cc: req?.body?.cc,
subject: req.body.subject subject: req?.body?.subject,
email
// info, // info,
}); });
} }
@@ -70,12 +70,11 @@ const sendServerEmail = async ({ subject, text }) => {
} }
}, },
(err, info) => { (err, info) => {
console.log(err || info); logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err || info });
} }
); );
} catch (error) { } catch (error) {
console.log(error); logger.log("server-email-failure", "error", null, null, { error });
logger.log("server-email-failure", "error", null, null, error);
} }
}; };
@@ -88,8 +87,7 @@ const sendProManagerWelcomeEmail = async ({ to, subject, html }) => {
html html
}); });
} catch (error) { } catch (error) {
console.log(error); logger.log("server-email-failure", "error", null, null, { error });
logger.log("server-email-failure", "error", null, null, error);
} }
}; };
@@ -108,12 +106,12 @@ const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachmen
attachments: attachments || null attachments: attachments || null
}, },
(err, info) => { (err, info) => {
console.log(err || info); // (message, type, user, record, meta
logger.log("server-email", err ? "error" : "debug", null, null, { message: err || info });
} }
); );
} catch (error) { } catch (error) {
console.log(error); logger.log("server-email-failure", "error", null, null, { error });
logger.log("server-email-failure", "error", null, null, error);
} }
}; };
@@ -184,9 +182,8 @@ const sendEmail = async (req, res) => {
} }
}, },
(err, info) => { (err, info) => {
console.log(err || info);
if (info) { if (info) {
logger.log("send-email-success", "DEBUG", req.user.email, null, { logger.log("send-email-success", "DEBUG", req?.user?.email, null, {
from: `${req.body.from.name} <${req.body.from.address}>`, from: `${req.body.from.name} <${req.body.from.address}>`,
replyTo: req.body.ReplyTo.Email, replyTo: req.body.ReplyTo.Email,
to: req.body.to, to: req.body.to,
@@ -205,7 +202,7 @@ const sendEmail = async (req, res) => {
success: true //response: info success: true //response: info
}); });
} else { } else {
logger.log("send-email-failure", "ERROR", req.user.email, null, { logger.log("send-email-failure", "ERROR", req?.user?.email, null, {
from: `${req.body.from.name} <${req.body.from.address}>`, from: `${req.body.from.name} <${req.body.from.address}>`,
replyTo: req.body.ReplyTo.Email, replyTo: req.body.ReplyTo.Email,
to: req.body.to, to: req.body.to,
@@ -290,7 +287,9 @@ ${body.bounce?.bouncedRecipients.map(
` `
}, },
(err, info) => { (err, info) => {
console.log("***", err || info); logger.log("sns-error", err ? "error" : "debug", "api", null, {
message: err ? JSON.stringify(error) : info
});
} }
); );
} }

View File

@@ -18,10 +18,10 @@ const tasksEmailQueue = taskEmailQueue();
const tasksEmailQueueCleanup = async () => { const tasksEmailQueueCleanup = async () => {
try { try {
// Example async operation // Example async operation
console.log("Performing Tasks Email Reminder process cleanup..."); // console.log("Performing Tasks Email Reminder process cleanup...");
await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve())); await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve()));
} catch (err) { } catch (err) {
console.error("Tasks Email Reminder process cleanup failed:", err); // console.error("Tasks Email Reminder process cleanup failed:", err);
} }
}; };

View File

@@ -10,8 +10,9 @@ const logger = require("../utils/logger");
const taskEmailQueue = () => const taskEmailQueue = () =>
new Queue( new Queue(
(taskIds, cb) => { (taskIds, cb) => {
console.log("Processing reminds for taskIds: ", taskIds.join(", ")); logger.log("Processing reminds for taskIds: ", "silly", null, null, {
taskIds: taskIds?.join(", ")
});
// Set the remind_at_sent to the current time. // Set the remind_at_sent to the current time.
const now = moment().toISOString(); const now = moment().toISOString();

View File

@@ -269,10 +269,14 @@ const sendNotification = async (req, res) => {
}) })
.then((response) => { .then((response) => {
// Response is a message ID string. // Response is a message ID string.
console.log("Successfully sent message:", response); logger.log("Successfully sent message:", "debug", req?.user?.email, null, {
response
});
}) })
.catch((error) => { .catch((error) => {
console.log("Error sending message:", error); logger.log("Successfully sent message:", "error", req?.user?.email, null, {
error
});
}); });
res.sendStatus(200); res.sendStatus(200);

View File

@@ -19,7 +19,8 @@ async function JobCosting(req, res) {
const BearerToken = req.BearerToken; const BearerToken = req.BearerToken;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null); //Uncomment for further testing
// logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null);
try { try {
const resp = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_JOB_COSTING_DETAILS, { const resp = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_JOB_COSTING_DETAILS, {
@@ -46,7 +47,10 @@ async function JobCostingMulti(req, res) {
const BearerToken = req.BearerToken; const BearerToken = req.BearerToken;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("job-costing-multi-start", "DEBUG", req.user.email, jobids, null); //Uncomment for further testing
// logger.log("job-costing-multi-start", "DEBUG", req?.user?.email, null, {
// jobids
// });
try { try {
const resp = await client const resp = await client
@@ -244,7 +248,8 @@ async function JobCostingMulti(req, res) {
data: ret data: ret
}); });
} catch (error) { } catch (error) {
logger.log("job-costing-multi-error", "ERROR", req.user.email, [jobids], { logger.log("job-costing-multi-error", "ERROR", req?.user?.email, null, {
jobids,
message: error.message, message: error.message,
stack: error.stack stack: error.stack
}); });
@@ -282,7 +287,13 @@ function GenerateCostingData(job) {
if (val.mod_lbr_ty) { if (val.mod_lbr_ty) {
const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown"; const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown";
if (laborProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.mod_lbr_ty); //Uncomment for further testing
// if (laborProfitCenter === "Unknown") {
// logger.log("job-costing unknown type", "debug", null, null, {
// line_desc: val.line_desc,
// mod_lbr_ty: val.mod_lbr_ty
// });
// }
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
@@ -349,10 +360,22 @@ function GenerateCostingData(job) {
if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") { if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") {
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type); //Uncomment for further testing
// if (partsProfitCenter === "Unknown" || !partsProfitCenter) {
// logger.log(
// partsProfitCenter === "Unknown"
// ? "job-costing unknown type"
// : "Unknown cost/profit center mapping for parts.",
// "debug",
// null,
// null,
// {
// line_desc: val.line_desc,
// part_type: val.part_type
// }
// );
// }
if (!partsProfitCenter)
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
let partsAmount = Dinero({ let partsAmount = Dinero({
amount: val.act_price_before_ppc amount: val.act_price_before_ppc
? Math.round(val.act_price_before_ppc * 100) ? Math.round(val.act_price_before_ppc * 100)
@@ -409,10 +432,22 @@ function GenerateCostingData(job) {
if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) { if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) {
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type); //Uncomment for further testing
// if (partsProfitCenter === "Unknown" || !partsProfitCenter) {
// logger.log(
// partsProfitCenter === "Unknown"
// ? "job-costing unknown type"
// : "job-costing Unknown cost/profit center mapping for sublet",
// "debug",
// null,
// null,
// {
// line_desc: val.line_desc,
// part_type: val.part_type
// }
// );
// }
if (!partsProfitCenter)
console.log("Unknown cost/profit center mapping for sublet.", val.line_desc, val.part_type);
const partsAmount = Dinero({ const partsAmount = Dinero({
amount: Math.round((val.act_price || 0) * 100) amount: Math.round((val.act_price || 0) * 100)
}) })
@@ -443,9 +478,14 @@ function GenerateCostingData(job) {
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate. //If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown"; const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
if (partsProfitCenter === "Unknown") { //Uncomment for further testing
console.log("Unknown type", val.line_desc, val.part_type); // if (partsProfitCenter === "Unknown") {
} // logger.log("job-costing unknown type", "debug", null, null, {
// line_desc: val.line_desc,
// part_type: val.part_type
// });
// }
const partsAmount = Dinero({ const partsAmount = Dinero({
amount: Math.round((val.act_price || 0) * 100) amount: Math.round((val.act_price || 0) * 100)
}) })
@@ -476,7 +516,7 @@ function GenerateCostingData(job) {
if (!hasMapaLine) { if (!hasMapaLine) {
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]]) if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero(); jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[ jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
defaultProfits["MAPA"] defaultProfits["MAPA"]
].add( ].add(

View File

@@ -26,7 +26,7 @@ exports.totalsSsu = async function (req, res) {
const BearerToken = req.BearerToken; const BearerToken = req.BearerToken;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null); logger.log("job-totals-ssu-USA", "DEBUG", req?.user?.email, id);
try { try {
const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, { const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, {
@@ -47,7 +47,7 @@ exports.totalsSsu = async function (req, res) {
res.status(200).send(); res.status(200).send();
} catch (error) { } catch (error) {
logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, id, { logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, {
jobid: id, jobid: id,
error error
}); });
@@ -84,12 +84,10 @@ async function Totals(req, res) {
const logger = req.logger; const logger = req.logger;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, { logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, {
jobid: job.id jobid: job.id
}); });
logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null);
await AutoAddAtsIfRequired({ job, client }); await AutoAddAtsIfRequired({ job, client });
try { try {
@@ -961,7 +959,9 @@ function CalculateTaxesTotals(job, otherTotals) {
} }
} }
} catch (error) { } catch (error) {
console.error("Key with issue", key); logger.log("job-totals-USA Key with issue", "error", null, null, {
key
});
} }
}); });
@@ -1026,7 +1026,9 @@ function CalculateTaxesTotals(job, otherTotals) {
totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd); totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd);
} }
} catch (error) { } catch (error) {
console.error("PFP Calculation error", error); logger.log("job-totals-USA - PFP Calculation Error", "error", null, null, {
error
});
} }
}); });

View File

@@ -15,7 +15,7 @@ const jobUpdated = async (req, res) => {
}); });
} }
logger.log("job-update", "INFO", req.user?.email, null, { logger.log("job-update", "DEBUG", req.user?.email, null, {
message: `Job updated event received from Hasura`, message: `Job updated event received from Hasura`,
jobid: req?.body?.event?.data?.new?.id jobid: req?.body?.event?.data?.new?.id
}); });

View File

@@ -16,7 +16,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
(!req.headers.authorization || !req.headers.authorization.startsWith("Bearer ")) && (!req.headers.authorization || !req.headers.authorization.startsWith("Bearer ")) &&
!(req.cookies && req.cookies.__session) !(req.cookies && req.cookies.__session)
) { ) {
console.error("Unauthorized attempt. No authorization provided."); logger.log("api-authorization-call", "warn", req?.user?.email, null, {
type: "unauthorized",
path: req.path,
body: req.body
});
return res.status(403).send("Unauthorized"); return res.status(403).send("Unauthorized");
} }
@@ -32,10 +36,10 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
idToken = req.cookies.__session; idToken = req.cookies.__session;
} else { } else {
// No cookie // No cookie
console.error("Unauthorized attempt. No cookie provided."); logger.log("api-unauthorized-call", "warn", null, null, {
logger.log("api-unauthorized-call", "WARN", null, null, { type: "unauthorized",
req, path: req.path,
type: "no-cookie" body: req.body
}); });
return res.status(403).send("Unauthorized"); return res.status(403).send("Unauthorized");
@@ -47,11 +51,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
req.user = decodedIdToken; req.user = decodedIdToken;
next(); next();
} catch (error) { } catch (error) {
logger.log("api-unauthorized-call", "WARN", null, null, { logger.log("api-unauthorized-call", "warn", null, null, {
path: req.path, path: req.path,
body: req.body, body: req.body,
type: "unauthroized", type: "unauthorized",
...error ...error
}); });

View File

@@ -9,11 +9,9 @@ require("dotenv").config({
}); });
exports.mixdataUpload = async (req, res) => { exports.mixdataUpload = async (req, res) => {
const { bodyshopid } = req.body;
const client = req.userGraphQLClient; const client = req.userGraphQLClient;
logger.log("job-mixdata-upload", "DEBUG", req.user.email, null, null); logger.log("job-mixdata-upload", "DEBUG", req?.user?.email, null, null);
try { try {
for (const element of req.files) { for (const element of req.files) {
@@ -23,7 +21,7 @@ exports.mixdataUpload = async (req, res) => {
explicitArray: false explicitArray: false
}); });
logger.log("job-mixdata-parse", "DEBUG", req.user.email, inboundRequest); logger.log("job-mixdata-parse", "DEBUG", req?.user?.email, null, { inboundRequest });
const ScaleType = DetermineScaleType(inboundRequest); const ScaleType = DetermineScaleType(inboundRequest);
const RoNumbersFromInboundRequest = GetListOfRos(inboundRequest, ScaleType); const RoNumbersFromInboundRequest = GetListOfRos(inboundRequest, ScaleType);
@@ -70,7 +68,7 @@ function DetermineScaleType(inboundRequest) {
const ret = { type: "", verson: 0 }; const ret = { type: "", verson: 0 };
//PPG Mix Data //PPG Mix Data
if (inboundRequest.PPG && inboundRequest.PPG.Header.Protocol.Name === "PPG") { if (inboundRequest?.PPG?.Header?.Protocol?.Name === "PPG") {
return { return {
type: inboundRequest.PPG.Header.Protocol.Name, type: inboundRequest.PPG.Header.Protocol.Name,
company: "PPG", company: "PPG",
@@ -80,13 +78,13 @@ function DetermineScaleType(inboundRequest) {
} }
function GetListOfRos(inboundRequest, ScaleType) { function GetListOfRos(inboundRequest, ScaleType) {
if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") { if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") {
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => r.RONumber); return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => r.RONumber);
} }
} }
function GenerateMixDataArray(inboundRequest, ScaleType, jobHash) { function GenerateMixDataArray(inboundRequest, ScaleType, jobHash) {
if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") { if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") {
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => { return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => {
return { return {
jobid: jobHash[r.RONumber]?.jobid, jobid: jobHash[r.RONumber]?.jobid,

View File

@@ -45,12 +45,12 @@ exports.payall = async function (req, res) {
const path = diffParser(diff); const path = diffParser(diff);
if (diff.op === "add") { if (diff.op === "add") {
console.log(Object.keys(diff.val)); // console.log(Object.keys(diff.val));
if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) { if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) {
//Multiple values to add. //Multiple values to add.
Object.keys(diff.val).forEach((key) => { Object.keys(diff.val).forEach((key) => {
console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]); // console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]);
console.log("Rate", Object.keys(diff.val[key])[0]); // console.log("Rate", Object.keys(diff.val[key])[0]);
ticketsToInsert.push({ ticketsToInsert.push({
task_name: "Pay All", task_name: "Pay All",
jobid: job.id, jobid: job.id,

View File

@@ -49,7 +49,7 @@ exports.job = async (req, res) => {
if (bucketId) { if (bucketId) {
load.productionTotal[bucketId].count = load.productionTotal[bucketId].count + 1; load.productionTotal[bucketId].count = load.productionTotal[bucketId].count + 1;
} else { } else {
console.log("Uh oh, this job doesn't fit in a bucket!", item); // console.log("Uh oh, this job doesn't fit in a bucket!", item);
} }
}); });
@@ -254,7 +254,7 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => {
if (bucketId) { if (bucketId) {
newLoad[bucketId].count = newLoad[bucketId].count + 1; newLoad[bucketId].count = newLoad[bucketId].count + 1;
} else { } else {
console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job); // console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job);
} }
}); });
@@ -263,10 +263,10 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => {
if (bucketId) { if (bucketId) {
newLoad[bucketId].count = newLoad[bucketId].count - 1; newLoad[bucketId].count = newLoad[bucketId].count - 1;
if (newLoad[bucketId].count < 0) { if (newLoad[bucketId].count < 0) {
console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job); // console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job);
} }
} else { } else {
console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job); // console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job);
} }
}); });

View File

@@ -39,7 +39,7 @@ const processor = async (req, res) => {
} }
}); });
} catch (error) { } catch (error) {
console.log("error", error); // console.log("error", error);
res.status(400).send(error); res.status(400).send(error);
} }
}; };

View File

@@ -6,10 +6,11 @@ const client = require("../graphql-client/graphql-client").client;
const emailer = require("../email/sendemail"); const emailer = require("../email/sendemail");
const moment = require("moment-timezone"); const moment = require("moment-timezone");
const converter = require("json-2-csv"); const converter = require("json-2-csv");
const logger = require("../utils/logger");
exports.taskHandler = async (req, res) => { exports.taskHandler = async (req, res) => {
try { try {
const { bodyshopid, query, variables, text, to, subject, timezone } = req.body; const { query, variables, text, to, subject, timezone } = req.body;
//Check the variables to see if they are an object. //Check the variables to see if they are an object.
Object.keys(variables).forEach((key) => { Object.keys(variables).forEach((key) => {
@@ -32,8 +33,10 @@ exports.taskHandler = async (req, res) => {
text, text,
attachments: [{ filename: "query.csv", content: csv }] attachments: [{ filename: "query.csv", content: csv }]
}) })
.catch((err) => { .catch((error) => {
console.error("Errors sending CSV Email."); logger.log("Tasks - Error sending CSV EMAIL", "error", req?.user?.email, null, {
error
});
}); });
return res.status(200).send(csv); return res.status(200).send(csv);

View File

@@ -8,7 +8,7 @@ const InstanceManager = require("../utils/instanceMgr").default;
const winston = require("winston"); const winston = require("winston");
const WinstonCloudWatch = require("winston-cloudwatch"); const WinstonCloudWatch = require("winston-cloudwatch");
const { isString, isEmpty } = require("lodash"); const { isString, isEmpty } = require("lodash");
const { networkInterfaces } = require("node:os"); const { networkInterfaces, hostname } = require("node:os");
const createLogger = () => { const createLogger = () => {
try { try {
@@ -28,9 +28,6 @@ const createLogger = () => {
if (isLocal) { if (isLocal) {
winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`; winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
console.log(
`Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}`
);
} }
const levelFilter = (levels) => { const levelFilter = (levels) => {
@@ -43,19 +40,22 @@ const createLogger = () => {
})(); })();
}; };
const getPrivateIP = () => { const getHostNameOrIP = () => {
// Try to get the hostname first
const hostName = hostname();
if (hostName) return hostName;
const interfaces = networkInterfaces(); const interfaces = networkInterfaces();
for (const name of Object.keys(interfaces)) { for (const name of Object.keys(interfaces)) {
for (const iface of interfaces[name]) { for (const iface of interfaces[name]) {
// Find an IPv4 address that's not internal (like localhost)
if (iface.family === "IPv4" && !iface.internal) { if (iface.family === "IPv4" && !iface.internal) {
return iface.address; return iface.address;
} }
} }
} }
return "127.0.0.1"; return "127.0.0.1";
}; };
const createProductionTransport = (level, logStreamName, filters) => { const createProductionTransport = (level, logStreamName, filters) => {
return new WinstonCloudWatch({ return new WinstonCloudWatch({
level, level,
@@ -65,7 +65,7 @@ const createLogger = () => {
}); });
}; };
const hostname = process.env.HOSTNAME || getPrivateIP(); const internalHostname = process.env.HOSTNAME || getHostNameOrIP();
const getDevelopmentTransports = () => [ const getDevelopmentTransports = () => [
new winston.transports.Console({ new winston.transports.Console({
@@ -74,7 +74,7 @@ const createLogger = () => {
winston.format.colorize(), winston.format.colorize(),
winston.format.timestamp(), winston.format.timestamp(),
winston.format.printf(({ level, message, timestamp, user, record, meta }) => { winston.format.printf(({ level, message, timestamp, user, record, meta }) => {
const hostnameColor = `\x1b[34m${hostname}\x1b[0m`; // Blue const hostnameColor = `\x1b[34m${internalHostname}\x1b[0m`; // Blue
const timestampColor = `\x1b[36m${timestamp}\x1b[0m`; // Cyan const timestampColor = `\x1b[36m${timestamp}\x1b[0m`; // Cyan
const labelColor = "\x1b[33m"; // Yellow const labelColor = "\x1b[33m"; // Yellow
const separatorColor = "\x1b[35m|\x1b[0m"; // Magenta for separators const separatorColor = "\x1b[35m|\x1b[0m"; // Magenta for separators
@@ -106,13 +106,19 @@ const createLogger = () => {
: [...getDevelopmentTransports(), ...getProductionTransports()] : [...getDevelopmentTransports(), ...getProductionTransports()]
}); });
if (isLocal) {
winstonLogger.debug(
`CloudWatch set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}`
);
}
const log = (message, type, user, record, meta) => { const log = (message, type, user, record, meta) => {
winstonLogger.log({ winstonLogger.log({
level: type.toLowerCase(), level: type.toLowerCase(),
message, message,
user, user,
record, record,
hostname, hostname: internalHostname,
meta meta
}); });
}; };

View File

@@ -41,7 +41,8 @@ const redisSocketEvents = ({
// Register Socket Events // Register Socket Events
const registerSocketEvents = (socket) => { const registerSocketEvents = (socket) => {
createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`); // Uncomment for further testing
// createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`);
// Token Update Events // Token Update Events
const registerUpdateEvents = (socket) => { const registerUpdateEvents = (socket) => {
@@ -54,12 +55,13 @@ const redisSocketEvents = ({
// If We ever want to persist user Data across workers // If We ever want to persist user Data across workers
// await setSessionData(socket.id, "user", user); // await setSessionData(socket.id, "user", user);
createLogEvent(socket, "debug", "Token updated successfully"); // Uncomment for further testing
// createLogEvent(socket, "debug", "Token updated successfully");
socket.emit("token-updated", { success: true }); socket.emit("token-updated", { success: true });
} catch (error) { } catch (error) {
if (error.code === "auth/id-token-expired") { if (error.code === "auth/id-token-expired") {
createLogEvent(socket, "WARNING", "Stale token received, waiting for new token"); createLogEvent(socket, "warn", "Stale token received, waiting for new token");
socket.emit("token-updated", { socket.emit("token-updated", {
success: false, success: false,
error: "Stale token." error: "Stale token."
@@ -80,7 +82,7 @@ const redisSocketEvents = ({
try { try {
const room = getBodyshopRoom(bodyshopUUID); const room = getBodyshopRoom(bodyshopUUID);
socket.join(room); socket.join(room);
createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`); // createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`);
} catch (error) { } catch (error) {
createLogEvent(socket, "error", `Error joining room: ${error}`); createLogEvent(socket, "error", `Error joining room: ${error}`);
} }
@@ -114,7 +116,9 @@ const redisSocketEvents = ({
// Disconnect Events // Disconnect Events
const registerDisconnectEvents = (socket) => { const registerDisconnectEvents = (socket) => {
const disconnect = () => { const disconnect = () => {
createLogEvent(socket, "debug", `User disconnected.`); // Uncomment for further testing
// createLogEvent(socket, "debug", `User disconnected.`);
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
for (const room of rooms) { for (const room of rooms) {
socket.leave(room); socket.leave(room);