3
.gitignore
vendored
3
.gitignore
vendored
@@ -113,3 +113,6 @@ firebase/.env
|
|||||||
!.elasticbeanstalk/*.cfg.yml
|
!.elasticbeanstalk/*.cfg.yml
|
||||||
!.elasticbeanstalk/*.global.yml
|
!.elasticbeanstalk/*.global.yml
|
||||||
logs/oAuthClient-log.log
|
logs/oAuthClient-log.log
|
||||||
|
|
||||||
|
|
||||||
|
.node-persist/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.7.1">
|
<babeledit_project be_version="2.7.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -37159,6 +37159,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>parts_label_multiple</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>parts_label_single</name>
|
<name>parts_label_single</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import cleanAxios from "../../utils/CleanAxios";
|
|||||||
import { store } from "../../redux/store";
|
import { store } from "../../redux/store";
|
||||||
import { addMediaForJob } from "../../redux/media/media.actions";
|
import { addMediaForJob } from "../../redux/media/media.actions";
|
||||||
import normalizeUrl from "normalize-url";
|
import normalizeUrl from "normalize-url";
|
||||||
|
import { notification } from "antd";
|
||||||
|
import i18n from "i18next";
|
||||||
|
|
||||||
export const handleUpload = async ({ ev, context }) => {
|
export const handleUpload = async ({ ev, context }) => {
|
||||||
const { onError, onSuccess, onProgress, file } = ev;
|
const { onError, onSuccess, onProgress, file } = ev;
|
||||||
@@ -45,6 +47,11 @@ export const handleUpload = async ({ ev, context }) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
onSuccess && onSuccess(file);
|
onSuccess && onSuccess(file);
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "docuploadsuccess",
|
||||||
|
message: i18n.t("documents.successes.insert"),
|
||||||
|
});
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
addMediaForJob({
|
addMediaForJob({
|
||||||
jobid,
|
jobid,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { selectAllMedia } from "../../redux/media/media.selectors";
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { CreateExplorerLinkForJob } from "../../utils/localmedia";
|
import { CreateExplorerLinkForJob } from "../../utils/localmedia";
|
||||||
import DocumentsLocalUploadComponent from "../documents-local-upload/documents-local-upload.component";
|
import DocumentsLocalUploadComponent from "../documents-local-upload/documents-local-upload.component";
|
||||||
|
import JobsDocumentsLocalDeleteButton from "./jobs-documents-local-gallery.delete.component";
|
||||||
import JobsLocalGalleryDownloadButton from "./jobs-documents-local-gallery.download";
|
import JobsLocalGalleryDownloadButton from "./jobs-documents-local-gallery.download";
|
||||||
import JobsDocumentsLocalGalleryReassign from "./jobs-documents-local-gallery.reassign.component";
|
import JobsDocumentsLocalGalleryReassign from "./jobs-documents-local-gallery.reassign.component";
|
||||||
import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-gallery.selectall.component";
|
import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-gallery.selectall.component";
|
||||||
@@ -101,6 +102,7 @@ export function JobsDocumentsLocalGallery({
|
|||||||
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
||||||
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
||||||
<JobsLocalGalleryDownloadButton job={job} />
|
<JobsLocalGalleryDownloadButton job={job} />
|
||||||
|
<JobsDocumentsLocalDeleteButton jobid={job.id} />
|
||||||
</Space>
|
</Space>
|
||||||
<Card>
|
<Card>
|
||||||
<DocumentsLocalUploadComponent
|
<DocumentsLocalUploadComponent
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { QuestionCircleOutlined } from "@ant-design/icons";
|
||||||
|
import { Button, notification, Popconfirm } from "antd";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import cleanAxios from "../../utils/CleanAxios";
|
||||||
|
//Context: currentUserEmail, bodyshop, jobid, invoiceid
|
||||||
|
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { getJobMedia } from "../../redux/media/media.actions";
|
||||||
|
import { selectAllMedia } from "../../redux/media/media.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
allMedia: selectAllMedia,
|
||||||
|
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
getJobMedia: (id) => dispatch(getJobMedia(id)),
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(JobsDocumentsLocalDeleteButton);
|
||||||
|
|
||||||
|
export function JobsDocumentsLocalDeleteButton({
|
||||||
|
bodyshop,
|
||||||
|
getJobMedia,
|
||||||
|
allMedia,
|
||||||
|
jobid,
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
logImEXEvent("job_documents_delete");
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const delres = await cleanAxios.post(
|
||||||
|
`${bodyshop.localmediaserverhttp}/jobs/delete`,
|
||||||
|
{
|
||||||
|
jobid: jobid,
|
||||||
|
files: ((allMedia && allMedia[jobid]) || [])
|
||||||
|
.filter((i) => i.isSelected)
|
||||||
|
.map((i) => i.filename),
|
||||||
|
},
|
||||||
|
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (delres.errors) {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("documents.errors.deleting", {
|
||||||
|
message: JSON.stringify(delres.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.open({
|
||||||
|
key: "docdeletedsuccesfully",
|
||||||
|
type: "success",
|
||||||
|
message: t("documents.successes.delete"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getJobMedia(jobid);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popconfirm
|
||||||
|
icon={<QuestionCircleOutlined style={{ color: "red" }} />}
|
||||||
|
onConfirm={handleDelete}
|
||||||
|
title={t("documents.labels.confirmdelete")}
|
||||||
|
okText={t("general.actions.delete")}
|
||||||
|
okButtonProps={{ type: "danger" }}
|
||||||
|
cancelText={t("general.actions.cancel")}
|
||||||
|
>
|
||||||
|
<Button loading={loading}>{t("documents.actions.delete")}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Card, Form, InputNumber, Popover } from "antd";
|
import { Button, Card, Form, InputNumber, Popover, Radio } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -24,7 +24,8 @@ export function PrintCenterJobsLabels({ bodyshop, jobId }) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
form.submit();
|
form.submit();
|
||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
};
|
};
|
||||||
@@ -33,12 +34,12 @@ export function PrintCenterJobsLabels({ bodyshop, jobId }) {
|
|||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async ({ template, ...values }) => {
|
||||||
const { sendtype, ...restVals } = values;
|
const { sendtype, ...restVals } = values;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await GenerateDocument(
|
await GenerateDocument(
|
||||||
{
|
{
|
||||||
name: TemplateList("job_special").folder_label_multiple.key,
|
name: TemplateList("job_special")[template].key,
|
||||||
variables: { id: jobId },
|
variables: { id: jobId },
|
||||||
context: restVals,
|
context: restVals,
|
||||||
},
|
},
|
||||||
@@ -48,6 +49,7 @@ export function PrintCenterJobsLabels({ bodyshop, jobId }) {
|
|||||||
);
|
);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
|
form.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
@@ -58,13 +60,28 @@ export function PrintCenterJobsLabels({ bodyshop, jobId }) {
|
|||||||
layout="vertical"
|
layout="vertical"
|
||||||
form={form}
|
form={form}
|
||||||
>
|
>
|
||||||
|
<Form.Item required name="template">
|
||||||
|
<Radio.Group>
|
||||||
|
<Radio.Button value="parts_label_multiple">
|
||||||
|
{t("printcenter.jobs.parts_label_multiple")}
|
||||||
|
</Radio.Button>
|
||||||
|
<Radio.Button value="folder_label_multiple">
|
||||||
|
{t("printcenter.jobs.folder_label_multiple")}
|
||||||
|
</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
required
|
||||||
label={t("printcenter.jobs.labels.position")}
|
label={t("printcenter.jobs.labels.position")}
|
||||||
name="position"
|
name="position"
|
||||||
>
|
>
|
||||||
<InputNumber min={1} precision={0} />
|
<InputNumber min={1} precision={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("printcenter.jobs.labels.count")} name="count">
|
<Form.Item
|
||||||
|
required
|
||||||
|
label={t("printcenter.jobs.labels.count")}
|
||||||
|
name="count"
|
||||||
|
>
|
||||||
<InputNumber min={1} precision={0} max={99} />
|
<InputNumber min={1} precision={0} max={99} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Button type="primary" loading={loading} onClick={handleOk}>
|
<Button type="primary" loading={loading} onClick={handleOk}>
|
||||||
|
|||||||
@@ -2181,7 +2181,7 @@
|
|||||||
"filing_coversheet_portrait": "Filing Coversheet (Portrait)",
|
"filing_coversheet_portrait": "Filing Coversheet (Portrait)",
|
||||||
"final_invoice": "Final Invoice",
|
"final_invoice": "Final Invoice",
|
||||||
"fippa_authorization": "FIPPA Authorization",
|
"fippa_authorization": "FIPPA Authorization",
|
||||||
"folder_label_multiple": "Folder Label Multiple",
|
"folder_label_multiple": "Folder Label - Multi",
|
||||||
"glass_express_checklist": "Glass Express Checklist",
|
"glass_express_checklist": "Glass Express Checklist",
|
||||||
"guarantee": "Repair Guarantee",
|
"guarantee": "Repair Guarantee",
|
||||||
"individual_job_note": "Job Note RO # {{ro_number}}",
|
"individual_job_note": "Job Note RO # {{ro_number}}",
|
||||||
@@ -2202,6 +2202,7 @@
|
|||||||
"mpi_eglass_auth": "MPI - eGlass Auth",
|
"mpi_eglass_auth": "MPI - eGlass Auth",
|
||||||
"mpi_final_acct_sheet": "MPI - Final Accounting Sheet",
|
"mpi_final_acct_sheet": "MPI - Final Accounting Sheet",
|
||||||
"paint_grid": "Paint Grid",
|
"paint_grid": "Paint Grid",
|
||||||
|
"parts_label_multiple": "Parts Label - Multi",
|
||||||
"parts_label_single": "Parts Label - Single",
|
"parts_label_single": "Parts Label - Single",
|
||||||
"parts_list": "Parts List",
|
"parts_list": "Parts List",
|
||||||
"parts_order": "Parts Order Confirmation",
|
"parts_order": "Parts Order Confirmation",
|
||||||
|
|||||||
@@ -2202,6 +2202,7 @@
|
|||||||
"mpi_eglass_auth": "",
|
"mpi_eglass_auth": "",
|
||||||
"mpi_final_acct_sheet": "",
|
"mpi_final_acct_sheet": "",
|
||||||
"paint_grid": "",
|
"paint_grid": "",
|
||||||
|
"parts_label_multiple": "",
|
||||||
"parts_label_single": "",
|
"parts_label_single": "",
|
||||||
"parts_list": "",
|
"parts_list": "",
|
||||||
"parts_order": "",
|
"parts_order": "",
|
||||||
|
|||||||
@@ -2202,6 +2202,7 @@
|
|||||||
"mpi_eglass_auth": "",
|
"mpi_eglass_auth": "",
|
||||||
"mpi_final_acct_sheet": "",
|
"mpi_final_acct_sheet": "",
|
||||||
"paint_grid": "",
|
"paint_grid": "",
|
||||||
|
"parts_label_multiple": "",
|
||||||
"parts_label_single": "",
|
"parts_label_single": "",
|
||||||
"parts_list": "",
|
"parts_list": "",
|
||||||
"parts_order": "",
|
"parts_order": "",
|
||||||
|
|||||||
@@ -504,6 +504,12 @@ export const TemplateList = (type, context) => {
|
|||||||
key: "folder_label_multiple",
|
key: "folder_label_multiple",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
},
|
},
|
||||||
|
parts_label_multiple: {
|
||||||
|
title: i18n.t("printcenter.jobs.parts_label_multiple"),
|
||||||
|
description: "Parts Label Multiple",
|
||||||
|
key: "parts_label_multiple",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
csi_invitation_action: {
|
csi_invitation_action: {
|
||||||
title: i18n.t("printcenter.jobs.csi_invitation_action"),
|
title: i18n.t("printcenter.jobs.csi_invitation_action"),
|
||||||
description: "CSI invite",
|
description: "CSI invite",
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Must set the environment variables using:
|
Must set the environment variables using:
|
||||||
|
|
||||||
firebase functions:config:set auth.graphql_endpoint="https://db.development.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!"
|
firebase functions:config:set auth.graphql_endpoint="https://db.dev.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
version: 2
|
version: 2
|
||||||
endpoint: https://db.development.bodyshop.app
|
endpoint: https://db.dev.bodyshop.app
|
||||||
admin_secret: Dev-BodyShopApp!
|
admin_secret: Dev-BodyShopApp!
|
||||||
metadata_directory: metadata
|
metadata_directory: metadata
|
||||||
actions:
|
actions:
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
- function:
|
- function:
|
||||||
schema: public
|
|
||||||
name: search_bills
|
name: search_bills
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_cccontracts
|
name: search_cccontracts
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_dms_vehicles
|
name: search_dms_vehicles
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_exportlog
|
name: search_exportlog
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_inventory
|
name: search_inventory
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_jobs
|
name: search_jobs
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_owners
|
name: search_owners
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_payments
|
name: search_payments
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_phonebook
|
name: search_phonebook
|
||||||
- function:
|
|
||||||
schema: public
|
schema: public
|
||||||
|
- function:
|
||||||
name: search_vehicles
|
name: search_vehicles
|
||||||
|
schema: public
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@
|
|||||||
"moment-timezone": "^0.5.34",
|
"moment-timezone": "^0.5.34",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"node-mailjet": "^5.1.0",
|
"node-mailjet": "^5.1.0",
|
||||||
|
"node-persist": "^3.1.0",
|
||||||
"node-quickbooks": "^2.0.39",
|
"node-quickbooks": "^2.0.39",
|
||||||
"nodemailer": "^6.7.7",
|
"nodemailer": "^6.7.7",
|
||||||
"phone": "^3.1.23",
|
"phone": "^3.1.23",
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ app.post("/qbo/payments", fb.validateFirebaseIdToken, qbo.payments);
|
|||||||
|
|
||||||
var data = require("./server/data/data");
|
var data = require("./server/data/data");
|
||||||
app.post("/data/ah", data.autohouse);
|
app.post("/data/ah", data.autohouse);
|
||||||
app.post("/data/arms", data.arms);
|
app.post("/record-handler/arms", data.arms);
|
||||||
|
|
||||||
var taskHandler = require("./server/tasks/tasks");
|
var taskHandler = require("./server/tasks/tasks");
|
||||||
app.post("/taskHandler", taskHandler.taskHandler);
|
app.post("/taskHandler", taskHandler.taskHandler);
|
||||||
@@ -238,6 +238,7 @@ app.get("/", async function (req, res) {
|
|||||||
res.status(200).send("Access Forbidden.");
|
res.status(200).send("Access Forbidden.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.listen(port, (error) => {
|
server.listen(port, (error) => {
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
logger.log(
|
logger.log(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const queries = require("../graphql-client/queries");
|
|||||||
const Dinero = require("dinero.js");
|
const Dinero = require("dinero.js");
|
||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
const storage = require("node-persist");
|
||||||
const _ = require("lodash");
|
const _ = require("lodash");
|
||||||
const logger = require("../utils/logger");
|
const logger = require("../utils/logger");
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
@@ -13,6 +13,7 @@ require("dotenv").config({
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
const soap = require("soap");
|
const soap = require("soap");
|
||||||
|
const { sendServerEmail } = require("../email/sendemail");
|
||||||
|
|
||||||
const entegralEndpoint =
|
const entegralEndpoint =
|
||||||
process.env.NODE_ENV === "production"
|
process.env.NODE_ENV === "production"
|
||||||
@@ -24,27 +25,63 @@ const uuid = require("uuid").v4;
|
|||||||
|
|
||||||
const momentFormat = "yyyy-MM-DDTHH:mm:ss.SSS";
|
const momentFormat = "yyyy-MM-DDTHH:mm:ss.SSS";
|
||||||
|
|
||||||
|
function pollFunc(fn, timeout, interval) {
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
(interval = interval || 1000), (canPoll = true);
|
||||||
|
|
||||||
|
(function p() {
|
||||||
|
canPoll =
|
||||||
|
timeout === 0 ? true : new Date().getTime() - startTime <= timeout;
|
||||||
|
if (fn() && canPoll) {
|
||||||
|
// ensures the function exucutes
|
||||||
|
setTimeout(p, interval);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
pollFunc(getEntegralShopData, 0, 5 * 60 * 1000); //Set the metadata to refresh every 5 minutes.
|
||||||
|
|
||||||
|
async function getEntegralShopData() {
|
||||||
|
const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
||||||
|
await storage.init({ logging: true });
|
||||||
|
logger.log("set-entegral-shops-local-storage", "DEBUG", "API", null, null);
|
||||||
|
await storage.setItem("entegralShops", bodyshops);
|
||||||
|
return true; //Continue execution.
|
||||||
|
}
|
||||||
|
|
||||||
exports.default = async (req, res) => {
|
exports.default = async (req, res) => {
|
||||||
//Query for the List of Bodyshop Clients.
|
//Query for the List of Bodyshop Clients.
|
||||||
logger.log("arms-start", "DEBUG", "api", null, null);
|
const job = req.body.event.data.new;
|
||||||
const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
logger.log("arms-job-update", "DEBUG", "api", job.id, null);
|
||||||
|
|
||||||
const allErrors = [];
|
let allEntegralShops = await storage.getItem("entegralShops");
|
||||||
try {
|
|
||||||
for (const bodyshop of bodyshops) {
|
|
||||||
logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
|
||||||
shopname: bodyshop.shopname,
|
|
||||||
});
|
|
||||||
const erroredJobs = [];
|
|
||||||
try {
|
|
||||||
const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, {
|
|
||||||
bodyshopid: bodyshop.id,
|
|
||||||
});
|
|
||||||
const jobsToPush = [];
|
|
||||||
|
|
||||||
jobs.forEach((job) => {
|
if (!allEntegralShops) {
|
||||||
|
await getEntegralShopData();
|
||||||
|
allEntegralShops = await storage.getItem("entegralShops");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Is this job part of an entegral shop?
|
||||||
|
const bodyshop = allEntegralShops.find((b) => b.id === job.shopid);
|
||||||
|
if (!bodyshop) {
|
||||||
|
//This job is not for entegral based shops.
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "PRODUCTION") {
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//TODO: Check if an update should even be sent.
|
||||||
|
if (false) {
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const transId = uuid(); // Can this actually be the job id?
|
const transId = uuid(); // Can this actually be the job id?
|
||||||
|
|
||||||
let obj = {
|
let obj = {
|
||||||
RqUID: transId,
|
RqUID: transId,
|
||||||
DocumentInfo: {
|
DocumentInfo: {
|
||||||
@@ -71,9 +108,7 @@ exports.default = async (req, res) => {
|
|||||||
).format(momentFormat),
|
).format(momentFormat),
|
||||||
ArrivalDateTime:
|
ArrivalDateTime:
|
||||||
job.actual_in &&
|
job.actual_in &&
|
||||||
moment(job.actual_in)
|
moment(job.actual_in).tz(bodyshop.timezone).format(momentFormat),
|
||||||
.tz(bodyshop.timezone)
|
|
||||||
.format(momentFormat),
|
|
||||||
ArrivalOdometerReading: job.kmin,
|
ArrivalOdometerReading: job.kmin,
|
||||||
TargetCompletionDateTime:
|
TargetCompletionDateTime:
|
||||||
job.scheduled_completion &&
|
job.scheduled_completion &&
|
||||||
@@ -105,7 +140,7 @@ exports.default = async (req, res) => {
|
|||||||
CompanyName: job.ins_co_nm,
|
CompanyName: job.ins_co_nm,
|
||||||
IDInfo: {
|
IDInfo: {
|
||||||
IDQualifierCode: "US",
|
IDQualifierCode: "US",
|
||||||
IDNum: 44, // ** Not sure where to get this entegral ID from?
|
//IDNum: 44, // ** Not sure where to get this entegral ID from?
|
||||||
},
|
},
|
||||||
// Communications: [
|
// Communications: [
|
||||||
// {
|
// {
|
||||||
@@ -481,33 +516,25 @@ exports.default = async (req, res) => {
|
|||||||
TotalType: "LAB",
|
TotalType: "LAB",
|
||||||
TotalTypeDesc: "Body Labor",
|
TotalTypeDesc: "Body Labor",
|
||||||
TotalHours: job.job_totals.rates.lab.hours,
|
TotalHours: job.job_totals.rates.lab.hours,
|
||||||
TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "LAF",
|
TotalType: "LAF",
|
||||||
TotalTypeDesc: "Frame Labor",
|
TotalTypeDesc: "Frame Labor",
|
||||||
TotalHours: job.job_totals.rates.laf.hours,
|
TotalHours: job.job_totals.rates.laf.hours,
|
||||||
TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "LAM",
|
TotalType: "LAM",
|
||||||
TotalTypeDesc: "Mechanical Labor",
|
TotalTypeDesc: "Mechanical Labor",
|
||||||
TotalHours: job.job_totals.rates.lam.hours,
|
TotalHours: job.job_totals.rates.lam.hours,
|
||||||
TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "LAR",
|
TotalType: "LAR",
|
||||||
TotalTypeDesc: "Refinish Labor",
|
TotalTypeDesc: "Refinish Labor",
|
||||||
TotalHours: job.job_totals.rates.lar.hours,
|
TotalHours: job.job_totals.rates.lar.hours,
|
||||||
TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
PartsTotalsInfo: [
|
PartsTotalsInfo: [
|
||||||
@@ -579,16 +606,12 @@ exports.default = async (req, res) => {
|
|||||||
{
|
{
|
||||||
TotalType: "MAPA",
|
TotalType: "MAPA",
|
||||||
TotalTypeDesc: "Paint Materials",
|
TotalTypeDesc: "Paint Materials",
|
||||||
TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "MASH",
|
TotalType: "MASH",
|
||||||
TotalTypeDesc: "Shop Materials",
|
TotalTypeDesc: "Shop Materials",
|
||||||
TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat(
|
TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// TotalType: "MAHW",
|
// TotalType: "MAHW",
|
||||||
@@ -607,9 +630,7 @@ exports.default = async (req, res) => {
|
|||||||
{
|
{
|
||||||
TotalType: "OTTW",
|
TotalType: "OTTW",
|
||||||
TotalTypeDesc: "Towing",
|
TotalTypeDesc: "Towing",
|
||||||
TotalAmt: Dinero(job.job_totals.additional.towing).toFormat(
|
TotalAmt: Dinero(job.job_totals.additional.towing).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "OTAC",
|
TotalType: "OTAC",
|
||||||
@@ -624,17 +645,15 @@ exports.default = async (req, res) => {
|
|||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
TotalSubType: "TT",
|
TotalSubType: "TT",
|
||||||
TotalTypeDesc: "Gross Total",
|
TotalTypeDesc: "Gross Total",
|
||||||
TotalAmt: Dinero(
|
TotalAmt: Dinero(job.job_totals.totals.total_repairs).toFormat(
|
||||||
job.job_totals.totals.total_repairs
|
"0.00"
|
||||||
).toFormat("0.00"),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
TotalSubType: "T2",
|
TotalSubType: "T2",
|
||||||
TotalTypeDesc: "Net Total",
|
TotalTypeDesc: "Net Total",
|
||||||
TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat(
|
TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
@@ -648,9 +667,7 @@ exports.default = async (req, res) => {
|
|||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
TotalSubType: "F7",
|
TotalSubType: "F7",
|
||||||
TotalTypeDesc: "Sales Tax",
|
TotalTypeDesc: "Sales Tax",
|
||||||
TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat(
|
TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat("0.00"),
|
||||||
"0.00"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
@@ -664,9 +681,9 @@ exports.default = async (req, res) => {
|
|||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
TotalSubType: "D8",
|
TotalSubType: "D8",
|
||||||
TotalTypeDesc: "Bottom Line Discount",
|
TotalTypeDesc: "Bottom Line Discount",
|
||||||
TotalAmt: Dinero(
|
TotalAmt: Dinero(job.job_totals.additional.adjustments).toFormat(
|
||||||
job.job_totals.additional.adjustments
|
"0.00"
|
||||||
).toFormat("0.00"),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
@@ -708,9 +725,9 @@ exports.default = async (req, res) => {
|
|||||||
TotalType: "TOT",
|
TotalType: "TOT",
|
||||||
TotalSubType: "CUST",
|
TotalSubType: "CUST",
|
||||||
TotalTypeDesc: "Customer Pay",
|
TotalTypeDesc: "Customer Pay",
|
||||||
TotalAmt: Dinero(
|
TotalAmt: Dinero(job.job_totals.totals.custPayable.total).toFormat(
|
||||||
job.job_totals.totals.custPayable.total
|
"0.00"
|
||||||
).toFormat("0.00"),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// RepairTotalsType: 1,
|
// RepairTotalsType: 1,
|
||||||
@@ -805,8 +822,73 @@ exports.default = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
deleteNullKeys(obj);
|
deleteNullKeys(obj);
|
||||||
jobsToPush.push(obj);
|
|
||||||
|
try {
|
||||||
|
const entegralSoapClient = await soap.createClientAsync(
|
||||||
|
entegralEndpoint,
|
||||||
|
{
|
||||||
|
ignoredNamespaces: true,
|
||||||
|
wsdl_options: {
|
||||||
|
// useEmptyTag: true,
|
||||||
|
},
|
||||||
|
wsdl_headers: {
|
||||||
|
Authorization: `Basic ${new Buffer.from(
|
||||||
|
`${process.env.ENTEGRAL_USER}:${process.env.ENTEGRAL_PASSWORD}`
|
||||||
|
).toString("base64")}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
entegralSoapClient.setSecurity(
|
||||||
|
new soap.BasicAuthSecurity(
|
||||||
|
process.env.ENTEGRAL_USER,
|
||||||
|
process.env.ENTEGRAL_PASSWORD
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const entegralResponse =
|
||||||
|
await entegralSoapClient.RepairOrderFolderAddRqAsync(
|
||||||
|
obj,
|
||||||
|
function (err, result, rawResponse, soapHeader, rawRequest) {
|
||||||
|
fs.writeFileSync(`./logs/arms-request.xml`, rawRequest);
|
||||||
|
fs.writeFileSync(`./logs/arms-response.xml`, rawResponse);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
sendServerEmail({
|
||||||
|
subject: `ARMS Update Failed: ${bodyshop.shopname} - ${job.ro_number}`,
|
||||||
|
text: `Error: ${JSON.stringify(error)}`,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json(err || result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const [result, rawResponse, , rawRequest] = entegralResponse;
|
||||||
|
} catch (error) {
|
||||||
|
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("arms-failed-job", "ERROR", "api", job.shopid, {
|
||||||
|
job: JSON.stringify({ id: job.id, ro_number: job.ro_number }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
const allErrors = [];
|
||||||
|
try {
|
||||||
|
for (const bodyshop of bodyshops) {
|
||||||
|
logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||||
|
shopname: bodyshop.shopname,
|
||||||
|
});
|
||||||
|
const erroredJobs = [];
|
||||||
|
try {
|
||||||
|
const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, {
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
});
|
||||||
|
const jobsToPush = [];
|
||||||
|
|
||||||
if (erroredJobs.length > 0) {
|
if (erroredJobs.length > 0) {
|
||||||
logger.log("arms-failed-jobs", "ERROR", "api", bodyshop.id, {
|
logger.log("arms-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||||
@@ -887,6 +969,7 @@ exports.default = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function GetSupplementNumber(joblines) {
|
function GetSupplementNumber(joblines) {
|
||||||
|
if (!joblines) return 0;
|
||||||
const max = _.max(
|
const max = _.max(
|
||||||
joblines.map((jl) => parseInt((jl.line_ind || "0").replace(/[^\d.-]/g, "")))
|
joblines.map((jl) => parseInt((jl.line_ind || "0").replace(/[^\d.-]/g, "")))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const logger = new graylog2.graylog({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function log(message, type, user, record, object) {
|
function log(message, type, user, record, object) {
|
||||||
if (type !== "ioevent" && type !== "DEBUG")
|
if (type !== "ioevent")
|
||||||
console.log(message, {
|
console.log(message, {
|
||||||
type,
|
type,
|
||||||
env: process.env.NODE_ENV || "development",
|
env: process.env.NODE_ENV || "development",
|
||||||
|
|||||||
@@ -2715,6 +2715,11 @@ node-mailjet@^5.1.0:
|
|||||||
json-bigint "^1.0.0"
|
json-bigint "^1.0.0"
|
||||||
url-join "^4.0.0"
|
url-join "^4.0.0"
|
||||||
|
|
||||||
|
node-persist@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-persist/-/node-persist-3.1.0.tgz#9d4b03950bba70d37d13d3d3551840e25fd17e09"
|
||||||
|
integrity sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw==
|
||||||
|
|
||||||
node-quickbooks@^2.0.39:
|
node-quickbooks@^2.0.39:
|
||||||
version "2.0.39"
|
version "2.0.39"
|
||||||
resolved "https://registry.yarnpkg.com/node-quickbooks/-/node-quickbooks-2.0.39.tgz#a2534d24063e8a0cea5bb80c66b0727c1c942081"
|
resolved "https://registry.yarnpkg.com/node-quickbooks/-/node-quickbooks-2.0.39.tgz#a2534d24063e8a0cea5bb80c66b0727c1c942081"
|
||||||
|
|||||||
Reference in New Issue
Block a user