Merged in release/2021-11-19 (pull request #266)

release/2021-11-19

Approved-by: Patrick Fic
This commit is contained in:
Patrick Fic
2021-11-18 01:30:23 +00:00
12 changed files with 492 additions and 149 deletions

View File

@@ -34872,6 +34872,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>settings</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>
</children>
</folder_node>
<folder_node>
@@ -35003,6 +35024,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>compact</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>detailpriority</name>
<definition_loaded>false</definition_loaded>
@@ -35024,6 +35066,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>employeeassignments</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>employeesearch</name>
<definition_loaded>false</definition_loaded>
@@ -35066,6 +35129,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>laborhrs</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>note</name>
<definition_loaded>false</definition_loaded>

View File

@@ -1,14 +1,13 @@
import React from "react";
import { Card, Row, Col, Dropdown } from "antd";
import { EyeFilled, CalendarOutlined } from "@ant-design/icons";
import { Card, Col, Row, Space, Typography } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import ProductionAlert from "../production-list-columns/production-list-columns.alert.component";
import { EyeFilled } from "@ant-design/icons";
import { Link } from "react-router-dom";
import "./production-board-card.styles.scss";
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
import { useTranslation } from "react-i18next";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import "./production-board-card.styles.scss";
export default function ProductionBoardCard(
technician,
@@ -17,13 +16,7 @@ export default function ProductionBoardCard(
cardSettings
) {
const { t } = useTranslation();
const menu = (
<div>
<Card title={t("general.labels.actions")}>
<ProductionRemoveButton jobId={card.id} />
</Card>
</div>
);
const [flipped, setFlipped] = useState(false);
let employee_body, employee_prep, employee_refinish, employee_csr;
if (card.employee_body) {
employee_body = bodyshop.employees.find((e) => e.id === card.employee_body);
@@ -41,36 +34,62 @@ export default function ProductionBoardCard(
}
return (
<Dropdown overlay={menu} trigger={["contextMenu"]}>
<Card
className="react-kanban-card imex-kanban-card tight-antd-rows"
title={`${card.ro_number || t("general.labels.na")} - ${
card.v_model_yr
} ${card.v_make_desc || ""} ${card.v_model_desc || ""}`}
>
<Card
className="react-kanban-card imex-kanban-card tight-antd-rows"
onDoubleClick={() => setFlipped(!flipped)}
>
<div style={{ display: "flex" }}>
<span style={{ fontWeight: "bold", flex: 1 }}>
{card.ro_number || t("general.labels.na")}
</span>
<Space size="small" align="start">
{cardSettings && cardSettings.alert && (
<ProductionAlert record={card} key="alert" />
)}
{technician ? (
<Link to={`/tech/joblookup?selected=${card.id}`}>
<EyeFilled />
</Link>
) : (
<Link to={`/manage/jobs/${card.id}`}>
<EyeFilled />
</Link>
)}
</Space>
</div>
{flipped ? (
<Row>
<Col span={24}>
<div className="ellipses">{`${card.ownr_fn || ""} ${
card.ownr_ln || ""
} ${card.ownr_co_nm || ""}`}</div>
</Col>
</Row>
<Row>
<Col span={12}>
<div className="ellipses">{card.clm_no || ""}</div>
</Col>
<Col span={12}>
<div className="ellipses">{card.ins_co_nm || ""}</div>
</Col>
</Row>
<Row>
<Col span={24}>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<div className="mex-flex-row__margin">
{cardSettings && cardSettings.clm_no === "back" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<div className="ellipses">{card.clm_no || ""}</div>
</Col>
)}
{cardSettings && cardSettings.ins_co_nm === "back" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<div className="ellipses">{card.ins_co_nm || ""}</div>
</Col>
)}
{cardSettings && cardSettings.laborhrs === "back" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<Space
size="small"
direction={
cardSettings && cardSettings.compact
? "horizontal"
: "vertical"
}
>
<div>{`B: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
<div>{`R: ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
</div>
<div className="mex-flex-row__margin">
</Space>
</Col>
)}
{cardSettings && cardSettings.employeeassignments === "back" && (
<Col span={12}>
<Space
direction="vertical"
wrap={cardSettings && cardSettings.compact}
>
<div>{`B: ${
employee_body
? `${employee_body.first_name} ${employee_body.last_name}`
@@ -91,35 +110,146 @@ export default function ProductionBoardCard(
? `${employee_csr.first_name} ${employee_csr.last_name}`
: ""
}`}</div>
</div>
</div>
</Col>
</Row>
<Row>
<Col span={18}>
<DateTimeFormatter>{card.scheduled_completion}</DateTimeFormatter>
</Col>
<Col span={6}>
<div>{card.alt_transport || ""}</div>
</Col>
</Row>
<div>
<ProductionListColumnProductionNote record={card} />
</div>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<ProductionAlert record={card} key="alert" />
<ProductionSubletsManageComponent subletJobLines={card.subletLines} />
{technician ? (
<Link to={`/tech/joblookup?selected=${card.id}`}>
<EyeFilled />
</Link>
) : (
<Link to={`/manage/jobs/${card.id}`}>
<EyeFilled />
</Link>
</Space>
</Col>
)}
</div>
</Card>
</Dropdown>
{cardSettings && cardSettings.scheduled_completion === "back" && (
<Col span={12}>
<Space>
<CalendarOutlined />
<DateTimeFormatter format="MM/DD">
{card.scheduled_completion}
</DateTimeFormatter>
</Space>
</Col>
)}
{cardSettings && cardSettings.ats === "back" && (
<Col span={12}>
<Col span={cardSettings && cardSettings.compact ? 24 : 6}>
<div>{card.alt_transport || ""}</div>
</Col>
</Col>
)}
{cardSettings && cardSettings.sublets === "back" && (
<Col span={12}>
<ProductionSubletsManageComponent
subletJobLines={card.subletLines}
/>
</Col>
)}
{cardSettings && cardSettings.production_note === "back" && (
<Col span={24}>
{cardSettings && cardSettings.production_note === "back" && (
<ProductionListColumnProductionNote record={card} />
)}
</Col>
)}
</Row>
) : (
<Row>
<Col span={24}>
{cardSettings && cardSettings.compact ? (
<div className="ellipses">{`${card.ownr_ln || ""} ${
card.ownr_co_nm || ""
}`}</div>
) : (
<div className="ellipses">{`${card.ownr_ln || ""}, ${
card.ownr_fn || ""
} ${card.ownr_co_nm || ""}`}</div>
)}
</Col>
<Col span={24}>
<div className="ellipses">{`${card.v_model_yr || ""} ${
card.v_make_desc || ""
} ${card.v_model_desc || ""}`}</div>
</Col>
{cardSettings && cardSettings.clm_no === "front" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<div className="ellipses">{card.clm_no || ""}</div>
</Col>
)}
{cardSettings && cardSettings.ins_co_nm === "front" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<div className="ellipses">{card.ins_co_nm || ""}</div>
</Col>
)}
{cardSettings && cardSettings.laborhrs === "front" && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<Space
size="small"
direction={
cardSettings && cardSettings.compact
? "horizontal"
: "vertical"
}
>
<div>{`B: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
<div>{`R: ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
</Space>
</Col>
)}
{cardSettings && cardSettings.employeeassignments === "front" && (
<Col span={24}>
<Space
direction="vertical"
wrap={cardSettings && cardSettings.compact}
>
<div>{`B: ${
employee_body
? `${employee_body.first_name} ${employee_body.last_name}`
: ""
}`}</div>
<div>{`P: ${
employee_prep
? `${employee_prep.first_name} ${employee_prep.last_name}`
: ""
}`}</div>
<div>{`R: ${
employee_refinish
? `${employee_refinish.first_name} ${employee_refinish.last_name}`
: ""
}`}</div>
<div>{`CSR: ${
employee_csr
? `${employee_csr.first_name} ${employee_csr.last_name}`
: ""
}`}</div>
</Space>
</Col>
)}
{cardSettings && cardSettings.scheduled_completion === "front" && (
<Col span={12}>
<Space>
<CalendarOutlined />
<DateTimeFormatter format="MM/DD">
{card.scheduled_completion}
</DateTimeFormatter>
</Space>
</Col>
)}
{cardSettings && cardSettings.ats === "front" && (
<Col span={12}>
<div>{card.alt_transport || ""}</div>
</Col>
)}
{cardSettings && cardSettings.sublets === "front" && (
<Col span={12}>
<ProductionSubletsManageComponent
subletJobLines={card.subletLines}
/>
</Col>
)}
{cardSettings && cardSettings.production_note === "front" && (
<Col span={24}>
{cardSettings && cardSettings.production_note === "front" && (
<ProductionListColumnProductionNote record={card} />
)}
</Col>
)}
</Row>
)}
</Card>
);
}

View File

@@ -1,6 +1,16 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Dropdown, Form, Switch } from "antd";
import React, { useEffect } from "react";
import {
Button,
Card,
Col,
Form,
notification,
Popover,
Radio,
Row,
Switch,
} from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
@@ -8,70 +18,149 @@ export default function ProductionBoardKanbanCardSettings({
associationSettings,
}) {
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
useEffect(() => {
form.setFieldsValue(
associationSettings && associationSettings.kanban_settings
);
}, [form, associationSettings]);
}, [form, associationSettings, visible]);
const { t } = useTranslation();
const handleFinish = async (values) => {
await updateKbSettings({
setLoading(true);
const result = await updateKbSettings({
variables: {
id: associationSettings && associationSettings.id,
ks: values,
},
});
if (result.errors) {
notification.open({
type: "error",
message: t("production.errors.settings", {
error: JSON.stringify(result.errors),
}),
});
}
setVisible(false);
setLoading(false);
};
const overlay = (
<div>
<Card>
<Form form={form} onFinish={handleFinish}>
<Form.Item
label={t("production.labels.compact")}
name="compact"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.laborhrs")}
name="laborhrs"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.employeeassignments")}
name="employeeassignments"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.alert")}
name="alert"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("production.labels.sublets")}
name="sublets"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form form={form} onFinish={handleFinish} layout="vertical">
<Row gutter={[16, 16]}>
<Col span={12}>
<Form.Item
label={t("production.labels.compact")}
name="compact"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item label={t("production.labels.clm_no")} name="clm_no">
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t("production.labels.ins_co_nm")}
name="ins_co_nm"
>
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t("production.labels.laborhrs")}
name="laborhrs"
>
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t("production.labels.employeeassignments")}
name="employeeassignments"
>
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t("production.labels.scheduled_completion")}
name="scheduled_completion"
>
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>{" "}
</Col>
<Col span={12}>
<Form.Item label={t("production.labels.ats")} name="ats">
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t("production.labels.production_note")}
name="production_note"
>
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label={t("production.labels.alert")} name="alert">
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label={t("production.labels.sublets")} name="sublets">
<Radio.Group>
<Radio value="front">Front</Radio>
<Radio value="back">Back</Radio>
<Radio value="off">Off</Radio>
</Radio.Group>
</Form.Item>
</Col>
</Row>
</Form>
<Button
onClick={() => {
form.submit();
}}
>
{t("general.actions.save")}
</Button>
</Card>
</div>
);
return (
<Dropdown trigger="click" overlay={overlay}>
<Button>{t("production.labels.cardsettings")}</Button>
</Dropdown>
<Popover content={overlay} visible={visible}>
<Button loading={loading} onClick={() => setVisible(true)}>
{t("production.labels.cardsettings")}
</Button>
</Popover>
);
}

