Merged in release/2022-01-14 (pull request #349)
release/2022-01-14 Approved-by: Patrick Fic
This commit is contained in:
@@ -38007,6 +38007,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>production_by_category</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>production_by_csr</name>
|
<name>production_by_csr</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import ProductionListLastContacted from "./production-list-columns.lastcontacted
|
|||||||
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
|
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
|
||||||
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
||||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||||
|
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||||
|
|
||||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||||
@@ -251,6 +252,29 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
render: (text, record) => <ProductionListColumnStatus record={record} />,
|
render: (text, record) => <ProductionListColumnStatus record={record} />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t("jobs.fields.category"),
|
||||||
|
dataIndex: "category",
|
||||||
|
key: "category",
|
||||||
|
ellipsis: true,
|
||||||
|
|
||||||
|
filters:
|
||||||
|
(bodyshop &&
|
||||||
|
bodyshop.md_categories.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s,
|
||||||
|
value: [s],
|
||||||
|
};
|
||||||
|
})) ||
|
||||||
|
[],
|
||||||
|
onFilter: (value, record) => value.includes(record.category),
|
||||||
|
sorter: (a, b) => alphaSort(a.category, b.category),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "category" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<ProductionListColumnCategory record={record} />
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t("production.labels.bodyhours"),
|
title: i18n.t("production.labels.bodyhours"),
|
||||||
dataIndex: "labhrs",
|
dataIndex: "labhrs",
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { useMutation } from "@apollo/client";
|
||||||
|
import { Dropdown, Menu, Spin } from "antd";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
export function ProductionListColumnCategory({ record, bodyshop }) {
|
||||||
|
const [updateJob] = useMutation(UPDATE_JOB);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleSetStatus = async (e) => {
|
||||||
|
logImEXEvent("production_change_status");
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
const { key } = e;
|
||||||
|
await updateJob({
|
||||||
|
variables: {
|
||||||
|
jobId: record.id,
|
||||||
|
job: {
|
||||||
|
category: key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
overlay={
|
||||||
|
<Menu
|
||||||
|
style={{ maxHeight: "200px", overflowY: "auto" }}
|
||||||
|
onClick={handleSetStatus}
|
||||||
|
>
|
||||||
|
{bodyshop.md_categories.map((item) => (
|
||||||
|
<Menu.Item key={item}>{item}</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
trigger={["click"]}
|
||||||
|
>
|
||||||
|
<div style={{ width: "100%", height: "19px", cursor: "pointer" }}>
|
||||||
|
{record.category}
|
||||||
|
{loading && <Spin />}
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ProductionListColumnCategory);
|
||||||
@@ -88,6 +88,12 @@ export function ProductionListTable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
console.log(
|
||||||
|
"🚀 ~ file: production-list-table.component.jsx ~ line 91 ~ pagination, filters, sorter",
|
||||||
|
pagination,
|
||||||
|
filters,
|
||||||
|
sorter
|
||||||
|
);
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
filteredInfo: filters,
|
filteredInfo: filters,
|
||||||
@@ -265,6 +271,7 @@ export function ProductionListTable({
|
|||||||
columns={columns.map((c, index) => {
|
columns={columns.map((c, index) => {
|
||||||
return {
|
return {
|
||||||
...c,
|
...c,
|
||||||
|
filteredValue: state.filteredInfo[c.key] || null,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
||||||
title: headerItem(c),
|
title: headerItem(c),
|
||||||
|
|||||||
@@ -25,15 +25,20 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
|||||||
const { ssbuckets } = bodyshop;
|
const { ssbuckets } = bodyshop;
|
||||||
|
|
||||||
const data = useMemo(() => {
|
const data = useMemo(() => {
|
||||||
return Object.keys(loadData.expectedLoad).map((key) => {
|
return (
|
||||||
const metadataBucket = ssbuckets.filter((b) => b.id === key)[0];
|
(loadData &&
|
||||||
|
loadData.expectedLoad &&
|
||||||
|
Object.keys(loadData.expectedLoad).map((key) => {
|
||||||
|
const metadataBucket = ssbuckets.filter((b) => b.id === key)[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bucket: loadData.expectedLoad[key].label,
|
bucket: loadData.expectedLoad[key].label,
|
||||||
current: loadData.expectedLoad[key].count,
|
current: loadData.expectedLoad[key].count,
|
||||||
target: metadataBucket && metadataBucket.target,
|
target: metadataBucket && metadataBucket.target,
|
||||||
};
|
};
|
||||||
});
|
})) ||
|
||||||
|
[]
|
||||||
|
);
|
||||||
}, [loadData, ssbuckets]);
|
}, [loadData, ssbuckets]);
|
||||||
|
|
||||||
const popContent = (
|
const popContent = (
|
||||||
|
|||||||
@@ -75,9 +75,17 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
|||||||
<div>
|
<div>
|
||||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||||
<>
|
<>
|
||||||
<DataLabel label={t("bodyshop.labels.dms.cdk_dealerid")}>
|
{bodyshop.cdk_dealerid && (
|
||||||
{form.getFieldValue("cdk_dealerid")}
|
<DataLabel label={t("bodyshop.labels.dms.cdk_dealerid")}>
|
||||||
</DataLabel>
|
{form.getFieldValue("cdk_dealerid")}
|
||||||
|
</DataLabel>
|
||||||
|
)}
|
||||||
|
{bodyshop.pbs_serialnumber && (
|
||||||
|
<DataLabel label={t("bodyshop.labels.dms.pbs_serialnumber")}>
|
||||||
|
{form.getFieldValue("pbs_serialnumber")}
|
||||||
|
</DataLabel>
|
||||||
|
)}
|
||||||
|
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.dms.default_journal")}
|
label={t("bodyshop.fields.dms.default_journal")}
|
||||||
@@ -158,11 +166,11 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
|||||||
label={t("jobs.fields.dms.payer.control_type")}
|
label={t("jobs.fields.dms.payer.control_type")}
|
||||||
key={`${index}control_type`}
|
key={`${index}control_type`}
|
||||||
name={[field.name, "control_type"]}
|
name={[field.name, "control_type"]}
|
||||||
rules={[
|
// rules={[
|
||||||
{
|
// {
|
||||||
required: true,
|
// required: true,
|
||||||
},
|
// },
|
||||||
]}
|
// ]}
|
||||||
>
|
>
|
||||||
<Select showSearch>
|
<Select showSearch>
|
||||||
<Select.Option value="ro_number">
|
<Select.Option value="ro_number">
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
|
|||||||
ro_number
|
ro_number
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
|
category
|
||||||
ownr_co_nm
|
ownr_co_nm
|
||||||
v_model_yr
|
v_model_yr
|
||||||
v_model_desc
|
v_model_desc
|
||||||
@@ -193,6 +194,7 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
|
|||||||
status
|
status
|
||||||
ro_number
|
ro_number
|
||||||
ownr_fn
|
ownr_fn
|
||||||
|
category
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ownr_co_nm
|
ownr_co_nm
|
||||||
v_model_yr
|
v_model_yr
|
||||||
@@ -263,6 +265,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
|||||||
id
|
id
|
||||||
updated_at
|
updated_at
|
||||||
status
|
status
|
||||||
|
category
|
||||||
ro_number
|
ro_number
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
|
|||||||
@@ -2260,6 +2260,7 @@
|
|||||||
"parts_not_recieved": "Parts Not Received",
|
"parts_not_recieved": "Parts Not Received",
|
||||||
"payments_by_date": "Payments by Date",
|
"payments_by_date": "Payments by Date",
|
||||||
"payments_by_date_type": "Payments by Date and Type",
|
"payments_by_date_type": "Payments by Date and Type",
|
||||||
|
"production_by_category": "Production by Category",
|
||||||
"production_by_csr": "Production by CSR",
|
"production_by_csr": "Production by CSR",
|
||||||
"production_by_last_name": "Production by Last Name",
|
"production_by_last_name": "Production by Last Name",
|
||||||
"production_by_repair_status": "Production by Status",
|
"production_by_repair_status": "Production by Status",
|
||||||
|
|||||||
@@ -2260,6 +2260,7 @@
|
|||||||
"parts_not_recieved": "",
|
"parts_not_recieved": "",
|
||||||
"payments_by_date": "",
|
"payments_by_date": "",
|
||||||
"payments_by_date_type": "",
|
"payments_by_date_type": "",
|
||||||
|
"production_by_category": "",
|
||||||
"production_by_csr": "",
|
"production_by_csr": "",
|
||||||
"production_by_last_name": "",
|
"production_by_last_name": "",
|
||||||
"production_by_repair_status": "",
|
"production_by_repair_status": "",
|
||||||
|
|||||||
@@ -2260,6 +2260,7 @@
|
|||||||
"parts_not_recieved": "",
|
"parts_not_recieved": "",
|
||||||
"payments_by_date": "",
|
"payments_by_date": "",
|
||||||
"payments_by_date_type": "",
|
"payments_by_date_type": "",
|
||||||
|
"production_by_category": "",
|
||||||
"production_by_csr": "",
|
"production_by_csr": "",
|
||||||
"production_by_last_name": "",
|
"production_by_last_name": "",
|
||||||
"production_by_repair_status": "",
|
"production_by_repair_status": "",
|
||||||
|
|||||||
@@ -1598,6 +1598,14 @@ export const TemplateList = (type, context) => {
|
|||||||
//idtype: "vendor",
|
//idtype: "vendor",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
production_by_category: {
|
||||||
|
title: i18n.t("reportcenter.templates.production_by_category"),
|
||||||
|
description: "",
|
||||||
|
subject: i18n.t("reportcenter.templates.production_by_category"),
|
||||||
|
key: "production_by_category",
|
||||||
|
//idtype: "vendor",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(!type || type === "special"
|
...(!type || type === "special"
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ app.get("/test", async function (req, res) {
|
|||||||
"git rev-parse --short HEAD"
|
"git rev-parse --short HEAD"
|
||||||
);
|
);
|
||||||
logger.log("test-api-status", "DEBUG", "api", { commit });
|
logger.log("test-api-status", "DEBUG", "api", { commit });
|
||||||
|
sendEmail.sendServerEmail({
|
||||||
|
subject: `API Check - ${process.env.NODE_ENV}`,
|
||||||
|
text: `Server API check has come in. `,
|
||||||
|
});
|
||||||
res.status(200).send(`OK - ${commit}`);
|
res.status(200).send(`OK - ${commit}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ require("dotenv").config({
|
|||||||
let Client = require("ssh2-sftp-client");
|
let Client = require("ssh2-sftp-client");
|
||||||
|
|
||||||
const client = require("../graphql-client/graphql-client").client;
|
const client = require("../graphql-client/graphql-client").client;
|
||||||
|
const { sendServerEmail } = require("../email/sendemail");
|
||||||
const AHDineroFormat = "0.00";
|
const AHDineroFormat = "0.00";
|
||||||
const AhDateFormat = "MMDDYYYY";
|
const AhDateFormat = "MMDDYYYY";
|
||||||
|
|
||||||
@@ -112,16 +113,6 @@ exports.default = async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (process.env.NODE_ENV !== "production") {
|
|
||||||
for (const xmlObj of allxmlsToUpload) {
|
|
||||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(allxmlsToUpload);
|
|
||||||
return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
let sftp = new Client();
|
let sftp = new Client();
|
||||||
sftp.on("error", (errors) =>
|
sftp.on("error", (errors) =>
|
||||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
||||||
@@ -155,7 +146,17 @@ exports.default = async (req, res) => {
|
|||||||
} finally {
|
} finally {
|
||||||
sftp.end();
|
sftp.end();
|
||||||
}
|
}
|
||||||
|
sendServerEmail({
|
||||||
|
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
||||||
|
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||||
|
|
||||||
|
Uploaded: ${JSON.stringify(
|
||||||
|
allxmlsToUpload.map((x) => x.filename),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}
|
||||||
|
`,
|
||||||
|
});
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(200).json(error);
|
res.status(200).json(error);
|
||||||
@@ -682,13 +683,11 @@ const CreateCosts = (job) => {
|
|||||||
ticketTotalsByCostCenter[defaultCosts.LAM] || Dinero(),
|
ticketTotalsByCostCenter[defaultCosts.LAM] || Dinero(),
|
||||||
StructuralLaborTotalCost:
|
StructuralLaborTotalCost:
|
||||||
ticketTotalsByCostCenter[defaultCosts.LAS] || Dinero(),
|
ticketTotalsByCostCenter[defaultCosts.LAS] || Dinero(),
|
||||||
ElectricalLaborTotalCost:
|
ElectricalLaborTotalCost:
|
||||||
ticketTotalsByCostCenter[defaultCosts.LAE] || Dinero(),
|
ticketTotalsByCostCenter[defaultCosts.LAE] || Dinero(),
|
||||||
FrameLaborTotalCost:
|
FrameLaborTotalCost: ticketTotalsByCostCenter[defaultCosts.LAF] || Dinero(),
|
||||||
ticketTotalsByCostCenter[defaultCosts.LAF] || Dinero(),
|
GlassLaborTotalCost: ticketTotalsByCostCenter[defaultCosts.LAG] || Dinero(),
|
||||||
GlassLaborTotalCost:
|
DetailLaborTotalCost:
|
||||||
ticketTotalsByCostCenter[defaultCosts.LAG] || Dinero(),
|
|
||||||
DetailLaborTotalCost:
|
|
||||||
ticketTotalsByCostCenter[defaultCosts.LAD] || Dinero(),
|
ticketTotalsByCostCenter[defaultCosts.LAD] || Dinero(),
|
||||||
PMTotalCost: billTotalsByCostCenters[defaultCosts.MAPA] || Dinero(),
|
PMTotalCost: billTotalsByCostCenters[defaultCosts.MAPA] || Dinero(),
|
||||||
BMTotalCost: billTotalsByCostCenters[defaultCosts.MASH] || Dinero(),
|
BMTotalCost: billTotalsByCostCenters[defaultCosts.MASH] || Dinero(),
|
||||||
|
|||||||
@@ -18,6 +18,34 @@ let transporter = nodemailer.createTransport({
|
|||||||
SES: { ses, aws },
|
SES: { ses, aws },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exports.sendServerEmail = async function ({ subject, text }) {
|
||||||
|
try {
|
||||||
|
transporter.sendMail(
|
||||||
|
{
|
||||||
|
from: `ImEX Online API - ${process.env.NODE_ENV} <noreply@imex.online>`,
|
||||||
|
to: ["patrick@snapt.ca"],
|
||||||
|
subject: subject,
|
||||||
|
text: text,
|
||||||
|
ses: {
|
||||||
|
// optional extra arguments for SendRawEmail
|
||||||
|
Tags: [
|
||||||
|
{
|
||||||
|
Name: "tag_name",
|
||||||
|
Value: "tag_value",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(err, info) => {
|
||||||
|
console.log(err || info);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
logger.log("server-email-failure", "error", null, null, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
exports.sendEmail = async (req, res) => {
|
exports.sendEmail = async (req, res) => {
|
||||||
logger.log("send-email", "DEBUG", req.user.email, null, {
|
logger.log("send-email", "DEBUG", req.user.email, null, {
|
||||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||||
|
|||||||
Reference in New Issue
Block a user