Merged in release/2022-04-15 (pull request #448)

Release/2022 04 15
This commit is contained in:
Patrick Fic
2022-04-14 17:48:45 +00:00
45 changed files with 5564 additions and 4904 deletions

View File

@@ -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
@@ -3654,6 +3654,27 @@
</translation>
</translations>
</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>
<name>bill_federal_tax_rate</name>
<definition_loaded>false</definition_loaded>
@@ -4753,6 +4774,27 @@
</translation>
</translations>
</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>
<name>state</name>
<definition_loaded>false</definition_loaded>
@@ -4860,6 +4902,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>md_parts_order_comment</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>md_payment_types</name>
<definition_loaded>false</definition_loaded>
@@ -20313,6 +20376,27 @@
</concept_node>
</children>
</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>
<name>ca_bc_pvrt</name>
<definition_loaded>false</definition_loaded>
@@ -23215,6 +23299,27 @@
</concept_node>
</children>
</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>
<name>rate_la1</name>
<definition_loaded>false</definition_loaded>
@@ -43210,6 +43315,63 @@
</folder_node>
</children>
</folder_node>
<folder_node>
<name>users</name>
<children>
<folder_node>
<name>errors</name>
<children>
<folder_node>
<name>signinerror</name>
<children>
<concept_node>
<name>auth/user-not-found</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>auth/wrong-password</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>
</children>
</folder_node>
</children>
</folder_node>
<folder_node>
<name>vehicles</name>
<children>

View File

@@ -8,13 +8,13 @@
"@asseinfo/react-kanban": "^2.2.0",
"@craco/craco": "^6.4.3",
"@fingerprintjs/fingerprintjs": "^3.3.3",
"@sentry/react": "^6.19.3",
"@sentry/tracing": "^6.19.3",
"@sentry/react": "^6.19.6",
"@sentry/tracing": "^6.19.6",
"@splitsoftware/splitio-react": "^1.3.1-rc.1",
"@stripe/react-stripe-js": "^1.7.0",
"@stripe/stripe-js": "^1.26.0",
"@stripe/react-stripe-js": "^1.7.1",
"@stripe/stripe-js": "^1.27.0",
"@tanem/react-nprogress": "^4.0.12",
"antd": "^4.19.3",
"antd": "^4.19.5",
"apollo-link-logger": "^2.0.0",
"axios": "^0.26.1",
"craco-less": "^1.20.0",
@@ -25,16 +25,16 @@
"exifr": "^7.1.3",
"firebase": "^9.6.10",
"graphql": "^16.3.0",
"i18next": "^21.6.14",
"i18next": "^21.6.16",
"i18next-browser-languagedetector": "^6.1.4",
"jsoneditor": "^9.7.4",
"jsreport-browser-client-dist": "^1.3.0",
"libphonenumber-js": "^1.9.50",
"libphonenumber-js": "^1.9.51",
"logrocket": "^2.2.1",
"markerjs2": "^2.20.0",
"markerjs2": "^2.21.0",
"moment-business-days": "^1.2.0",
"moment-timezone": "^0.5.34",
"phone": "^3.1.14",
"phone": "^3.1.15",
"preval.macro": "^5.0.0",
"prop-types": "^15.8.1",
"query-string": "^7.1.1",
@@ -48,10 +48,10 @@
"react-drag-listview": "^0.1.9",
"react-grid-gallery": "^0.5.5",
"react-grid-layout": "^1.3.4",
"react-i18next": "^11.16.2",
"react-i18next": "^11.16.5",
"react-icons": "^4.3.1",
"react-number-format": "^4.9.1",
"react-redux": "^7.2.7",
"react-redux": "^7.2.8",
"react-resizable": "^3.0.4",
"react-router-dom": "^5.3.0",
"react-scripts": "^4.0.3",
@@ -64,7 +64,7 @@
"redux-saga": "^1.1.3",
"redux-state-sync": "^3.1.2",
"reselect": "^4.1.5",
"sass": "^1.49.10",
"sass": "^1.50.0",
"socket.io-client": "^4.4.1",
"styled-components": "^5.3.5",
"subscriptions-transport-ws": "^0.11.0",

View File

@@ -14,6 +14,7 @@ import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useLocation, useHistory } from "react-router-dom";
import {
DELETE_BILL_LINE,
INSERT_NEW_BILL_LINES,
UPDATE_BILL_LINE,
} from "../../graphql/bill-lines.queries";
@@ -58,6 +59,7 @@ export function BillDetailEditcontainer({
const [update_bill] = useMutation(UPDATE_BILL);
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
const [deleteBillLine] = useMutation(DELETE_BILL_LINE);
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.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) => {
const { deductedfromlbr, jobline, ...il } = billline;
delete il.__typename;
@@ -142,6 +158,7 @@ export function BillDetailEditcontainer({
);
}
});
await Promise.all(updates);
insertAuditTrail({

View File

@@ -114,7 +114,7 @@ export function BillFormComponent({
<Form.Item
label={t("bills.fields.vendor")}
name="vendorid"
style={{ display: billEdit ? "none" : null }}
// style={{ display: billEdit ? "none" : null }}
rules={[
{
required: true,
@@ -229,6 +229,7 @@ export function BillFormComponent({
({ getFieldValue }) => ({
validator(rule, value) {
if (
!bodyshop.bill_allow_post_to_closed &&
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
job.status === bodyshop.md_ro_statuses.default_exported ||
job.status === bodyshop.md_ro_statuses.default_void) &&

View File

@@ -1,9 +1,10 @@
import { useLazyQuery } from "@apollo/client";
import { LoadingOutlined } from "@ant-design/icons";
import { AutoComplete, Divider, Space } from "antd";
import _ from "lodash";
import React from "react";
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 PhoneNumberFormatter from "../../utils/PhoneFormatter";
import AlertComponent from "../alert/alert.component";
@@ -12,8 +13,9 @@ import OwnerNameDisplay, {
} from "../owner-name-display/owner-name-display.component";
export default function GlobalSearch() {
const { t } = useTranslation();
const [callSearch, { error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
const history = useHistory();
const [callSearch, { loading, error, data }] =
useLazyQuery(GLOBAL_SEARCH_QUERY);
const executeSearch = (v) => {
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
@@ -171,8 +173,13 @@ export default function GlobalSearch() {
<AutoComplete
options={options}
onSearch={handleSearch}
suffixIcon={loading && <LoadingOutlined spin />}
defaultActiveFirstOption
placeholder={t("general.labels.globalsearch")}
allowClear
onSelect={(val, opt) => {
history.push(opt.label.props.to);
}}
></AutoComplete>
);
}

View File

@@ -49,11 +49,11 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
GenerateDocument(
{
name: TemplateList("job_special").thirdpartypayer.key,
name: TemplateList("job_special").special_thirdpartypayer.key,
variables: { id: jobId },
context: restVals,
},
{ subject: TemplateList("job_special").thirdpartypayer.subject },
{ subject: TemplateList("job_special").special_thirdpartypayer.subject },
sendtype
);
};

View File

@@ -41,9 +41,10 @@ import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.con
import _ from "lodash";
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
import JobLinesExpander from "./job-lines-expander.component";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
jobRO: selectJobReadOnly,
technician: selectTechnician,
});
@@ -56,6 +57,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function JobLinesComponent({
bodyshop,
jobRO,
technician,
setPartsOrderContext,
@@ -75,6 +77,9 @@ export function JobLinesComponent({
filteredInfo: {},
});
const { t } = useTranslation();
const jobIsPrivate = bodyshop.md_ins_cos.find(
(c) => c.name === job.ins_co_nm
)?.private;
const columns = [
{
@@ -286,7 +291,7 @@ export function JobLinesComponent({
key: "actions",
render: (text, record) => (
<div>
{record.manual_line && (
{(record.manual_line || jobIsPrivate) && (
<Space>
<Button
disabled={jobRO}
@@ -457,7 +462,7 @@ export function JobLinesComponent({
<JobLinesExpander jobline={record} jobid={job.id} />
),
rowExpandable: (record) => true,
expandRowByClick: true,
//expandRowByClick: true,
expandIcon: ({ expanded, onExpand, record }) =>
expanded ? (
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />

View File

@@ -216,6 +216,7 @@ export function JobLinesUpsertModalComponent({
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
console.log(value);
if (!value || getFieldValue("part_type") !== "PAE") {
return Promise.resolve();
}
@@ -226,7 +227,10 @@ export function JobLinesUpsertModalComponent({
}),
({ getFieldValue }) => ({
validator(rule, value) {
if (!!getFieldValue("part_type") === !!value) {
console.log(value, !!value);
if (
!!getFieldValue("part_type") === (!!value || value === 0)
) {
return Promise.resolve();
}
return Promise.reject(

View File

@@ -18,7 +18,7 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import axios from "axios";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -53,6 +53,12 @@ export function JobsConvertButton({
variables: { jobId: job.id, ...values },
});
if (values.ca_gst_registrant) {
await axios.post("/job/totalsssu", {
id: job.id,
});
}
if (!res.errors) {
refetch();
notification["success"]({

View File

@@ -88,6 +88,33 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
</Form.Item>
<CABCpvrtCalculator form={form} disabled={jobRO} />
</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>
<Form.Item
@@ -100,7 +127,13 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
label={t("jobs.fields.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
label={t("jobs.fields.local_tax_rate")}

View File

@@ -1,13 +1,10 @@
import { notification } from "antd";
import axios from "axios";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { setPartnerVersion } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import {store} from '../../redux/store'
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -21,45 +18,48 @@ export default connect(
mapDispatchToProps
)(PartnerPingComponent);
export function PartnerPingComponent({ bodyshop, setPartnerVersion }) {
const { t } = useTranslation();
export function PartnerPingComponent({ bodyshop, }) {
useEffect(() => {
// Create an scoped async function in the hook
async function checkPartnerStatus() {
if (!bodyshop) return;
try {
//if (process.env.NODE_ENV === "development") return;
const PartnerResponse = await axios.post("http://localhost:1337/ping/");
const { appver, qbpath } = PartnerResponse.data;
setPartnerVersion(appver);
console.log({ appver, qbpath });
if (
!qbpath &&
!(
bodyshop &&
(bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
bodyshop.accountingconfig.qbo)
)
) {
notification["error"]({
title: "",
message: t("general.messages.noacctfilepath"),
});
}
} catch (error) {
console.log(error);
notification["error"]({
title: "",
message: t("general.messages.partnernotrunning"),
});
}
}
// Execute the created function directly
checkPartnerStatus();
checkPartnerStatus(bodyshop);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [bodyshop]);
return <></>;
}
export async function checkPartnerStatus(bodyshop) {
if (!bodyshop) return;
try {
//if (process.env.NODE_ENV === "development") return;
const PartnerResponse = await axios.post("http://localhost:1337/ping/");
// const {
// appver, //qbpath
// } = PartnerResponse.data;
console.log(PartnerResponse.data)
store.dispatch(setPartnerVersion(PartnerResponse.data));
// if (
// checkAcctPath &&
// !qbpath &&
// !(
// bodyshop &&
// (bodyshop.cdk_dealerid ||
// bodyshop.pbs_serialnumber ||
// bodyshop.accountingconfig.qbo)
// )
// ) {
// notification["error"]({
// title: "",
// message: i18n.t("general.messages.noacctfilepath"),
// });
// }
} catch (error) {
console.log("ImEX Online Partner is not running.", error);
// notification["error"]({
// title: "",
// message: i18n.t("general.messages.partnernotrunning"),
// });
}
}

View File

@@ -1,4 +1,4 @@
import { DeleteFilled, WarningFilled } from "@ant-design/icons";
import { DeleteFilled, WarningFilled, DownOutlined } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import {
Divider,
@@ -9,6 +9,8 @@ import {
Space,
Tag,
Select,
Menu,
Dropdown,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -39,6 +41,7 @@ export function PartsOrderModalComponent({
isReturn,
preferredMake,
job,
form,
}) {
const [sendType, setSendType] = sendTypeState;
const { OEConnection } = useTreatments(
@@ -52,6 +55,21 @@ export function PartsOrderModalComponent({
bodyshop.imexshopid
);
const { t } = useTranslation();
const handleClick = ({ item, key, keyPath }) => {
form.setFieldsValue({ comments: item.props.value });
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_parts_order_comment.map((comment, idx) => (
<Menu.Item value={comment.comment} key={idx}>
{comment.label}
</Menu.Item>
))}
</Menu>
</div>
);
return (
<div>
@@ -243,7 +261,23 @@ export function PartsOrderModalComponent({
);
}}
</Form.List>
<Form.Item name="comments" label={t("parts_orders.fields.comments")}>
<Form.Item
name="comments"
label={
<Space>
{t("parts_orders.fields.comments")}
<Dropdown overlay={menu}>
<a
className="ant-dropdown-link"
href=" #"
onClick={(e) => e.preventDefault()}
>
<DownOutlined />
</a>
</Dropdown>
</Space>
}
>
<Input.TextArea rows={3} />
</Form.Item>
<Radio.Group

View File

@@ -346,6 +346,7 @@ export function PartsOrderModalContainer({
<LoadingSpinner />
) : (
<PartsOrderModalComponent
form={form}
vendorList={(data && data.vendors) || []}
sendTypeState={sendTypeState}
isReturn={isReturn}

View File

@@ -79,6 +79,13 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
sorter: (a, b) =>
alphaSort(
a.v_make_desc + a.v_model_desc,
b.v_make_desc + b.v_model_desc
),
sortOrder:
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
render: (text, record) => (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""

View File

@@ -558,6 +558,13 @@ export default function ShopInfoGeneral({ form }) {
>
<Switch />
</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
name={["md_ded_notes"]}
label={t("bodyshop.fields.md_ded_notes")}
@@ -811,14 +818,23 @@ export default function ShopInfoGeneral({ form }) {
>
<Input />
</Form.Item>
<Space>
<Form.Item
label={t("bodyshop.fields.md_ins_co.zip")}
key={`${index}zip`}
name={[field.name, "zip"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_ins_co.zip")}
key={`${index}zip`}
name={[field.name, "zip"]}
>
<Input />
</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
onClick={() => {
remove(field.name);
@@ -1311,6 +1327,72 @@ export default function ShopInfoGeneral({ form }) {
}}
</Form.List>
</LayoutFormRow>
<LayoutFormRow grow header={t("bodyshop.fields.md_parts_order_comment")}>
<Form.List name={["md_parts_order_comment"]}>
{(fields, { add, remove, move }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key}>
<LayoutFormRow noDivider>
<Form.Item
label={t("general.labels.label")}
key={`${index}label`}
name={[field.name, "label"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("parts_orders.fields.comments")}
key={`${index}comment`}
name={[field.name, "comment"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Space wrap>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
</Space>
</LayoutFormRow>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
{t("general.actions.add")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</LayoutFormRow>
</div>
);
}

View File

@@ -81,7 +81,10 @@ export function SignInComponent({
/>
</Form.Item>
{signInError ? (
<AlertComponent type="error" message={signInError.message} />
<AlertComponent
type="error"
message={t(`users.errors.signinerror.${signInError.code}`)}
/>
) : null}
<Button
className="login-btn"

View File

@@ -25,6 +25,7 @@ export default function VendorsFormComponent({
formLoading,
handleDelete,
responsibilityCenters,
selectedvendor,
}) {
const { t } = useTranslation();
const client = useApolloClient();
@@ -52,7 +53,12 @@ export default function VendorsFormComponent({
>
{t("general.actions.save")}
</Button>
<Button type="danger" onClick={handleDelete} loading={formLoading}>
<Button
type="danger"
disabled={selectedvendor === "new"}
onClick={handleDelete}
loading={formLoading}
>
{t("general.actions.delete")}
</Button>

View File

@@ -39,30 +39,30 @@ function VendorsFormContainer({ refetch, bodyshop }) {
const [insertvendor] = useMutation(INSERT_NEW_VENDOR);
const [deleteVendor] = useMutation(DELETE_VENDOR);
const handleDelete = () => {
const handleDelete = async () => {
setFormLoading(true);
deleteVendor({
const result = await deleteVendor({
variables: { id: selectedvendor },
refetchQueries: ["QUERY_ALL_VENDORS"],
})
.then((r) => {
notification["success"]({
message: t("vendors.successes.deleted"),
});
delete search.selectedvendor;
history.push({ search: queryString.stringify(search) });
if (refetch)
refetch().then((r) => {
form.resetFields();
});
setFormLoading(false);
})
.catch((error) => {
notification["error"]({
message: t("vendors.errors.deleting"),
});
setFormLoading(false);
});
console.log(result);
if (result.errors) {
notification["error"]({
message: t("vendors.errors.deleting"),
});
} else {
notification["success"]({
message: t("vendors.successes.deleted"),
});
delete search.selectedvendor;
history.push({ search: queryString.stringify(search) });
if (refetch)
refetch().then((r) => {
form.resetFields();
});
}
setFormLoading(false);
};
const handleFinish = async (values) => {
@@ -139,6 +139,7 @@ function VendorsFormContainer({ refetch, bodyshop }) {
formLoading={formLoading}
handleDelete={handleDelete}
responsibilityCenters={bodyshop.md_responsibility_centers || null}
selectedvendor={selectedvendor}
/>
) : (
t("vendors.labels.noneselected")

View File

@@ -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`
mutation INSERT_NEW_BILL_LINES($billLines: [billlines_insert_input!]!) {

View File

@@ -104,6 +104,8 @@ export const QUERY_BODYSHOP = gql`
ss_configuration
md_from_emails
last_name_first
md_parts_order_comment
bill_allow_post_to_closed
employees {
user_email
id
@@ -205,6 +207,8 @@ export const UPDATE_SHOP = gql`
ss_configuration
md_from_emails
last_name_first
md_parts_order_comment
bill_allow_post_to_closed
employees {
id
first_name

View File

@@ -611,6 +611,8 @@ export const GET_JOB_BY_PK = gql`
ownerid
ded_note
materials
auto_add_ats
rate_ats
owner {
id
ownr_fn

View File

@@ -5,16 +5,19 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
import AlertComponent from "../../components/alert/alert.component";
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_BILLS_FOR_EXPORT } from "../../graphql/accounting.queries";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectPartnerVersion } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
partnerVersion: selectPartnerVersion,
});
const mapDispatchToProps = (dispatch) => ({
@@ -26,6 +29,7 @@ export function AccountingPayablesContainer({
bodyshop,
setBreadcrumbs,
setSelectedHeader,
partnerVersion,
}) {
const { t } = useTranslation();
@@ -38,7 +42,8 @@ export function AccountingPayablesContainer({
label: t("titles.bc.accounting-payables"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
checkPartnerStatus(bodyshop, true);
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
const { loading, error, data } = useQuery(QUERY_BILLS_FOR_EXPORT, {
fetchPolicy: "network-only",
@@ -47,9 +52,24 @@ export function AccountingPayablesContainer({
if (error) return <AlertComponent message={error.message} type="error" />;
const noPath =
!partnerVersion?.qbpath &&
!(
bodyshop &&
(bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
bodyshop.accountingconfig.qbo)
);
return (
<div>
<RbacWrapper action="accounting:payables">
{noPath && (
<AlertComponent
type="error"
message={t("general.messages.noacctfilepath")}
/>
)}
<AccountingPayablesTable
loadaing={loading}
bills={data ? data.bills : []}

View File

@@ -12,9 +12,12 @@ import {
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
import { selectPartnerVersion } from "../../redux/application/application.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
partnerVersion: selectPartnerVersion,
});
const mapDispatchToProps = (dispatch) => ({
@@ -25,6 +28,7 @@ export function AccountingPaymentsContainer({
bodyshop,
setBreadcrumbs,
setSelectedHeader,
partnerVersion,
}) {
const { t } = useTranslation();
@@ -37,7 +41,8 @@ export function AccountingPaymentsContainer({
label: t("titles.bc.accounting-payments"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
checkPartnerStatus(bodyshop, true);
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
const { loading, error, data } = useQuery(QUERY_PAYMENTS_FOR_EXPORT, {
fetchPolicy: "network-only",
@@ -45,10 +50,23 @@ export function AccountingPaymentsContainer({
});
if (error) return <AlertComponent message={error.message} type="error" />;
const noPath =
!partnerVersion?.qbpath &&
!(
bodyshop &&
(bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
bodyshop.accountingconfig.qbo)
);
return (
<div>
<RbacWrapper action="accounting:payments">
{noPath && (
<AlertComponent
type="error"
message={t("general.messages.noacctfilepath")}
/>
)}
<AccountingPaymentsTable
loadaing={loading}
payments={data ? data.payments : []}

View File

@@ -12,9 +12,12 @@ import {
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
import { selectPartnerVersion } from "../../redux/application/application.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
partnerVersion: selectPartnerVersion,
});
const mapDispatchToProps = (dispatch) => ({
@@ -25,6 +28,7 @@ export function AccountingReceivablesContainer({
bodyshop,
setBreadcrumbs,
setSelectedHeader,
partnerVersion,
}) {
const { t } = useTranslation();
@@ -37,7 +41,8 @@ export function AccountingReceivablesContainer({
label: t("titles.bc.accounting-receivables"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
checkPartnerStatus(bodyshop, true);
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
const { loading, error, data } = useQuery(QUERY_JOBS_FOR_EXPORT, {
variables: {
@@ -48,9 +53,25 @@ export function AccountingReceivablesContainer({
});
if (error) return <AlertComponent message={error.message} type="error" />;
const noPath =
!partnerVersion?.qbpath &&
!(
bodyshop &&
(bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
bodyshop.accountingconfig.qbo)
);
return (
<div>
<RbacWrapper action="accounting:receivables">
{noPath && (
<AlertComponent
type="error"
message={t("general.messages.noacctfilepath")}
/>
)}
<AccountingReceivablesTable
loadaing={loading}
jobs={data ? data.jobs : []}

View File

@@ -1,4 +1,4 @@
import { SyncOutlined } from "@ant-design/icons";
import { SyncOutlined, EditFilled } from "@ant-design/icons";
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
import queryString from "query-string";
import React, { useState } from "react";
@@ -141,7 +141,9 @@ export function BillsListPage({
render: (text, record) => (
<Space wrap>
<Link to={`/manage/bills?billid=${record.id}`}>
<Button>{t("bills.actions.edit")}</Button>
<Button>
<EditFilled />
</Button>
</Link>
{
// <Button

View File

@@ -3,12 +3,19 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import JobsAvailableTableContainer from "../../components/jobs-available-table/jobs-available-table.container";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectPartnerVersion } from "../../redux/application/application.selectors";
const mapStateToProps = createStructuredSelector({
partnerVersion: selectPartnerVersion,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -16,6 +23,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function JobsAvailablePageContainer({
partnerVersion,
setBreadcrumbs,
setSelectedHeader,
}) {
@@ -40,9 +48,18 @@ export function JobsAvailablePageContainer({
</Link>
}
/>
{!partnerVersion && (
<AlertComponent
type="warning"
message={t("general.messages.partnernotrunning")}
/>
)}
<JobsAvailableTableContainer />
</div>
</RbacWrapper>
);
}
export default connect(null, mapDispatchToProps)(JobsAvailablePageContainer);
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsAvailablePageContainer);

View File

@@ -233,6 +233,7 @@
},
"appt_length": "Default Appointment Length",
"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_local_tax_rate": "Bill - Provincial/State Tax Rate %",
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
@@ -295,12 +296,14 @@
"md_ins_co": {
"city": "City",
"name": "Insurance Company Name",
"private": "Private",
"state": "Province/State",
"street1": "Street 1",
"street2": "Street 2",
"zip": "Zip/Postal Code"
},
"md_jobline_presets": "Jobline Presets",
"md_parts_order_comment": "Parts Orders Comments",
"md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources",
"messaginglabel": "Messaging Preset Label",
@@ -1243,6 +1246,7 @@
"08": "Left Rear Side",
"09": "Left Side"
},
"auto_add_ats": "Automatically Add/Update ATS",
"ca_bc_pvrt": "PVRT",
"ca_customer_gst": "Customer Portion of GST",
"ca_gst_registrant": "GST Registrant",
@@ -1390,6 +1394,7 @@
"production_vars": {
"note": "Production Note"
},
"rate_ats": "ATS Rate",
"rate_la1": "LA1",
"rate_la2": "LA2",
"rate_la3": "LA3",
@@ -2573,6 +2578,14 @@
"passwordchanged": "Password changed successfully. "
}
},
"users": {
"errors": {
"signinerror": {
"auth/user-not-found": "A user with this email does not exist.",
"auth/wrong-password": "The email and password combination you provided is incorrect."
}
}
},
"vehicles": {
"errors": {
"noaccess": "The vehicle does not exist or you do not have access to it.",

View File

@@ -233,6 +233,7 @@
},
"appt_length": "",
"attach_pdf_to_email": "",
"bill_allow_post_to_closed": "",
"bill_federal_tax_rate": "",
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
@@ -295,12 +296,14 @@
"md_ins_co": {
"city": "",
"name": "",
"private": "",
"state": "",
"street1": "",
"street2": "",
"zip": ""
},
"md_jobline_presets": "",
"md_parts_order_comment": "",
"md_payment_types": "",
"md_referral_sources": "",
"messaginglabel": "",
@@ -1243,6 +1246,7 @@
"08": "",
"09": ""
},
"auto_add_ats": "",
"ca_bc_pvrt": "",
"ca_customer_gst": "",
"ca_gst_registrant": "",
@@ -1390,6 +1394,7 @@
"production_vars": {
"note": ""
},
"rate_ats": "",
"rate_la1": "Tarifa LA1",
"rate_la2": "Tarifa LA2",
"rate_la3": "Tarifa LA3",
@@ -2573,6 +2578,14 @@
"passwordchanged": ""
}
},
"users": {
"errors": {
"signinerror": {
"auth/user-not-found": "",
"auth/wrong-password": ""
}
}
},
"vehicles": {
"errors": {
"noaccess": "El vehículo no existe o usted no tiene acceso a él.",

View File

@@ -233,6 +233,7 @@
},
"appt_length": "",
"attach_pdf_to_email": "",
"bill_allow_post_to_closed": "",
"bill_federal_tax_rate": "",
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
@@ -295,12 +296,14 @@
"md_ins_co": {
"city": "",
"name": "",
"private": "",
"state": "",
"street1": "",
"street2": "",
"zip": ""
},
"md_jobline_presets": "",
"md_parts_order_comment": "",
"md_payment_types": "",
"md_referral_sources": "",
"messaginglabel": "",
@@ -1243,6 +1246,7 @@
"08": "",
"09": ""
},
"auto_add_ats": "",
"ca_bc_pvrt": "",
"ca_customer_gst": "",
"ca_gst_registrant": "",
@@ -1390,6 +1394,7 @@
"production_vars": {
"note": ""
},
"rate_ats": "",
"rate_la1": "Taux LA1",
"rate_la2": "Taux LA2",
"rate_la3": "Taux LA3",
@@ -2573,6 +2578,14 @@
"passwordchanged": ""
}
},
"users": {
"errors": {
"signinerror": {
"auth/user-not-found": "",
"auth/wrong-password": ""
}
}
},
"vehicles": {
"errors": {
"noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.",

View File

@@ -24,6 +24,7 @@ export default async function RenderTemplate(
let { contextData, useShopSpecificTemplate } = await fetchContextData(
templateObject
);
console.log(templateObject.name)
const { ignoreCustomMargins } = Templates[templateObject.name];
let reportRequest = {

View File

@@ -476,7 +476,7 @@ export const TemplateList = (type, context) => {
: {}),
...(!type || type === "job_special"
? {
thirdpartypayer: {
special_thirdpartypayer: {
title: i18n.t("printcenter.jobs.thirdpartypayer"),
description: "CSI invite",
key: "special_thirdpartypayer",

View File

@@ -2094,14 +2094,14 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@sentry/browser@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.3.tgz#b4cfc6eba48d10a5fdf096c05ca11303354edb8b"
integrity sha512-E8UA6IN8z9hL6aGzOHUzqgNZiBwARkA89i8ncKB9QU1/+jl7598ZLziN4+uyPeZiRquEz8Ub7Ve1eacs1u+fbw==
"@sentry/browser@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.6.tgz#75be467667fffa1f4745382fc7a695568609c634"
integrity sha512-V5QyY1cO1iuFCI78dOFbHV7vckbeQEPPq3a5dGSXlBQNYnd9Ec5xoxp5nRNpWQPOZ8/Ixt9IgRxdqVTkWib51g==
dependencies:
"@sentry/core" "6.19.3"
"@sentry/types" "6.19.3"
"@sentry/utils" "6.19.3"
"@sentry/core" "6.19.6"
"@sentry/types" "6.19.6"
"@sentry/utils" "6.19.6"
tslib "^1.9.3"
"@sentry/cli@^1.73.0":
@@ -2117,69 +2117,69 @@
proxy-from-env "^1.1.0"
which "^2.0.2"
"@sentry/core@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.3.tgz#88268afc8c42716c455ad77bb4bed2bbf96abd83"
integrity sha512-RcGmYdkrE3VYBMl9Hgv4GKsC8FEVUdWYsfGIcT/btwP2YpBeUaTZl+1vV9r3Ncdl125LqzP5CKSj5otVxiEg6g==
"@sentry/core@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.6.tgz#7d4649d0148b5d0be1358ab02e2f869bf7363e9a"
integrity sha512-biEotGRr44/vBCOegkTfC9rwqaqRKIpFljKGyYU6/NtzMRooktqOhjmjmItNCMRknArdeaQwA8lk2jcZDXX3Og==
dependencies:
"@sentry/hub" "6.19.3"
"@sentry/minimal" "6.19.3"
"@sentry/types" "6.19.3"
"@sentry/utils" "6.19.3"
"@sentry/hub" "6.19.6"
"@sentry/minimal" "6.19.6"
"@sentry/types" "6.19.6"
"@sentry/utils" "6.19.6"
tslib "^1.9.3"
"@sentry/hub@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.3.tgz#d555c83404f19ac9b68f336b051b8e7a9d75feb0"
integrity sha512-iYbkrxEZt6CrHP3U3r54MARVZSs3YHjAMUMOTlC16s/Amz1McwV95XtI3NJaqMhwzl7R5vbGrs3xOtLg1V1Uyw==
"@sentry/hub@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.6.tgz#ada83ceca0827c49534edfaba018221bc1eb75e1"
integrity sha512-PuEOBZxvx3bjxcXmWWZfWXG+orojQiWzv9LQXjIgroVMKM/GG4QtZbnWl1hOckUj7WtKNl4hEGO2g/6PyCV/vA==
dependencies:
"@sentry/types" "6.19.3"
"@sentry/utils" "6.19.3"
"@sentry/types" "6.19.6"
"@sentry/utils" "6.19.6"
tslib "^1.9.3"
"@sentry/minimal@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.3.tgz#b9b7f0d7f0cd2341b243318668ac01458f9d7889"
integrity sha512-xy/6ThHK8B2NJT98nWrx6V9eVgUbzq2N/8lv5/QqrKsICjxx22TRC8Q6zPg/o7BYcrY5vpugSEbIeErTnyxHDA==
"@sentry/minimal@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.6.tgz#b6cced3708e25d322039e68ebdf8fadfa445bf7d"
integrity sha512-T1NKcv+HTlmd8EbzUgnGPl4ySQGHWMCyZ8a8kXVMZOPDzphN3fVIzkYzWmSftCWp0rpabXPt9aRF2mfBKU+mAQ==
dependencies:
"@sentry/hub" "6.19.3"
"@sentry/types" "6.19.3"
"@sentry/hub" "6.19.6"
"@sentry/types" "6.19.6"
tslib "^1.9.3"
"@sentry/react@^6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.19.3.tgz#6b2bfb19faa55cf83af593a5778bb23cd2cf60a3"
integrity sha512-Zza1RX0+1tFCM1Hfq3Yl50cbc/ml0V/katw4aVZIU6+vEgvk5EuSFKU2LtblmJkpID7x6UwWz+1qgXumZPze6Q==
"@sentry/react@^6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.19.6.tgz#4c07168637bfcef4d6556a2c4548b74a61eaed87"
integrity sha512-RnWZ7clg1lRgf/JFNnTOs8ZPCv566E5CwFXXb6swyjPYUMcIn95XujDQU9SU4hXZ4qXd9BRvifxqyxvq0LMXNw==
dependencies:
"@sentry/browser" "6.19.3"
"@sentry/minimal" "6.19.3"
"@sentry/types" "6.19.3"
"@sentry/utils" "6.19.3"
"@sentry/browser" "6.19.6"
"@sentry/minimal" "6.19.6"
"@sentry/types" "6.19.6"
"@sentry/utils" "6.19.6"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry/tracing@^6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.19.3.tgz#dfdbd5019486c899bdf352b1152d5d253544ef70"
integrity sha512-3lyb4yCFH/ltEQSyKM96g2c74vvKIwByx8fLDS4FHYQQDXY+xPcs+zyK8L1Fs5PRFAUciEOK5TS9qwELom5K4w==
"@sentry/tracing@^6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.19.6.tgz#faa156886afe441730f03cf9ac9c4982044b7135"
integrity sha512-STZdlEtTBqRmPw6Vjkzi/1kGkGPgiX0zdHaSOhSeA2HXHwx7Wnfu7veMKxtKWdO+0yW9QZGYOYqp0GVf4Swujg==
dependencies:
"@sentry/hub" "6.19.3"
"@sentry/minimal" "6.19.3"
"@sentry/types" "6.19.3"
"@sentry/utils" "6.19.3"
"@sentry/hub" "6.19.6"
"@sentry/minimal" "6.19.6"
"@sentry/types" "6.19.6"
"@sentry/utils" "6.19.6"
tslib "^1.9.3"
"@sentry/types@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.3.tgz#94b19da68d4d23561efb1014f72968bcea85cd0c"
integrity sha512-jHhqxp8MIWSfOc3krorirTGKTEaSFO6XrAvi+2AZhr6gvOChwOgzgrN2ZqesJcZmgCsqWV21u3usSwYeRrjOJA==
"@sentry/types@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.6.tgz#70513f9dca05d23d7ab9c2a6cb08d4db6763ca67"
integrity sha512-QH34LMJidEUPZK78l+Frt3AaVFJhEmIi05Zf8WHd9/iTt+OqvCHBgq49DDr1FWFqyYWm/QgW/3bIoikFpfsXyQ==
"@sentry/utils@6.19.3":
version "6.19.3"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.3.tgz#0c3a3f0b86c12e3b079e56e37a44e62a1226043d"
integrity sha512-GdC9B/FK7qd0zItY43135bYbhuVSawE18bIrQDNuno8gTpDJ5OgShpTN9zR53AmMh16/lwKNnV3ZZjlpKcxuNw==
"@sentry/utils@6.19.6":
version "6.19.6"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.6.tgz#2ddc9ef036c3847084c43d0e5a55e4646bdf9021"
integrity sha512-fAMWcsguL0632eWrROp/vhPgI7sBj/JROWVPzpabwVkm9z3m1rQm6iLFn4qfkZL8Ozy6NVZPXOQ7EXmeU24byg==
dependencies:
"@sentry/types" "6.19.3"
"@sentry/types" "6.19.6"
tslib "^1.9.3"
"@sentry/webpack-plugin@^1.18.8":
@@ -2226,17 +2226,17 @@
shallowequal "^1.1.0"
unfetch "^4.1.0"
"@stripe/react-stripe-js@^1.7.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.7.0.tgz#83c993a09a903703205d556617f9729784a896c3"
integrity sha512-L20v8Jq0TDZFL2+y+uXD751t6q9SalSFkSYZpmZ2VWrGZGK7HAGfRQ804dzYSSr5fGenW6iz6y7U0YKfC/TK3g==
"@stripe/react-stripe-js@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.7.1.tgz#6e1db8f4a0eaf2193b153173d4aa7c38b681310d"
integrity sha512-GiUPoMo0xVvmpRD6JR9JAhAZ0W3ZpnYZNi0KE+91+tzrSFVpChKZbeSsJ5InlZhHFk9NckJCt1wOYBTqNsvt3A==
dependencies:
prop-types "^15.7.2"
"@stripe/stripe-js@^1.26.0":
version "1.26.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.26.0.tgz#45670924753c01e18d0544ea1f1067b474aaa96f"
integrity sha512-4R1vC75yKaCVFARW3bhelf9+dKt4NP4iZY/sIjGK7AAMBVvZ47eG74NvsAIUdUnhOXSWFMjdFWqv+etk5BDW4g==
"@stripe/stripe-js@^1.27.0":
version "1.27.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.27.0.tgz#ab0c82fa89fd40260de4414f69868b769e810550"
integrity sha512-SEiybUBu+tlsFKuzdFFydxxjkbrdzHo0tz/naYC5Dt9or/Ux2gcKJBPYQ4RmqQCNHFxgyNj6UYsclywwhe2inQ==
"@surma/rollup-plugin-off-main-thread@^1.1.1":
version "1.4.2"
@@ -3187,10 +3187,10 @@ ansi-styles@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
antd@^4.19.3:
version "4.19.3"
resolved "https://registry.yarnpkg.com/antd/-/antd-4.19.3.tgz#2b6bb938bda9850c797db59c8923f3c8a14a6693"
integrity sha512-q4oT2lIM0Fb60MfcdtjH6LFQcmo5MuM27PN3nJMsRG1FeiQ9n+OPFlkQSdtb0ZWFIFjTH3p0W02T6SbB2U7ChQ==
antd@^4.19.5:
version "4.19.5"
resolved "https://registry.yarnpkg.com/antd/-/antd-4.19.5.tgz#38d08f3e1391a7a69c2ca76f50968bb12ec2ac93"
integrity sha512-C4H/VJqlVO5iMvHZyiV27R8SbPs4jsOKCGPhDXIHUry/RnUCbMmVeQaPRfUIxSI1NbqDflsuQfevPtz1svyIlg==
dependencies:
"@ant-design/colors" "^6.0.0"
"@ant-design/icons" "^4.7.0"
@@ -3208,7 +3208,7 @@ antd@^4.19.3:
rc-dialog "~8.6.0"
rc-drawer "~4.4.2"
rc-dropdown "~3.3.2"
rc-field-form "~1.24.0"
rc-field-form "~1.25.0"
rc-image "~5.2.5"
rc-input "~0.0.1-alpha.5"
rc-input-number "~7.3.0"
@@ -7399,10 +7399,10 @@ i18next-browser-languagedetector@^6.1.4:
dependencies:
"@babel/runtime" "^7.14.6"
i18next@^21.6.14:
version "21.6.14"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.14.tgz#2bc199fba7f4da44b5952d7df0a3814a6e5c3943"
integrity sha512-XL6WyD+xlwQwbieXRlXhKWoLb/rkch50/rA+vl6untHnJ+aYnkQ0YDZciTWE78PPhOpbi2gR0LTJCJpiAhA+uQ==
i18next@^21.6.16:
version "21.6.16"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.16.tgz#8cff8c3ba2ffaf8438a8c83fe284083f15cf3941"
integrity sha512-xJlzrVxG9CyAGsbMP1aKuiNr1Ed2m36KiTB7hjGMG2Zo4idfw3p9THUEu+GjBwIgEZ7F11ZbCzJcfv4uyfKNuw==
dependencies:
"@babel/runtime" "^7.17.2"
@@ -8883,10 +8883,10 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
libphonenumber-js@^1.9.50:
version "1.9.50"
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.50.tgz#f5028a2c4cc47a69d69a0de3629afad97a613712"
integrity sha512-cCzQPChw2XbordcO2LKiw5Htx5leHVfFk/EXkxNHqJfFo7Fndcb1kF5wPJpc316vCJhhikedYnVysMh3Sc7Ocw==
libphonenumber-js@^1.9.51:
version "1.9.51"
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.51.tgz#c2529e391bdf68d1e60e283419f58c9ad4de4185"
integrity sha512-MGidRDs7s2nUybwrB/UjZT4nPXZPYQZQTu/sF3/O2v/DocmD8N6G+a9kwDt2qm7DaOo35XRt7hAIbYL+ml942Q==
lie@~3.3.0:
version "3.3.0"
@@ -9165,10 +9165,10 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
markerjs2@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/markerjs2/-/markerjs2-2.20.0.tgz#400b83f8bbdcc2ac99aa3ae29a514fec1f1bebe9"
integrity sha512-uk5LEQsQJJ7brNW5xCSvUW3m+1IH/A6bj+ellbaQfmiYPVH7S8JMRUlu+QrAW8jX8UtCoKdBplS+mZEXGyNMpg==
markerjs2@^2.21.0:
version "2.21.0"
resolved "https://registry.yarnpkg.com/markerjs2/-/markerjs2-2.21.0.tgz#f2b4c524c058300709b54c0db2086569d00d9b1a"
integrity sha512-SC0/6VfT52laKWmnDQDKRqMREKhGzltJYWHaGFhoJza36IplFfrVRA1IYSPqHa5xKPApQmEn7fyNiSgfCi2VRA==
material-colors@^1.2.1:
version "1.2.6"
@@ -10215,10 +10215,10 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
phone@^3.1.14:
version "3.1.14"
resolved "https://registry.yarnpkg.com/phone/-/phone-3.1.14.tgz#9fc3c0b662737395e1e0f758ecd344062e2b5137"
integrity sha512-VoeEXhHgNfvMqPE5QD6usnh+wZbCqbEUQcAqwNZkGXKfktjb6ISVEbWa85SiYxdrdzTQFj7GD0hpQNSEREBbJQ==
phone@^3.1.15:
version "3.1.15"
resolved "https://registry.yarnpkg.com/phone/-/phone-3.1.15.tgz#6d950005272626b6ab3a1cecb0ca2f4a5c558278"
integrity sha512-9p7uIFcuKB+lspsRNV+TfRJdG8Zm6rytFnuu+ScurXcvlJSDwJVpO5R5AFb0QaUvliMaeOkYdkHOSHjtHIRbeg==
picocolors@^0.2.1:
version "0.2.1"
@@ -11383,10 +11383,10 @@ rc-dropdown@~3.3.2:
rc-trigger "^5.0.4"
rc-util "^5.17.0"
rc-field-form@~1.24.0:
version "1.24.0"
resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.24.0.tgz#2510a5c34713831ddcb412d4560be9057fc0dc5e"
integrity sha512-5beNBU5gEyi8YRYyqbTWSu5hO0jZQN0AWpY3U7TcllUKrDLcZZdRXuAOpyxJQcttWFs+UAFsbcRAUtnOGBjl7w==
rc-field-form@~1.25.0:
version "1.25.2"
resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.25.2.tgz#de418194b7aca2f1b6e0e059edd97b5cf624f68a"
integrity sha512-FXGScWibDlwIlKY15T1YOA7VTtMJwqxxXdDjHB56ZNx7wGbE4vK+Fe2zcymyakGZD0ej8NUP5LGr7qBVWaVpUQ==
dependencies:
"@babel/runtime" "^7.8.4"
async-validator "^4.0.2"
@@ -11900,10 +11900,10 @@ react-grid-layout@^1.3.4:
react-draggable "^4.0.0"
react-resizable "^3.0.4"
react-i18next@^11.16.2:
version "11.16.2"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.16.2.tgz#650b18c12a624057ee2651ba4b4a989b526be554"
integrity sha512-1iuZduvARUelL5ux663FvIoDZExwFO+9QtRAAt4uvs1/aun4cUZt8XBrVg7iiDgNls9cOSORAhE7Ri5KA9RMvg==
react-i18next@^11.16.5:
version "11.16.5"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.16.5.tgz#5258784b9b617c443811307072a434ec7447c70a"
integrity sha512-dkDN9suVU/jaD9A0xM4qNU9++LwgueWZn5XGTDEKTZeBgsd3q17ssTQXlSbEb0Gl0iLDdUKU7MrdjQjDc33ztA==
dependencies:
"@babel/runtime" "^7.14.5"
html-escaper "^2.0.2"
@@ -11977,10 +11977,10 @@ react-redux@^7.2.0:
prop-types "^15.7.2"
react-is "^17.0.2"
react-redux@^7.2.7:
version "7.2.7"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.7.tgz#f5edd4e4bc34ec8787451d77d16663abf12f8be9"
integrity sha512-kpstUHhXgT5HOLwzoRhDr3AWHO7H5mgTN5pX1H02OuoIMaZiOLYlul8vgan2WE8eEttAEMew8Npgzd3C6Asdow==
react-redux@^7.2.8:
version "7.2.8"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de"
integrity sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==
dependencies:
"@babel/runtime" "^7.15.4"
"@types/react-redux" "^7.1.20"
@@ -12729,10 +12729,10 @@ sass-loader@^10.0.5:
schema-utils "^3.0.0"
semver "^7.3.2"
sass@^1.49.10:
version "1.49.10"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.10.tgz#7b83cee0f03bbba443111b3f94944fde2b0c7a6b"
integrity sha512-w37zfWJwKu4I78U4z63u1mmgoncq+v3iOB4yzQMPyAPVHHawaQSnu9C9ysGQnZEhW609jkcLioJcMCqm75JMdg==
sass@^1.50.0:
version "1.50.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.50.0.tgz#3e407e2ebc53b12f1e35ce45efb226ea6063c7c8"
integrity sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"

View File

@@ -0,0 +1 @@
{}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "md_parts_order_comment" jsonb
-- not null default jsonb_build_array();

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "md_parts_order_comment" jsonb
not null default jsonb_build_array();

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "bill_allow_post_to_closed" boolean
-- not null default 'false';

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "bill_allow_post_to_closed" boolean
not null default 'false';

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."jobs" add column "auto_add_ats" boolean
-- null default 'false';

View File

@@ -0,0 +1,2 @@
alter table "public"."jobs" add column "auto_add_ats" boolean
null default 'false';

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."jobs" add column "rate_ats" numeric
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."jobs" add column "rate_ats" numeric
null;

View File

@@ -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 = `
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
insert_messages(objects: $msg) {
@@ -970,6 +1002,8 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
ca_bc_pvrt
ca_customer_gst
materials
auto_add_ats
rate_ats
joblines(where: { removed: { _eq: false } }){
id
line_no

View File

@@ -24,7 +24,7 @@ exports.totalsSsu = async function (req, res) {
});
const newTotals = await TotalsServerSide(
{ body: { job: job.jobs_by_pk } },
{ body: { job: job.jobs_by_pk, client: client } },
res,
true
);
@@ -53,7 +53,9 @@ exports.totalsSsu = async function (req, res) {
//IMPORTANT*** These two functions MUST be mirrrored.
async function TotalsServerSide(req, res) {
const { job } = req.body;
const { job, client } = req.body;
await AutoAddAtsIfRequired({ job: job, client: client });
try {
let ret = {
parts: CalculatePartsTotals(job.joblines),
@@ -78,6 +80,16 @@ async function Totals(req, res) {
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 {
let ret = {
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) {
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);

View File

@@ -201,7 +201,9 @@ exports.job = async (req, res) => {
.filter((p) => p.isValid() && p.isAfter(yesterday)),
moment().tz(timezone).add(15, "days"),
]);
const range = Math.round(moment.duration(end.diff(today)).asDays());
const range = Math.round(
moment.duration(end.add(20, "days").diff(today)).asDays()
);
for (var day = 0; day < range; day++) {
const current = moment(today)
.tz(timezone)