View File

@@ -18,6 +18,7 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
import styled from "styled-components";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -145,8 +146,26 @@ export function ProductionBoardKanbanComponent({
)
.toFixed(1);
const Container = styled.div`
.react-kanban-card-skeleton,
.react-kanban-card,
.react-kanban-card-adder-form {
box-sizing: border-box;
max-width: ${associationSettings &&
associationSettings.kanban_settings &&
associationSettings.kanban_settings.compact
? "145"
: "250"}px;
min-width: ${associationSettings &&
associationSettings.kanban_settings &&
associationSettings.kanban_settings.compact
? "145"
: "250"}px;
}
`;
return (
<div>
<Container>
<IndefiniteLoading loading={isMoving} />
<PageHeader
title={
@@ -183,12 +202,12 @@ export function ProductionBoardKanbanComponent({
technician,
card,
bodyshop,
associationSettings.kanban_settings
associationSettings && associationSettings.kanban_settings
)
}
onCardDragEnd={handleDragEnd}
/>
</div>
</Container>
);
}
export default connect(

View File

@@ -4,23 +4,16 @@
.react-kanban-card {
border-radius: 3px;
background-color: #fff;
padding: 10px;
padding: 4px;
margin-bottom: 7px;
}
.react-kanban-card-skeleton,
.react-kanban-card,
.react-kanban-card-adder-form {
box-sizing: border-box;
max-width: 250px;
min-width: 250px;
}
.react-kanban-card-skeleton-compact,
.react-kanban-card-compact,
.react-kanban-card-adder-form-compact {
box-sizing: border-box;
max-width: 120px;
min-width: 120px;
}
// .react-kanban-card-skeleton,
// .react-kanban-card,
// .react-kanban-card-adder-form {
// box-sizing: border-box;
// max-width: 145px;
// min-width: 145px;
// }
.react-kanban-card--dragging {
box-shadow: 2px 2px grey;
@@ -36,7 +29,7 @@
justify-content: space-between;
}
.react-kanban-column {
padding: 15px;
padding: 10px;
border-radius: 2px;
background-color: #eee;
margin: 5px;

View File

@@ -1385,7 +1385,7 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
},
({ getFieldValue }) => ({
validator(rule, value) {
if (costOptions.includes(value)) {
if (profitOptions.includes(value)) {
return Promise.resolve();
}
return Promise.reject(

View File

@@ -2078,7 +2078,8 @@
},
"errors": {
"boardupdate": "Error encountered updating job. {{message}}",
"removing": "Error removing from production board. {{error}}"
"removing": "Error removing from production board. {{error}}",
"settings": "Error saving board settings: {{error}}"
},
"labels": {
"alert": "Alert",
@@ -2087,9 +2088,12 @@
"bodyhours": "B",
"bodypriority": "B/P",
"cardsettings": "Card Settings",
"compact": "Compact Cards",
"detailpriority": "D/P",
"employeeassignments": "Employee Assignments",
"employeesearch": "Employee Search",
"jobdetail": "Job Details",
"laborhrs": "Labor Hours",
"note": "Production Note",
"paintpriority": "P/P",
"refinishhours": "R",

View File

@@ -2078,7 +2078,8 @@
},
"errors": {
"boardupdate": "",
"removing": ""
"removing": "",
"settings": ""
},
"labels": {
"alert": "",
@@ -2087,9 +2088,12 @@
"bodyhours": "",
"bodypriority": "",
"cardsettings": "",
"compact": "",
"detailpriority": "",
"employeeassignments": "",
"employeesearch": "",
"jobdetail": "",
"laborhrs": "",
"note": "",
"paintpriority": "",
"refinishhours": "",

View File

@@ -2078,7 +2078,8 @@
},
"errors": {
"boardupdate": "",
"removing": ""
"removing": "",
"settings": ""
},
"labels": {
"alert": "",
@@ -2087,9 +2088,12 @@
"bodyhours": "",
"bodypriority": "",
"cardsettings": "",
"compact": "",
"detailpriority": "",
"employeeassignments": "",
"employeesearch": "",
"jobdetail": "",
"laborhrs": "",
"note": "",
"paintpriority": "",
"refinishhours": "",

View File

@@ -12,7 +12,9 @@ export function DateFormatter(props) {
export function DateTimeFormatter(props) {
return props.children
? moment(props.children).format("MM/DD/YYYY hh:mm a")
? moment(props.children).format(
props.format ? props.format : "MM/DD/YYYY hh:mm a"
)
: null;
}

View File

@@ -37,7 +37,6 @@ exports.default = async function ReloadCdkMakes(req, res) {
const BearerToken = req.headers.authorization;
//Query all CDK Models
const newList = await GetCdkMakes(req, cdk_dealerid);
console.log("🚀 ~ file: cdk-get-makes.js ~ line 40 ~ newList", newList);
//Clear out the existing records
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
@@ -69,10 +68,6 @@ exports.default = async function ReloadCdkMakes(req, res) {
};
}),
});
console.log(
"🚀 ~ file: cdk-get-makes.js ~ line 66 ~ insertResult",
insertResult
);
logger.log(
"cdk-replace-makes-models-success",
@@ -121,9 +116,28 @@ async function GetCdkMakes(req, cdk_dealerid) {
);
CheckCdkResponseForError(null, soapResponseVehicleSearch);
const [
result, //rawResponse, soapheader, rawRequest
] = soapResponseVehicleSearch;
const [result, rawResponse, , rawRequest] = soapResponseVehicleSearch;
logger.log(
"cdk-replace-makes-models-request",
"ERROR",
req.user.email,
null,
{
cdk_dealerid,
xml: rawRequest,
}
);
logger.log(
"cdk-replace-makes-models-response",
"ERROR",
req.user.email,
null,
{
cdk_dealerid,
xml: rawResponse,
}
);
return result.return;
} catch (error) {

View File

@@ -172,7 +172,7 @@ async function CdkSelectedCustomer(socket, selectedCustomerId) {
`{6} Successfully posted sransaction to DMS.`
);
await MarkJobExported(socket, socket.JobData.id);
//await MarkJobExported(socket, socket.JobData.id);
CdkBase.createLogEvent(
socket,
@@ -856,9 +856,9 @@ async function InsertServiceVehicleHistory(socket) {
roNumber: socket.JobData.ro_number.match(/\d+/g),
mileage: socket.txEnvelope.kmout,
openDate: moment(socket.JobData.actual_in).format("YYYY-MM-DD"),
openTime: moment(socket.JobData.actual_in).format("HH:MM:SS"),
openTime: moment(socket.JobData.actual_in).format("HH:MM:ss"),
closeDate: moment(socket.JobData.invoice_date).format("YYYY-MM-DD"),
closeTime: moment(socket.JobData.invoice_date).format("HH:MM:SS"),
closeTime: moment(socket.JobData.invoice_date).format("HH:MM:ss"),
comments: socket.txEnvelope.story,
cashierID: socket.JobData.bodyshop.cdk_configuration.cashierid,
},