Merge branch 'release/2021-09-10' into feature/cdk-cert

This commit is contained in:
Patrick Fic
2021-09-13 10:08:15 -07:00
10 changed files with 7944 additions and 7511 deletions

View File

@@ -5819,6 +5819,27 @@
<folder_node>
<name>responsibilitycenters</name>
<children>
<concept_node>
<name>LA4</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>ap</name>
<definition_loaded>false</definition_loaded>
@@ -5903,6 +5924,69 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>la1</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>la2</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>la3</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>lab</name>
<definition_loaded>false</definition_loaded>
@@ -6344,6 +6428,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>pasl</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>refund</name>
<definition_loaded>false</definition_loaded>

View File

@@ -81,11 +81,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<span style={{ margin: "0rem .5rem" }}>/</span>
<CurrencyFormatter>{job.owner_owing}</CurrencyFormatter>
</DataLabel>
{job.converted && (
<DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} />
</DataLabel>
)}
<DataLabel label={t("jobs.fields.alt_transport")}>
{job.alt_transport}
<JobAltTransportChange job={job} />
@@ -183,6 +179,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<DataLabel key="4" label={t("vehicles.fields.v_vin")}>
{`${job.v_vin || t("general.labels.na")}`}
</DataLabel>
<DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} job={job} />
</DataLabel>
</div>
</Card>
</Col>

View File

