Compare commits
23 Commits
release/20
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61e6511547 | ||
|
|
85346e203b | ||
|
|
c565e2199d | ||
|
|
8fa0946cfa | ||
|
|
a1ab254d6f | ||
|
|
99d3943955 | ||
|
|
2415b4c2b4 | ||
|
|
99c7ba1fbc | ||
|
|
36e593f806 | ||
|
|
d825c04850 | ||
|
|
ca7dfacec4 | ||
|
|
1138540518 | ||
|
|
59db305cb8 | ||
|
|
fea69fe3a5 | ||
|
|
43e4ff911e | ||
|
|
ae4cff98e7 | ||
|
|
3650cacb51 | ||
|
|
c2bf6841e1 | ||
|
|
f41b94d16d | ||
|
|
24da0207e5 | ||
|
|
bf34765e6b | ||
|
|
4c98a347f5 | ||
|
|
840e760619 |
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"eslint.workingDirectories": ["./client", "./"],
|
||||
"xml.fileAssociations": [
|
||||
{
|
||||
"pattern": "**/Test.xml",
|
||||
|
||||
13
README.MD
13
README.MD
@@ -1,14 +1,3 @@
|
||||
Yarn Dependency Management:
|
||||
To force upgrades for some packages:
|
||||
yarn upgrade-interactive --latest
|
||||
|
||||
To Start Hasura CLI:
|
||||
npx hasura console
|
||||
|
||||
Migrating to Staging:
|
||||
npx hasura migrate apply --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||
npx hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret 'Test-ImEXOnlineBySnaptSoftware!'
|
||||
|
||||
NGROK TEsting:
|
||||
./ngrok.exe http http://localhost:4000 -host-header="localhost:4000"
|
||||
|
||||
@@ -21,4 +10,4 @@ hasura migrate apply --version "1620771761757" --skip-execution --endpoint https
|
||||
hasura migrate status --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||
|
||||
Generate the license file:
|
||||
$ generate-license-file --input package.json --output third-party-licenses.txt --overwrite
|
||||
$ generate-license-file --input package.json --output third-party-licenses.txt --overwrite
|
||||
@@ -4339,6 +4339,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>dms_control_override</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>dms_wip_acctnumber</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -42140,6 +42161,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>production_over_time</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>psr_by_make</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -42161,6 +42203,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>purchase_return_ratio_grouped_by_vendor_detail</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>purchase_return_ratio_grouped_by_vendor_summary</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>purchases_by_cost_center_detail</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -8,6 +8,6 @@ REACT_APP_CLOUDINARY_API_KEY=957865933348715
|
||||
REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
||||
REACT_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
|
||||
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||
REACT_APP_AXIOS_BASE_API_URL=https://api.imex.online/
|
||||
REACT_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
||||
REACT_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||
REACT_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||
@@ -4,69 +4,69 @@
|
||||
"private": true,
|
||||
"proxy": "http://localhost:4000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@apollo/client": "^3.7.9",
|
||||
"@asseinfo/react-kanban": "^2.2.0",
|
||||
"@craco/craco": "^6.4.5",
|
||||
"@craco/craco": "^7.0.0",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
||||
"@jsreport/browser-client": "^3.1.0",
|
||||
"@sentry/react": "^7.28.1",
|
||||
"@sentry/tracing": "^7.28.1",
|
||||
"@splitsoftware/splitio-react": "^1.6.0",
|
||||
"@sentry/react": "^7.40.0",
|
||||
"@sentry/tracing": "^7.40.0",
|
||||
"@splitsoftware/splitio-react": "^1.8.1",
|
||||
"@tanem/react-nprogress": "^5.0.8",
|
||||
"antd": "^4.22.3",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"axios": "^0.27.2",
|
||||
"craco-less": "^1.20.0",
|
||||
"antd": "^4.24.8",
|
||||
"apollo-link-logger": "^2.0.1",
|
||||
"axios": "^1.3.4",
|
||||
"craco-less": "^2.0.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "^16.0.1",
|
||||
"enquire-js": "^0.2.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"exifr": "^7.1.3",
|
||||
"firebase": "^9.9.1",
|
||||
"graphql": "^16.5.0",
|
||||
"i18next": "^21.8.14",
|
||||
"i18next-browser-languagedetector": "^6.1.4",
|
||||
"firebase": "^9.17.1",
|
||||
"graphql": "^16.6.0",
|
||||
"i18next": "^22.4.10",
|
||||
"i18next-browser-languagedetector": "^7.0.1",
|
||||
"jsoneditor": "^9.9.0",
|
||||
"jsreport-browser-client-dist": "^1.3.0",
|
||||
"libphonenumber-js": "^1.10.9",
|
||||
"libphonenumber-js": "^1.10.21",
|
||||
"logrocket": "^3.0.1",
|
||||
"markerjs2": "^2.22.0",
|
||||
"markerjs2": "^2.28.1",
|
||||
"moment-business-days": "^1.2.0",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"normalize-url": "^7.0.3",
|
||||
"phone": "^3.1.23",
|
||||
"moment-timezone": "^0.5.41",
|
||||
"normalize-url": "^8.0.0",
|
||||
"phone": "^3.1.35",
|
||||
"preval.macro": "^5.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"query-string": "^7.1.3",
|
||||
"rc-queue-anim": "^2.0.0",
|
||||
"rc-scroll-anim": "^2.7.6",
|
||||
"react": "^17.0.2",
|
||||
"react-big-calendar": "^1.5.0",
|
||||
"react-big-calendar": "^1.6.8",
|
||||
"react-color": "^2.19.3",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-drag-listview": "^0.2.1",
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^11.18.1",
|
||||
"react-icons": "^4.4.0",
|
||||
"react-number-format": "^4.9.3",
|
||||
"react-redux": "^7.2.8",
|
||||
"react-i18next": "^12.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-number-format": "^5.1.3",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-resizable": "^3.0.4",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-scripts": "^5.0.1",
|
||||
"react-sticky": "^6.0.3",
|
||||
"react-sublime-video": "^0.2.5",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"recharts": "^2.1.12",
|
||||
"redux": "^4.2.0",
|
||||
"recharts": "^2.4.3",
|
||||
"redux": "^4.2.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-saga": "^1.2.2",
|
||||
"redux-state-sync": "^3.1.4",
|
||||
"reselect": "^4.1.6",
|
||||
"sass": "^1.54.0",
|
||||
"socket.io-client": "^4.5.1",
|
||||
"styled-components": "^5.3.5",
|
||||
"reselect": "^4.1.7",
|
||||
"sass": "^1.58.3",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"styled-components": "^5.3.6",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
"web-vitals": "^2.1.4",
|
||||
"workbox-background-sync": "^6.5.3",
|
||||
|
||||
@@ -42,6 +42,7 @@ export function ChatConversationContainer({ bodyshop, selectedConversation }) {
|
||||
MARK_MESSAGES_AS_READ_BY_CONVERSATION,
|
||||
{
|
||||
variables: { conversationId: selectedConversation },
|
||||
refetchQueries: ["UNREAD_CONVERSATION_COUNT"],
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
id: cache.identify({
|
||||
|
||||
@@ -10,7 +10,10 @@ import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { CONVERSATION_LIST_QUERY } from "../../graphql/conversations.queries";
|
||||
import {
|
||||
CONVERSATION_LIST_QUERY,
|
||||
UNREAD_CONVERSATION_COUNT,
|
||||
} from "../../graphql/conversations.queries";
|
||||
import { toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
||||
import {
|
||||
selectChatVisible,
|
||||
@@ -37,9 +40,17 @@ export function ChatPopupComponent({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [pollInterval, setpollInterval] = useState(0);
|
||||
|
||||
const { data: unreadData } = useQuery(UNREAD_CONVERSATION_COUNT, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
...(pollInterval > 0 ? { pollInterval } : {}),
|
||||
});
|
||||
|
||||
const { loading, data, refetch, called } = useQuery(CONVERSATION_LIST_QUERY, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
skip: !chatVisible,
|
||||
...(pollInterval > 0 ? { pollInterval } : {}),
|
||||
});
|
||||
|
||||
@@ -57,12 +68,14 @@ export function ChatPopupComponent({
|
||||
if (called && chatVisible) refetch();
|
||||
}, [chatVisible, called, refetch]);
|
||||
|
||||
const unreadCount = data
|
||||
? data.conversations.reduce(
|
||||
(acc, val) => val.messages_aggregate.aggregate.count + acc,
|
||||
0
|
||||
)
|
||||
: 0;
|
||||
// const unreadCount = data
|
||||
// ? data.conversations.reduce(
|
||||
// (acc, val) => val.messages_aggregate.aggregate.count + acc,
|
||||
// 0
|
||||
// )
|
||||
// : 0;
|
||||
|
||||
const unreadCount = unreadData?.messages_aggregate.aggregate.count || 0;
|
||||
|
||||
return (
|
||||
<Badge count={unreadCount}>
|
||||
|
||||
@@ -289,7 +289,7 @@ export function JobLinesUpsertModalComponent({
|
||||
name="prt_dsmk_p"
|
||||
initialValue={0}
|
||||
>
|
||||
<InputNumber precision={0} min={0} max={100} />
|
||||
<InputNumber precision={0} min={-100} max={100} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("joblines.fields.tax_part")}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
||||
import Axios from "axios";
|
||||
import Dinero from "dinero.js";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobLineEditModal: selectJobLineEditModal,
|
||||
});
|
||||
@@ -40,7 +41,15 @@ function JobLinesUpsertModalContainer({
|
||||
manual_line: !(
|
||||
jobLineEditModal.context && jobLineEditModal.context.id
|
||||
),
|
||||
...UndefinedToNull(values),
|
||||
...UndefinedToNull({
|
||||
...values,
|
||||
prt_dsmk_m: Dinero({
|
||||
amount: Math.round((values.act_price || 0) * 100),
|
||||
})
|
||||
.percentage(Math.abs(values.prt_dsmk_p || 0))
|
||||
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
|
||||
.toFormat(0.0),
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -68,7 +77,15 @@ function JobLinesUpsertModalContainer({
|
||||
const r = await updateJobLine({
|
||||
variables: {
|
||||
lineId: jobLineEditModal.context.id,
|
||||
line: values,
|
||||
line: {
|
||||
...values,
|
||||
prt_dsmk_m: Dinero({
|
||||
amount: Math.round(values.act_price * 100),
|
||||
})
|
||||
.percentage(Math.abs(values.prt_dsmk_p || 0))
|
||||
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
|
||||
.toFormat(0.0),
|
||||
},
|
||||
},
|
||||
refetchQueries: ["GET_LINE_TICKET_BY_PK"],
|
||||
});
|
||||
|
||||
@@ -9,7 +9,11 @@ const colSpan = {
|
||||
lg: { span: 12 },
|
||||
};
|
||||
|
||||
export default function JobsCreateVehicleInfoComponent({ loading, vehicles }) {
|
||||
export default function JobsCreateVehicleInfoComponent({
|
||||
loading,
|
||||
vehicles,
|
||||
form,
|
||||
}) {
|
||||
const [state, setState] = useContext(JobCreateContext);
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@@ -58,7 +62,7 @@ export default function JobsCreateVehicleInfoComponent({ loading, vehicles }) {
|
||||
/>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<JobsCreateVehicleInfoNewComponent />
|
||||
<JobsCreateVehicleInfoNewComponent form={form}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ export default function JobsCreateVehicleInfoContainer({ form }) {
|
||||
<JobsCreateVehicleInfoComponent
|
||||
loading={loading}
|
||||
vehicles={data ? data.search_vehicles : null}
|
||||
form={form}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@ import { useTranslation } from "react-i18next";
|
||||
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import JobsCreateVehicleInfoPredefined from "./jobs-create-vehicle-info.predefined.component";
|
||||
|
||||
export default function JobsCreateVehicleInfoNewComponent() {
|
||||
export default function JobsCreateVehicleInfoNewComponent({ form }) {
|
||||
const [state] = useContext(JobCreateContext);
|
||||
|
||||
const { t } = useTranslation();
|
||||
@@ -25,7 +26,7 @@ export default function JobsCreateVehicleInfoNewComponent() {
|
||||
<Input disabled={!state.vehicle.new} />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow>
|
||||
<LayoutFormRow grow noDivider>
|
||||
<Form.Item
|
||||
label={t("vehicles.fields.v_color")}
|
||||
name={["vehicle", "data", "v_color"]}
|
||||
@@ -52,8 +53,9 @@ export default function JobsCreateVehicleInfoNewComponent() {
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
|
||||
<LayoutFormRow grow>
|
||||
<LayoutFormRow grow noDivider>
|
||||
<Form.Item
|
||||
span={10}
|
||||
label={t("vehicles.fields.v_make_desc")}
|
||||
name={["vehicle", "data", "v_make_desc"]}
|
||||
rules={[
|
||||
@@ -66,6 +68,7 @@ export default function JobsCreateVehicleInfoNewComponent() {
|
||||
<Input disabled={!state.vehicle.new} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
span={11}
|
||||
label={t("vehicles.fields.v_model_desc")}
|
||||
name={["vehicle", "data", "v_model_desc"]}
|
||||
rules={[
|
||||
@@ -77,6 +80,11 @@ export default function JobsCreateVehicleInfoNewComponent() {
|
||||
>
|
||||
<Input disabled={!state.vehicle.new} />
|
||||
</Form.Item>
|
||||
<JobsCreateVehicleInfoPredefined
|
||||
disabled={!state.vehicle.new}
|
||||
form={form}
|
||||
span={1}
|
||||
/>
|
||||
</LayoutFormRow>
|
||||
|
||||
<LayoutFormRow header={t("vehicles.forms.registration")} grow>
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
|
||||
import { Button, Input, Popover, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PredefinedVehicles from "./predefined-vehicles.js";
|
||||
|
||||
export default function JobsCreateVehicleInfoPredefined({ disabled, form }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const { t } = useTranslation();
|
||||
const handleOpenChange = (newOpen) => {
|
||||
setOpen(newOpen);
|
||||
setSearch("");
|
||||
};
|
||||
const filteredPredefinedVehicles =
|
||||
search === ""
|
||||
? PredefinedVehicles
|
||||
: PredefinedVehicles.filter(
|
||||
(v) =>
|
||||
v.make.toLowerCase().includes(search.toLowerCase()) ||
|
||||
v.model.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
|
||||
const popContent = () => (
|
||||
<div>
|
||||
<Table
|
||||
size="small"
|
||||
title={() => <Input.Search onSearch={(value) => setSearch(value)} />}
|
||||
dataSource={filteredPredefinedVehicles}
|
||||
columns={[
|
||||
{
|
||||
dataIndex: "make",
|
||||
key: "make",
|
||||
title: t("vehicles.fields.v_make_desc"),
|
||||
},
|
||||
{
|
||||
dataIndex: "model",
|
||||
key: "model",
|
||||
title: t("vehicles.fields.v_model_desc"),
|
||||
},
|
||||
{
|
||||
dataIndex: "select",
|
||||
key: "select",
|
||||
title: t("general.labels.actions"),
|
||||
render: (value, record) => (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
form.setFieldsValue({
|
||||
vehicle: {
|
||||
data: {
|
||||
v_make_desc: record.make,
|
||||
v_model_desc: record.model,
|
||||
},
|
||||
},
|
||||
});
|
||||
setOpen(false);
|
||||
setSearch("");
|
||||
}}
|
||||
>
|
||||
<PlusOutlined />
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Popover
|
||||
content={popContent}
|
||||
trigger="click"
|
||||
open={open}
|
||||
placement="left"
|
||||
onOpenChange={handleOpenChange}
|
||||
destroyTooltipOnHide
|
||||
>
|
||||
<SearchOutlined style={{ cursor: "pointer" }} />
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -256,7 +256,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
</FormRow>
|
||||
<FormRow header={t("jobs.forms.other")}>
|
||||
<Form.Item label={t("jobs.fields.category")} name="category">
|
||||
<Select disabled={jobRO}>
|
||||
<Select disabled={jobRO} allowClear>
|
||||
{bodyshop.md_categories.map((s) => (
|
||||
<Select.Option key={s} value={s}>
|
||||
{s}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import cleanAxios from "../../utils/CleanAxios";
|
||||
import formatBytes from "../../utils/formatbytes";
|
||||
import yauzl from "yauzl";
|
||||
//import yauzl from "yauzl";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
@@ -69,44 +69,44 @@ export function JobsDocumentsDownloadButton({
|
||||
setDownload(null);
|
||||
if (Direct_Media_Download.treatment === "on") {
|
||||
try {
|
||||
const parentDir = await window.showDirectoryPicker({
|
||||
id: "media",
|
||||
startIn: "downloads",
|
||||
});
|
||||
// const parentDir = await window.showDirectoryPicker({
|
||||
// id: "media",
|
||||
// startIn: "downloads",
|
||||
// });
|
||||
|
||||
const directory = await parentDir.getDirectoryHandle(identifier, {
|
||||
create: true,
|
||||
});
|
||||
// const directory = await parentDir.getDirectoryHandle(identifier, {
|
||||
// create: true,
|
||||
// });
|
||||
|
||||
yauzl.fromBuffer(
|
||||
Buffer.from(theDownloadedZip.data),
|
||||
{},
|
||||
(err, zipFile) => {
|
||||
if (err) throw err;
|
||||
zipFile.on("entry", (entry) => {
|
||||
zipFile.openReadStream(entry, async (readErr, readStream) => {
|
||||
if (readErr) {
|
||||
zipFile.close();
|
||||
throw readErr;
|
||||
}
|
||||
if (err) throw err;
|
||||
let fileSystemHandle = await directory.getFileHandle(
|
||||
entry.fileName,
|
||||
{
|
||||
create: true,
|
||||
}
|
||||
);
|
||||
const writable = await fileSystemHandle.createWritable();
|
||||
readStream.on("data", async function (chunk) {
|
||||
await writable.write(chunk);
|
||||
});
|
||||
readStream.on("end", async function () {
|
||||
await writable.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
// yauzl.fromBuffer(
|
||||
// Buffer.from(theDownloadedZip.data),
|
||||
// {},
|
||||
// (err, zipFile) => {
|
||||
// if (err) throw err;
|
||||
// zipFile.on("entry", (entry) => {
|
||||
// zipFile.openReadStream(entry, async (readErr, readStream) => {
|
||||
// if (readErr) {
|
||||
// zipFile.close();
|
||||
// throw readErr;
|
||||
// }
|
||||
// if (err) throw err;
|
||||
// let fileSystemHandle = await directory.getFileHandle(
|
||||
// entry.fileName,
|
||||
// {
|
||||
// create: true,
|
||||
// }
|
||||
// );
|
||||
// const writable = await fileSystemHandle.createWritable();
|
||||
// readStream.on("data", async function (chunk) {
|
||||
// await writable.write(chunk);
|
||||
// });
|
||||
// readStream.on("end", async function () {
|
||||
// await writable.close();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
standardMediaDownload(theDownloadedZip.data);
|
||||
|
||||
@@ -55,6 +55,7 @@ export function ProductionListTable({
|
||||
const assoc = bodyshop.associations.find(
|
||||
(a) => a.useremail === currentUser.email
|
||||
);
|
||||
|
||||
if (assoc) {
|
||||
await updateDefaultProdView({
|
||||
variables: { assocId: assoc.id, view: value },
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function ProfileShopsComponent({
|
||||
),
|
||||
},
|
||||
];
|
||||
console.log("🚀 ~ file: profile-shops.component.jsx:45 ~ data", data);
|
||||
|
||||
const filteredData =
|
||||
search === ""
|
||||
? data
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import {
|
||||
QUERY_ALL_ASSOCIATIONS,
|
||||
UPDATE_ASSOCIATION,
|
||||
UPDATE_ACTIVE_ASSOCIATION,
|
||||
} from "../../graphql/associations.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ProfileShopsComponent from "./profile-shops.component";
|
||||
@@ -13,9 +13,13 @@ import { getToken } from "firebase/messaging";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
@@ -25,14 +29,18 @@ export default connect(
|
||||
mapDispatchToProps
|
||||
)(ProfileShopsContainer);
|
||||
|
||||
export function ProfileShopsContainer({ bodyshop }) {
|
||||
export function ProfileShopsContainer({ bodyshop, currentUser }) {
|
||||
const { loading, error, data } = useQuery(QUERY_ALL_ASSOCIATIONS, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
email: currentUser.email,
|
||||
},
|
||||
skip: !currentUser,
|
||||
});
|
||||
const [updateAssocation] = useMutation(UPDATE_ASSOCIATION);
|
||||
const [updateActiveAssociation] = useMutation(UPDATE_ACTIVE_ASSOCIATION);
|
||||
|
||||
const updateActiveShop = async (activeShopId) => {
|
||||
const updateActiveShop = async (newActiveAssocId) => {
|
||||
logImEXEvent("profile_change_active_shop");
|
||||
|
||||
try {
|
||||
@@ -46,16 +54,12 @@ export function ProfileShopsContainer({ bodyshop }) {
|
||||
} catch (error) {
|
||||
console.log("No FCM token. Skipping unsubscribe.");
|
||||
}
|
||||
await Promise.all(
|
||||
data.associations.map(async (record) => {
|
||||
await updateAssocation({
|
||||
variables: {
|
||||
assocId: record.id,
|
||||
assocActive: record.id === activeShopId ? true : false,
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
await updateActiveAssociation({
|
||||
variables: {
|
||||
newActiveAssocId: newActiveAssocId,
|
||||
},
|
||||
});
|
||||
|
||||
//Force window refresh.
|
||||
|
||||
|
||||
@@ -217,7 +217,9 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
{t("jobs.fields.ponumber")}
|
||||
</Select.Option>
|
||||
<Select.Option value="account_number">
|
||||
{t("jobs.fields.dms.control_type.account_number")}
|
||||
{t(
|
||||
"jobs.fields.dms.control_type.account_number"
|
||||
)}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
@@ -423,6 +425,15 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
<Input onBlur={handleBlur} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{bodyshop.cdk_dealerid && (
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.dms.dms_control_override")}
|
||||
key={`${index}dms_control_override`}
|
||||
name={[field.name, "dms_control_override"]}
|
||||
>
|
||||
<Input onBlur={handleBlur} />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
@@ -546,6 +557,15 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
<Input onBlur={handleBlur} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{bodyshop.cdk_dealerid && (
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.dms.dms_control_override")}
|
||||
key={`${index}dms_control_override`}
|
||||
name={[field.name, "dms_control_override"]}
|
||||
>
|
||||
<Input onBlur={handleBlur} />
|
||||
</Form.Item>
|
||||
)}
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
|
||||
@@ -42,7 +42,9 @@ export default function ShopUsersAuthEdit({ association }) {
|
||||
</div>
|
||||
)}
|
||||
{!visible && (
|
||||
<div style={{ cursor: "pointer" }} onClick={() => setVisible(true)}>
|
||||
<div
|
||||
style={{ cursor: "pointer" }} //onClick={() => setVisible(true)}
|
||||
>
|
||||
{association.authlevel || t("general.labels.na")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { gql } from "@apollo/client";
|
||||
|
||||
export const QUERY_ALL_ASSOCIATIONS = gql`
|
||||
query QUERY_ALL_ASSOCIATIONS {
|
||||
associations(order_by: { bodyshop: { shopname: asc } }) {
|
||||
query QUERY_ALL_ASSOCIATIONS($email: String) {
|
||||
associations(
|
||||
where: { useremail: { _eq: $email } }
|
||||
order_by: { bodyshop: { shopname: asc } }
|
||||
) {
|
||||
id
|
||||
active
|
||||
bodyshop {
|
||||
@@ -27,6 +30,30 @@ export const UPDATE_ASSOCIATION = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const UPDATE_ACTIVE_ASSOCIATION = gql`
|
||||
mutation UPDATE_ACTIVE_ASSOCIATION($newActiveAssocId: uuid) {
|
||||
nweActive: update_associations(
|
||||
where: { id: { _eq: $newActiveAssocId } }
|
||||
_set: { active: true }
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
shopid
|
||||
active
|
||||
}
|
||||
}
|
||||
inactive: update_associations(
|
||||
where: { id: { _neq: $newActiveAssocId } }
|
||||
_set: { active: false }
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
shopid
|
||||
active
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_ACTIVE_PROD_LIST_VIEW = gql`
|
||||
mutation UPDATE_ACTIVE_PROD_LIST_VIEW($assocId: uuid, $view: String) {
|
||||
|
||||
@@ -12,6 +12,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
query QUERY_BODYSHOP {
|
||||
bodyshops(where: { associations: { active: { _eq: true } } }) {
|
||||
associations {
|
||||
id
|
||||
authlevel
|
||||
useremail
|
||||
default_prod_list_view
|
||||
|
||||
@@ -31,6 +31,18 @@ import { gql } from "@apollo/client";
|
||||
// }
|
||||
// `;
|
||||
|
||||
export const UNREAD_CONVERSATION_COUNT = gql`
|
||||
query UNREAD_CONVERSATION_COUNT {
|
||||
messages_aggregate(
|
||||
where: { read: { _eq: false }, isoutbound: { _eq: false } }
|
||||
) {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const CONVERSATION_LIST_QUERY = gql`
|
||||
query CONVERSATION_LIST_QUERY {
|
||||
conversations(
|
||||
|
||||
@@ -2060,6 +2060,7 @@ export const QUERY_JOB_EXPORT_DMS = gql`
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ins_co_nm
|
||||
kmin
|
||||
kmout
|
||||
v_make_desc
|
||||
|
||||
@@ -101,7 +101,10 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
];
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
console.log(`connect_error due to ${err}`, err);
|
||||
notification.error({ message: err.message });
|
||||
});
|
||||
socket.on("log-event", (payload) => {
|
||||
setLogs((logs) => {
|
||||
return [...logs, payload];
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function JobsCreateComponent({ form }) {
|
||||
const steps = [
|
||||
{
|
||||
title: t("jobs.labels.create.vehicleinfo"),
|
||||
content: <JobsCreateVehicleInfoContainer />,
|
||||
content: <JobsCreateVehicleInfoContainer form={form} />,
|
||||
validation:
|
||||
!!state.vehicle.new ||
|
||||
!!state.vehicle.selectedid ||
|
||||
|
||||
@@ -51,6 +51,7 @@ import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.comp
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -96,7 +97,7 @@ export function JobsDetailPage({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
...values,
|
||||
...UndefinedToNull(values, ["alt_transport", "category", "referral_source"]),
|
||||
parts_tax_rates: {
|
||||
...job.parts_tax_rates,
|
||||
...values.parts_tax_rates,
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"disablebillwip": "Disable bill WIP for A/P Posting",
|
||||
"disablecontactvehiclecreation": "Disable Contact & Vehicle Updates/Creation",
|
||||
"dms_acctnumber": "DMS Account #",
|
||||
"dms_control_override": "Static Control # Override",
|
||||
"dms_wip_acctnumber": "DMS W.I.P. Account #",
|
||||
"generic_customer_number": "Generic Customer Number",
|
||||
"itc_federal": "Federal Tax is ITC?",
|
||||
@@ -2485,6 +2486,7 @@
|
||||
"production_by_target_date": "Production by Target Date",
|
||||
"production_by_technician": "Production by Technician",
|
||||
"production_by_technician_one": "Production filtered by Technician",
|
||||
"production_over_time": "Production Level over Time",
|
||||
"psr_by_make": "Percent of Sales by Vehicle Make",
|
||||
"purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)",
|
||||
"purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)",
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"disablebillwip": "",
|
||||
"disablecontactvehiclecreation": "",
|
||||
"dms_acctnumber": "",
|
||||
"dms_control_override": "",
|
||||
"dms_wip_acctnumber": "",
|
||||
"generic_customer_number": "",
|
||||
"itc_federal": "",
|
||||
@@ -2485,6 +2486,7 @@
|
||||
"production_by_target_date": "",
|
||||
"production_by_technician": "",
|
||||
"production_by_technician_one": "",
|
||||
"production_over_time": "",
|
||||
"psr_by_make": "",
|
||||
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
||||
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"disablebillwip": "",
|
||||
"disablecontactvehiclecreation": "",
|
||||
"dms_acctnumber": "",
|
||||
"dms_control_override": "",
|
||||
"dms_wip_acctnumber": "",
|
||||
"generic_customer_number": "",
|
||||
"itc_federal": "",
|
||||
@@ -2485,6 +2486,7 @@
|
||||
"production_by_target_date": "",
|
||||
"production_by_technician": "",
|
||||
"production_by_technician_one": "",
|
||||
"production_over_time": "",
|
||||
"psr_by_make": "",
|
||||
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
||||
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import NumberFormat from "react-number-format";
|
||||
import { NumericFormat } from "react-number-format";
|
||||
|
||||
export default function CurrencyFormatter(props) {
|
||||
return (
|
||||
<NumberFormat
|
||||
<NumericFormat
|
||||
thousandSeparator={true}
|
||||
decimalScale={2}
|
||||
fixedDecimalScale={true}
|
||||
|
||||
@@ -142,7 +142,7 @@ middlewares.push(
|
||||
|
||||
const cache = new InMemoryCache({});
|
||||
|
||||
export default new ApolloClient({
|
||||
const client = new ApolloClient({
|
||||
link: ApolloLink.from(middlewares),
|
||||
cache,
|
||||
connectToDevTools: process.env.NODE_ENV !== "production",
|
||||
@@ -161,3 +161,4 @@ export default new ApolloClient({
|
||||
},
|
||||
},
|
||||
});
|
||||
export default client;
|
||||
|
||||
@@ -1841,6 +1841,20 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "purchases",
|
||||
},
|
||||
production_over_time: {
|
||||
title: i18n.t("reportcenter.templates.production_over_time"),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.production_over_time"
|
||||
),
|
||||
key: "production_over_time",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.actual_in"),
|
||||
},
|
||||
group: "jobs",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "courtesycarcontract"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
export default function UndefinedToNull(obj) {
|
||||
export default function UndefinedToNull(obj, keys) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (keys && keys.indexOf(key) >= 0) {
|
||||
if (obj[key] === undefined) obj[key] = null;
|
||||
} else {
|
||||
if (obj[key] === undefined) obj[key] = null;
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
11164
client/yarn.lock
11164
client/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -223,11 +223,9 @@
|
||||
- kanban_settings
|
||||
- qbo_realmId
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
- table:
|
||||
name: audit_trail
|
||||
@@ -4502,6 +4500,62 @@
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
- table:
|
||||
name: payment_response
|
||||
schema: public
|
||||
object_relationships:
|
||||
- name: bodyshop
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
- name: job
|
||||
using:
|
||||
foreign_key_constraint_on: jobid
|
||||
- name: payment
|
||||
using:
|
||||
foreign_key_constraint_on: paymentid
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- amount
|
||||
- bodyshopid
|
||||
- declinereason
|
||||
- ext_paymentid
|
||||
- jobid
|
||||
- paymentid
|
||||
- response
|
||||
- successful
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- successful
|
||||
- response
|
||||
- amount
|
||||
- declinereason
|
||||
- ext_paymentid
|
||||
- bodyshopid
|
||||
- id
|
||||
- jobid
|
||||
- paymentid
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
- table:
|
||||
name: payments
|
||||
schema: public
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."jobs_idx_date_open";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "jobs_idx_date_open" on
|
||||
"public"."jobs" using btree ("date_open");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."jobs_idx_date_invoiced";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "jobs_idx_date_invoiced" on
|
||||
"public"."jobs" using btree ("date_invoiced");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_bills_vendorid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_bills_vendorid" on
|
||||
"public"."bills" using btree ("vendorid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_parts_orders_vendorid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_parts_orders_vendorid" on
|
||||
"public"."parts_orders" using btree ("vendorid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_ccc_jobid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_ccc_jobid" on
|
||||
"public"."cccontracts" using btree ("jobid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_ccc_courtesycarid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_ccc_courtesycarid" on
|
||||
"public"."cccontracts" using btree ("courtesycarid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_jobs_actual_completion";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_jobs_actual_completion" on
|
||||
"public"."jobs" using btree ("actual_completion");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_jobs_actual_in";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_jobs_actual_in" on
|
||||
"public"."jobs" using btree ("actual_in");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_jobs_employee_csr";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_jobs_employee_csr" on
|
||||
"public"."jobs" using btree ("employee_csr");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_jobs_body_csr";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_jobs_body_csr" on
|
||||
"public"."jobs" using btree ("employee_body");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_jobs_employee_refinish";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_jobs_employee_refinish" on
|
||||
"public"."jobs" using btree ("employee_refinish");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_timetickets_employeeid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_timetickets_employeeid" on
|
||||
"public"."timetickets" using btree ("employeeid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_timetickets_cost_center";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_timetickets_cost_center" on
|
||||
"public"."timetickets" using btree ("cost_center");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_scoreboard_jobid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_scoreboard_jobid" on
|
||||
"public"."scoreboard" using btree ("jobid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_scoreboard_date";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_scoreboard_date" on
|
||||
"public"."scoreboard" using btree ("date");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_payments_date";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_payments_date" on
|
||||
"public"."payments" using btree ("date");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."exportlog_createdat";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "exportlog_createdat" on
|
||||
"public"."exportlog" using btree ("created_at");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_transitions_jobid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_transitions_jobid" on
|
||||
"public"."transitions" using btree ("jobid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_transitions_start";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_transitions_start" on
|
||||
"public"."transitions" using btree ("start");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_transitions_end";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_transitions_end" on
|
||||
"public"."transitions" using btree ("end");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_audit_bodyshopid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_audit_bodyshopid" on
|
||||
"public"."audit_trail" using btree ("bodyshopid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_audit_jobid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_audit_jobid" on
|
||||
"public"."audit_trail" using btree ("jobid");
|
||||
@@ -0,0 +1 @@
|
||||
DROP INDEX IF EXISTS "public"."idx_audit_billid";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE INDEX "idx_audit_billid" on
|
||||
"public"."audit_trail" using btree ("billid");
|
||||
11
hasura/migrations/1676337846761_run_sql_migration/down.sql
Normal file
11
hasura/migrations/1676337846761_run_sql_migration/down.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- CREATE INDEX idx_phonebook_firstname ON public.phonebook USING gin (firstname public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_lastname ON public.phonebook USING gin (lastname public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_company ON public.phonebook USING gin (company public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_address1 ON public.phonebook USING gin (address1 public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_phone1 ON public.phonebook USING gin (phone1 public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_phone2 ON public.phonebook USING gin (phone2 public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_email ON public.phonebook USING gin (email public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_phonebook_category ON public.phonebook USING gin (category public.gin_trgm_ops);
|
||||
-- CREATE INDEX idx_vendor_name ON public.vendors USING gin (name public.gin_trgm_ops);
|
||||
9
hasura/migrations/1676337846761_run_sql_migration/up.sql
Normal file
9
hasura/migrations/1676337846761_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE INDEX idx_phonebook_firstname ON public.phonebook USING gin (firstname public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_lastname ON public.phonebook USING gin (lastname public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_company ON public.phonebook USING gin (company public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_address1 ON public.phonebook USING gin (address1 public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_phone1 ON public.phonebook USING gin (phone1 public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_phone2 ON public.phonebook USING gin (phone2 public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_email ON public.phonebook USING gin (email public.gin_trgm_ops);
|
||||
CREATE INDEX idx_phonebook_category ON public.phonebook USING gin (category public.gin_trgm_ops);
|
||||
CREATE INDEX idx_vendor_name ON public.vendors USING gin (name public.gin_trgm_ops);
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."payment_response";
|
||||
@@ -0,0 +1,2 @@
|
||||
CREATE TABLE "public"."payment_response" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "bodyshopid" uuid NOT NULL, "jobid" uuid, "paymentid" uuid, "successful" boolean NOT NULL DEFAULT false, "ext_paymentid" text NOT NULL, "amount" numeric NOT NULL, "declinereason" text, "response" jsonb NOT NULL DEFAULT jsonb_build_object(), PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("paymentid") REFERENCES "public"."payments"("id") ON UPDATE cascade ON DELETE cascade);
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
5634
package-lock.json
generated
5634
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -17,41 +17,41 @@
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.1181.0",
|
||||
"aws-sdk": "^2.1326.0",
|
||||
"axios": "^0.27.2",
|
||||
"bluebird": "^3.7.2",
|
||||
"body-parser": "^1.20.0",
|
||||
"cloudinary": "^1.30.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"cloudinary": "^1.34.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"csrf": "^3.1.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "16.0.1",
|
||||
"express": "^4.18.1",
|
||||
"firebase-admin": "^11.0.0",
|
||||
"graphql": "^16.5.0",
|
||||
"dotenv": "16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"firebase-admin": "^11.5.0",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^4.2.0",
|
||||
"graylog2": "^0.2.1",
|
||||
"inline-css": "^4.0.1",
|
||||
"inline-css": "^4.0.2",
|
||||
"intuit-oauth": "^4.0.0",
|
||||
"json-2-csv": "^3.17.1",
|
||||
"json-2-csv": "^3.19.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"moment-timezone": "^0.5.41",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-mailjet": "^5.1.0",
|
||||
"node-persist": "^3.1.0",
|
||||
"node-quickbooks": "^2.0.39",
|
||||
"nodemailer": "^6.7.7",
|
||||
"phone": "^3.1.23",
|
||||
"node-mailjet": "^6.0.2",
|
||||
"node-persist": "^3.1.3",
|
||||
"node-quickbooks": "^2.0.41",
|
||||
"nodemailer": "^6.9.1",
|
||||
"phone": "^3.1.35",
|
||||
"query-string": "^7.1.1",
|
||||
"soap": "^0.45.0",
|
||||
"socket.io": "^4.5.0",
|
||||
"ssh2-sftp-client": "^9.0.2",
|
||||
"soap": "^1.0.0",
|
||||
"socket.io": "^4.6.1",
|
||||
"ssh2-sftp-client": "^9.0.4",
|
||||
"stripe": "^9.15.0",
|
||||
"twilio": "^3.80.0",
|
||||
"uuid": "^8.3.2",
|
||||
"twilio": "^4.8.0",
|
||||
"uuid": "^9.0.0",
|
||||
"xml2js": "^0.4.23",
|
||||
"xmlbuilder2": "^3.0.2"
|
||||
},
|
||||
|
||||
@@ -1092,7 +1092,13 @@ async function GenerateTransWips(socket) {
|
||||
if (alloc.sale.getAmount() > 0 && !alloc.tax) {
|
||||
const item = {
|
||||
acct: alloc.profitCenter.dms_acctnumber,
|
||||
cntl: socket.JobData.ro_number,
|
||||
cntl:
|
||||
alloc.profitCenter.dms_control_override &&
|
||||
alloc.profitCenter.dms_control_override !== null &&
|
||||
alloc.profitCenter.dms_control_override !== undefined &&
|
||||
alloc.profitCenter.dms_control_override?.trim() !== ""
|
||||
? alloc.profitCenter.dms_control_override
|
||||
: socket.JobData.ro_number,
|
||||
cntl2: null,
|
||||
credtMemoNo: null,
|
||||
postAmt: alloc.sale.multiply(-1).getAmount(),
|
||||
@@ -1109,7 +1115,13 @@ async function GenerateTransWips(socket) {
|
||||
if (alloc.cost.getAmount() > 0 && !alloc.tax) {
|
||||
const item = {
|
||||
acct: alloc.costCenter.dms_acctnumber,
|
||||
cntl: socket.JobData.ro_number,
|
||||
cntl:
|
||||
alloc.costCenter.dms_control_override &&
|
||||
alloc.costCenter.dms_control_override !== null &&
|
||||
alloc.costCenter.dms_control_override !== undefined &&
|
||||
alloc.costCenter.dms_control_override?.trim() !== ""
|
||||
? alloc.costCenter.dms_control_override
|
||||
: socket.JobData.ro_number,
|
||||
cntl2: null,
|
||||
credtMemoNo: null,
|
||||
postAmt: alloc.cost.getAmount(),
|
||||
@@ -1123,7 +1135,13 @@ async function GenerateTransWips(socket) {
|
||||
|
||||
const itemWip = {
|
||||
acct: alloc.costCenter.dms_wip_acctnumber,
|
||||
cntl: socket.JobData.ro_number,
|
||||
cntl:
|
||||
alloc.costCenter.dms_control_override &&
|
||||
alloc.costCenter.dms_control_override !== null &&
|
||||
alloc.costCenter.dms_control_override !== undefined &&
|
||||
alloc.costCenter.dms_control_override?.trim() !== ""
|
||||
? alloc.costCenter.dms_control_override
|
||||
: socket.JobData.ro_number,
|
||||
cntl2: null,
|
||||
credtMemoNo: null,
|
||||
postAmt: alloc.cost.multiply(-1).getAmount(),
|
||||
@@ -1158,7 +1176,13 @@ async function GenerateTransWips(socket) {
|
||||
if (alloc.sale.getAmount() > 0) {
|
||||
const item2 = {
|
||||
acct: alloc.profitCenter.dms_acctnumber,
|
||||
cntl: socket.JobData.ro_number,
|
||||
cntl:
|
||||
alloc.profitCenter.dms_control_override &&
|
||||
alloc.profitCenter.dms_control_override !== null &&
|
||||
alloc.profitCenter.dms_control_override !== undefined &&
|
||||
alloc.profitCenter.dms_control_override?.trim() !== ""
|
||||
? alloc.profitCenter.dms_control_override
|
||||
: socket.JobData.ro_number,
|
||||
cntl2: null,
|
||||
credtMemoNo: null,
|
||||
postAmt: alloc.sale.multiply(-1).getAmount(),
|
||||
|
||||
@@ -42,14 +42,16 @@ function pollFunc(fn, timeout, interval) {
|
||||
pollFunc(getEntegralShopData, 0, 5 * 60 * 1000); //Set the metadata to refresh every 5 minutes.
|
||||
|
||||
async function getEntegralShopData() {
|
||||
await storage.init({ logging: true });
|
||||
const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
||||
logger.log("set-entegral-shops-local-storage", "DEBUG", "API", null, null);
|
||||
await storage.setItem("entegralShops", bodyshops);
|
||||
return true; //Continue execution.
|
||||
// await storage.init({ logging: true });
|
||||
// const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
||||
// 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) => {
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
//Query for the List of Bodyshop Clients.
|
||||
const job = req.body.event.data.new;
|
||||
logger.log("arms-job-update", "DEBUG", "api", job.id, null);
|
||||
|
||||
@@ -28,7 +28,7 @@ exports.sendServerEmail = async function ({ subject, text }) {
|
||||
transporter.sendMail(
|
||||
{
|
||||
from: `ImEX Online API - ${process.env.NODE_ENV} <noreply@imex.online>`,
|
||||
to: ["patrick@snapt.ca"],
|
||||
to: ["patrick@imexsystems.ca"],
|
||||
subject: subject,
|
||||
text: text,
|
||||
ses: {
|
||||
|
||||
Reference in New Issue
Block a user