Merged in release/2022-04-15 (pull request #445)
release/2022-04-15 Approved-by: Patrick Fic
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.7.1">
|
<babeledit_project be_version="2.7.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -3654,6 +3654,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>bill_allow_post_to_closed</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>bill_federal_tax_rate</name>
|
<name>bill_federal_tax_rate</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4753,6 +4774,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>private</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>state</name>
|
<name>state</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -20334,6 +20376,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>auto_add_ats</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>ca_bc_pvrt</name>
|
<name>ca_bc_pvrt</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -23236,6 +23299,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>rate_ats</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>rate_la1</name>
|
<name>rate_la1</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useHistory } from "react-router-dom";
|
import { useLocation, useHistory } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
|
DELETE_BILL_LINE,
|
||||||
INSERT_NEW_BILL_LINES,
|
INSERT_NEW_BILL_LINES,
|
||||||
UPDATE_BILL_LINE,
|
UPDATE_BILL_LINE,
|
||||||
} from "../../graphql/bill-lines.queries";
|
} from "../../graphql/bill-lines.queries";
|
||||||
@@ -58,6 +59,7 @@ export function BillDetailEditcontainer({
|
|||||||
const [update_bill] = useMutation(UPDATE_BILL);
|
const [update_bill] = useMutation(UPDATE_BILL);
|
||||||
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
||||||
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
|
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
|
||||||
|
const [deleteBillLine] = useMutation(DELETE_BILL_LINE);
|
||||||
|
|
||||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||||
.filter((screen) => !!screen[1])
|
.filter((screen) => !!screen[1])
|
||||||
@@ -107,6 +109,20 @@ export function BillDetailEditcontainer({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Find bill lines that were deleted.
|
||||||
|
const deletedJobLines = [];
|
||||||
|
|
||||||
|
data.bills_by_pk.billlines.forEach((a) => {
|
||||||
|
const matchingRecord = billlines.find((b) => b.id === a.id);
|
||||||
|
if (!matchingRecord) {
|
||||||
|
deletedJobLines.push(a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
deletedJobLines.forEach((d) => {
|
||||||
|
updates.push(deleteBillLine({ variables: { id: d.id } }));
|
||||||
|
});
|
||||||
|
|
||||||
billlines.forEach((billline) => {
|
billlines.forEach((billline) => {
|
||||||
const { deductedfromlbr, jobline, ...il } = billline;
|
const { deductedfromlbr, jobline, ...il } = billline;
|
||||||
delete il.__typename;
|
delete il.__typename;
|
||||||
@@ -142,6 +158,7 @@ export function BillDetailEditcontainer({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(updates);
|
await Promise.all(updates);
|
||||||
|
|
||||||
insertAuditTrail({
|
insertAuditTrail({
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ export function BillFormComponent({
|
|||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
if (
|
if (
|
||||||
|
!bodyshop.bill_allow_post_to_closed &&
|
||||||
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
|
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
|
||||||
job.status === bodyshop.md_ro_statuses.default_exported ||
|
job.status === bodyshop.md_ro_statuses.default_exported ||
|
||||||
job.status === bodyshop.md_ro_statuses.default_void) &&
|
job.status === bodyshop.md_ro_statuses.default_void) &&
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useLazyQuery } from "@apollo/client";
|
import { useLazyQuery } from "@apollo/client";
|
||||||
|
import { LoadingOutlined } from "@ant-design/icons";
|
||||||
import { AutoComplete, Divider, Space } from "antd";
|
import { AutoComplete, Divider, Space } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useHistory } from "react-router-dom";
|
||||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
@@ -12,8 +13,9 @@ import OwnerNameDisplay, {
|
|||||||
} from "../owner-name-display/owner-name-display.component";
|
} from "../owner-name-display/owner-name-display.component";
|
||||||
export default function GlobalSearch() {
|
export default function GlobalSearch() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const history = useHistory();
|
||||||
const [callSearch, { error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
|
const [callSearch, { loading, error, data }] =
|
||||||
|
useLazyQuery(GLOBAL_SEARCH_QUERY);
|
||||||
|
|
||||||
const executeSearch = (v) => {
|
const executeSearch = (v) => {
|
||||||
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
|
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
|
||||||
@@ -171,8 +173,13 @@ export default function GlobalSearch() {
|
|||||||
<AutoComplete
|
<AutoComplete
|
||||||
options={options}
|
options={options}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
|
suffixIcon={loading && <LoadingOutlined spin />}
|
||||||
|
defaultActiveFirstOption
|
||||||
placeholder={t("general.labels.globalsearch")}
|
placeholder={t("general.labels.globalsearch")}
|
||||||
allowClear
|
allowClear
|
||||||
|
onSelect={(val, opt) => {
|
||||||
|
history.push(opt.label.props.to);
|
||||||
|
}}
|
||||||
></AutoComplete>
|
></AutoComplete>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.con
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
||||||
import JobLinesExpander from "./job-lines-expander.component";
|
import JobLinesExpander from "./job-lines-expander.component";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
bodyshop: selectBodyshop,
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
});
|
});
|
||||||
@@ -56,6 +57,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function JobLinesComponent({
|
export function JobLinesComponent({
|
||||||
|
bodyshop,
|
||||||
jobRO,
|
jobRO,
|
||||||
technician,
|
technician,
|
||||||
setPartsOrderContext,
|
setPartsOrderContext,
|
||||||
@@ -75,6 +77,9 @@ export function JobLinesComponent({
|
|||||||
filteredInfo: {},
|
filteredInfo: {},
|
||||||
});
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const jobIsPrivate = bodyshop.md_ins_cos.find(
|
||||||
|
(c) => c.name === job.ins_co_nm
|
||||||
|
)?.private;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -286,7 +291,7 @@ export function JobLinesComponent({
|
|||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<div>
|
||||||
{record.manual_line && (
|
{(record.manual_line || jobIsPrivate) && (
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ export function JobLinesUpsertModalComponent({
|
|||||||
rules={[
|
rules={[
|
||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
|
console.log(value);
|
||||||
if (!value || getFieldValue("part_type") !== "PAE") {
|
if (!value || getFieldValue("part_type") !== "PAE") {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -226,7 +227,10 @@ export function JobLinesUpsertModalComponent({
|
|||||||
}),
|
}),
|
||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
if (!!getFieldValue("part_type") === !!value) {
|
console.log(value, !!value);
|
||||||
|
if (
|
||||||
|
!!getFieldValue("part_type") === (!!value || value === 0)
|
||||||
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
|
|||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import axios from "axios";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -53,6 +53,12 @@ export function JobsConvertButton({
|
|||||||
variables: { jobId: job.id, ...values },
|
variables: { jobId: job.id, ...values },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (values.ca_gst_registrant) {
|
||||||
|
await axios.post("/job/totalsssu", {
|
||||||
|
id: job.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!res.errors) {
|
if (!res.errors) {
|
||||||
refetch();
|
refetch();
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
|
|||||||
@@ -88,6 +88,33 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||||
</Space>
|
</Space>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.auto_add_ats")}
|
||||||
|
name="auto_add_ats"
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
nostyle
|
||||||
|
shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}
|
||||||
|
>
|
||||||
|
{() => {
|
||||||
|
if (form.getFieldValue("auto_add_ats"))
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.rate_ats")}
|
||||||
|
name="rate_ats"
|
||||||
|
initialValue={bodyshop.shoprates.rate_atp}
|
||||||
|
>
|
||||||
|
<CurrencyInput disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -100,7 +127,13 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
label={t("jobs.fields.state_tax_rate")}
|
label={t("jobs.fields.state_tax_rate")}
|
||||||
name="state_tax_rate"
|
name="state_tax_rate"
|
||||||
>
|
>
|
||||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO} autoComplete="new-password"/>
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
precision={2}
|
||||||
|
disabled={jobRO}
|
||||||
|
autoComplete="new-password"
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.local_tax_rate")}
|
label={t("jobs.fields.local_tax_rate")}
|
||||||
|
|||||||
@@ -558,6 +558,13 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["bill_allow_post_to_closed"]}
|
||||||
|
label={t("bodyshop.fields.bill_allow_post_to_closed")}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["md_ded_notes"]}
|
name={["md_ded_notes"]}
|
||||||
label={t("bodyshop.fields.md_ded_notes")}
|
label={t("bodyshop.fields.md_ded_notes")}
|
||||||
@@ -811,14 +818,23 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Space>
|
<Form.Item
|
||||||
<Form.Item
|
label={t("bodyshop.fields.md_ins_co.zip")}
|
||||||
label={t("bodyshop.fields.md_ins_co.zip")}
|
key={`${index}zip`}
|
||||||
key={`${index}zip`}
|
name={[field.name, "zip"]}
|
||||||
name={[field.name, "zip"]}
|
>
|
||||||
>
|
<Input />
|
||||||
<Input />
|
</Form.Item>
|
||||||
</Form.Item>
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_ins_co.private")}
|
||||||
|
key={`${index}private`}
|
||||||
|
name={[field.name, "private"]}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Space wrap>
|
||||||
<DeleteFilled
|
<DeleteFilled
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ export const UPDATE_BILL_LINE = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const DELETE_BILL_LINE = gql`
|
||||||
|
mutation DELETE_BILL_LINE($id: uuid!) {
|
||||||
|
delete_billlines_by_pk(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const INSERT_NEW_BILL_LINES = gql`
|
export const INSERT_NEW_BILL_LINES = gql`
|
||||||
mutation INSERT_NEW_BILL_LINES($billLines: [billlines_insert_input!]!) {
|
mutation INSERT_NEW_BILL_LINES($billLines: [billlines_insert_input!]!) {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export const QUERY_BODYSHOP = gql`
|
|||||||
md_from_emails
|
md_from_emails
|
||||||
last_name_first
|
last_name_first
|
||||||
md_parts_order_comment
|
md_parts_order_comment
|
||||||
|
bill_allow_post_to_closed
|
||||||
employees {
|
employees {
|
||||||
user_email
|
user_email
|
||||||
id
|
id
|
||||||
@@ -207,6 +208,7 @@ export const UPDATE_SHOP = gql`
|
|||||||
md_from_emails
|
md_from_emails
|
||||||
last_name_first
|
last_name_first
|
||||||
md_parts_order_comment
|
md_parts_order_comment
|
||||||
|
bill_allow_post_to_closed
|
||||||
employees {
|
employees {
|
||||||
id
|
id
|
||||||
first_name
|
first_name
|
||||||
|
|||||||
@@ -611,6 +611,8 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
ownerid
|
ownerid
|
||||||
ded_note
|
ded_note
|
||||||
materials
|
materials
|
||||||
|
auto_add_ats
|
||||||
|
rate_ats
|
||||||
owner {
|
owner {
|
||||||
id
|
id
|
||||||
ownr_fn
|
ownr_fn
|
||||||
|
|||||||
@@ -233,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "Default Appointment Length",
|
"appt_length": "Default Appointment Length",
|
||||||
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
||||||
|
"bill_allow_post_to_closed": "Allow Bills to be posted to Closed Jobs",
|
||||||
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
||||||
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
@@ -295,6 +296,7 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"name": "Insurance Company Name",
|
"name": "Insurance Company Name",
|
||||||
|
"private": "Private",
|
||||||
"state": "Province/State",
|
"state": "Province/State",
|
||||||
"street1": "Street 1",
|
"street1": "Street 1",
|
||||||
"street2": "Street 2",
|
"street2": "Street 2",
|
||||||
@@ -1244,6 +1246,7 @@
|
|||||||
"08": "Left Rear Side",
|
"08": "Left Rear Side",
|
||||||
"09": "Left Side"
|
"09": "Left Side"
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "Automatically Add/Update ATS",
|
||||||
"ca_bc_pvrt": "PVRT",
|
"ca_bc_pvrt": "PVRT",
|
||||||
"ca_customer_gst": "Customer Portion of GST",
|
"ca_customer_gst": "Customer Portion of GST",
|
||||||
"ca_gst_registrant": "GST Registrant",
|
"ca_gst_registrant": "GST Registrant",
|
||||||
@@ -1391,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": "Production Note"
|
"note": "Production Note"
|
||||||
},
|
},
|
||||||
|
"rate_ats": "ATS Rate",
|
||||||
"rate_la1": "LA1",
|
"rate_la1": "LA1",
|
||||||
"rate_la2": "LA2",
|
"rate_la2": "LA2",
|
||||||
"rate_la3": "LA3",
|
"rate_la3": "LA3",
|
||||||
|
|||||||
@@ -233,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
"attach_pdf_to_email": "",
|
"attach_pdf_to_email": "",
|
||||||
|
"bill_allow_post_to_closed": "",
|
||||||
"bill_federal_tax_rate": "",
|
"bill_federal_tax_rate": "",
|
||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
@@ -295,6 +296,7 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "",
|
"city": "",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"private": "",
|
||||||
"state": "",
|
"state": "",
|
||||||
"street1": "",
|
"street1": "",
|
||||||
"street2": "",
|
"street2": "",
|
||||||
@@ -1244,6 +1246,7 @@
|
|||||||
"08": "",
|
"08": "",
|
||||||
"09": ""
|
"09": ""
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "",
|
||||||
"ca_bc_pvrt": "",
|
"ca_bc_pvrt": "",
|
||||||
"ca_customer_gst": "",
|
"ca_customer_gst": "",
|
||||||
"ca_gst_registrant": "",
|
"ca_gst_registrant": "",
|
||||||
@@ -1391,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
|
"rate_ats": "",
|
||||||
"rate_la1": "Tarifa LA1",
|
"rate_la1": "Tarifa LA1",
|
||||||
"rate_la2": "Tarifa LA2",
|
"rate_la2": "Tarifa LA2",
|
||||||
"rate_la3": "Tarifa LA3",
|
"rate_la3": "Tarifa LA3",
|
||||||
|
|||||||
@@ -233,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
"attach_pdf_to_email": "",
|
"attach_pdf_to_email": "",
|
||||||
|
"bill_allow_post_to_closed": "",
|
||||||
"bill_federal_tax_rate": "",
|
"bill_federal_tax_rate": "",
|
||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
@@ -295,6 +296,7 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "",
|
"city": "",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"private": "",
|
||||||
"state": "",
|
"state": "",
|
||||||
"street1": "",
|
"street1": "",
|
||||||
"street2": "",
|
"street2": "",
|
||||||
@@ -1244,6 +1246,7 @@
|
|||||||
"08": "",
|
"08": "",
|
||||||
"09": ""
|
"09": ""
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "",
|
||||||
"ca_bc_pvrt": "",
|
"ca_bc_pvrt": "",
|
||||||
"ca_customer_gst": "",
|
"ca_customer_gst": "",
|
||||||
"ca_gst_registrant": "",
|
"ca_gst_registrant": "",
|
||||||
@@ -1391,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
|
"rate_ats": "",
|
||||||
"rate_la1": "Taux LA1",
|
"rate_la1": "Taux LA1",
|
||||||
"rate_la2": "Taux LA2",
|
"rate_la2": "Taux LA2",
|
||||||
"rate_la3": "Taux LA3",
|
"rate_la3": "Taux LA3",
|
||||||
|
|||||||
@@ -20,6 +20,38 @@ mutation UNARCHIVE_CONVERSATION($id: uuid!) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports.INSERT_NEW_JOB_LINE = `
|
||||||
|
mutation INSERT_NEW_JOB_LINE($lineInput: [joblines_insert_input!]!) {
|
||||||
|
insert_joblines(objects: $lineInput) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports.UPDATE_JOB_LINE = `
|
||||||
|
mutation UPDATE_JOB_LINE($lineId: uuid!, $line: joblines_set_input!) {
|
||||||
|
update_joblines(where: { id: { _eq: $lineId } }, _set: $line) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
notes
|
||||||
|
mod_lbr_ty
|
||||||
|
part_qty
|
||||||
|
db_price
|
||||||
|
act_price
|
||||||
|
line_desc
|
||||||
|
line_no
|
||||||
|
oem_partno
|
||||||
|
notes
|
||||||
|
location
|
||||||
|
status
|
||||||
|
removed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports.RECEIVE_MESSAGE = `
|
exports.RECEIVE_MESSAGE = `
|
||||||
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
|
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
|
||||||
insert_messages(objects: $msg) {
|
insert_messages(objects: $msg) {
|
||||||
@@ -970,6 +1002,8 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
|
|||||||
ca_bc_pvrt
|
ca_bc_pvrt
|
||||||
ca_customer_gst
|
ca_customer_gst
|
||||||
materials
|
materials
|
||||||
|
auto_add_ats
|
||||||
|
rate_ats
|
||||||
joblines(where: { removed: { _eq: false } }){
|
joblines(where: { removed: { _eq: false } }){
|
||||||
id
|
id
|
||||||
line_no
|
line_no
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const newTotals = await TotalsServerSide(
|
const newTotals = await TotalsServerSide(
|
||||||
{ body: { job: job.jobs_by_pk } },
|
{ body: { job: job.jobs_by_pk, client: client } },
|
||||||
res,
|
res,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,9 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
|
|
||||||
//IMPORTANT*** These two functions MUST be mirrrored.
|
//IMPORTANT*** These two functions MUST be mirrrored.
|
||||||
async function TotalsServerSide(req, res) {
|
async function TotalsServerSide(req, res) {
|
||||||
const { job } = req.body;
|
const { job, client } = req.body;
|
||||||
|
await AutoAddAtsIfRequired({ job: job, client: client });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let ret = {
|
let ret = {
|
||||||
parts: CalculatePartsTotals(job.joblines),
|
parts: CalculatePartsTotals(job.joblines),
|
||||||
@@ -78,6 +80,16 @@ async function Totals(req, res) {
|
|||||||
jobid: job.id,
|
jobid: job.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const BearerToken = req.headers.authorization;
|
||||||
|
const { id } = req.body;
|
||||||
|
logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null);
|
||||||
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||||
|
headers: {
|
||||||
|
Authorization: BearerToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await AutoAddAtsIfRequired({ job, client });
|
||||||
try {
|
try {
|
||||||
let ret = {
|
let ret = {
|
||||||
parts: CalculatePartsTotals(job.joblines),
|
parts: CalculatePartsTotals(job.joblines),
|
||||||
@@ -96,6 +108,83 @@ async function Totals(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function AutoAddAtsIfRequired({ job, client }) {
|
||||||
|
//Check if ATS should be automatically added.
|
||||||
|
if (job.auto_add_ats) {
|
||||||
|
//Get the total sum of hours that should be the ATS amount.
|
||||||
|
//Check to see if an ATS line exists.
|
||||||
|
let atsLineIndex = null;
|
||||||
|
const atsHours = job.joblines.reduce((acc, val, index) => {
|
||||||
|
if (val.line_desc && val.line_desc.toLowerCase() === "ats amount") {
|
||||||
|
atsLineIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
val.mod_lbr_ty !== "LA1" &&
|
||||||
|
val.mod_lbr_ty !== "LA2" &&
|
||||||
|
val.mod_lbr_ty !== "LA3" &&
|
||||||
|
val.mod_lbr_ty !== "LA4" &&
|
||||||
|
val.mod_lbr_ty !== "LAU" &&
|
||||||
|
val.mod_lbr_ty !== "LAG" &&
|
||||||
|
val.mod_lbr_ty !== "LAS" &&
|
||||||
|
val.mod_lbr_ty !== "LAA"
|
||||||
|
) {
|
||||||
|
acc = acc + val.mod_lb_hrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const atsAmount = atsHours * (job.rate_ats || 0);
|
||||||
|
//If it does, update it in place, and make sure it is updated for local calculations.
|
||||||
|
if (atsLineIndex === null) {
|
||||||
|
const newAtsLine = {
|
||||||
|
jobid: job.id,
|
||||||
|
alt_partm: null,
|
||||||
|
line_no: 35,
|
||||||
|
unq_seq: 0,
|
||||||
|
line_ind: "E",
|
||||||
|
line_desc: "ATS Amount",
|
||||||
|
line_ref: 0.0,
|
||||||
|
part_type: null,
|
||||||
|
oem_partno: null,
|
||||||
|
db_price: 0.0,
|
||||||
|
act_price: atsAmount,
|
||||||
|
part_qty: 1,
|
||||||
|
mod_lbr_ty: null,
|
||||||
|
db_hrs: 0.0,
|
||||||
|
mod_lb_hrs: 0.0,
|
||||||
|
lbr_op: "OP13",
|
||||||
|
lbr_amt: 0.0,
|
||||||
|
op_code_desc: "ADDITIONAL COSTS",
|
||||||
|
status: null,
|
||||||
|
location: null,
|
||||||
|
tax_part: true,
|
||||||
|
db_ref: null,
|
||||||
|
manual_line: true,
|
||||||
|
prt_dsmk_p: 0.0,
|
||||||
|
prt_dsmk_m: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await client.request(queries.INSERT_NEW_JOB_LINE, {
|
||||||
|
lineInput: [newAtsLine],
|
||||||
|
});
|
||||||
|
|
||||||
|
job.joblines.push(newAtsLine);
|
||||||
|
}
|
||||||
|
//If it does not, create one for local calculations and insert it.
|
||||||
|
else {
|
||||||
|
const result = await client.request(queries.UPDATE_JOB_LINE, {
|
||||||
|
line: { act_price: atsAmount },
|
||||||
|
lineId: job.joblines[atsLineIndex].id,
|
||||||
|
});
|
||||||
|
job.joblines[atsLineIndex].act_price = atsAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(job.jobLines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function CalculateRatesTotals(ratesList) {
|
function CalculateRatesTotals(ratesList) {
|
||||||
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
|
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user