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>
|
||||
</translations>
|
||||
</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>
|
||||
<name>production_by_csr</name>
|
||||
<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 ProductionListColumnNote from "./production-list-columns.productionnote.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";
|
||||
|
||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
@@ -251,6 +252,29 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
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"),
|
||||
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) => {
|
||||
console.log(
|
||||
"🚀 ~ file: production-list-table.component.jsx ~ line 91 ~ pagination, filters, sorter",
|
||||
pagination,
|
||||
filters,
|
||||
sorter
|
||||
);
|
||||
setState({
|
||||
...state,
|
||||
filteredInfo: filters,
|
||||
@@ -265,6 +271,7 @@ export function ProductionListTable({
|
||||
columns={columns.map((c, index) => {
|
||||
return {
|
||||
...c,
|
||||
filteredValue: state.filteredInfo[c.key] || null,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
||||
title: headerItem(c),
|
||||
|
||||
@@ -25,15 +25,20 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
const { ssbuckets } = bodyshop;
|
||||
|
||||
const data = useMemo(() => {
|
||||
return Object.keys(loadData.expectedLoad).map((key) => {
|
||||
const metadataBucket = ssbuckets.filter((b) => b.id === key)[0];
|
||||
return (
|
||||
(loadData &&
|
||||
loadData.expectedLoad &&
|
||||
Object.keys(loadData.expectedLoad).map((key) => {
|
||||
const metadataBucket = ssbuckets.filter((b) => b.id === key)[0];
|
||||
|
||||
return {
|
||||
bucket: loadData.expectedLoad[key].label,
|
||||
current: loadData.expectedLoad[key].count,
|
||||
target: metadataBucket && metadataBucket.target,
|
||||
};
|
||||
});
|
||||
return {
|
||||
bucket: loadData.expectedLoad[key].label,
|
||||
current: loadData.expectedLoad[key].count,
|
||||
target: metadataBucket && metadataBucket.target,
|
||||
};
|
||||
})) ||
|
||||
[]
|
||||
);
|
||||
}, [loadData, ssbuckets]);
|
||||
|
||||
const popContent = (
|
||||
|
||||
@@ -75,9 +75,17 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
<div>
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<>
|
||||
<DataLabel label={t("bodyshop.labels.dms.cdk_dealerid")}>
|
||||
{form.getFieldValue("cdk_dealerid")}
|
||||
</DataLabel>
|
||||
{bodyshop.cdk_dealerid && (
|
||||
<DataLabel label={t("bodyshop.labels.dms.cdk_dealerid")}>
|
||||
{form.getFieldValue("cdk_dealerid")}
|
||||
</DataLabel>
|
||||
)}
|
||||
{bodyshop.pbs_serialnumber && (
|
||||
<DataLabel label={t("bodyshop.labels.dms.pbs_serialnumber")}>
|
||||
{form.getFieldValue("pbs_serialnumber")}
|
||||
</DataLabel>
|
||||
)}
|
||||
|
||||
<LayoutFormRow>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.dms.default_journal")}
|
||||
@@ -158,11 +166,11 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
label={t("jobs.fields.dms.payer.control_type")}
|
||||
key={`${index}control_type`}
|
||||
name={[field.name, "control_type"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
// rules={[
|
||||
// {
|
||||
// required: true,
|
||||
// },
|
||||
// ]}
|
||||
>
|
||||
<Select showSearch>
|
||||
<Select.Option value="ro_number">
|
||||
|
||||
@@ -123,6 +123,7 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
|
||||
ro_number
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
category
|
||||
ownr_co_nm
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
@@ -193,6 +194,7 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
|
||||
status
|
||||
ro_number
|
||||
ownr_fn
|
||||
category
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
v_model_yr
|
||||
@@ -263,6 +265,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
||||
id
|
||||
updated_at
|
||||
status
|
||||
category
|
||||
ro_number
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
|
||||
@@ -2260,6 +2260,7 @@
|
||||
"parts_not_recieved": "Parts Not Received",
|
||||
"payments_by_date": "Payments by Date",
|
||||
"payments_by_date_type": "Payments by Date and Type",
|
||||
"production_by_category": "Production by Category",
|
||||
"production_by_csr": "Production by CSR",
|
||||
"production_by_last_name": "Production by Last Name",
|
||||
"production_by_repair_status": "Production by Status",
|
||||
|
||||
@@ -2260,6 +2260,7 @@
|
||||
"parts_not_recieved": "",
|
||||
"payments_by_date": "",
|
||||
"payments_by_date_type": "",
|
||||
"production_by_category": "",
|
||||
"production_by_csr": "",
|
||||
"production_by_last_name": "",
|
||||
"production_by_repair_status": "",
|
||||
|
||||
@@ -2260,6 +2260,7 @@
|
||||
"parts_not_recieved": "",
|
||||
"payments_by_date": "",
|
||||
"payments_by_date_type": "",
|
||||
"production_by_category": "",
|
||||
"production_by_csr": "",
|
||||
"production_by_last_name": "",
|
||||
"production_by_repair_status": "",
|
||||
|
||||
@@ -1598,6 +1598,14 @@ export const TemplateList = (type, context) => {
|
||||
//idtype: "vendor",
|
||||
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"
|
||||
|
||||
@@ -68,6 +68,10 @@ app.get("/test", async function (req, res) {
|
||||
"git rev-parse --short HEAD"
|
||||
);
|
||||
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}`);
|
||||
});
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ require("dotenv").config({
|
||||
let Client = require("ssh2-sftp-client");
|
||||
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const { sendServerEmail } = require("../email/sendemail");
|
||||
const AHDineroFormat = "0.00";
|
||||
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();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
||||
@@ -155,7 +146,17 @@ exports.default = async (req, res) => {
|
||||
} finally {
|
||||
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);
|
||||
} catch (error) {
|
||||
res.status(200).json(error);
|
||||
@@ -682,13 +683,11 @@ const CreateCosts = (job) => {
|
||||
ticketTotalsByCostCenter[defaultCosts.LAM] || Dinero(),
|
||||
StructuralLaborTotalCost:
|
||||
ticketTotalsByCostCenter[defaultCosts.LAS] || Dinero(),
|
||||
ElectricalLaborTotalCost:
|
||||
ElectricalLaborTotalCost:
|
||||
ticketTotalsByCostCenter[defaultCosts.LAE] || Dinero(),
|
||||
FrameLaborTotalCost:
|
||||
ticketTotalsByCostCenter[defaultCosts.LAF] || Dinero(),
|
||||
GlassLaborTotalCost:
|
||||
ticketTotalsByCostCenter[defaultCosts.LAG] || Dinero(),
|
||||
DetailLaborTotalCost:
|
||||
FrameLaborTotalCost: ticketTotalsByCostCenter[defaultCosts.LAF] || Dinero(),
|
||||
GlassLaborTotalCost: ticketTotalsByCostCenter[defaultCosts.LAG] || Dinero(),
|
||||
DetailLaborTotalCost:
|
||||
ticketTotalsByCostCenter[defaultCosts.LAD] || Dinero(),
|
||||
PMTotalCost: billTotalsByCostCenters[defaultCosts.MAPA] || Dinero(),
|
||||
BMTotalCost: billTotalsByCostCenters[defaultCosts.MASH] || Dinero(),
|
||||
|
||||
@@ -18,6 +18,34 @@ let transporter = nodemailer.createTransport({
|
||||
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) => {
|
||||
logger.log("send-email", "DEBUG", req.user.email, null, {
|
||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||
|
||||
Reference in New Issue
Block a user