@@ -1,112 +1,19 @@
import React, { useState } from "react";
import { useQuery, useMutation } from "@apollo/client";
import { Tag, Space, Button, Popover, Card, Form } from "antd";
import {
DELETE_RELATED_RO,
INSERT_RELATED_ROS,
QUERY_RELATED_ROS,
} from "../../graphql/jobs.queries";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import AlertComponent from "../alert/alert.component";
import { PlusCircleOutlined } from "@ant-design/icons";
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
import { useTranslation } from "react-i18next";
import { Space, Tag } from "antd";
import React from "react";
import { Link } from "react-router-dom";
export default function JobsRelatedRos({ jobid }) {
const [roSearchVisible, setRoSearchVisible] = useState(false);
const [saveLoading, setSaveLoading] = useState(false);
const [insertRelationship] = useMutation(INSERT_RELATED_ROS);
const [deleteRelationship] = useMutation(DELETE_RELATED_RO);
const { loading, error, data } = useQuery(QUERY_RELATED_ROS, {
variables: { jobid },
skip: !jobid,
});
const { t } = useTranslation();
if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type="error" />;
const relatedJobs = data.relatedjobs.map((r) => {
if (r.parentjob === jobid) {
return { relationshipid: r.id, ...r.childjob_rel };
}
return { relationshipid: r.id, ...r.parentjob_rel };
});
const handleAddRo = async ({ relatedjobid }) => {
setSaveLoading(true);
await insertRelationship({
variables: { relationship: { parentjob: jobid, childjob: relatedjobid } },
update(cache, { data }) {
cache.modify({
fields: {
relatedjobs(rj, { readField }) {
return [rj, data.insert_relatedjobs_one];
},
},
});
},
});
setSaveLoading(false);
setRoSearchVisible(false);
};
const handleDelete = async (id) => {
setSaveLoading(true);
await deleteRelationship({
variables: {
relationshipid: id,
},
update(cache, { data }) {
cache.modify({
fields: {
relatedjobs(rj, { readField }) {
return rj.filter((r) => r.id !== id);
},
},
});
},
});
setSaveLoading(false);
setRoSearchVisible(false);
};
const popContent = (
<Card style={{ minWidth: "25rem" }}>
<Form layout="vertical" onFinish={handleAddRo}>
<Form.Item
name="relatedjobid"
label={t("jobs.fields.ro_number")}
rules={[{ required: true }]}
>
<JobSearchSelectComponent convertedOnly />
</Form.Item>
<Space>
<Button loading={saveLoading} htmlType="submit">
{t("general.actions.add")}
</Button>
<Button onClick={() => setRoSearchVisible(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
</Card>
);
export default function JobsRelatedRos({ jobid, job }) {
return (
<Space wrap>
{relatedJobs.map((r) => (
<Tag key={r.id} closable onClose={() => handleDelete(r.relationshipid)}>
<Link to={`/manage/jobs/${r?.id}`}>{r.ro_number}</Link>
</Tag>
))}
<Popover content={popContent} visible={roSearchVisible}>
<Button type="link" onClick={() => setRoSearchVisible(true)}>
<PlusCircleOutlined />
</Button>
</Popover>
{job.vehicle.jobs
.filter((j) => j.id !== job.id)
.map((j) => (
<Tag key={j.id}>
<Link to={`/manage/jobs/${j?.id}`}>{`${j.ro_number || "N/A"}${
j.clm_no ? ` | ${j.clm_no}` : ""
}${j.status ? ` | ${j.status}` : ""}`}</Link>
</Tag>
))}
</Space>
);
}

View File

@@ -698,6 +698,90 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la1"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}costs-LA1`}
name={[field.name, "costs", "LA1"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la2"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}costs-LA2`}
name={[field.name, "costs", "LA2"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la3"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}costs-LA3`}
name={[field.name, "costs", "LA3"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la4"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}costs-LA4`}
name={[field.name, "costs", "LA4"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.paa"
@@ -887,6 +971,27 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.pasl"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}costs-PASL`}
name={[field.name, "costs", "PASL"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.tow"
@@ -1164,6 +1269,90 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la1"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}profits-LA1`}
name={[field.name, "profits", "LA1"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la2"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}profits-LA2`}
name={[field.name, "profits", "LA2"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la3"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}profits-LA3`}
name={[field.name, "profits", "LA3"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.la4"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}profits-LA4`}
name={[field.name, "profits", "LA4"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.paa"
@@ -1353,6 +1542,27 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.pasl"
)}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
key={`${index}profits-PASL`}
name={[field.name, "profits", "PASL"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t(
"bodyshop.fields.responsibilitycenters.tow"
@@ -1625,6 +1835,78 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la1")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "costs", "LA1"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la2")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "costs", "LA2"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la3")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "costs", "LA3"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la4")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "costs", "LA4"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.paa")}
rules={[
@@ -1787,6 +2069,24 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.pasl")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "costs", "PASL"]}
>
<Select>
{costOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.tow")}
rules={[
@@ -2023,6 +2323,78 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la1")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "profits", "LA1"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la2")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "profits", "LA2"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la3")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "profits", "LA3"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.la4")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "profits", "LA4"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.paa")}
rules={[
@@ -2185,6 +2557,24 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.pasl")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={["md_responsibility_centers", "defaults", "profits", "PASL"]}
>
<Select>
{profitOptions.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.tow")}
rules={[

View File

@@ -384,6 +384,12 @@ export const GET_JOB_BY_PK = gql`
v_model_desc
v_make_desc
v_color
jobs {
id
ro_number
status
clm_no
}
}
available_jobs {
id
@@ -700,6 +706,11 @@ export const QUERY_JOB_CARD_DETAILS = gql`
v_model_desc
v_color
plate_no
jobs {
id
clm_no
ro_number
}
}
actual_completion
actual_delivery

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -294,11 +294,7 @@ const generateInvoiceQbxml = (
}
}
// Labor Lines
if (
jobline.profitcenter_labor &&
jobline.mod_lb_hrs &&
jobline.mod_lb_hrs > 0
) {
if (jobline.profitcenter_labor && jobline.mod_lb_hrs) {
const DineroAmount = Dinero({
amount: Math.round(
jobs_by_pk[`rate_${jobline.mod_lbr_ty.toLowerCase()}`] * 100

View File

@@ -242,7 +242,16 @@ function CalculatePartsTotals(jobLines) {
subtotal: acc.sublets.subtotal.add(
Dinero({
amount: Math.round(value.act_price * 100),
}).multiply(value.part_qty || 0)
})
.multiply(value.part_qty || 0)
.add(
Dinero({
amount: Math.round(value.act_price * 100),
})
.multiply(value.part_qty || 0)
.percentage(Math.abs(value.prt_dsmk_p || 0))
.multiply(value.prt_dsmk_p > 0 ? 1 : -1)
)
),
},
};
@@ -306,6 +315,7 @@ function CalculatePartsTotals(jobLines) {
},
sublets: {
subtotal: Dinero({ amount: 0 }),
total: Dinero({ amount: 0 }),
},
}