Compare commits
38 Commits
feature/cd
...
feature/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
098754125b | ||
|
|
ae4a864533 | ||
|
|
27d9322ced | ||
|
|
f5003080db | ||
|
|
3b992edc21 | ||
|
|
3e1663bf18 | ||
|
|
9a60149d75 | ||
|
|
54b483333f | ||
|
|
990ec1a553 | ||
|
|
6bd49a461e | ||
|
|
0d30fc0e32 | ||
|
|
7ce4264309 | ||
|
|
5385e6918b | ||
|
|
a8ad65000d | ||
|
|
ae9ca0ac3b | ||
|
|
9fd23e9181 | ||
|
|
a288a1a2a4 | ||
|
|
33e2201524 | ||
|
|
34422dfef7 | ||
|
|
c6635845f5 | ||
|
|
e770232e1d | ||
|
|
51dcf3a7c6 | ||
|
|
afd745917d | ||
|
|
aa8e12ef58 | ||
|
|
41bbda7bcf | ||
|
|
f19289362d | ||
|
|
2d546d92b5 | ||
|
|
1360a73028 | ||
|
|
7de224831f | ||
|
|
e9cda93898 | ||
|
|
2c1f5a9f34 | ||
|
|
d88d7ebebd | ||
|
|
17dcc2efd8 | ||
|
|
3391d7d3f4 | ||
|
|
bccb5e353b | ||
|
|
8e05105917 | ||
|
|
81babca775 | ||
|
|
fe8dd2a920 |
@@ -1 +1 @@
|
||||
client_max_body_size 15M;
|
||||
client_max_body_size 50M;
|
||||
@@ -3014,6 +3014,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>attach_pdf_to_email</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>
|
||||
@@ -11679,6 +11700,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>pdfcopywillbeattached</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>preview</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -16516,6 +16558,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>markpstexempt</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>markpstexemptconfirm</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>postbills</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -29914,6 +29998,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>refnumber</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>sendtype</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -30420,6 +30525,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>key_tag</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>paint_grid</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>parts_label_single</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -30714,6 +30861,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>stolen_recovery_checklist</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>supplement_request</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32484,6 +32652,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>gsr_by_csr</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>gsr_by_delivery_date</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32673,6 +32862,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>hours_sold_detail_closed_csr</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>hours_sold_detail_closed_ins_co</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32715,6 +32925,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>hours_sold_detail_open_csr</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>hours_sold_detail_open_ins_co</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32757,6 +32988,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>hours_sold_summary_closed_csr</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>hours_sold_summary_closed_ins_co</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32799,6 +33051,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>hours_sold_summary_open_csr</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>hours_sold_summary_open_ins_co</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32820,6 +33093,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>job_costing_ro_csr</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>job_costing_ro_date_detail</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32925,6 +33219,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>open_orders_csr</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>open_orders_estimator</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -81,6 +81,7 @@ function BillEnterModalContainer({
|
||||
},
|
||||
],
|
||||
},
|
||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID"],
|
||||
});
|
||||
console.log("adjustmentsToInsert", adjustmentsToInsert);
|
||||
const adjKeys = Object.keys(adjustmentsToInsert);
|
||||
|
||||
@@ -37,6 +37,8 @@ export default function EmailOverlayComponent({ form, selectedMediaState }) {
|
||||
</Form.Item>
|
||||
|
||||
<Divider>{t("emails.labels.preview")}</Divider>
|
||||
<strong>{t("emails.labels.pdfcopywillbeattached")}</strong>
|
||||
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
|
||||
@@ -43,6 +43,10 @@ export function EmailOverlayContainer({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [sending, setSending] = useState(false);
|
||||
const [rawHtml, setRawHtml] = useState("");
|
||||
const [pdfCopytoAttach, setPdfCopytoAttach] = useState({
|
||||
filename: null,
|
||||
pdf: null,
|
||||
});
|
||||
const [selectedMedia, setSelectedMedia] = useState([]);
|
||||
|
||||
const defaultEmailFrom = {
|
||||
@@ -59,17 +63,17 @@ export function EmailOverlayContainer({
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("email_send_from_modal");
|
||||
|
||||
const attachments = [];
|
||||
//const attachments = [];
|
||||
|
||||
if (values.fileList)
|
||||
await asyncForEach(values.fileList, async (f) => {
|
||||
const t = {
|
||||
ContentType: f.type,
|
||||
Filename: f.name,
|
||||
Base64Content: (await toBase64(f.originFileObj)).split(",")[1],
|
||||
};
|
||||
attachments.push(t);
|
||||
});
|
||||
// if (values.fileList)
|
||||
// await asyncForEach(values.fileList, async (f) => {
|
||||
// const t = {
|
||||
// ContentType: f.type,
|
||||
// Filename: f.name,
|
||||
// Base64Content: (await toBase64(f.originFileObj)).split(",")[1],
|
||||
// };
|
||||
// attachments.push(t);
|
||||
// });
|
||||
|
||||
setSending(true);
|
||||
try {
|
||||
@@ -77,11 +81,28 @@ export function EmailOverlayContainer({
|
||||
...defaultEmailFrom,
|
||||
...values,
|
||||
html: rawHtml,
|
||||
attachments:
|
||||
values.fileList &&
|
||||
(await Promise.all(
|
||||
values.fileList.map(async (f) => await toBase64(f.originFileObj))
|
||||
)),
|
||||
attachments: [
|
||||
...(values.fileList
|
||||
? await Promise.all(
|
||||
values.fileList.map(async (f) => {
|
||||
return {
|
||||
filename: f.name,
|
||||
path: await toBase64(f.originFileObj),
|
||||
};
|
||||
})
|
||||
)
|
||||
: []),
|
||||
...(pdfCopytoAttach.pdf
|
||||
? [
|
||||
{
|
||||
path: pdfCopytoAttach.pdf,
|
||||
filename:
|
||||
pdfCopytoAttach.filename &&
|
||||
`${pdfCopytoAttach.filename}.pdf`,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
media: selectedMedia.filter((m) => m.isSelected).map((m) => m.src),
|
||||
//attachments,
|
||||
});
|
||||
@@ -99,13 +120,22 @@ export function EmailOverlayContainer({
|
||||
const render = async () => {
|
||||
logImEXEvent("email_render_template", { template: emailConfig.template });
|
||||
setLoading(true);
|
||||
let html = await RenderTemplate(emailConfig.template, bodyshop, true);
|
||||
let { html, pdf, filename } = await RenderTemplate(
|
||||
emailConfig.template,
|
||||
bodyshop,
|
||||
true
|
||||
);
|
||||
|
||||
const response = await axios.post("/render/inlinecss", {
|
||||
html: html,
|
||||
url: `${window.location.protocol}://${window.location.host}/`,
|
||||
});
|
||||
setRawHtml(response.data);
|
||||
|
||||
if (pdf) {
|
||||
setPdfCopytoAttach({ pdf, filename });
|
||||
}
|
||||
|
||||
form.setFieldsValue({
|
||||
...emailConfig.messageOptions,
|
||||
cc:
|
||||
@@ -166,8 +196,8 @@ const toBase64 = (file) =>
|
||||
reader.onerror = (error) => reject(error);
|
||||
});
|
||||
|
||||
const asyncForEach = async (array, callback) => {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
};
|
||||
// const asyncForEach = async (array, callback) => {
|
||||
// for (let index = 0; index < array.length; index++) {
|
||||
// await callback(array[index], index, array);
|
||||
// }
|
||||
// };
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function GlobalSearch() {
|
||||
<span>{`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${
|
||||
job.v_model_desc || ""
|
||||
}`}</span>
|
||||
<span>{`${job.clm_no}`}</span>
|
||||
<span>{`${job.clm_no || ""}`}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
@@ -91,8 +91,8 @@ export default function GlobalSearch() {
|
||||
vehicle.v_make_desc || ""
|
||||
} ${vehicle.v_model_desc || ""}`}
|
||||
</span>
|
||||
<span>{vehicle.plate_no}</span>
|
||||
<span> {vehicle.v_vin}</span>
|
||||
<span>{vehicle.plate_no || ""}</span>
|
||||
<span> {vehicle.v_vin || ""}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
@@ -108,10 +108,11 @@ export default function GlobalSearch() {
|
||||
label: (
|
||||
<Link to={`/manage/jobs/${payment.job.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<span>{payment.paymentnum}</span>
|
||||
<span>{payment.job.ro_number}</span>
|
||||
<span>{payment.job.memo}</span>
|
||||
<span>{payment.job.amount}</span>
|
||||
<span>{payment.job.transactionid}</span>
|
||||
<span>{payment.memo || ""}</span>
|
||||
<span>{payment.amount || ""}</span>
|
||||
<span>{payment.transactionid || ""}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
|
||||
@@ -161,7 +161,7 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("printcenter.jobs.3rdpartyfields.ponumber")}
|
||||
label={t("printcenter.jobs.3rdpartyfields.refnumber")}
|
||||
name="ponumber"
|
||||
>
|
||||
<Input />
|
||||
|
||||
@@ -295,18 +295,18 @@ export function JobLinesComponent({
|
||||
onClick={async () => {
|
||||
await deleteJobLine({
|
||||
variables: { joblineId: record.id },
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
id: cache.identify(job),
|
||||
fields: {
|
||||
joblines(existingJobLines, { readField }) {
|
||||
return existingJobLines.filter(
|
||||
(jlRef) => record.id !== readField("id", jlRef)
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
// update(cache) {
|
||||
// cache.modify({
|
||||
// id: cache.identify(job),
|
||||
// fields: {
|
||||
// joblines(existingJobLines, { readField }) {
|
||||
// return existingJobLines.filter(
|
||||
// (jlRef) => record.id !== readField("id", jlRef)
|
||||
// );
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// },
|
||||
});
|
||||
await axios.post("/job/totalsssu", {
|
||||
id: job.id,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Card, Space, Table } from "antd";
|
||||
import { EditFilled } from "@ant-design/icons";
|
||||
import Dinero from "dinero.js";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -115,16 +116,29 @@ export function JobPayments({
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: TemplateList("payment").payment_receipt.key,
|
||||
variables: { id: record.id },
|
||||
}}
|
||||
messageObject={{
|
||||
to: job.ownr_ea,
|
||||
}}
|
||||
id={job.id}
|
||||
/>
|
||||
<Space wrap>
|
||||
<Button
|
||||
disabled={record.exportedat}
|
||||
onClick={() => {
|
||||
setPaymentContext({
|
||||
actions: { refetch: refetch },
|
||||
context: record,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<EditFilled />
|
||||
</Button>
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: TemplateList("payment").payment_receipt.key,
|
||||
variables: { id: record.id },
|
||||
}}
|
||||
messageObject={{
|
||||
to: job.ownr_ea,
|
||||
}}
|
||||
id={job.id}
|
||||
/>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Checkbox, PageHeader, Table } from "antd";
|
||||
import { Checkbox, Table, Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
@@ -21,6 +21,7 @@ export default function JobReconciliationBillsTable({
|
||||
title: t("billlines.fields.line_desc"),
|
||||
dataIndex: "line_desc",
|
||||
key: "line_desc",
|
||||
width: "35%",
|
||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||
@@ -29,6 +30,8 @@ export default function JobReconciliationBillsTable({
|
||||
title: t("billlines.labels.from"),
|
||||
dataIndex: "from",
|
||||
key: "from",
|
||||
width: "20%",
|
||||
ellipsis: true,
|
||||
render: (text, record) =>
|
||||
`${record.bill.vendor && record.bill.vendor.name} / ${
|
||||
record.bill.invoice_number
|
||||
@@ -57,7 +60,7 @@ export default function JobReconciliationBillsTable({
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("billlines.fields.quantity"),
|
||||
title: t("joblines.fields.part_qty"),
|
||||
dataIndex: "quantity",
|
||||
key: "quantity",
|
||||
sorter: (a, b) => a.quantity - b.quantity,
|
||||
@@ -86,10 +89,12 @@ export default function JobReconciliationBillsTable({
|
||||
};
|
||||
|
||||
return (
|
||||
<PageHeader title={t("bills.labels.bills")}>
|
||||
<div>
|
||||
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
||||
<Table
|
||||
pagination={false}
|
||||
scroll={{ y: "40vh", x: true }}
|
||||
size="small"
|
||||
scroll={{ y: "80vh", x: true }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={invoiceLineData}
|
||||
@@ -99,6 +104,6 @@ export default function JobReconciliationBillsTable({
|
||||
selectedRowKeys: selectedLines,
|
||||
}}
|
||||
/>
|
||||
</PageHeader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,21 +22,23 @@ export default function JobReconciliationModalComponent({ job, bills }) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<JobReconciliationPartsTable
|
||||
jobLineData={jobLineData}
|
||||
jobLineState={jobLineState}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<JobReconciliationBillsTable
|
||||
invoiceLineData={invoiceLineData}
|
||||
billLineState={billLineState}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Row gutter={8}>
|
||||
<Col span={12}>
|
||||
<JobReconciliationPartsTable
|
||||
jobLineData={jobLineData}
|
||||
jobLineState={jobLineState}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<JobReconciliationBillsTable
|
||||
invoiceLineData={invoiceLineData}
|
||||
billLineState={billLineState}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row>
|
||||
<JobReconciliationTotals
|
||||
jobLines={jobLineData}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
.imex-reconciliation-modal {
|
||||
top: 20px;
|
||||
.ant-modal-content {
|
||||
height: 95vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.ant-modal-body {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { selectReconciliation } from "../../redux/modals/modals.selectors";
|
||||
import JobReconciliationModalComponent from "./job-reconciliation-modal.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import "./job-reconciliation-modal.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reconciliationModal: selectReconciliation,
|
||||
@@ -38,23 +39,23 @@ function JobReconciliationModalContainer({
|
||||
return (
|
||||
<Modal
|
||||
title={t("jobs.labels.reconciliationheader")}
|
||||
width={"90%"}
|
||||
width={"95%"}
|
||||
visible={visible}
|
||||
okText={t("general.actions.close")}
|
||||
onOk={handleCancel}
|
||||
onCancel={handleCancel}
|
||||
cancelButtonProps={{ display: "none" }}
|
||||
destroyOnClose
|
||||
className="imex-reconciliation-modal"
|
||||
>
|
||||
<LoadingSpinner loading={loading}>
|
||||
{error && <AlertComponent message={error.message} type="error" />}
|
||||
{data && (
|
||||
<JobReconciliationModalComponent
|
||||
job={data && data.jobs_by_pk}
|
||||
bills={data && data.bills}
|
||||
/>
|
||||
)}
|
||||
</LoadingSpinner>
|
||||
{loading && <LoadingSpinner loading={loading} />}
|
||||
{error && <AlertComponent message={error.message} type="error" />}
|
||||
{data && (
|
||||
<JobReconciliationModalComponent
|
||||
job={data && data.jobs_by_pk}
|
||||
bills={data && data.bills}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageHeader, Table } from "antd";
|
||||
import { Table, Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
@@ -102,11 +102,13 @@ export default function JobReconcilitionPartsTable({
|
||||
};
|
||||
|
||||
return (
|
||||
<PageHeader title={t("jobs.labels.lines")}>
|
||||
<div>
|
||||
<Typography.Title level={4}>{t("jobs.labels.lines")}</Typography.Title>
|
||||
<Table
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
scroll={{ y: "40vh", x: true }}
|
||||
size="small"
|
||||
scroll={{ y: "80vh", x: true }}
|
||||
rowKey="id"
|
||||
dataSource={jobLineData}
|
||||
onChange={handleTableChange}
|
||||
@@ -122,6 +124,6 @@ export default function JobReconcilitionPartsTable({
|
||||
<div style={{ fontStyle: "italic", margin: "4px" }}>
|
||||
{t("jobs.labels.reconciliation.removedpartsstrikethrough")}
|
||||
</div>
|
||||
</PageHeader>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import { useLazyQuery } from "@apollo/client";
|
||||
import { Empty, Select } from "antd";
|
||||
import { Empty, Select, Space, Tag } from "antd";
|
||||
import _ from "lodash";
|
||||
import React, { forwardRef, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -80,13 +80,20 @@ const JobSearchSelect = (
|
||||
{theOptions
|
||||
? theOptions.map((o) => (
|
||||
<Option key={o.id} value={o.id} status={o.status}>
|
||||
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
|
||||
o.ro_number || t("general.labels.na")
|
||||
} | ${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
||||
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
|
||||
o.v_model_desc || ""
|
||||
}`}
|
||||
<Space align="center">
|
||||
<span>
|
||||
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
|
||||
o.ro_number || t("general.labels.na")
|
||||
} | ${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
||||
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
|
||||
o.v_model_desc || ""
|
||||
}`}
|
||||
</span>
|
||||
<Tag>
|
||||
<strong>{o.status}</strong>
|
||||
</Tag>
|
||||
</Space>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { DownCircleFilled } from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Dropdown, Menu, notification } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus);
|
||||
|
||||
export function JobsAdminStatus({ bodyshop, job }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS);
|
||||
const updateJobStatus = (status) => {
|
||||
mutationUpdateJobstatus({
|
||||
variables: { jobId: job.id, status: status },
|
||||
})
|
||||
.then((r) => {
|
||||
notification["success"]({ message: t("jobs.successes.save") });
|
||||
// refetch();
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({ message: t("jobs.errors.saving") });
|
||||
});
|
||||
};
|
||||
|
||||
const statusmenu = (
|
||||
<Menu
|
||||
onClick={(e) => {
|
||||
updateJobStatus(e.key);
|
||||
}}
|
||||
>
|
||||
{bodyshop.md_ro_statuses.statuses.map((item) => (
|
||||
<Menu.Item key={item}>{item}</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus">
|
||||
<Button shape="round">
|
||||
<span>{job.status}</span>
|
||||
|
||||
<DownCircleFilled />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
|
||||
query: GET_ALL_JOBLINES_BY_PK,
|
||||
variables: { id: jobId },
|
||||
});
|
||||
|
||||
const existingLines = _.cloneDeep(existingLinesFromDb);
|
||||
const linesToInsert = [];
|
||||
const linesToUpdate = [];
|
||||
@@ -19,11 +20,14 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
|
||||
const matchingIndex = existingLines.findIndex(
|
||||
(eL) => eL.unq_seq === newLine.unq_seq
|
||||
);
|
||||
|
||||
//Should do a check to make sure there is only 1 matching unq sequence number.
|
||||
|
||||
if (matchingIndex >= 0) {
|
||||
//Found a relevant matching line. Add it to lines to update.
|
||||
linesToUpdate.push({
|
||||
id: existingLines[matchingIndex].id,
|
||||
newData: newLine,
|
||||
newData: { ...newLine, removed: false },
|
||||
});
|
||||
|
||||
//Splice out item we found for performance.
|
||||
|
||||
@@ -11,7 +11,8 @@ import FormItemPhone, {
|
||||
PhoneItemFormatterValidation,
|
||||
} from "../form-items-formatted/phone-form-item.component";
|
||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
||||
import { JobsDetailRatesParts } from "../jobs-detail-rates/jobs-detail-rates.parts.component";
|
||||
import JobsDetailRatesParts from "../jobs-detail-rates/jobs-detail-rates.parts.component";
|
||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -187,7 +188,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
||||
header={t("menus.jobsdetail.financials")}
|
||||
>
|
||||
<JobsDetailRatesChangeButton form={form} />
|
||||
|
||||
<JobsMarkPstExempt form={form} />
|
||||
<LayoutFormRow>
|
||||
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
||||
<CurrencyInput />
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { Form, Input, InputNumber, Select, Space, Switch, Tooltip } from "antd";
|
||||
import {
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Tooltip,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -7,6 +16,7 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
|
||||
import CABCpvrtCalculator from "../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
import JobsDetailRatesParts from "./jobs-detail-rates.parts.component";
|
||||
|
||||
@@ -103,8 +113,19 @@ export function JobsDetailRates({ jobRO, form, job }) {
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO} />
|
||||
<FormRow header={t("jobs.forms.laborrates")}>
|
||||
<Divider
|
||||
orientation="left"
|
||||
type="horizontal"
|
||||
style={{ marginTop: ".8rem", float: "right" }}
|
||||
>
|
||||
{t("jobs.forms.laborrates")}
|
||||
</Divider>
|
||||
<Space>
|
||||
<div></div>
|
||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO} />
|
||||
<JobsMarkPstExempt form={form} />
|
||||
</Space>
|
||||
<FormRow noDivider>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.labor_rate_desc")}
|
||||
name="labor_rate_desc"
|
||||
@@ -180,7 +201,6 @@ export function JobsDetailRates({ jobRO, form, job }) {
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
|
||||
<JobsDetailRatesParts form={form} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -19,7 +19,11 @@ export function JobsDetailRatesParts({
|
||||
|
||||
return (
|
||||
<Collapse defaultActiveKey={expanded && "rates"}>
|
||||
<Collapse.Panel header={t("jobs.labels.parts_tax_rates")} key="rates">
|
||||
<Collapse.Panel
|
||||
forceRender
|
||||
header={t("jobs.labels.parts_tax_rates")}
|
||||
key="rates"
|
||||
>
|
||||
<LayoutFormRow header={t("joblines.fields.part_types.PAA")}>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.parts_tax_rates.prt_discp")}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Popconfirm, Button } from "antd";
|
||||
import React from "react";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import _ from "lodash";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
});
|
||||
|
||||
export function JobsMarkPstExempt({ jobRO, form }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleConfirm = () => {
|
||||
const newPartRates = _.cloneDeep(form.getFieldValue("parts_tax_rates"));
|
||||
|
||||
Object.keys(newPartRates).forEach((key) => {
|
||||
newPartRates[key] = {
|
||||
...newPartRates[key],
|
||||
prt_tax_in: false,
|
||||
prt_tax_rt: 0,
|
||||
};
|
||||
});
|
||||
|
||||
form.setFieldsValue({
|
||||
state_tax_rate: 0,
|
||||
tax_lbr_rt: 0,
|
||||
tax_levies_rt: 0,
|
||||
tax_sub_rt: 0,
|
||||
tax_shop_mat_rt: 0,
|
||||
tax_paint_mat_rt: 0,
|
||||
tax_str_rt: 0,
|
||||
tax_tow_rt: 0,
|
||||
parts_tax_rates: newPartRates,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Popconfirm
|
||||
onConfirm={handleConfirm}
|
||||
disabled={jobRO}
|
||||
okText={t("general.labels.yes")}
|
||||
cancelText={t("general.labels.no")}
|
||||
title={t("jobs.actions.markpstexemptconfirm")}
|
||||
>
|
||||
<Button type="link" disabled={jobRO}>
|
||||
{t("jobs.actions.markpstexempt")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, null)(JobsMarkPstExempt);
|
||||
@@ -31,11 +31,14 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicleid",
|
||||
key: "vehicleid",
|
||||
render: (text, record) => (
|
||||
<Link to={`/manage/vehicles/${record.vehicleid}`}>
|
||||
{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc}`}
|
||||
</Link>
|
||||
),
|
||||
render: (text, record) =>
|
||||
record.vehicleid ? (
|
||||
<Link to={`/manage/vehicles/${record.vehicleid}`}>
|
||||
{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc}`}
|
||||
</Link>
|
||||
) : (
|
||||
t("jobs.errors.novehicle")
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.clm_no"),
|
||||
|
||||
@@ -90,7 +90,11 @@ export function PartsOrderListTableComponent({
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
disabled={jobRO || record.return}
|
||||
disabled={
|
||||
jobRO ||
|
||||
record.return ||
|
||||
record.vendor.id === bodyshop.inhousevendorid
|
||||
}
|
||||
onClick={() => {
|
||||
logImEXEvent("parts_order_receive_bill");
|
||||
setPartsReceiveContext({
|
||||
@@ -139,7 +143,10 @@ export function PartsOrderListTableComponent({
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button
|
||||
disabled={jobRO ? !record.return : jobRO}
|
||||
disabled={
|
||||
(jobRO ? !record.return : jobRO) ||
|
||||
record.vendor.id === bodyshop.inhousevendorid
|
||||
}
|
||||
onClick={() => {
|
||||
logImEXEvent("parts_order_receive_bill");
|
||||
|
||||
@@ -157,7 +164,7 @@ export function PartsOrderListTableComponent({
|
||||
quantity: pol.quantity,
|
||||
|
||||
actual_price: pol.act_price,
|
||||
cost_center: pol.jobline.part_type
|
||||
cost_center: pol.jobline?.part_type
|
||||
? responsibilityCenters.defaults.costs[
|
||||
pol.jobline.part_type
|
||||
] || null
|
||||
|
||||
@@ -101,7 +101,9 @@ export function PartsOrderModalContainer({
|
||||
|
||||
const jobLinesResult = await updateJobLines({
|
||||
variables: {
|
||||
ids: values.parts_order_lines.data.map((item) => item.job_line_id),
|
||||
ids: values.parts_order_lines.data
|
||||
.filter((item) => item.job_line_id)
|
||||
.map((item) => item.job_line_id),
|
||||
status: isReturn
|
||||
? bodyshop.md_order_statuses.default_returned || "Returned*"
|
||||
: bodyshop.md_order_statuses.default_ordered || "Ordered*",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useLazyQuery } from "@apollo/client";
|
||||
import { Button, DatePicker, Form, Radio } from "antd";
|
||||
import { Button, DatePicker, Form, Radio, Space } from "antd";
|
||||
import moment from "moment";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -13,6 +13,7 @@ import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||
import "./report-center-modal.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reportCenterModal: selectReportCenter,
|
||||
@@ -86,6 +87,7 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
|
||||
<Form.Item
|
||||
name="key"
|
||||
label={t("reportcenter.labels.key")}
|
||||
// className="radio-group-columns"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
@@ -93,12 +95,21 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Radio.Group style={{ columns: "3 auto" }}>
|
||||
{Object.keys(Templates).map((key) => (
|
||||
<Radio key={key} value={key}>
|
||||
{Templates[key].title}
|
||||
</Radio>
|
||||
))}
|
||||
<Radio.Group>
|
||||
<Space
|
||||
direction="vertical"
|
||||
wrap
|
||||
size="small"
|
||||
style={{
|
||||
maxHeight: "50vh",
|
||||
}}
|
||||
>
|
||||
{Object.keys(Templates).map((key) => (
|
||||
<Radio key={key} value={key}>
|
||||
{Templates[key].title}
|
||||
</Radio>
|
||||
))}
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item dependencies={["key"]}>
|
||||
|
||||
@@ -31,7 +31,7 @@ export function ReportCenterModalContainer({
|
||||
onCancel={() => toggleModalVisible()}
|
||||
cancelButtonProps={{ style: { display: "none" } }}
|
||||
destroyOnClose
|
||||
width="60%"
|
||||
width="80%"
|
||||
>
|
||||
<ReportCenterModalComponent />
|
||||
</Modal>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.radio-group-columns {
|
||||
.ant-radio-group {
|
||||
// display: block;
|
||||
}
|
||||
.ant-radio-wrapper {
|
||||
display: block;
|
||||
span {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,6 +436,14 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<CurrencyInput />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={["attach_pdf_to_email"]}
|
||||
label={t("bodyshop.fields.attach_pdf_to_email")}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
||||
<Form.List name={["md_messaging_presets"]}>
|
||||
|
||||
@@ -91,6 +91,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
md_jobline_presets
|
||||
cdk_dealerid
|
||||
features
|
||||
attach_pdf_to_email
|
||||
employees {
|
||||
id
|
||||
active
|
||||
@@ -178,6 +179,7 @@ export const UPDATE_SHOP = gql`
|
||||
jc_hourly_rates
|
||||
md_jobline_presets
|
||||
cdk_dealerid
|
||||
attach_pdf_to_email
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -23,19 +23,6 @@ export const GET_ALL_JOBLINES_BY_PK = gql`
|
||||
notes
|
||||
location
|
||||
tax_part
|
||||
parts_order_lines {
|
||||
id
|
||||
parts_order {
|
||||
id
|
||||
order_number
|
||||
order_date
|
||||
user_email
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -228,7 +215,11 @@ export const generateJobLinesUpdatesForInvoicing = (joblines) => {
|
||||
|
||||
export const DELETE_JOB_LINE_BY_PK = gql`
|
||||
mutation DELETE_JOB_LINE_BY_PK($joblineId: uuid!) {
|
||||
delete_joblines_by_pk(id: $joblineId) {
|
||||
update_joblines_by_pk(
|
||||
pk_columns: { id: $joblineId }
|
||||
_set: { removed: true }
|
||||
) {
|
||||
removed
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,6 +559,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
}
|
||||
payments {
|
||||
id
|
||||
jobid
|
||||
amount
|
||||
payer
|
||||
created_at
|
||||
@@ -566,6 +567,8 @@ export const GET_JOB_BY_PK = gql`
|
||||
transactionid
|
||||
memo
|
||||
date
|
||||
type
|
||||
exportedat
|
||||
}
|
||||
cccontracts {
|
||||
id
|
||||
@@ -686,6 +689,8 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
v_make_desc
|
||||
v_model_desc
|
||||
v_color
|
||||
v_vin
|
||||
plate_st
|
||||
plate_no
|
||||
vehicle {
|
||||
id
|
||||
@@ -1040,6 +1045,7 @@ export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql`
|
||||
v_make_desc
|
||||
v_model_desc
|
||||
v_model_yr
|
||||
status
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -36,6 +36,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
search_payments(args: { search: $search }) {
|
||||
id
|
||||
amount
|
||||
paymentnum
|
||||
job {
|
||||
ro_number
|
||||
id
|
||||
|
||||
@@ -81,48 +81,52 @@ export default class Home extends React.Component {
|
||||
dataSource={Banner00DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
// <Content4
|
||||
// id="Content4_0"
|
||||
// key="Content4_0"
|
||||
// dataSource={Content40DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
<Content1
|
||||
id="Content1_0"
|
||||
key="Content1_0"
|
||||
dataSource={Content10DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
<Content0
|
||||
id="Content0_0"
|
||||
key="Content0_0"
|
||||
dataSource={Content00DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
<Pricing2
|
||||
id="Pricing2_0"
|
||||
key="Pricing2_0"
|
||||
dataSource={Pricing20DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
// <Pricing1
|
||||
// id="Pricing1_1"
|
||||
// key="Pricing1_1"
|
||||
// dataSource={Pricing11DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
// <Content3
|
||||
// id="Content3_0"
|
||||
// key="Content3_0"
|
||||
// dataSource={Content30DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
// <Content12
|
||||
// id="Content12_0"
|
||||
// key="Content12_0"
|
||||
// dataSource={Content120DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
...(process.env.NODE_ENV !== "production"
|
||||
? [
|
||||
// <Content4
|
||||
// id="Content4_0"
|
||||
// key="Content4_0"
|
||||
// dataSource={Content40DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
<Content1
|
||||
id="Content1_0"
|
||||
key="Content1_0"
|
||||
dataSource={Content10DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
<Content0
|
||||
id="Content0_0"
|
||||
key="Content0_0"
|
||||
dataSource={Content00DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
<Pricing2
|
||||
id="Pricing2_0"
|
||||
key="Pricing2_0"
|
||||
dataSource={Pricing20DataSource}
|
||||
isMobile={this.state.isMobile}
|
||||
/>,
|
||||
// <Pricing1
|
||||
// id="Pricing1_1"
|
||||
// key="Pricing1_1"
|
||||
// dataSource={Pricing11DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
// <Content3
|
||||
// id="Content3_0"
|
||||
// key="Content3_0"
|
||||
// dataSource={Content30DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
// <Content12
|
||||
// id="Content12_0"
|
||||
// key="Content12_0"
|
||||
// dataSource={Content120DataSource}
|
||||
// isMobile={this.state.isMobile}
|
||||
// />,
|
||||
]
|
||||
: []),
|
||||
<Footer1
|
||||
id="Footer1_0"
|
||||
key="Footer1_0"
|
||||
|
||||
@@ -12,7 +12,6 @@ import AlertComponent from "../../components/alert/alert.component";
|
||||
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -79,12 +78,10 @@ export function ExportLogsPageComponent({ bodyshop }) {
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
sortOrder: sortcolumn === "ro_number" && sortorder,
|
||||
|
||||
render: (text, record) =>
|
||||
record.job && (
|
||||
<Link to={"/manage/jobs/" + record.job && record.job.id}>
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
{(record.job && record.job.ro_number) || t("general.labels.na")}
|
||||
</Link>
|
||||
),
|
||||
|
||||
@@ -15,6 +15,8 @@ import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassoci
|
||||
import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component";
|
||||
import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
|
||||
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
@@ -96,6 +98,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
<JobsAdminDeleteIntake job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminStatus job={data ? data.jobs_by_pk : {}} />
|
||||
</Space>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
@@ -42,9 +42,26 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
||||
setLoading(true);
|
||||
const result = await client.mutate({
|
||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
|
||||
});
|
||||
if (result.errors) {
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: new Date(),
|
||||
actual_in: values.actual_in,
|
||||
actual_completion: values.actual_completion,
|
||||
actual_delivery: values.actual_delivery,
|
||||
},
|
||||
},
|
||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||
awaitRefetchQueries: true,
|
||||
});
|
||||
|
||||
if (!result.errors) {
|
||||
notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
@@ -56,18 +73,6 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
||||
});
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: new Date(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
@@ -84,6 +89,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
||||
}),
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
"label": "Label"
|
||||
},
|
||||
"appt_length": "Default Appointment Length",
|
||||
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
||||
"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 %",
|
||||
@@ -742,6 +743,7 @@
|
||||
"attachments": "Attachments",
|
||||
"documents": "Documents",
|
||||
"generatingemail": "Generating email...",
|
||||
"pdfcopywillbeattached": "A PDF copy of this email will be attached when it is sent.",
|
||||
"preview": "Email Preview"
|
||||
},
|
||||
"successes": {
|
||||
@@ -1034,6 +1036,8 @@
|
||||
"intake": "Intake",
|
||||
"manualnew": "Create New Job Manually",
|
||||
"mark": "Mark",
|
||||
"markpstexempt": "Mark Job PST Exempt",
|
||||
"markpstexemptconfirm": "Are you sure you want to do this? To undo this, you must manually update all PST rates.",
|
||||
"postbills": "Post Bills",
|
||||
"printCenter": "Print Center",
|
||||
"recalculate": "Recalculate",
|
||||
@@ -1441,11 +1445,11 @@
|
||||
"name": "ImEX Online",
|
||||
"status": "System Status"
|
||||
},
|
||||
"slogan": "The future of shop management systems. "
|
||||
"slogan": "A whole new kind of shop management system."
|
||||
},
|
||||
"hero": {
|
||||
"button": "Learn More",
|
||||
"title": "Bringing the future to the collision repair process."
|
||||
"button": "Coming Soon",
|
||||
"title": "A whole new kind of shop management system."
|
||||
},
|
||||
"labels": {
|
||||
"features": "Features",
|
||||
@@ -1805,6 +1809,7 @@
|
||||
"depreciation": "Depreciation",
|
||||
"other": "Other",
|
||||
"ponumber": "PO Number",
|
||||
"refnumber": "Reference Number",
|
||||
"sendtype": "Send by",
|
||||
"state": "Province/State",
|
||||
"zip": "Postal Code/Zip"
|
||||
@@ -1830,6 +1835,8 @@
|
||||
"invoice_total_payable": "Invoice (Total Payable)",
|
||||
"job_costing_ro": "Job Costing",
|
||||
"job_notes": "Job Notes",
|
||||
"key_tag": "Key Tag",
|
||||
"paint_grid": "Paint Grid",
|
||||
"parts_label_single": "Parts Label - Single",
|
||||
"parts_list": "Parts List",
|
||||
"parts_order": "Parts Order Confirmation",
|
||||
@@ -1844,6 +1851,7 @@
|
||||
"qc_sheet": "Quality Control Sheet",
|
||||
"ro_totals": "RO Totals",
|
||||
"ro_with_description": "RO Summary with Descriptions",
|
||||
"stolen_recovery_checklist": "Stolen Recovery Checklist",
|
||||
"supplement_request": "Supplement Request",
|
||||
"thank_you_ro": "Thank You Letter",
|
||||
"thirdpartypayer": "Third Party Payer",
|
||||
@@ -1960,27 +1968,34 @@
|
||||
"export_payables": "Export Log - Payables",
|
||||
"export_payments": "Export Log - Payments",
|
||||
"export_receivables": "Export Log - Receivables",
|
||||
"gsr_by_csr": "Gross Sales by CSR",
|
||||
"gsr_by_delivery_date": "Gross Sales by Delivery Date",
|
||||
"gsr_by_estimator": "Gross Sales by Estimator",
|
||||
"gsr_by_exported_date": "Gross Sales by Export Date",
|
||||
"gsr_by_ins_co": "Gross Sales by Insurance Company'",
|
||||
"gsr_by_ins_co": "Gross Sales by Insurance Company",
|
||||
"gsr_by_make": "Gross Sales by Vehicle Make",
|
||||
"gsr_by_referral": "Gross Sales by Referral Source",
|
||||
"gsr_by_ro": "Gross Sales by RO",
|
||||
"gsr_labor_only": "Gross Sales - Labor Only",
|
||||
"hours_sold_detail_closed": "Hours Sold Detail - Closed",
|
||||
"hours_sold_detail_closed_csr": "Hours Sold Detail - Closed by CSR",
|
||||
"hours_sold_detail_closed_ins_co": "Hours Sold Detail - Closed by Source",
|
||||
"hours_sold_detail_open": "Hours Sold Detail - Open",
|
||||
"hours_sold_detail_open_csr": "Hours Sold Detail - Open by CSR",
|
||||
"hours_sold_detail_open_ins_co": "Hours Sold Detail - Open by Source",
|
||||
"hours_sold_summary_closed": "Hours Sold Summary - Closed",
|
||||
"hours_sold_summary_closed_csr": "Hours Sold Summary - Closed by CSR",
|
||||
"hours_sold_summary_closed_ins_co": "Hours Sold Summary - Closed by Source",
|
||||
"hours_sold_summary_open": "Hours Sold Summary - Open",
|
||||
"hours_sold_summary_open_csr": "Hours Sold Summary - Open CSR",
|
||||
"hours_sold_summary_open_ins_co": "Hours Sold Summary - Open by Source",
|
||||
"job_costing_ro_csr": "Job Costing by CSR",
|
||||
"job_costing_ro_date_detail": "Job Costing by RO - Detail",
|
||||
"job_costing_ro_date_summary": "Job Costing by RO - Summary",
|
||||
"job_costing_ro_estimator": "Job Costing by Estimator",
|
||||
"job_costing_ro_ins_co": "Job Costing by RO Source",
|
||||
"open_orders": "Open Orders by Date",
|
||||
"open_orders_csr": "Open Orders by CSR",
|
||||
"open_orders_estimator": "Open Orders by Estimator",
|
||||
"open_orders_ins_co": "Open Orders by Insurance Company",
|
||||
"parts_backorder": "Backordered Parts",
|
||||
@@ -2282,7 +2297,7 @@
|
||||
"city": "City",
|
||||
"cost_center": "Cost Center",
|
||||
"country": "Country",
|
||||
"discount": "Discount %",
|
||||
"discount": "Discount % (as decimal)",
|
||||
"display_name": "Display Name",
|
||||
"due_date": "Payment Due Date",
|
||||
"email": "Contact Email",
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
"label": ""
|
||||
},
|
||||
"appt_length": "",
|
||||
"attach_pdf_to_email": "",
|
||||
"bill_federal_tax_rate": "",
|
||||
"bill_local_tax_rate": "",
|
||||
"bill_state_tax_rate": "",
|
||||
@@ -742,6 +743,7 @@
|
||||
"attachments": "",
|
||||
"documents": "",
|
||||
"generatingemail": "",
|
||||
"pdfcopywillbeattached": "",
|
||||
"preview": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -1034,6 +1036,8 @@
|
||||
"intake": "",
|
||||
"manualnew": "",
|
||||
"mark": "",
|
||||
"markpstexempt": "",
|
||||
"markpstexemptconfirm": "",
|
||||
"postbills": "Contabilizar facturas",
|
||||
"printCenter": "Centro de impresión",
|
||||
"recalculate": "",
|
||||
@@ -1805,6 +1809,7 @@
|
||||
"depreciation": "",
|
||||
"other": "",
|
||||
"ponumber": "",
|
||||
"refnumber": "",
|
||||
"sendtype": "",
|
||||
"state": "",
|
||||
"zip": ""
|
||||
@@ -1830,6 +1835,8 @@
|
||||
"invoice_total_payable": "",
|
||||
"job_costing_ro": "",
|
||||
"job_notes": "",
|
||||
"key_tag": "",
|
||||
"paint_grid": "",
|
||||
"parts_label_single": "",
|
||||
"parts_list": "",
|
||||
"parts_order": "",
|
||||
@@ -1844,6 +1851,7 @@
|
||||
"qc_sheet": "",
|
||||
"ro_totals": "",
|
||||
"ro_with_description": "",
|
||||
"stolen_recovery_checklist": "",
|
||||
"supplement_request": "",
|
||||
"thank_you_ro": "",
|
||||
"thirdpartypayer": "",
|
||||
@@ -1960,6 +1968,7 @@
|
||||
"export_payables": "",
|
||||
"export_payments": "",
|
||||
"export_receivables": "",
|
||||
"gsr_by_csr": "",
|
||||
"gsr_by_delivery_date": "",
|
||||
"gsr_by_estimator": "",
|
||||
"gsr_by_exported_date": "",
|
||||
@@ -1969,18 +1978,24 @@
|
||||
"gsr_by_ro": "",
|
||||
"gsr_labor_only": "",
|
||||
"hours_sold_detail_closed": "",
|
||||
"hours_sold_detail_closed_csr": "",
|
||||
"hours_sold_detail_closed_ins_co": "",
|
||||
"hours_sold_detail_open": "",
|
||||
"hours_sold_detail_open_csr": "",
|
||||
"hours_sold_detail_open_ins_co": "",
|
||||
"hours_sold_summary_closed": "",
|
||||
"hours_sold_summary_closed_csr": "",
|
||||
"hours_sold_summary_closed_ins_co": "",
|
||||
"hours_sold_summary_open": "",
|
||||
"hours_sold_summary_open_csr": "",
|
||||
"hours_sold_summary_open_ins_co": "",
|
||||
"job_costing_ro_csr": "",
|
||||
"job_costing_ro_date_detail": "",
|
||||
"job_costing_ro_date_summary": "",
|
||||
"job_costing_ro_estimator": "",
|
||||
"job_costing_ro_ins_co": "",
|
||||
"open_orders": "",
|
||||
"open_orders_csr": "",
|
||||
"open_orders_estimator": "",
|
||||
"open_orders_ins_co": "",
|
||||
"parts_backorder": "",
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
"label": ""
|
||||
},
|
||||
"appt_length": "",
|
||||
"attach_pdf_to_email": "",
|
||||
"bill_federal_tax_rate": "",
|
||||
"bill_local_tax_rate": "",
|
||||
"bill_state_tax_rate": "",
|
||||
@@ -742,6 +743,7 @@
|
||||
"attachments": "",
|
||||
"documents": "",
|
||||
"generatingemail": "",
|
||||
"pdfcopywillbeattached": "",
|
||||
"preview": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -1034,6 +1036,8 @@
|
||||
"intake": "",
|
||||
"manualnew": "",
|
||||
"mark": "",
|
||||
"markpstexempt": "",
|
||||
"markpstexemptconfirm": "",
|
||||
"postbills": "Poster des factures",
|
||||
"printCenter": "Centre d'impression",
|
||||
"recalculate": "",
|
||||
@@ -1805,6 +1809,7 @@
|
||||
"depreciation": "",
|
||||
"other": "",
|
||||
"ponumber": "",
|
||||
"refnumber": "",
|
||||
"sendtype": "",
|
||||
"state": "",
|
||||
"zip": ""
|
||||
@@ -1830,6 +1835,8 @@
|
||||
"invoice_total_payable": "",
|
||||
"job_costing_ro": "",
|
||||
"job_notes": "",
|
||||
"key_tag": "",
|
||||
"paint_grid": "",
|
||||
"parts_label_single": "",
|
||||
"parts_list": "",
|
||||
"parts_order": "",
|
||||
@@ -1844,6 +1851,7 @@
|
||||
"qc_sheet": "",
|
||||
"ro_totals": "",
|
||||
"ro_with_description": "",
|
||||
"stolen_recovery_checklist": "",
|
||||
"supplement_request": "",
|
||||
"thank_you_ro": "",
|
||||
"thirdpartypayer": "",
|
||||
@@ -1960,6 +1968,7 @@
|
||||
"export_payables": "",
|
||||
"export_payments": "",
|
||||
"export_receivables": "",
|
||||
"gsr_by_csr": "",
|
||||
"gsr_by_delivery_date": "",
|
||||
"gsr_by_estimator": "",
|
||||
"gsr_by_exported_date": "",
|
||||
@@ -1969,18 +1978,24 @@
|
||||
"gsr_by_ro": "",
|
||||
"gsr_labor_only": "",
|
||||
"hours_sold_detail_closed": "",
|
||||
"hours_sold_detail_closed_csr": "",
|
||||
"hours_sold_detail_closed_ins_co": "",
|
||||
"hours_sold_detail_open": "",
|
||||
"hours_sold_detail_open_csr": "",
|
||||
"hours_sold_detail_open_ins_co": "",
|
||||
"hours_sold_summary_closed": "",
|
||||
"hours_sold_summary_closed_csr": "",
|
||||
"hours_sold_summary_closed_ins_co": "",
|
||||
"hours_sold_summary_open": "",
|
||||
"hours_sold_summary_open_csr": "",
|
||||
"hours_sold_summary_open_ins_co": "",
|
||||
"job_costing_ro_csr": "",
|
||||
"job_costing_ro_date_detail": "",
|
||||
"job_costing_ro_date_summary": "",
|
||||
"job_costing_ro_estimator": "",
|
||||
"job_costing_ro_ins_co": "",
|
||||
"open_orders": "",
|
||||
"open_orders_csr": "",
|
||||
"open_orders_estimator": "",
|
||||
"open_orders_ins_co": "",
|
||||
"parts_backorder": "",
|
||||
|
||||
@@ -8,6 +8,7 @@ import { setEmailOptions } from "../redux/email/email.actions";
|
||||
import { store } from "../redux/store";
|
||||
import client from "../utils/GraphQLClient";
|
||||
import { TemplateList } from "./TemplateConstants";
|
||||
import _ from "lodash";
|
||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||
jsreport.serverUrl = server;
|
||||
|
||||
@@ -39,8 +40,10 @@ export default async function RenderTemplate(
|
||||
offset: moment().utcOffset(),
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const render = await jsreport.renderAsync(reportRequest);
|
||||
|
||||
if (!renderAsHtml) {
|
||||
render.download(
|
||||
(Templates[templateObject.name] &&
|
||||
@@ -48,8 +51,21 @@ export default async function RenderTemplate(
|
||||
""
|
||||
);
|
||||
} else {
|
||||
let pdf;
|
||||
if (bodyshop.attach_pdf_to_email) {
|
||||
const pdfRequest = _.cloneDeep(reportRequest);
|
||||
pdfRequest.template.recipe = "chrome-pdf";
|
||||
const pdfRender = await jsreport.renderAsync(pdfRequest);
|
||||
pdf = pdfRender.toDataURI();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(render.toString());
|
||||
resolve({
|
||||
pdf,
|
||||
filename:
|
||||
Templates[templateObject.name] &&
|
||||
Templates[templateObject.name].title,
|
||||
html: render.toString(),
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -69,6 +69,14 @@ export const TemplateList = (type, context) => {
|
||||
disabled: false,
|
||||
group: "pre",
|
||||
},
|
||||
stolen_recovery_checklist: {
|
||||
title: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
|
||||
description: "All Jobs Notes",
|
||||
subject: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
|
||||
key: "stolen_recovery_checklist",
|
||||
disabled: false,
|
||||
group: "pre",
|
||||
},
|
||||
vehicle_check_in: {
|
||||
title: i18n.t("printcenter.jobs.vehicle_check_in"),
|
||||
description: "All Jobs Notes",
|
||||
@@ -150,6 +158,22 @@ export const TemplateList = (type, context) => {
|
||||
disabled: false,
|
||||
group: "ro",
|
||||
},
|
||||
key_tag: {
|
||||
title: i18n.t("printcenter.jobs.key_tag"),
|
||||
description: "All Jobs Notes",
|
||||
subject: i18n.t("printcenter.jobs.key_tag"),
|
||||
key: "key_tag",
|
||||
disabled: false,
|
||||
group: "ro",
|
||||
},
|
||||
paint_grid: {
|
||||
title: i18n.t("printcenter.jobs.paint_grid"),
|
||||
description: "All Jobs Notes",
|
||||
subject: i18n.t("printcenter.jobs.paint_grid"),
|
||||
key: "paint_grid",
|
||||
disabled: false,
|
||||
group: "ro",
|
||||
},
|
||||
worksheet_by_line_number: {
|
||||
title: i18n.t("printcenter.jobs.worksheet_by_line_number"),
|
||||
description: "All Jobs Notes",
|
||||
@@ -728,6 +752,67 @@ export const TemplateList = (type, context) => {
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
|
||||
hours_sold_detail_closed_csr: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_closed_csr"
|
||||
),
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_closed_csr"
|
||||
),
|
||||
key: "hours_sold_detail_closed_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_invoiced"),
|
||||
},
|
||||
},
|
||||
hours_sold_detail_open_csr: {
|
||||
title: i18n.t("reportcenter.templates.hours_sold_detail_open_csr"),
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_open_csr"
|
||||
),
|
||||
key: "hours_sold_detail_open_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
hours_sold_summary_closed_csr: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_summary_closed_csr"
|
||||
),
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.hours_sold_summary_closed_csr"
|
||||
),
|
||||
key: "hours_sold_summary_closed_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_invoiced"),
|
||||
},
|
||||
},
|
||||
hours_sold_summary_open_csr: {
|
||||
title: i18n.t("reportcenter.templates.hours_sold_summary_open_csr"),
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.hours_sold_summary_open_csr"
|
||||
),
|
||||
key: "hours_sold_summary_open_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_invoiced"),
|
||||
},
|
||||
},
|
||||
estimator_detail: {
|
||||
title: i18n.t("reportcenter.templates.estimator_detail"),
|
||||
description: "",
|
||||
@@ -790,6 +875,18 @@ export const TemplateList = (type, context) => {
|
||||
field: i18n.t("jobs.fields.date_invoiced"),
|
||||
},
|
||||
},
|
||||
job_costing_ro_csr: {
|
||||
title: i18n.t("reportcenter.templates.job_costing_ro_csr"),
|
||||
description: "",
|
||||
subject: i18n.t("reportcenter.templates.job_costing_ro_csr"),
|
||||
key: "job_costing_ro_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
job_costing_ro_ins_co: {
|
||||
title: i18n.t("reportcenter.templates.job_costing_ro_ins_co"),
|
||||
description: "",
|
||||
@@ -840,6 +937,18 @@ export const TemplateList = (type, context) => {
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
gsr_by_csr: {
|
||||
title: i18n.t("reportcenter.templates.gsr_by_csr"),
|
||||
description: "",
|
||||
subject: i18n.t("reportcenter.templates.gsr_by_csr"),
|
||||
key: "gsr_by_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_invoiced"),
|
||||
},
|
||||
},
|
||||
gsr_by_make: {
|
||||
title: i18n.t("reportcenter.templates.gsr_by_make"),
|
||||
description: "",
|
||||
@@ -949,6 +1058,18 @@ export const TemplateList = (type, context) => {
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
open_orders_csr: {
|
||||
title: i18n.t("reportcenter.templates.open_orders_csr"),
|
||||
description: "",
|
||||
subject: i18n.t("reportcenter.templates.open_orders_csr"),
|
||||
key: "open_orders_csr",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
},
|
||||
open_orders_estimator: {
|
||||
title: i18n.t("reportcenter.templates.open_orders_estimator"),
|
||||
description: "",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
11
hasura/migrations/1625768789569_run_sql_migration/up.yaml
Normal file
11
hasura/migrations/1625768789569_run_sql_migration/up.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE OR REPLACE FUNCTION public.search_payments(search text)\n RETURNS
|
||||
SETOF payments\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search
|
||||
= '' then\n return query select * from payments ;\n else \n return query
|
||||
SELECT\n p.*\nFROM\n payments p, jobs j\nWHERE\np.jobid = j.id AND\n(\nsearch
|
||||
<% p.paymentnum OR\nsearch <% j.ownr_fn OR\nsearch <% j.ownr_ln OR\nsearch <%
|
||||
j.ownr_co_nm OR\nsearch <% j.ro_number OR\n search <% (p.payer) OR\n search
|
||||
<% (p.transactionid) OR\n search <% (p.memo));\n end if;\n\n\tEND\n$function$;"
|
||||
type: run_sql
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: alter table "public"."vehicles" add constraint "vehicles_v_vin_shopid_key"
|
||||
unique ("v_vin", "shopid");
|
||||
type: run_sql
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: alter table "public"."vehicles" drop constraint "vehicles_v_vin_shopid_key";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "attach_pdf_to_email";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "attach_pdf_to_email" boolean
|
||||
NOT NULL DEFAULT False;
|
||||
type: run_sql
|
||||
@@ -0,0 +1,87 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- accountingconfig
|
||||
- address1
|
||||
- address2
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- bill_tax_rates
|
||||
- cdk_dealerid
|
||||
- city
|
||||
- country
|
||||
- created_at
|
||||
- default_adjustment_rate
|
||||
- deliverchecklist
|
||||
- email
|
||||
- enforce_class
|
||||
- enforce_referral
|
||||
- features
|
||||
- federal_tax_id
|
||||
- id
|
||||
- imexshopid
|
||||
- inhousevendorid
|
||||
- insurance_vendor_id
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- jobsizelimit
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
- md_classes
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
- md_labor_rates
|
||||
- md_messaging_presets
|
||||
- md_notes_presets
|
||||
- md_order_statuses
|
||||
- md_parts_locations
|
||||
- md_payment_types
|
||||
- md_rbac
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- messagingservicesid
|
||||
- phone
|
||||
- prodtargethrs
|
||||
- production_config
|
||||
- region_config
|
||||
- schedule_end_time
|
||||
- schedule_start_time
|
||||
- scoreboard_target
|
||||
- shopname
|
||||
- shoprates
|
||||
- speedprint
|
||||
- ssbuckets
|
||||
- state
|
||||
- state_tax_id
|
||||
- stripe_acct_id
|
||||
- sub_status
|
||||
- target_touchtime
|
||||
- template_header
|
||||
- textid
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- website
|
||||
- workingdays
|
||||
- zip_post
|
||||
computed_fields: []
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,88 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- accountingconfig
|
||||
- address1
|
||||
- address2
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- attach_pdf_to_email
|
||||
- bill_tax_rates
|
||||
- cdk_dealerid
|
||||
- city
|
||||
- country
|
||||
- created_at
|
||||
- default_adjustment_rate
|
||||
- deliverchecklist
|
||||
- email
|
||||
- enforce_class
|
||||
- enforce_referral
|
||||
- features
|
||||
- federal_tax_id
|
||||
- id
|
||||
- imexshopid
|
||||
- inhousevendorid
|
||||
- insurance_vendor_id
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- jobsizelimit
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
- md_classes
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
- md_labor_rates
|
||||
- md_messaging_presets
|
||||
- md_notes_presets
|
||||
- md_order_statuses
|
||||
- md_parts_locations
|
||||
- md_payment_types
|
||||
- md_rbac
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- messagingservicesid
|
||||
- phone
|
||||
- prodtargethrs
|
||||
- production_config
|
||||
- region_config
|
||||
- schedule_end_time
|
||||
- schedule_start_time
|
||||
- scoreboard_target
|
||||
- shopname
|
||||
- shoprates
|
||||
- speedprint
|
||||
- ssbuckets
|
||||
- state
|
||||
- state_tax_id
|
||||
- stripe_acct_id
|
||||
- sub_status
|
||||
- target_touchtime
|
||||
- template_header
|
||||
- textid
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- website
|
||||
- workingdays
|
||||
- zip_post
|
||||
computed_fields: []
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,79 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- accountingconfig
|
||||
- address1
|
||||
- address2
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- bill_tax_rates
|
||||
- city
|
||||
- country
|
||||
- created_at
|
||||
- default_adjustment_rate
|
||||
- deliverchecklist
|
||||
- email
|
||||
- enforce_class
|
||||
- enforce_referral
|
||||
- federal_tax_id
|
||||
- id
|
||||
- inhousevendorid
|
||||
- insurance_vendor_id
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
- md_classes
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
- md_labor_rates
|
||||
- md_messaging_presets
|
||||
- md_notes_presets
|
||||
- md_order_statuses
|
||||
- md_parts_locations
|
||||
- md_payment_types
|
||||
- md_rbac
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- phone
|
||||
- prodtargethrs
|
||||
- production_config
|
||||
- schedule_end_time
|
||||
- schedule_start_time
|
||||
- scoreboard_target
|
||||
- shopname
|
||||
- shoprates
|
||||
- speedprint
|
||||
- ssbuckets
|
||||
- state
|
||||
- state_tax_id
|
||||
- target_touchtime
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- website
|
||||
- workingdays
|
||||
- zip_post
|
||||
filter:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,80 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- accountingconfig
|
||||
- address1
|
||||
- address2
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- attach_pdf_to_email
|
||||
- bill_tax_rates
|
||||
- city
|
||||
- country
|
||||
- created_at
|
||||
- default_adjustment_rate
|
||||
- deliverchecklist
|
||||
- email
|
||||
- enforce_class
|
||||
- enforce_referral
|
||||
- federal_tax_id
|
||||
- id
|
||||
- inhousevendorid
|
||||
- insurance_vendor_id
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
- md_classes
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
- md_labor_rates
|
||||
- md_messaging_presets
|
||||
- md_notes_presets
|
||||
- md_order_statuses
|
||||
- md_parts_locations
|
||||
- md_payment_types
|
||||
- md_rbac
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- phone
|
||||
- prodtargethrs
|
||||
- production_config
|
||||
- schedule_end_time
|
||||
- schedule_start_time
|
||||
- scoreboard_target
|
||||
- shopname
|
||||
- shoprates
|
||||
- speedprint
|
||||
- ssbuckets
|
||||
- state
|
||||
- state_tax_id
|
||||
- target_touchtime
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- website
|
||||
- workingdays
|
||||
- zip_post
|
||||
filter:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -756,6 +756,7 @@ tables:
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- attach_pdf_to_email
|
||||
- bill_tax_rates
|
||||
- cdk_dealerid
|
||||
- city
|
||||
@@ -831,6 +832,7 @@ tables:
|
||||
- appt_alt_transport
|
||||
- appt_colors
|
||||
- appt_length
|
||||
- attach_pdf_to_email
|
||||
- bill_tax_rates
|
||||
- city
|
||||
- country
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"phone": "^2.4.20",
|
||||
"soap": "^0.39.0",
|
||||
"socket.io": "^4.1.2",
|
||||
"ssh2-sftp-client": "^7.0.0",
|
||||
"stripe": "^8.148.0",
|
||||
"twilio": "^3.62.0",
|
||||
"xmlbuilder2": "^2.4.1"
|
||||
|
||||
@@ -139,7 +139,7 @@ app.post("/qbo/authorize", qbo.authorize);
|
||||
app.get("/qbo/callback", qbo.callback);
|
||||
|
||||
var data = require("./server/data/data");
|
||||
app.get("/data/ah", data.autohouse);
|
||||
app.post("/data/ah", data.autohouse);
|
||||
|
||||
var ioevent = require("./server/ioevent/ioevent");
|
||||
app.post("/ioevent", ioevent.default);
|
||||
|
||||
@@ -288,7 +288,7 @@ const generateInvoiceQbxml = (
|
||||
});
|
||||
// console.log("Done creating hash", JSON.stringify(invoiceLineHash));
|
||||
|
||||
if (!hasMapaLine) {
|
||||
if (!hasMapaLine && jobs_by_pk.job_totals.rates.mapa.total.amount > 0) {
|
||||
console.log("Adding MAPA Line Manually.");
|
||||
const mapaAccountName = responsibilityCenters.defaults.profits.MAPA;
|
||||
|
||||
@@ -313,7 +313,7 @@ const generateInvoiceQbxml = (
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasMashLine) {
|
||||
if (!hasMashLine && jobs_by_pk.job_totals.rates.mash.total.amount > 0) {
|
||||
console.log("Adding MASH Line Manually.");
|
||||
|
||||
const mashAccountName = responsibilityCenters.defaults.profits.MASH;
|
||||
@@ -424,9 +424,11 @@ const generateInvoiceQbxml = (
|
||||
TxnDate: moment(jobs_by_pk.date_invoiced).format("YYYY-MM-DD"),
|
||||
RefNumber: jobs_by_pk.ro_number,
|
||||
ShipAddress: {
|
||||
Addr1: `${jobs_by_pk.ownr_fn || ""} ${jobs_by_pk.ownr_ln || ""} ${
|
||||
jobs_by_pk.ownr_co_nm || ""
|
||||
}`,
|
||||
Addr1: jobs_by_pk.ownr_co_nm
|
||||
? jobs_by_pk.ownr_co_nm.substring(0, 30)
|
||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
||||
jobs_by_pk.ownr_fn || ""
|
||||
}`.substring(0, 30)}`,
|
||||
Addr2: jobs_by_pk.ownr_addr1,
|
||||
Addr3: jobs_by_pk.ownr_addr2,
|
||||
City: jobs_by_pk.ownr_city,
|
||||
|
||||
@@ -17,12 +17,13 @@ exports.generateOwnerTier = (jobs_by_pk, isThreeTier, twotierpref) => {
|
||||
if (isThreeTier) {
|
||||
//It's always gonna be the owner now. Same as 2 tier by name
|
||||
return jobs_by_pk.ownr_co_nm
|
||||
? `${jobs_by_pk.ownr_co_nm} - ${jobs_by_pk.ownr_ln || ""} ${
|
||||
jobs_by_pk.ownr_fn || ""
|
||||
} #${jobs_by_pk.owner.accountingid || ""}`
|
||||
: `${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""} #${
|
||||
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
||||
jobs_by_pk.owner.accountingid || ""
|
||||
}`;
|
||||
}`
|
||||
: `${`${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""}`.substring(
|
||||
0,
|
||||
30
|
||||
)} #${jobs_by_pk.owner.accountingid || ""}`;
|
||||
} else {
|
||||
//What's the 2 tier pref?
|
||||
if (twotierpref === "source") {
|
||||
@@ -31,12 +32,12 @@ exports.generateOwnerTier = (jobs_by_pk, isThreeTier, twotierpref) => {
|
||||
} else {
|
||||
//Same as 3 tier
|
||||
return jobs_by_pk.ownr_co_nm
|
||||
? `${jobs_by_pk.ownr_co_nm} - ${jobs_by_pk.ownr_ln || ""} ${
|
||||
jobs_by_pk.ownr_fn || ""
|
||||
} #${jobs_by_pk.owner.accountingid || ""}`
|
||||
: `${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""} #${
|
||||
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
||||
jobs_by_pk.owner.accountingid || ""
|
||||
}`;
|
||||
}`
|
||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
||||
jobs_by_pk.ownr_fn || ""
|
||||
}`.substring(0, 30)} #${jobs_by_pk.owner.accountingid || ""}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,42 +11,124 @@ require("dotenv").config({
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
let Client = require("ssh2-sftp-client");
|
||||
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const AHDineroFormat = "0.00";
|
||||
const AhDateFormat = "MMDDYYYY";
|
||||
|
||||
const repairOpCodes = ["OP4", "OP9", "OP10"];
|
||||
const replaceOpCodes = ["OP2", "OP5", "OP11", "OP12"];
|
||||
|
||||
const ftpSetup = {
|
||||
host: process.env.AUTOHOUSE_HOST,
|
||||
port: process.env.AUTOHOUSE_PORT,
|
||||
username: process.env.AUTOHOUSE_USER,
|
||||
password: process.env.AUTOHOUSE_PASSWORD,
|
||||
//debug: console.log,
|
||||
};
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
//Get Client Dataset.
|
||||
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY);
|
||||
//Query for the List of Bodyshop Clients.
|
||||
console.log("Starting Autohouse datapump request.");
|
||||
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
||||
|
||||
const erroredJobs = [];
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
try {
|
||||
for (const bodyshop of bodyshops) {
|
||||
console.log("Starting extract for ", bodyshop.shopname);
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY, {
|
||||
bodyshopid: bodyshop.id,
|
||||
});
|
||||
|
||||
const autoHouseObject = {
|
||||
AutoHouseExport: {
|
||||
RepairOrder: jobs.map((j) =>
|
||||
CreateRepairOrderTag(j, (job, error) => {
|
||||
erroredJobs.push({ job, error });
|
||||
})
|
||||
),
|
||||
},
|
||||
};
|
||||
const autoHouseObject = {
|
||||
AutoHouseExport: {
|
||||
RepairOrder: jobs.map((j) =>
|
||||
CreateRepairOrderTag(
|
||||
{ ...j, bodyshop },
|
||||
function ({ job, error }) {
|
||||
erroredJobs.push({ job: job, error: error.toString() });
|
||||
}
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
console.log(
|
||||
"***Number of Failed jobs***: ",
|
||||
erroredJobs.length,
|
||||
JSON.stringify(erroredJobs.map((x) => x.error))
|
||||
);
|
||||
var ret = builder
|
||||
.create(autoHouseObject, {
|
||||
version: "1.0",
|
||||
encoding: "UTF-8",
|
||||
})
|
||||
.end({ pretty: true, allowEmptyTags: true });
|
||||
console.log(
|
||||
bodyshop.shopname,
|
||||
"***Number of Failed jobs***: ",
|
||||
erroredJobs.length,
|
||||
JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||
);
|
||||
|
||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
||||
res.type("application/xml");
|
||||
//res.sendFile(ret);
|
||||
res.send(ret);
|
||||
var ret = builder
|
||||
.create(autoHouseObject, {
|
||||
version: "1.0",
|
||||
encoding: "UTF-8",
|
||||
})
|
||||
.end({ pretty: true, allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
xml: ret,
|
||||
filename: `IM_${bodyshop.imexshopid}_${moment().format(
|
||||
"DDMMYYYY_HHMMSS"
|
||||
)}.xml`,
|
||||
});
|
||||
|
||||
console.log("Finished extract for shop ", bodyshop.shopname);
|
||||
} catch (error) {
|
||||
//Error at the shop level.
|
||||
console.log("Error at shop level", bodyshop.shopname, error);
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
fatal: true,
|
||||
errors: [error.toString()],
|
||||
});
|
||||
} finally {
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
errors: erroredJobs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
console.log("Error in FTP client", JSON.stringify(errors))
|
||||
);
|
||||
try {
|
||||
//Connect to the FTP and upload all.
|
||||
|
||||
await sftp.connect(ftpSetup);
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
console.log("Uploading", xmlObj.filename);
|
||||
const uploadResult = await sftp.put(
|
||||
Buffer.from(xmlObj.xml),
|
||||
`/${xmlObj.filename}`
|
||||
);
|
||||
console.log(
|
||||
"🚀 ~ file: autohouse.js ~ line 94 ~ uploadResult",
|
||||
uploadResult
|
||||
);
|
||||
}
|
||||
|
||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
||||
} catch (error) {
|
||||
console.log("Error when connecting to FTP", error);
|
||||
} finally {
|
||||
sftp.end();
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
res.JSON(error).sendStatus(500);
|
||||
}
|
||||
};
|
||||
|
||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
@@ -58,9 +140,9 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
const ret = {
|
||||
RepairOrderInformation: {
|
||||
ShopInternalName: job.bodyshop.autohouseid,
|
||||
ID: job.id,
|
||||
ID: parseInt(job.ro_number.match(/\d/g).join(""), 10),
|
||||
RO: job.ro_number,
|
||||
Est: job.id, //We no longer use estimate id.
|
||||
Est: parseInt(job.ro_number.match(/\d/g).join(""), 10), //We no longer use estimate id.
|
||||
GUID: job.id,
|
||||
TransType: StatusMapping(job.status, job.bodyshop.md_ro_statuses),
|
||||
ShopName: job.bodyshop.shopname,
|
||||
@@ -69,8 +151,12 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
ShopState: job.bodyshop.state,
|
||||
ShopZip: job.bodyshop.zip_post,
|
||||
ShopPhone: job.bodyshop.phone,
|
||||
EstimatorID: `${job.est_ct_fn || ""} ${job.est_ct_ln || ""}`,
|
||||
EstimatorName: `${job.est_ct_fn || ""} ${job.est_ct_ln || ""}`,
|
||||
EstimatorID: `${job.est_ct_ln ? job.est_ct_ln : ""}${
|
||||
job.est_ct_ln ? ", " : ""
|
||||
}${job.est_ct_fn ? job.est_ct_fn : ""}`,
|
||||
EstimatorName: `${job.est_ct_ln ? job.est_ct_ln : ""}${
|
||||
job.est_ct_ln ? ", " : ""
|
||||
}${job.est_ct_fn ? job.est_ct_fn : ""}`,
|
||||
},
|
||||
CustomerInformation: {
|
||||
FirstName: job.ownr_fn,
|
||||
@@ -410,7 +496,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
return ret;
|
||||
} catch (error) {
|
||||
console.log("Error calculating job", error);
|
||||
errorCallback(job, error);
|
||||
errorCallback({ job, error });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -611,6 +697,3 @@ const generateNullDetailLine = () => {
|
||||
EstimateAmount: null,
|
||||
};
|
||||
};
|
||||
|
||||
const repairOpCodes = ["OP4", "OP9", "OP10"];
|
||||
const replaceOpCodes = ["OP2", "OP5", "OP11", "OP12"];
|
||||
|
||||
@@ -48,7 +48,8 @@ exports.sendEmail = async (req, res) => {
|
||||
...((req.body.attachments &&
|
||||
req.body.attachments.map((a) => {
|
||||
return {
|
||||
path: a,
|
||||
filename: a.filename,
|
||||
path: a.path,
|
||||
};
|
||||
})) ||
|
||||
[]),
|
||||
|
||||
@@ -57,6 +57,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
ownerid
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
ownr_co_nm
|
||||
ownr_addr1
|
||||
ownr_addr2
|
||||
ownr_zip
|
||||
@@ -356,8 +357,8 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
|
||||
}
|
||||
}`;
|
||||
|
||||
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
|
||||
jobs(where: {_and: [{updated_at: {_gt: $start}}, {bodyshop: {autohouseid: {_is_null: false}}}]}) {
|
||||
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) {
|
||||
jobs(where: {_and: [{converted :{_eq: true}},{updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) {
|
||||
id
|
||||
ro_number
|
||||
status
|
||||
@@ -432,10 +433,10 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
|
||||
md_ro_statuses
|
||||
md_order_statuses
|
||||
autohouseid
|
||||
md_responsibility_centers
|
||||
jc_hourly_rates
|
||||
md_responsibility_centers
|
||||
jc_hourly_rates
|
||||
}
|
||||
joblines (where:{removed: {_eq:false}}){
|
||||
joblines(where: {removed: {_eq: false}}) {
|
||||
id
|
||||
line_no
|
||||
status
|
||||
@@ -451,40 +452,40 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
|
||||
part_type
|
||||
oem_partno
|
||||
lbr_op
|
||||
profitcenter_part
|
||||
profitcenter_labor
|
||||
billlines (order_by:{bill:{date:desc_nulls_last}}) {
|
||||
profitcenter_part
|
||||
profitcenter_labor
|
||||
billlines(order_by: {bill: {date: desc_nulls_last}}) {
|
||||
actual_cost
|
||||
actual_price
|
||||
quantity
|
||||
bill {
|
||||
vendor{
|
||||
vendor {
|
||||
name
|
||||
}
|
||||
invoice_number
|
||||
}
|
||||
}
|
||||
|
||||
} bills {
|
||||
id
|
||||
federal_tax_rate
|
||||
local_tax_rate
|
||||
state_tax_rate
|
||||
is_credit_memo
|
||||
billlines {
|
||||
actual_cost
|
||||
cost_center
|
||||
id
|
||||
quantity
|
||||
}
|
||||
}
|
||||
timetickets {
|
||||
id
|
||||
rate
|
||||
}
|
||||
bills {
|
||||
id
|
||||
federal_tax_rate
|
||||
local_tax_rate
|
||||
state_tax_rate
|
||||
is_credit_memo
|
||||
billlines {
|
||||
actual_cost
|
||||
cost_center
|
||||
actualhrs
|
||||
productivehrs
|
||||
id
|
||||
quantity
|
||||
}
|
||||
}
|
||||
timetickets {
|
||||
id
|
||||
rate
|
||||
cost_center
|
||||
actualhrs
|
||||
productivehrs
|
||||
}
|
||||
area_of_damage
|
||||
employee_prep_rel {
|
||||
first_name
|
||||
@@ -506,6 +507,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
exports.UPDATE_JOB = `
|
||||
@@ -905,3 +907,24 @@ exports.INSERT_IOEVENT = ` mutation INSERT_IOEVENT($event: ioevents_insert_input
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
exports.GET_AUTOHOUSE_SHOPS = `query GET_AUTOHOUSE_SHOPS {
|
||||
bodyshops(where: {autohouseid: {_is_null: false}}){
|
||||
|
||||
id
|
||||
shopname
|
||||
address1
|
||||
city
|
||||
state
|
||||
zip_post
|
||||
country
|
||||
phone
|
||||
md_ro_statuses
|
||||
md_order_statuses
|
||||
autohouseid
|
||||
md_responsibility_centers
|
||||
jc_hourly_rates
|
||||
imexshopid
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
63
yarn.lock
63
yarn.lock
@@ -529,7 +529,7 @@ asap@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||
|
||||
asn1@~0.2.3:
|
||||
asn1@^0.2.4, asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
@@ -644,7 +644,7 @@ batch@^0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
||||
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
@@ -915,6 +915,16 @@ concat-stream@^1.4.7:
|
||||
readable-stream "^2.2.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concat-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
|
||||
integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.0.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concurrently@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.0.2.tgz#4ecdfc78a72a6f626a3a5d3c2a7a81962f3663e3"
|
||||
@@ -999,6 +1009,13 @@ cors@2.8.5, cors@~2.8.5:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cpu-features@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.2.tgz#9f636156f1155fd04bdbaa028bb3c2fbef3cea7a"
|
||||
integrity sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==
|
||||
dependencies:
|
||||
nan "^2.14.1"
|
||||
|
||||
cross-fetch@^3.0.6:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
|
||||
@@ -1345,6 +1362,11 @@ entities@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||
|
||||
err-code@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
|
||||
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
@@ -2839,6 +2861,11 @@ ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
nan@^2.14.1, nan@^2.14.2:
|
||||
version "2.14.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
|
||||
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
|
||||
|
||||
natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
@@ -3136,6 +3163,14 @@ progress@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||
|
||||
promise-retry@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
|
||||
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
|
||||
dependencies:
|
||||
err-code "^2.0.2"
|
||||
retry "^0.12.0"
|
||||
|
||||
protobufjs@^6.10.2, protobufjs@^6.8.6:
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.2.tgz#b9cb6bd8ec8f87514592ba3fdfd28e93f33a469b"
|
||||
@@ -3347,7 +3382,7 @@ readable-stream@2, readable-stream@^2.2.2, readable-stream@^2.3.5, readable-stre
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
@@ -3431,7 +3466,7 @@ retry-request@^4.0.0, retry-request@^4.1.1:
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
|
||||
retry@0.12.0:
|
||||
retry@0.12.0, retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
|
||||
@@ -3766,6 +3801,26 @@ sprintf-js@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
ssh2-sftp-client@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ssh2-sftp-client/-/ssh2-sftp-client-7.0.0.tgz#38c3420319156d030a80ac9db1df7459d2ba42a0"
|
||||
integrity sha512-o++ryEeSbAQ6GzjuXs6BHnST6zsoWUZYt9cLy6XQ4+WdL6jNuU6UjyQzvg1J3IgN4LpCSAI+9EyTeKeIb0AfSQ==
|
||||
dependencies:
|
||||
concat-stream "^2.0.0"
|
||||
promise-retry "^2.0.1"
|
||||
ssh2 "^1.1.0"
|
||||
|
||||
ssh2@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.1.0.tgz#43dd24930e15e317687f519d6b40270d9cd00d00"
|
||||
integrity sha512-CidQLG2ZacoT0Z7O6dOyisj4JdrOrLVJ4KbHjVNz9yI1vO08FAYQPcnkXY9BP8zeYo+J/nBgY6Gg4R7w4WFWtg==
|
||||
dependencies:
|
||||
asn1 "^0.2.4"
|
||||
bcrypt-pbkdf "^1.0.2"
|
||||
optionalDependencies:
|
||||
cpu-features "0.0.2"
|
||||
nan "^2.14.2"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
|
||||
Reference in New Issue
Block a user