Compare commits
44 Commits
feature/lo
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8d2dbc2e1 | ||
|
|
595ec72edd | ||
|
|
885a861f1e | ||
|
|
b213e5d54f | ||
|
|
653692b2a5 | ||
|
|
e1e5dda710 | ||
|
|
7f3b1413d7 | ||
|
|
528c68695f | ||
|
|
65a18acdc1 | ||
|
|
930b2791f2 | ||
|
|
1cf5a1fba8 | ||
|
|
83137b2d96 | ||
|
|
5832a5f529 | ||
|
|
f3ee20e89d | ||
|
|
bcd062dffd | ||
|
|
bd8b961bda | ||
|
|
43b6bdb024 | ||
|
|
3dfc6eede2 | ||
|
|
e70c11d4e6 | ||
|
|
abc7262584 | ||
|
|
e10ca9897c | ||
|
|
7e969e32b2 | ||
|
|
6f561e4caa | ||
|
|
97beb14209 | ||
|
|
5568a434b9 | ||
|
|
e92827aeb2 | ||
|
|
ac890bd92b | ||
|
|
0eaf23841a | ||
|
|
82c13eae9e | ||
|
|
708eb3c73f | ||
|
|
cdb8e48f0d | ||
|
|
90600cdff4 | ||
|
|
cdcfea988f | ||
|
|
26f58961a0 | ||
|
|
8daa0ac154 | ||
|
|
76fee429ea | ||
|
|
d1a65530a3 | ||
|
|
4613a93d09 | ||
|
|
faf1d638fb | ||
|
|
55144bd621 | ||
|
|
bbf908e5e1 | ||
|
|
9da126879e | ||
|
|
18fa00785c | ||
|
|
3192e918a4 |
@@ -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
|
||||
@@ -3586,6 +3586,27 @@
|
||||
<folder_node>
|
||||
<name>fields</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>ReceivableCustomField</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>address1</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -4577,6 +4598,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>localmediatoken</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>logo_img_footer_margin</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -31726,6 +31768,27 @@
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>addtorelatedro</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>newnoteplaceholder</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32013,6 +32076,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>note</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>ownr_addr1</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -33470,6 +33554,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>removefrompartsqueue</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>returnpartsorder</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -38625,6 +38730,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>credits_not_received_date_vendorid</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>csi</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -44165,6 +44291,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>notes</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>plate_no</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -4,54 +4,54 @@
|
||||
"private": true,
|
||||
"proxy": "http://localhost:4000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@apollo/client": "^3.6.2",
|
||||
"@asseinfo/react-kanban": "^2.2.0",
|
||||
"@craco/craco": "^6.4.3",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
||||
"@sentry/react": "^6.19.6",
|
||||
"@sentry/tracing": "^6.19.6",
|
||||
"@splitsoftware/splitio-react": "^1.4.0",
|
||||
"@stripe/react-stripe-js": "^1.7.1",
|
||||
"@stripe/stripe-js": "^1.27.0",
|
||||
"@tanem/react-nprogress": "^4.0.12",
|
||||
"antd": "^4.19.5",
|
||||
"@sentry/react": "^6.19.7",
|
||||
"@sentry/tracing": "^6.19.7",
|
||||
"@splitsoftware/splitio-react": "^1.4.1",
|
||||
"@stripe/react-stripe-js": "^1.8.0",
|
||||
"@stripe/stripe-js": "^1.29.0",
|
||||
"@tanem/react-nprogress": "^5.0.0",
|
||||
"antd": "^4.20.5",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"axios": "^0.26.1",
|
||||
"axios": "^0.27.2",
|
||||
"craco-less": "^1.20.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "^16.0.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"enquire-js": "^0.2.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"exifr": "^7.1.3",
|
||||
"firebase": "^9.6.11",
|
||||
"graphql": "^16.3.0",
|
||||
"i18next": "^21.6.16",
|
||||
"firebase": "^9.8.1",
|
||||
"graphql": "^16.5.0",
|
||||
"i18next": "^21.8.2",
|
||||
"i18next-browser-languagedetector": "^6.1.4",
|
||||
"jsoneditor": "^9.7.4",
|
||||
"jsreport-browser-client-dist": "^1.3.0",
|
||||
"libphonenumber-js": "^1.9.51",
|
||||
"logrocket": "^2.2.1",
|
||||
"markerjs2": "^2.21.1",
|
||||
"libphonenumber-js": "^1.9.53",
|
||||
"logrocket": "^3.0.0",
|
||||
"markerjs2": "^2.21.4",
|
||||
"moment-business-days": "^1.2.0",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"normalize-url": "^7.0.3",
|
||||
"phone": "^3.1.15",
|
||||
"phone": "^3.1.17",
|
||||
"preval.macro": "^5.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"rc-queue-anim": "^2.0.0",
|
||||
"rc-scroll-anim": "^2.7.6",
|
||||
"react": "^17.0.2",
|
||||
"react-big-calendar": "^0.38.2",
|
||||
"react-big-calendar": "^0.40.1",
|
||||
"react-color": "^2.19.3",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-drag-listview": "^0.1.9",
|
||||
"react-drag-listview": "^0.2.0",
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^11.16.6",
|
||||
"react-i18next": "^11.16.9",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-number-format": "^4.9.1",
|
||||
"react-number-format": "^4.9.3",
|
||||
"react-redux": "^7.2.8",
|
||||
"react-resizable": "^3.0.4",
|
||||
"react-router-dom": "^5.3.0",
|
||||
@@ -60,28 +60,28 @@
|
||||
"react-sublime-video": "^0.2.5",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"recharts": "^2.1.9",
|
||||
"redux": "^4.1.2",
|
||||
"redux": "^4.2.0",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-state-sync": "^3.1.2",
|
||||
"reselect": "^4.1.5",
|
||||
"sass": "^1.50.0",
|
||||
"socket.io-client": "^4.4.1",
|
||||
"sass": "^1.51.0",
|
||||
"socket.io-client": "^4.5.0",
|
||||
"styled-components": "^5.3.5",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
"web-vitals": "^2.1.4",
|
||||
"workbox-background-sync": "^6.5.2",
|
||||
"workbox-broadcast-update": "^6.5.2",
|
||||
"workbox-cacheable-response": "^6.5.2",
|
||||
"workbox-core": "^6.5.2",
|
||||
"workbox-expiration": "^6.5.2",
|
||||
"workbox-google-analytics": "^6.5.2",
|
||||
"workbox-navigation-preload": "^6.5.2",
|
||||
"workbox-precaching": "^6.5.2",
|
||||
"workbox-range-requests": "^6.5.2",
|
||||
"workbox-routing": "^6.5.2",
|
||||
"workbox-strategies": "^6.5.2",
|
||||
"workbox-streams": "^6.5.2",
|
||||
"workbox-background-sync": "^6.5.3",
|
||||
"workbox-broadcast-update": "^6.5.3",
|
||||
"workbox-cacheable-response": "^6.5.3",
|
||||
"workbox-core": "^6.5.3",
|
||||
"workbox-expiration": "^6.5.3",
|
||||
"workbox-google-analytics": "^6.5.3",
|
||||
"workbox-navigation-preload": "^6.5.3",
|
||||
"workbox-precaching": "^6.5.3",
|
||||
"workbox-range-requests": "^6.5.3",
|
||||
"workbox-routing": "^6.5.3",
|
||||
"workbox-strategies": "^6.5.3",
|
||||
"workbox-streams": "^6.5.3",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -118,11 +118,11 @@
|
||||
"react-error-overlay": "6.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sentry/webpack-plugin": "^1.18.8",
|
||||
"@sentry/webpack-plugin": "^1.18.9",
|
||||
"@testing-library/cypress": "^8.0.2",
|
||||
"cypress": "^9.5.3",
|
||||
"cypress": "^9.6.1",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"react-error-overlay": "6.0.10",
|
||||
"react-error-overlay": "6.0.11",
|
||||
"redux-logger": "^3.0.6",
|
||||
"source-map-explorer": "^2.5.2"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
||||
import BillMarkSelectedExported from "../payable-mark-selected-exported/payable-mark-selected-exported.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -28,7 +29,12 @@ export default connect(
|
||||
mapDispatchToProps
|
||||
)(AccountingPayablesTableComponent);
|
||||
|
||||
export function AccountingPayablesTableComponent({ bodyshop, loading, bills, refetch }) {
|
||||
export function AccountingPayablesTableComponent({
|
||||
bodyshop,
|
||||
loading,
|
||||
bills,
|
||||
refetch,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [selectedBills, setSelectedBills] = useState([]);
|
||||
const [transInProgress, setTransInProgress] = useState(false);
|
||||
@@ -143,15 +149,13 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref
|
||||
sorter: (a, b) => a.clm_total - b.clm_total,
|
||||
|
||||
render: (text, record) => (
|
||||
<div>
|
||||
<PayableExportButton
|
||||
billId={record.id}
|
||||
disabled={transInProgress || !!record.exported}
|
||||
loadingCallback={setTransInProgress}
|
||||
setSelectedBills={setSelectedBills}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</div>
|
||||
<PayableExportButton
|
||||
billId={record.id}
|
||||
disabled={transInProgress || !!record.exported}
|
||||
loadingCallback={setTransInProgress}
|
||||
setSelectedBills={setSelectedBills}
|
||||
refetch={refetch}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -177,6 +181,13 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
<BillMarkSelectedExported
|
||||
billids={selectedBills}
|
||||
disabled={transInProgress || selectedBills.length === 0}
|
||||
loadingCallback={setTransInProgress}
|
||||
completedCallback={setSelectedBills}
|
||||
refetch={refetch}
|
||||
/>
|
||||
<PayableExportAll
|
||||
billids={selectedBills}
|
||||
disabled={transInProgress || selectedBills.length === 0}
|
||||
|
||||
@@ -4,6 +4,7 @@ import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
@@ -14,7 +15,7 @@ import BillDeleteButton from "../bill-delete-button/bill-delete-button.component
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//jobRO: selectJobReadOnly,
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
@@ -29,6 +30,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
export function BillsListTableComponent({
|
||||
bodyshop,
|
||||
jobRO,
|
||||
job,
|
||||
billsQuery,
|
||||
handleOnRowClick,
|
||||
@@ -58,7 +60,9 @@ export function BillsListTableComponent({
|
||||
<BillDeleteButton bill={record} />
|
||||
<Button
|
||||
disabled={
|
||||
record.is_credit_memo || record.vendorid === bodyshop.inhousevendorid
|
||||
record.is_credit_memo ||
|
||||
record.vendorid === bodyshop.inhousevendorid ||
|
||||
jobRO
|
||||
}
|
||||
onClick={() => {
|
||||
setPartsOrderContext({
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function CABCpvrtCalculator({ disabled, form }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("job_ca_bc_pvrt_calculate");
|
||||
form.setFieldsValue({ ca_bc_pvrt: (values.rate * values.days).toFixed(2) });
|
||||
form.setFieldsValue({ ca_bc_pvrt: ((values.rate||0) * (values.days||0)).toFixed(2) });
|
||||
setVisibility(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Button, Card, Input, Space, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
@@ -105,6 +106,17 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
</Link>
|
||||
) : null,
|
||||
},
|
||||
{
|
||||
title: t("contracts.fields.scheduledreturn"),
|
||||
dataIndex: "scheduledreturn",
|
||||
key: "scheduledreturn",
|
||||
render: (text, record) =>
|
||||
record.cccontracts.length === 1 && (
|
||||
<DateTimeFormatter>
|
||||
{record.cccontracts[0].scheduledreturn}
|
||||
</DateTimeFormatter>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
|
||||
@@ -7,8 +7,12 @@ export const handleUpload = async ({ ev, context }) => {
|
||||
const { onError, onSuccess, onProgress, file } = ev;
|
||||
const { jobid, invoice_number, vendorid, callbackAfterUpload } = context;
|
||||
|
||||
const bodyshop = store.getState().user.bodyshop;
|
||||
var options = {
|
||||
headers: { "X-Requested-With": "XMLHttpRequest" },
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
ims_token: bodyshop.localmediatoken,
|
||||
},
|
||||
onUploadProgress: (e) => {
|
||||
if (!!onProgress) onProgress({ percent: (e.loaded / e.total) * 100 });
|
||||
},
|
||||
@@ -22,7 +26,6 @@ export const handleUpload = async ({ ev, context }) => {
|
||||
formData.append("vendorid", vendorid);
|
||||
}
|
||||
formData.append("file", file);
|
||||
const bodyshop = store.getState().user.bodyshop;
|
||||
|
||||
const imexMediaServerResponse = await cleanAxios.post(
|
||||
normalizeUrl(
|
||||
|
||||
@@ -24,7 +24,7 @@ export function JoblinePresetButton({ bodyshop, form }) {
|
||||
const menu = (
|
||||
<Menu>
|
||||
{bodyshop.md_jobline_presets.map((i, idx) => (
|
||||
<Menu.Item onClick={() => handleSelect(i)} key={idx}>
|
||||
<Menu.Item onClick={() => handleSelect(i)} key={idx}>
|
||||
{i.label}
|
||||
</Menu.Item>
|
||||
))}
|
||||
|
||||
@@ -16,15 +16,18 @@ export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<div>
|
||||
<Menu onClick={handleClick}>
|
||||
{bodyshop.md_filehandlers.map((est, idx) => (
|
||||
<Menu.Item value={est} key={idx}>
|
||||
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
<Menu
|
||||
onClick={handleClick}
|
||||
style={{
|
||||
columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1,
|
||||
}}
|
||||
>
|
||||
{bodyshop.md_filehandlers.map((est, idx) => (
|
||||
<Menu.Item value={est} key={idx} style={{ breakInside: "avoid" }}>
|
||||
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -216,6 +216,22 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
<DataLabel label={t("jobs.labels.relatedros")}>
|
||||
<JobsRelatedRos jobid={job.id} job={job} />
|
||||
</DataLabel>
|
||||
{job.vehicle && job.vehicle.notes && (
|
||||
<DataLabel label={t("vehicles.fields.notes")}>
|
||||
<span style={{ whiteSpace: "pre" }}>{job.vehicle.notes}</span>
|
||||
</DataLabel>
|
||||
)}
|
||||
{
|
||||
// job.vehicle && job.vehicle.v_paint_codes && (
|
||||
// <DataLabel label={t("vehicles.fields.v_paint_codes")}>
|
||||
// <span style={{ whiteSpace: "pre" }}>
|
||||
// {Object.keys(job.vehicle.v_paint_codes).map((key, idx) => (
|
||||
// <Tag key={idx}>{job.vehicle.v_paint_codes[key]}</Tag>
|
||||
// ))}
|
||||
// </span>
|
||||
// </DataLabel>
|
||||
// )
|
||||
}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { CreateExplorerLinkForJob } from "../../utils/localmedia";
|
||||
import DocumentsLocalUploadComponent from "../documents-local-upload/documents-local-upload.component";
|
||||
import JobsDocumentsLocalGalleryReassign from "./jobs-documents-local-gallery.reassign.component";
|
||||
import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-gallery.selectall.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -76,6 +77,7 @@ export function JobsDocumentsLocalGallery({
|
||||
<Button>{t("documents.labels.openinexplorer")}</Button>
|
||||
</a>
|
||||
<JobsDocumentsLocalGalleryReassign jobid={job.id} />
|
||||
<JobsDocumentsLocalGallerySelectAllComponent jobid={job.id} />
|
||||
</Space>
|
||||
<Card>
|
||||
<DocumentsLocalUploadComponent
|
||||
|
||||
@@ -39,11 +39,15 @@ export function JobsDocumentsLocalGalleryReassign({
|
||||
setLoading(true);
|
||||
const selectedDocuments = allMedia[jobid].filter((m) => m.isSelected);
|
||||
|
||||
await cleanAxios.post(`${bodyshop.localmediaserverhttp}/jobs/move`, {
|
||||
from_jobid: jobid,
|
||||
jobid: newJobid,
|
||||
files: selectedDocuments.map((f) => f.filename),
|
||||
});
|
||||
await cleanAxios.post(
|
||||
`${bodyshop.localmediaserverhttp}/jobs/move`,
|
||||
{
|
||||
from_jobid: jobid,
|
||||
jobid: newJobid,
|
||||
files: selectedDocuments.map((f) => f.filename),
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
|
||||
getJobMedia(jobid);
|
||||
setVisible(false);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Button, Space } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectAllmediaForJob,
|
||||
deselectAllMediaForJob,
|
||||
} from "../../redux/media/media.actions";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
selectAllmediaForJob: (jobid) => dispatch(selectAllmediaForJob(jobid)),
|
||||
deselectAllmediaForJob: (jobid) => dispatch(deselectAllMediaForJob(jobid)),
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsDocumentsLocalGallerySelectAllComponent);
|
||||
|
||||
export function JobsDocumentsLocalGallerySelectAllComponent({
|
||||
jobid,
|
||||
selectAllmediaForJob,
|
||||
deselectAllmediaForJob,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// onSelectImage={(index, image) => {
|
||||
// toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
// }}
|
||||
|
||||
const handleSelectAll = () => {
|
||||
selectAllmediaForJob({ jobid });
|
||||
};
|
||||
|
||||
const handleDeselectAll = () => {
|
||||
deselectAllmediaForJob({ jobid });
|
||||
};
|
||||
|
||||
return (
|
||||
<Space wrap>
|
||||
<Button onClick={handleSelectAll}>
|
||||
{t("general.actions.selectall")}
|
||||
</Button>
|
||||
|
||||
<Button onClick={handleDeselectAll}>
|
||||
{t("general.actions.deselectall")}
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
@@ -137,9 +137,9 @@ export function JobsList({ bodyshop }) {
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
return record.ownerid ? (
|
||||
<Link
|
||||
to={"/manage/owners/" + record.owner.id}
|
||||
to={"/manage/owners/" + record.ownerid}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
|
||||
@@ -61,6 +61,9 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) {
|
||||
jobId={jobId}
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk.notes : null}
|
||||
relatedRos={
|
||||
data ? data.jobs_by_pk.vehicle && data.jobs_by_pk.vehicle.jobs : null
|
||||
}
|
||||
refetch={refetch}
|
||||
deleteLoading={deleteLoading}
|
||||
handleNoteDelete={handleNoteDelete}
|
||||
|
||||
@@ -37,6 +37,7 @@ export function JobNotesComponent({
|
||||
setNoteUpsertContext,
|
||||
deleteLoading,
|
||||
ro_number,
|
||||
relatedRos,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const Templates = TemplateList("job_special", {
|
||||
@@ -149,6 +150,7 @@ export function JobNotesComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
jobId: jobId,
|
||||
relatedRos: relatedRos,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -1,51 +1,92 @@
|
||||
import { Col, Form, Input, Row, Switch } from "antd";
|
||||
import { Checkbox, Col, Form, Input, Row, Space, Switch, Tag } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectNoteUpsert } from "../../redux/modals/modals.selectors";
|
||||
import NotesPresetButton from "../notes-preset-button/notes-preset-button.component";
|
||||
|
||||
export default function NoteUpsertModalComponent({ form }) {
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
noteUpsertModal: selectNoteUpsert,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(NoteUpsertModalComponent);
|
||||
|
||||
export function NoteUpsertModalComponent({ form, noteUpsertModal }) {
|
||||
const { t } = useTranslation();
|
||||
const { jobId, existingNote, relatedRos } = noteUpsertModal.context;
|
||||
|
||||
const filteredRelatedRos = relatedRos
|
||||
? relatedRos.filter((j) => j.id !== jobId)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.critical")}
|
||||
name="critical"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.private")}
|
||||
name="private"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<NotesPresetButton form={form} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.text")}
|
||||
name="text"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={8}
|
||||
placeholder={t("notes.labels.newnoteplaceholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
<>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.critical")}
|
||||
name="critical"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.private")}
|
||||
name="private"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<NotesPresetButton form={form} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.text")}
|
||||
name="text"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={8}
|
||||
placeholder={t("notes.labels.newnoteplaceholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
<div>
|
||||
<div>{!existingNote && t("notes.labels.addtorelatedro")}</div>
|
||||
{!existingNote &&
|
||||
filteredRelatedRos.map((j, idx) => (
|
||||
<Space key={j.id} align="center">
|
||||
<Form.Item
|
||||
noStyle
|
||||
name={["relatedros", j.id]}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
<Tag>
|
||||
{`${j.ro_number || "N/A"}${j.clm_no ? ` | ${j.clm_no}` : ""}${
|
||||
j.status ? ` | ${j.status}` : ""
|
||||
}`}
|
||||
</Tag>
|
||||
</Space>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||
import { selectNoteUpsert } from "../../redux/modals/modals.selectors";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import NoteUpsertModalComponent from "./note-upsert-modal.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import NoteUpsertModalComponent from "./note-upsert-modal.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -48,7 +48,9 @@ export function NoteUpsertModalContainer({
|
||||
}
|
||||
}, [existingNote, form, visible]);
|
||||
|
||||
const handleFinish = (values) => {
|
||||
const handleFinish = async (formValues) => {
|
||||
const { relatedros, ...values } = formValues;
|
||||
|
||||
if (existingNote) {
|
||||
logImEXEvent("job_note_update");
|
||||
|
||||
@@ -70,24 +72,44 @@ export function NoteUpsertModalContainer({
|
||||
toggleModalVisible();
|
||||
} else {
|
||||
logImEXEvent("job_note_insert");
|
||||
const AdditionalNoteInserts = relatedros
|
||||
? Object.keys(relatedros).filter((key) => relatedros[key])
|
||||
: [];
|
||||
|
||||
insertNote({
|
||||
await insertNote({
|
||||
variables: {
|
||||
noteInput: [
|
||||
{ ...values, jobid: jobId, created_by: currentUser.email },
|
||||
],
|
||||
},
|
||||
}).then((r) => {
|
||||
if (refetch) refetch();
|
||||
form.resetFields();
|
||||
toggleModalVisible();
|
||||
notification["success"]({
|
||||
message: t("notes.successes.create"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: context.jobId,
|
||||
operation: AuditTrailMapping.jobnoteadded(),
|
||||
});
|
||||
|
||||
if (AdditionalNoteInserts.length > 0) {
|
||||
//Insert the others.
|
||||
AdditionalNoteInserts.forEach(async (newJobId) => {
|
||||
await insertNote({
|
||||
variables: {
|
||||
noteInput: [
|
||||
{ ...values, jobid: newJobId, created_by: currentUser.email },
|
||||
],
|
||||
},
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: newJobId,
|
||||
operation: AuditTrailMapping.jobnoteadded(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (refetch) refetch();
|
||||
form.resetFields();
|
||||
toggleModalVisible();
|
||||
notification["success"]({
|
||||
message: t("notes.successes.create"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: context.jobId,
|
||||
operation: AuditTrailMapping.jobnoteadded(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,9 +22,17 @@ export function NotesPresetButton({ bodyshop, form }) {
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<Menu>
|
||||
<Menu
|
||||
style={{
|
||||
columnCount: Math.floor(bodyshop.md_notes_presets.length / 10) + 1,
|
||||
}}
|
||||
>
|
||||
{bodyshop.md_notes_presets.map((i, idx) => (
|
||||
<Menu.Item onClick={() => handleSelect(i)} key={idx}>
|
||||
<Menu.Item
|
||||
onClick={() => handleSelect(i)}
|
||||
key={idx}
|
||||
style={{ breakInside: "avoid" }}
|
||||
>
|
||||
{i.label}
|
||||
</Menu.Item>
|
||||
))}
|
||||
|
||||
@@ -14,7 +14,6 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
||||
return (
|
||||
<div>
|
||||
<FormFieldsChanged form={form} />
|
||||
|
||||
<LayoutFormRow header={t("owners.forms.name")}>
|
||||
<Form.Item label={t("owners.fields.ownr_title")} name="ownr_title">
|
||||
<Input />
|
||||
@@ -29,7 +28,6 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
|
||||
<LayoutFormRow header={t("owners.forms.address")}>
|
||||
<Form.Item label={t("owners.fields.ownr_addr1")} name="ownr_addr1">
|
||||
<Input />
|
||||
@@ -50,7 +48,6 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
|
||||
<LayoutFormRow header={t("owners.forms.contact")}>
|
||||
<Form.Item
|
||||
label={t("owners.fields.allow_text_message")}
|
||||
@@ -98,6 +95,9 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<Form.Item label={t("owners.fields.note")} name="note">
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,14 @@ export default function OwnerFindModalComponent({
|
||||
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("owners.fields.note"),
|
||||
dataIndex: "note",
|
||||
key: "note",
|
||||
render: (text, record) => (
|
||||
<span style={{ whiteSpace: "pre" }}>{record.note}</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Select,
|
||||
Menu,
|
||||
Dropdown,
|
||||
Checkbox,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -114,6 +115,15 @@ export function PartsOrderModalComponent({
|
||||
</Space>
|
||||
</Tag>
|
||||
)}
|
||||
{!isReturn && (
|
||||
<Form.Item
|
||||
name="removefrompartsqueue"
|
||||
label={t("parts_orders.labels.removefrompartsqueue")}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
<Divider orientation="left">
|
||||
{t("parts_orders.labels.inthisorder")}
|
||||
@@ -280,6 +290,7 @@ export function PartsOrderModalComponent({
|
||||
>
|
||||
<Input.TextArea rows={3} />
|
||||
</Form.Item>
|
||||
|
||||
<Radio.Group
|
||||
defaultValue={sendType}
|
||||
onChange={(e) => setSendType(e.target.value)}
|
||||
|
||||
@@ -32,6 +32,7 @@ import PartsOrderModalComponent from "./parts-order-modal.component";
|
||||
import axios from "axios";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
import _ from "lodash";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -90,8 +91,9 @@ export function PartsOrderModalContainer({
|
||||
|
||||
const [insertPartOrder] = useMutation(INSERT_NEW_PARTS_ORDERS);
|
||||
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
const handleFinish = async ({ removefrompartsqueue, ...values }) => {
|
||||
logImEXEvent("parts_order_insert");
|
||||
setSaving(true);
|
||||
const insertResult = await insertPartOrder({
|
||||
@@ -99,6 +101,7 @@ export function PartsOrderModalContainer({
|
||||
po: [
|
||||
{
|
||||
...values,
|
||||
order_date: moment().format("YYYY-MM-DD"),
|
||||
orderedby: currentUser.email,
|
||||
jobid: jobId,
|
||||
user_email: currentUser.email,
|
||||
@@ -128,6 +131,17 @@ export function PartsOrderModalContainer({
|
||||
},
|
||||
});
|
||||
|
||||
if (!isReturn && removefrompartsqueue) {
|
||||
await updateJob({
|
||||
variables: {
|
||||
jobId: jobId,
|
||||
job: {
|
||||
queued_for_parts: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
insertAuditTrail({
|
||||
jobid: jobId,
|
||||
operation: isReturn
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Form, Modal, notification } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -31,7 +31,7 @@ export function PartsReceiveModalContainer({
|
||||
bodyshop,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { visible, context, actions } = partsReceiveModal;
|
||||
const { partsorderlines } = context;
|
||||
|
||||
@@ -42,7 +42,7 @@ export function PartsReceiveModalContainer({
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("parts_order_receive");
|
||||
|
||||
setLoading(true);
|
||||
const result = await Promise.all(
|
||||
values.partsorderlines.map((li) => {
|
||||
return receivePartsLine({
|
||||
@@ -75,7 +75,7 @@ export function PartsReceiveModalContainer({
|
||||
notification["success"]({
|
||||
message: t("parts_orders.successes.received"),
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
if (refetch) refetch();
|
||||
toggleModalVisible();
|
||||
};
|
||||
@@ -96,6 +96,7 @@ export function PartsReceiveModalContainer({
|
||||
title={t("parts_orders.labels.receive")}
|
||||
onCancel={() => toggleModalVisible()}
|
||||
onOk={() => form.submit()}
|
||||
okButtonProps={{ loading: loading }}
|
||||
destroyOnClose
|
||||
forceRender
|
||||
width="50%"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { gql, useMutation } from "@apollo/client";
|
||||
import { Button, notification } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectAuthLevel,
|
||||
selectBodyshop,
|
||||
} from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
authLevel: selectAuthLevel,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(BillMarkSelectedExported);
|
||||
|
||||
export function BillMarkSelectedExported({
|
||||
billids,
|
||||
disabled,
|
||||
loadingCallback,
|
||||
completedCallback,
|
||||
refetch,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [updateBill] = useMutation(gql`
|
||||
mutation UPDATE_BILL($billIds: [uuid!]!) {
|
||||
update_bills(where: { id: { _in: $billIds } }, _set: { exported: true }) {
|
||||
returning {
|
||||
id
|
||||
exported
|
||||
exported_at
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const handleUpdate = async () => {
|
||||
setLoading(true);
|
||||
loadingCallback(true);
|
||||
const result = await updateBill({
|
||||
variables: { billIds: billids },
|
||||
update(cache){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.errors) {
|
||||
notification["success"]({
|
||||
message: t("bills.successes.markexported"),
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("bills.errors.saving", {
|
||||
error: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
loadingCallback(false);
|
||||
completedCallback && completedCallback([]);
|
||||
setLoading(false);
|
||||
refetch && refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
<Button loading={loading} disabled={disabled} onClick={handleUpdate}>
|
||||
{t("bills.labels.markexported")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -42,17 +42,24 @@ export function ProductionColumnsComponent({
|
||||
};
|
||||
|
||||
const columnKeys = columns.map((i) => i.key);
|
||||
|
||||
const cols = dataSource({
|
||||
technician,
|
||||
state: tableState,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
});
|
||||
const menu = (
|
||||
<Menu onClick={handleAdd}>
|
||||
{dataSource({
|
||||
technician,
|
||||
state: tableState,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
})
|
||||
<Menu
|
||||
onClick={handleAdd}
|
||||
style={{
|
||||
columnCount: Math.max(Math.floor(cols.length / 10), 1),
|
||||
}}
|
||||
>
|
||||
{cols
|
||||
.filter((i) => !columnKeys.includes(i.key))
|
||||
.map((item) => (
|
||||
<Menu.Item key={item.key}>{item.title}</Menu.Item>
|
||||
<Menu.Item key={item.key} style={{ breakInside: "avoid" }}>
|
||||
{item.title}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -8,8 +8,11 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import moment from "moment";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import { GET_BLOCKED_DAYS } from "../../graphql/scoreboard.queries";
|
||||
import { useApolloClient, useQuery } from "@apollo/client";
|
||||
import {
|
||||
GET_BLOCKED_DAYS,
|
||||
QUERY_SCOREBOARD,
|
||||
} from "../../graphql/scoreboard.queries";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -22,10 +25,15 @@ export default connect(
|
||||
mapDispatchToProps
|
||||
)(ScoreboardDisplayComponent);
|
||||
|
||||
export function ScoreboardDisplayComponent({
|
||||
bodyshop,
|
||||
scoreboardSubscription,
|
||||
}) {
|
||||
export function ScoreboardDisplayComponent({ bodyshop }) {
|
||||
const scoreboardSubscription = useQuery(QUERY_SCOREBOARD, {
|
||||
variables: {
|
||||
start: moment().startOf("month"),
|
||||
end: moment().endOf("month"),
|
||||
},
|
||||
pollInterval: 60000,
|
||||
});
|
||||
|
||||
const { data } = scoreboardSubscription;
|
||||
const client = useApolloClient();
|
||||
const scoreBoardlist = (data && data.scoreboard) || [];
|
||||
|
||||
@@ -177,6 +177,27 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
|
||||
<Statistic value={values.toDatePaint.toFixed(1)} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(values.todayPaint + values.todayBody).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(values.weeklyPaint + values.weeklyBody).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(values.toDatePaint + values.toDateBody).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
@@ -352,10 +352,27 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["accountingconfig", "ReceivableCustomField1"]}
|
||||
label={t("bodyshop.fields.ReceivableCustomField", { number: 1 })}
|
||||
>
|
||||
{ReceivableCustomFieldSelect}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["accountingconfig", "ReceivableCustomField2"]}
|
||||
label={t("bodyshop.fields.ReceivableCustomField", { number: 2 })}
|
||||
>
|
||||
{ReceivableCustomFieldSelect}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["accountingconfig", "ReceivableCustomField3"]}
|
||||
label={t("bodyshop.fields.ReceivableCustomField", { number: 3 })}
|
||||
>
|
||||
{ReceivableCustomFieldSelect}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["md_classes"]}
|
||||
label={t("bodyshop.fields.md_classes")}
|
||||
dependencies={["enforce_class"]}
|
||||
rules={[
|
||||
({ getFieldValue }) => {
|
||||
return {
|
||||
@@ -603,6 +620,12 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["localmediatoken"]}
|
||||
label={t("bodyshop.fields.localmediatoken")}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
||||
<Form.List name={["md_messaging_presets"]}>
|
||||
@@ -701,7 +724,7 @@ export default function ShopInfoGeneral({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
<Input.TextArea rows={3} />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<DeleteFilled
|
||||
@@ -1469,3 +1492,11 @@ export default function ShopInfoGeneral({ form }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ReceivableCustomFieldSelect = (
|
||||
<Select>
|
||||
<Select.Option value="v_vin">VIN</Select.Option>
|
||||
<Select.Option value="clm_no">Claim No.</Select.Option>
|
||||
<Select.Option value="ded_amt">Deductible Amount</Select.Option>
|
||||
</Select>
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import TechClockInComponent from "./tech-job-clock-in-form.component";
|
||||
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
||||
import moment from "moment";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
@@ -27,14 +28,15 @@ export function TechClockInContainer({ technician, bodyshop }) {
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const theTime = (await axios.post("/utils/time")).data;
|
||||
|
||||
const result = await insertTimeTicket({
|
||||
variables: {
|
||||
timeTicketInput: [
|
||||
{
|
||||
bodyshopid: bodyshop.id,
|
||||
employeeid: technician.id,
|
||||
date: theTime,
|
||||
clockon: theTime,
|
||||
date: moment(theTime).format("YYYY-MM-DD"),
|
||||
clockon: moment(theTime),
|
||||
jobid: values.jobid,
|
||||
cost_center: values.cost_center,
|
||||
ciecacode:
|
||||
|
||||
@@ -55,9 +55,10 @@ export function TechClockOffButton({
|
||||
timeticket: {
|
||||
clockoff: (await axios.post("/utils/time")).data,
|
||||
...values,
|
||||
rate: emps && emps.rates.filter(
|
||||
(r) => r.cost_center === values.cost_center
|
||||
)[0]?.rate,
|
||||
rate:
|
||||
emps &&
|
||||
emps.rates.filter((r) => r.cost_center === values.cost_center)[0]
|
||||
?.rate,
|
||||
ciecacode:
|
||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||
? values.cost_center
|
||||
|
||||
@@ -6,15 +6,20 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import JobLinesContainer from "../job-detail-lines/job-lines.container";
|
||||
import JobsDetailHeader from "../jobs-detail-header/jobs-detail-header.component";
|
||||
import JobsDocumentsGalleryContainer from "../jobs-documents-gallery/jobs-documents-gallery.container";
|
||||
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
import JobNotesContainer from "../jobs-notes/jobs-notes.container";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop });
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPrintCenterContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "printCenter" })),
|
||||
@@ -29,7 +34,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
// },
|
||||
// };
|
||||
|
||||
export function JobDetailCards({ setPrintCenterContext }) {
|
||||
export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
@@ -110,7 +115,13 @@ export function JobDetailCards({ setPrintCenterContext }) {
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="documents" tab={t("jobs.labels.documents")}>
|
||||
<JobsDocumentsGalleryContainer jobId={searchParams.selected} />
|
||||
{bodyshop.uselocalmediaserver ? (
|
||||
<JobsDocumentsLocalGallery
|
||||
job={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
) : (
|
||||
<JobsDocumentsGalleryContainer jobId={searchParams.selected} />
|
||||
)}
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="notes" tab={t("jobs.labels.notes")}>
|
||||
<JobNotesContainer jobId={searchParams.selected} />
|
||||
@@ -121,4 +132,7 @@ export function JobDetailCards({ setPrintCenterContext }) {
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(JobDetailCards);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TechLookupJobsDrawer);
|
||||
|
||||
@@ -139,6 +139,9 @@ export default function VehicleDetailFormComponent({ form, loading }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<Form.Item label={t("vehicles.fields.notes")} name="notes">
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
uselocalmediaserver
|
||||
localmediaserverhttp
|
||||
localmediaservernetwork
|
||||
localmediatoken
|
||||
employees {
|
||||
user_email
|
||||
id
|
||||
@@ -218,6 +219,7 @@ export const UPDATE_SHOP = gql`
|
||||
uselocalmediaserver
|
||||
localmediaserverhttp
|
||||
localmediaservernetwork
|
||||
localmediatoken
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -86,6 +86,7 @@ export const QUERY_ALL_CC = gql`
|
||||
limit: 1
|
||||
) {
|
||||
id
|
||||
scheduledreturn
|
||||
job {
|
||||
id
|
||||
ro_number
|
||||
|
||||
@@ -12,6 +12,7 @@ export const QUERY_ALL_ACTIVE_JOBS = gql`
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
ownerid
|
||||
comment
|
||||
plate_no
|
||||
plate_st
|
||||
@@ -75,13 +76,9 @@ export const QUERY_PARTS_QUEUE = gql`
|
||||
v_make_desc
|
||||
v_color
|
||||
vehicleid
|
||||
actual_completion
|
||||
actual_delivery
|
||||
actual_in
|
||||
scheduled_in
|
||||
id
|
||||
clm_no
|
||||
clm_total
|
||||
owner_owing
|
||||
ro_number
|
||||
status
|
||||
updated_at
|
||||
@@ -534,6 +531,8 @@ export const GET_JOB_BY_PK = gql`
|
||||
v_model_desc
|
||||
v_make_desc
|
||||
v_color
|
||||
notes
|
||||
v_paint_codes
|
||||
jobs {
|
||||
id
|
||||
ro_number
|
||||
@@ -870,6 +869,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
v_model_desc
|
||||
v_color
|
||||
plate_no
|
||||
notes
|
||||
jobs {
|
||||
id
|
||||
clm_no
|
||||
|
||||
@@ -15,6 +15,14 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
vehicle{
|
||||
jobs{
|
||||
id
|
||||
ro_number
|
||||
status
|
||||
clm_no
|
||||
}
|
||||
}
|
||||
notes {
|
||||
created_at
|
||||
created_by
|
||||
|
||||
@@ -15,6 +15,7 @@ export const QUERY_SEARCH_OWNER_BY_IDX = gql`
|
||||
ownr_st
|
||||
ownr_zip
|
||||
id
|
||||
note
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -65,6 +66,7 @@ export const QUERY_OWNER_BY_ID = gql`
|
||||
ownr_title
|
||||
ownr_zip
|
||||
preferred_contact
|
||||
note
|
||||
jobs {
|
||||
id
|
||||
ro_number
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { gql } from "@apollo/client";
|
||||
|
||||
export const SUBSCRIPTION_SCOREBOARD = gql`
|
||||
subscription SUBSCRIPTION_SCOREBOARD($start: date!, $end: date!) {
|
||||
export const QUERY_SCOREBOARD = gql`
|
||||
query QUERY_SCOREBOARD($start: date!, $end: date!) {
|
||||
scoreboard(
|
||||
where: { _and: { date: { _gte: $start, _lte: $end } } }
|
||||
order_by: { date: asc }
|
||||
|
||||
@@ -27,6 +27,7 @@ export const QUERY_VEHICLE_BY_ID = gql`
|
||||
v_bstyle
|
||||
updated_at
|
||||
trim_color
|
||||
notes
|
||||
jobs {
|
||||
id
|
||||
ro_number
|
||||
|
||||
@@ -15,7 +15,7 @@ import OwnerNameDisplay from "../../components/owner-name-display/owner-name-dis
|
||||
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { onlyUnique } from "../../utils/arrayHelper";
|
||||
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||
import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -158,6 +158,17 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: t("jobs.fields.scheduled_in"),
|
||||
dataIndex: "scheduled_in",
|
||||
key: "scheduled_in",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => dateSort(a.scheduled_in, b.scheduled_in),
|
||||
sortOrder: sortcolumn === "scheduled_in" && sortorder,
|
||||
render: (text, record) => (
|
||||
<DateTimeFormatter>{record.scheduled_in}</DateTimeFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
@@ -194,13 +205,6 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||
sortOrder: sortcolumn === "clm_no" && sortorder,
|
||||
render: (text, record) => {
|
||||
return record.clm_no ? (
|
||||
<span>{record.clm_no}</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: t("jobs.fields.clm_total"),
|
||||
|
||||
@@ -160,6 +160,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete searchParams.search;
|
||||
searchParams.page = 1;
|
||||
history.push({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
>
|
||||
@@ -177,6 +178,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
placeholder={searchParams.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
searchParams.search = value;
|
||||
searchParams.page = 1;
|
||||
history.push({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -2,17 +2,14 @@ import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
|
||||
import {
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
} from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
|
||||
import { useSubscription } from "@apollo/client";
|
||||
import { SUBSCRIPTION_SCOREBOARD } from "../../graphql/scoreboard.queries";
|
||||
import moment from "moment";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -26,13 +23,6 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const scoreboardSubscription = useSubscription(SUBSCRIPTION_SCOREBOARD, {
|
||||
variables: {
|
||||
start: moment().startOf("month"),
|
||||
end: moment().endOf("month"),
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.scoreboard");
|
||||
setSelectedHeader("scoreboard");
|
||||
@@ -47,7 +37,7 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
return (
|
||||
<FeatureWrapper featureName="scoreboard">
|
||||
<RbacWrapper action="scoreboard:view">
|
||||
<ScoreboardDisplay scoreboardSubscription={scoreboardSubscription} />
|
||||
<ScoreboardDisplay />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
|
||||
@@ -32,3 +32,13 @@ export const toggleMediaSelected = ({ jobid, filename }) => ({
|
||||
type: MediaActionTypes.TOGGLE_MEDIA_SELECTED,
|
||||
payload: { jobid, filename },
|
||||
});
|
||||
|
||||
export const deselectAllMediaForJob = ({ jobid }) => ({
|
||||
type: MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: { jobid },
|
||||
});
|
||||
|
||||
export const selectAllmediaForJob = ({ jobid }) => ({
|
||||
type: MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: { jobid },
|
||||
});
|
||||
|
||||
@@ -26,6 +26,23 @@ const mediaReducer = (state = INITIAL_STATE, action) => {
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = true;
|
||||
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = false;
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -9,22 +9,23 @@ export function* onSetJobMedia() {
|
||||
}
|
||||
export function* getJobMedia({ payload: jobid }) {
|
||||
try {
|
||||
const localmediaserverhttp = (yield select(
|
||||
(state) => state.user.bodyshop.localmediaserverhttp
|
||||
)).trim();
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const imagesFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/jobs/list`,
|
||||
{
|
||||
jobid,
|
||||
}
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/bills/list`,
|
||||
{
|
||||
jobid,
|
||||
}
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
|
||||
yield put(
|
||||
@@ -66,9 +67,8 @@ export function* onSetBillMedia() {
|
||||
}
|
||||
export function* getBillMedia({ payload: { jobid, invoice_number } }) {
|
||||
try {
|
||||
const localmediaserverhttp = (yield select(
|
||||
(state) => state.user.bodyshop.localmediaserverhttp
|
||||
)).trim();
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
@@ -76,7 +76,8 @@ export function* getBillMedia({ payload: { jobid, invoice_number } }) {
|
||||
{
|
||||
jobid,
|
||||
invoice_number,
|
||||
}
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
|
||||
yield put(
|
||||
|
||||
@@ -4,9 +4,8 @@ const MediaActionTypes = {
|
||||
GET_MEDIA_FOR_JOB_ERROR: "GET_MEDIA_FOR_JOB_ERROR",
|
||||
ADD_MEDIA_FOR_JOB: "ADD_MEDIA_FOR_JOB",
|
||||
TOGGLE_MEDIA_SELECTED: "TOGGLE_MEDIA_SELECTED",
|
||||
POST_MEDIA_FOR_JOB: "POST_MEDIA_FOR_JOB",
|
||||
POST_MEDIA_FOR_JOB_SUCCESS: "POST_MEDIA_FOR_JOB_SUCCESS",
|
||||
POST_MEDIA_FOR_JOB_ERROR: "POST_MEDIA_FOR_JOB_ERROR",
|
||||
GET_MEDIA_FOR_BILL: "GET_MEDIA_FOR_BILL",
|
||||
SELECT_ALL_MEDIA_FOR_JOB: "SELECT_ALL_MEDIA_FOR_JOB",
|
||||
DESELECT_ALL_MEDIA_FOR_JOB: "DESELECT_ALL_MEDIA_FOR_JOB",
|
||||
};
|
||||
export default MediaActionTypes;
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
"saving": "Error encountered while saving. {{message}}"
|
||||
},
|
||||
"fields": {
|
||||
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
|
||||
"address1": "Address 1",
|
||||
"address2": "Address 2",
|
||||
"appt_alt_transport": "Appointment Alternative Transportation Options",
|
||||
@@ -284,6 +285,7 @@
|
||||
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
||||
"localmediaserverhttp": "Local Media Server - HTTP Path",
|
||||
"localmediaservernetwork": "Local Media Server - Network Path",
|
||||
"localmediatoken": "Local Media Server - Token",
|
||||
"logo_img_footer_margin": "Footer Margin (px)",
|
||||
"logo_img_header_margin": "Header Margin (px)",
|
||||
"logo_img_path": "Shop Logo",
|
||||
@@ -1864,6 +1866,7 @@
|
||||
"updatedat": "Updated At"
|
||||
},
|
||||
"labels": {
|
||||
"addtorelatedro": "Add to Related ROs",
|
||||
"newnoteplaceholder": "Add a note...",
|
||||
"notetoadd": "Note to Add"
|
||||
},
|
||||
@@ -1890,6 +1893,7 @@
|
||||
"address": "Address",
|
||||
"allow_text_message": "Permission to Text?",
|
||||
"name": "Name",
|
||||
"note": "Owner Note",
|
||||
"ownr_addr1": "Address",
|
||||
"ownr_addr2": "Address 2",
|
||||
"ownr_city": "City",
|
||||
@@ -1977,6 +1981,7 @@
|
||||
"parts_orders": "Parts Orders",
|
||||
"print": "Show Printed Form",
|
||||
"receive": "Receive Parts Order",
|
||||
"removefrompartsqueue": "Remove from Parts Queue?",
|
||||
"returnpartsorder": "Return Parts Order"
|
||||
},
|
||||
"successes": {
|
||||
@@ -2300,6 +2305,7 @@
|
||||
"attendance_employee": "Employee Attendance",
|
||||
"attendance_summary": "Attendance Summary (All Employees)",
|
||||
"credits_not_received_date": "Credits not Received by Date",
|
||||
"credits_not_received_date_vendorid": "Credits not Received by Vendor",
|
||||
"csi": "CSI Responses",
|
||||
"estimates_written_converted": "Estimates Written/Converted",
|
||||
"estimator_detail": "Jobs by Estimator (Detail)",
|
||||
@@ -2629,6 +2635,7 @@
|
||||
},
|
||||
"fields": {
|
||||
"description": "Vehicle Description",
|
||||
"notes": "Vehicle Notes",
|
||||
"plate_no": "License Plate",
|
||||
"plate_st": "Plate Jurisdiction",
|
||||
"trim_color": "Trim Color",
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
"saving": ""
|
||||
},
|
||||
"fields": {
|
||||
"ReceivableCustomField": "",
|
||||
"address1": "",
|
||||
"address2": "",
|
||||
"appt_alt_transport": "",
|
||||
@@ -284,6 +285,7 @@
|
||||
"lastnumberworkingdays": "",
|
||||
"localmediaserverhttp": "",
|
||||
"localmediaservernetwork": "",
|
||||
"localmediatoken": "",
|
||||
"logo_img_footer_margin": "",
|
||||
"logo_img_header_margin": "",
|
||||
"logo_img_path": "",
|
||||
@@ -1864,6 +1866,7 @@
|
||||
"updatedat": "Actualizado en"
|
||||
},
|
||||
"labels": {
|
||||
"addtorelatedro": "",
|
||||
"newnoteplaceholder": "Agrega una nota...",
|
||||
"notetoadd": ""
|
||||
},
|
||||
@@ -1890,6 +1893,7 @@
|
||||
"address": "Dirección",
|
||||
"allow_text_message": "Permiso de texto?",
|
||||
"name": "Nombre",
|
||||
"note": "",
|
||||
"ownr_addr1": "Dirección",
|
||||
"ownr_addr2": "Dirección 2",
|
||||
"ownr_city": "ciudad",
|
||||
@@ -1977,6 +1981,7 @@
|
||||
"parts_orders": "",
|
||||
"print": "Mostrar formulario impreso",
|
||||
"receive": "",
|
||||
"removefrompartsqueue": "",
|
||||
"returnpartsorder": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -2300,6 +2305,7 @@
|
||||
"attendance_employee": "",
|
||||
"attendance_summary": "",
|
||||
"credits_not_received_date": "",
|
||||
"credits_not_received_date_vendorid": "",
|
||||
"csi": "",
|
||||
"estimates_written_converted": "",
|
||||
"estimator_detail": "",
|
||||
@@ -2629,6 +2635,7 @@
|
||||
},
|
||||
"fields": {
|
||||
"description": "Descripcion del vehiculo",
|
||||
"notes": "",
|
||||
"plate_no": "Placa",
|
||||
"plate_st": "Jurisdicción de placas",
|
||||
"trim_color": "Recortar color",
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
"saving": ""
|
||||
},
|
||||
"fields": {
|
||||
"ReceivableCustomField": "",
|
||||
"address1": "",
|
||||
"address2": "",
|
||||
"appt_alt_transport": "",
|
||||
@@ -284,6 +285,7 @@
|
||||
"lastnumberworkingdays": "",
|
||||
"localmediaserverhttp": "",
|
||||
"localmediaservernetwork": "",
|
||||
"localmediatoken": "",
|
||||
"logo_img_footer_margin": "",
|
||||
"logo_img_header_margin": "",
|
||||
"logo_img_path": "",
|
||||
@@ -1864,6 +1866,7 @@
|
||||
"updatedat": "Mis à jour à"
|
||||
},
|
||||
"labels": {
|
||||
"addtorelatedro": "",
|
||||
"newnoteplaceholder": "Ajouter une note...",
|
||||
"notetoadd": ""
|
||||
},
|
||||
@@ -1890,6 +1893,7 @@
|
||||
"address": "Adresse",
|
||||
"allow_text_message": "Autorisation de texte?",
|
||||
"name": "Prénom",
|
||||
"note": "",
|
||||
"ownr_addr1": "Adresse",
|
||||
"ownr_addr2": "Adresse 2 ",
|
||||
"ownr_city": "Ville",
|
||||
@@ -1977,6 +1981,7 @@
|
||||
"parts_orders": "",
|
||||
"print": "Afficher le formulaire imprimé",
|
||||
"receive": "",
|
||||
"removefrompartsqueue": "",
|
||||
"returnpartsorder": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -2300,6 +2305,7 @@
|
||||
"attendance_employee": "",
|
||||
"attendance_summary": "",
|
||||
"credits_not_received_date": "",
|
||||
"credits_not_received_date_vendorid": "",
|
||||
"csi": "",
|
||||
"estimates_written_converted": "",
|
||||
"estimator_detail": "",
|
||||
@@ -2629,6 +2635,7 @@
|
||||
},
|
||||
"fields": {
|
||||
"description": "Description du véhicule",
|
||||
"notes": "",
|
||||
"plate_no": "Plaque d'immatriculation",
|
||||
"plate_st": "Juridiction de la plaque",
|
||||
"trim_color": "Couleur de garniture",
|
||||
|
||||
@@ -6,10 +6,10 @@ import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
import { getMainDefinition } from "@apollo/client/utilities";
|
||||
//import { split } from "apollo-link";
|
||||
import apolloLogger from "apollo-link-logger";
|
||||
import axios from "axios";
|
||||
//import axios from "axios";
|
||||
import { auth } from "../firebase/firebase.utils";
|
||||
import errorLink from "../graphql/apollo-error-handling";
|
||||
import { store } from "../redux/store";
|
||||
//import { store } from "../redux/store";
|
||||
const httpLink = new HttpLink({
|
||||
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT,
|
||||
});
|
||||
@@ -48,25 +48,25 @@ const roundTripLink = new ApolloLink((operation, forward) => {
|
||||
});
|
||||
|
||||
const TrackExecutionTime = async (operationName, time) => {
|
||||
if (process.env.NODE_ENV === "development") return;
|
||||
const rdxStore = store.getState();
|
||||
try {
|
||||
axios.post("/ioevent", {
|
||||
operationName,
|
||||
time,
|
||||
dbevent: true,
|
||||
user:
|
||||
rdxStore.user &&
|
||||
rdxStore.user.currentUser &&
|
||||
rdxStore.user.currentUser.email,
|
||||
imexshopid:
|
||||
rdxStore.user &&
|
||||
rdxStore.user.bodyshop &&
|
||||
rdxStore.user.bodyshop.imexshopid,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("IOEvent Error", error);
|
||||
}
|
||||
// if (process.env.NODE_ENV === "development") return;
|
||||
// const rdxStore = store.getState();
|
||||
// try {
|
||||
// axios.post("/ioevent", {
|
||||
// operationName,
|
||||
// time,
|
||||
// dbevent: true,
|
||||
// user:
|
||||
// rdxStore.user &&
|
||||
// rdxStore.user.currentUser &&
|
||||
// rdxStore.user.currentUser.email,
|
||||
// imexshopid:
|
||||
// rdxStore.user &&
|
||||
// rdxStore.user.bodyshop &&
|
||||
// rdxStore.user.bodyshop.imexshopid,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// console.log("IOEvent Error", error);
|
||||
// }
|
||||
};
|
||||
|
||||
const subscriptionMiddleware = {
|
||||
|
||||
@@ -1510,6 +1510,22 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
credits_not_received_date_vendorid: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.credits_not_received_date_vendorid"
|
||||
),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.credits_not_received_date_vendorid"
|
||||
),
|
||||
key: "credits_not_received_date_vendorid",
|
||||
idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
group: "purchases",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "courtesycarcontract"
|
||||
|
||||
@@ -2,5 +2,5 @@ import { store } from "../redux/store";
|
||||
|
||||
export function CreateExplorerLinkForJob({ jobid }) {
|
||||
const bodyshop = store.getState().user.bodyshop;
|
||||
return `imexmedia://${bodyshop.localmediaservernetwork}/Jobs/${jobid}`;
|
||||
return `imexmedia://${bodyshop.localmediaservernetwork}\\Jobs\\${jobid}`;
|
||||
}
|
||||
|
||||
1264
client/yarn.lock
1264
client/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -837,6 +837,7 @@
|
||||
- last_name_first
|
||||
- localmediaserverhttp
|
||||
- localmediaservernetwork
|
||||
- localmediatoken
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
@@ -927,6 +928,7 @@
|
||||
- last_name_first
|
||||
- localmediaserverhttp
|
||||
- localmediaservernetwork
|
||||
- localmediatoken
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
@@ -3821,32 +3823,36 @@
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- id
|
||||
- accountingid
|
||||
- allow_text_message
|
||||
- created_at
|
||||
- updated_at
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- id
|
||||
- note
|
||||
- ownr_addr1
|
||||
- ownr_addr2
|
||||
- ownr_city
|
||||
- ownr_st
|
||||
- ownr_zip
|
||||
- ownr_co_nm
|
||||
- ownr_ctry
|
||||
- ownr_ea
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ownr_ph1
|
||||
- preferred_contact
|
||||
- allow_text_message
|
||||
- shopid
|
||||
- ownr_ph2
|
||||
- ownr_co_nm
|
||||
- ownr_st
|
||||
- ownr_title
|
||||
- accountingid
|
||||
- ownr_zip
|
||||
- preferred_contact
|
||||
- shopid
|
||||
- updated_at
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- allow_text_message
|
||||
- accountingid
|
||||
- allow_text_message
|
||||
- created_at
|
||||
- id
|
||||
- note
|
||||
- ownr_addr1
|
||||
- ownr_addr2
|
||||
- ownr_city
|
||||
@@ -3861,10 +3867,8 @@
|
||||
- ownr_title
|
||||
- ownr_zip
|
||||
- preferred_contact
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- shopid
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
@@ -3879,8 +3883,11 @@
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- allow_text_message
|
||||
- accountingid
|
||||
- allow_text_message
|
||||
- created_at
|
||||
- id
|
||||
- note
|
||||
- ownr_addr1
|
||||
- ownr_addr2
|
||||
- ownr_city
|
||||
@@ -3895,10 +3902,8 @@
|
||||
- ownr_title
|
||||
- ownr_zip
|
||||
- preferred_contact
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- shopid
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
@@ -4923,60 +4928,62 @@
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- v_vin
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_color
|
||||
- v_paint_codes
|
||||
- v_bstyle
|
||||
- v_engine
|
||||
- shopid
|
||||
- db_v_code
|
||||
- id
|
||||
- notes
|
||||
- plate_no
|
||||
- plate_st
|
||||
- v_cond
|
||||
- v_prod_dt
|
||||
- v_type
|
||||
- v_trimcode
|
||||
- shopid
|
||||
- trim_color
|
||||
- v_mldgcode
|
||||
- v_options
|
||||
- v_tone
|
||||
- v_stage
|
||||
- updated_at
|
||||
- v_bstyle
|
||||
- v_color
|
||||
- v_cond
|
||||
- v_engine
|
||||
- v_make_desc
|
||||
- v_makecode
|
||||
- v_mldgcode
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_options
|
||||
- v_paint_codes
|
||||
- v_prod_dt
|
||||
- v_stage
|
||||
- v_tone
|
||||
- v_trimcode
|
||||
- v_type
|
||||
- v_vin
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- v_paint_codes
|
||||
- created_at
|
||||
- db_v_code
|
||||
- id
|
||||
- notes
|
||||
- plate_no
|
||||
- plate_st
|
||||
- shopid
|
||||
- trim_color
|
||||
- updated_at
|
||||
- v_bstyle
|
||||
- v_color
|
||||
- v_cond
|
||||
- v_engine
|
||||
- v_makecode
|
||||
- v_make_desc
|
||||
- v_makecode
|
||||
- v_mldgcode
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_options
|
||||
- v_paint_codes
|
||||
- v_prod_dt
|
||||
- v_stage
|
||||
- v_tone
|
||||
- v_trimcode
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- shopid
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
@@ -4991,31 +4998,32 @@
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- v_paint_codes
|
||||
- created_at
|
||||
- db_v_code
|
||||
- id
|
||||
- notes
|
||||
- plate_no
|
||||
- plate_st
|
||||
- shopid
|
||||
- trim_color
|
||||
- updated_at
|
||||
- v_bstyle
|
||||
- v_color
|
||||
- v_cond
|
||||
- v_engine
|
||||
- v_makecode
|
||||
- v_make_desc
|
||||
- v_makecode
|
||||
- v_mldgcode
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_options
|
||||
- v_paint_codes
|
||||
- v_prod_dt
|
||||
- v_stage
|
||||
- v_tone
|
||||
- v_trimcode
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- shopid
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."bodyshops" add column "localmediatoken" text
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."bodyshops" add column "localmediatoken" text
|
||||
null;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."vehicles" add column "notes" text
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."vehicles" add column "notes" text
|
||||
null;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."owners" add column "note" text
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."owners" add column "note" text
|
||||
null;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
64297
logs/oAuthClient-log.log
64297
logs/oAuthClient-log.log
File diff suppressed because one or more lines are too long
9612
package-lock.json
generated
9612
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@@ -3,8 +3,8 @@
|
||||
"version": "0.0.1",
|
||||
"license": "UNLICENSED",
|
||||
"engines": {
|
||||
"node": "16.15.0",
|
||||
"npm": "7.17.0"
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"setup": "yarn && cd client && yarn",
|
||||
@@ -17,21 +17,21 @@
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.1116.0",
|
||||
"axios": "^0.24.0",
|
||||
"aws-sdk": "^2.1136.0",
|
||||
"axios": "^0.27.2",
|
||||
"bluebird": "^3.7.2",
|
||||
"body-parser": "^1.20.0",
|
||||
"cloudinary": "^1.29.1",
|
||||
"cloudinary": "^1.30.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"csrf": "^3.1.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "10.0.0",
|
||||
"express": "^4.17.3",
|
||||
"firebase-admin": "^10.0.2",
|
||||
"graphql": "^16.3.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"dotenv": "16.0.1",
|
||||
"express": "^4.18.1",
|
||||
"firebase-admin": "^10.2.0",
|
||||
"graphql": "^16.5.0",
|
||||
"graphql-request": "^4.2.0",
|
||||
"graylog2": "^0.2.1",
|
||||
"inline-css": "^3.0.0",
|
||||
"intuit-oauth": "^4.0.0",
|
||||
@@ -40,16 +40,16 @@
|
||||
"moment": "^2.29.3",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"multer": "^1.4.4",
|
||||
"node-mailjet": "^3.3.10",
|
||||
"node-mailjet": "^3.4.1",
|
||||
"node-quickbooks": "^2.0.39",
|
||||
"nodemailer": "^6.7.3",
|
||||
"phone": "^3.1.15",
|
||||
"nodemailer": "^6.7.5",
|
||||
"phone": "^3.1.17",
|
||||
"query-string": "^7.1.1",
|
||||
"soap": "^0.43.0",
|
||||
"socket.io": "^4.4.1",
|
||||
"socket.io": "^4.5.0",
|
||||
"ssh2-sftp-client": "^8.0.0",
|
||||
"stripe": "^8.217.0",
|
||||
"twilio": "^3.76.1",
|
||||
"stripe": "^9.1.0",
|
||||
"twilio": "^3.77.0",
|
||||
"uuid": "^8.3.2",
|
||||
"xml2js": "^0.4.23",
|
||||
"xmlbuilder2": "^3.0.2"
|
||||
|
||||
@@ -147,7 +147,7 @@ exports.default = async (req, res) => {
|
||||
res.status(200).json(ret);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.log("qbo-payable-create-error", "ERROR", req.user.email, { error });
|
||||
logger.log("qbo-payable-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack });
|
||||
res.status(400).json(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,6 +179,7 @@ exports.default = async (req, res) => {
|
||||
ret.push({ paymentid: payment.id, success: true });
|
||||
} catch (error) {
|
||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, {
|
||||
|
||||
error:
|
||||
(error && error.authResponse && error.authResponse.body) ||
|
||||
(error && error.message),
|
||||
@@ -216,7 +217,7 @@ exports.default = async (req, res) => {
|
||||
res.status(200).json(ret);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, { error });
|
||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, { error: error.message, stack: error.stack });
|
||||
res.status(400).json(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -197,7 +197,8 @@ exports.default = async (req, res) => {
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.log("qbo-receivable-create-error", "ERROR", req.user.email, {
|
||||
error,
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
res.status(400).json(error);
|
||||
}
|
||||
@@ -503,7 +504,38 @@ async function InsertInvoice(
|
||||
bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && {
|
||||
DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid },
|
||||
}),
|
||||
|
||||
CustomField: [
|
||||
...(bodyshop.accountingconfig.ReceivableCustomField1
|
||||
? [
|
||||
{
|
||||
DefinitionId: "1",
|
||||
StringValue:
|
||||
job[bodyshop.accountingconfig.ReceivableCustomField1],
|
||||
Type: "StringType",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(bodyshop.accountingconfig.ReceivableCustomField2
|
||||
? [
|
||||
{
|
||||
DefinitionId: "2",
|
||||
StringValue:
|
||||
job[bodyshop.accountingconfig.ReceivableCustomField2],
|
||||
Type: "StringType",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(bodyshop.accountingconfig.ReceivableCustomField3
|
||||
? [
|
||||
{
|
||||
DefinitionId: "3",
|
||||
StringValue:
|
||||
job[bodyshop.accountingconfig.ReceivableCustomField3],
|
||||
Type: "StringType",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
...(bodyshop.accountingconfig &&
|
||||
bodyshop.accountingconfig.qbo &&
|
||||
bodyshop.accountingconfig.qbo_usa &&
|
||||
|
||||
@@ -57,7 +57,7 @@ exports.default = async (req, res) => {
|
||||
"ERROR",
|
||||
req.user.email,
|
||||
req.body.billsToQuery,
|
||||
{ error }
|
||||
{ error: error.message, stack: error.stack }
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ exports.default = async (req, res) => {
|
||||
"error",
|
||||
req.user.email,
|
||||
req.body.paymentsToQuery,
|
||||
error
|
||||
{ error: error.message, stack: error.stack }
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ exports.default = async (req, res) => {
|
||||
"error",
|
||||
req.user.email,
|
||||
req.body.jobIds,
|
||||
{ error: error }
|
||||
{ error: error.message, stack: error.stack }
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
|
||||
@@ -800,7 +800,7 @@ const CreateCosts = (job) => {
|
||||
};
|
||||
|
||||
const StatusMapping = (status, md_ro_statuses) => {
|
||||
//EST, SCH, ARR, IPR, RDY, DEL, CLO, CAN, UNDEFINED.
|
||||
//Possible return statuses EST, SCH, ARR, IPR, RDY, DEL, CLO, CAN, UNDEFINED.
|
||||
const {
|
||||
default_imported,
|
||||
default_open,
|
||||
@@ -823,8 +823,6 @@ const StatusMapping = (status, md_ro_statuses) => {
|
||||
else if (status === default_void) return "VOID";
|
||||
else if (md_ro_statuses.production_statuses.includes(status)) return "IPR";
|
||||
else return "UNDEFINED";
|
||||
|
||||
// default: return "UNDEFINED"
|
||||
};
|
||||
|
||||
const GenerateDetailLines = (job, line, statuses) => {
|
||||
|
||||
@@ -139,6 +139,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
jobs(where: {id: {_in: $ids}}) {
|
||||
id
|
||||
job_totals
|
||||
ded_amt
|
||||
date_invoiced
|
||||
ro_number
|
||||
clm_total
|
||||
@@ -459,6 +460,7 @@ exports.QUERY_PAYMENTS_FOR_EXPORT = `
|
||||
md_responsibility_centers
|
||||
accountingconfig
|
||||
timezone
|
||||
md_ins_cos
|
||||
}
|
||||
payments(where: {id: {_in: $payments}}) {
|
||||
id
|
||||
@@ -486,6 +488,7 @@ exports.QUERY_PAYMENTS_FOR_EXPORT = `
|
||||
bodyshop{
|
||||
accountingconfig
|
||||
md_responsibility_centers
|
||||
md_ins_cos
|
||||
}
|
||||
}
|
||||
transactionid
|
||||
@@ -914,7 +917,10 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
|
||||
est_co_nm
|
||||
est_ct_fn
|
||||
est_ct_ln
|
||||
|
||||
vehicle{
|
||||
id
|
||||
notes
|
||||
}
|
||||
est_ph1
|
||||
est_ea
|
||||
selling_dealer
|
||||
|
||||
Reference in New Issue
Block a user