Merged in release/2021-10-29 (pull request #257)

Release/2021 10 29
This commit is contained in:
Patrick Fic
2021-10-29 21:18:53 +00:00
29 changed files with 4801 additions and 199 deletions

1
.gitignore vendored
View File

@@ -112,3 +112,4 @@ firebase/.env
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
logs/oAuthClient-log.log

View File

@@ -33357,6 +33357,69 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>mpi_animal_checklist</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>mpi_eglass_auth</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>mpi_final_acct_sheet</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>paint_grid</name>
<definition_loaded>false</definition_loaded>
@@ -37015,6 +37078,37 @@
</folder_node>
</children>
</folder_node>
<folder_node>
<name>schedule</name>
<children>
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>manualevent</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
<folder_node>
<name>scoreboard</name>
<children>

View File

@@ -5,7 +5,7 @@
"proxy": "http://localhost:5000",
"dependencies": {
"@apollo/client": "^3.4.16",
"@craco/craco": "^6.3.0",
"@craco/craco": "^6.4.0",
"@fingerprintjs/fingerprintjs": "^3.3.0",
"@lourenci/react-kanban": "^2.1.0",
"@openreplay/tracker": "^3.4.4",
@@ -29,7 +29,7 @@
"exifr": "^7.1.3",
"firebase": "^9.1.3",
"graphql": "^15.6.1",
"i18next": "^21.3.2",
"i18next": "^21.3.3",
"i18next-browser-languagedetector": "^6.1.2",
"jsoneditor": "^9.5.6",
"jsreport-browser-client-dist": "^1.3.0",
@@ -44,7 +44,7 @@
"rc-queue-anim": "^2.0.0",
"rc-scroll-anim": "^2.7.6",
"react": "^17.0.1",
"react-big-calendar": "^0.36.1",
"react-big-calendar": "^0.38.0",
"react-color": "^2.19.3",
"react-cookie": "^4.1.1",
"react-dom": "^17.0.1",
@@ -66,9 +66,9 @@
"redux-saga": "^1.1.3",
"redux-state-sync": "^3.1.2",
"reselect": "^4.0.0",
"sass": "^1.43.2",
"sass": "^1.43.3",
"socket.io-client": "^4.3.2",
"styled-components": "^5.3.1",
"styled-components": "^5.3.3",
"subscriptions-transport-ws": "^0.9.18",
"web-vitals": "^2.1.2",
"workbox-background-sync": "^6.3.0",
@@ -115,7 +115,7 @@
]
},
"devDependencies": {
"@sentry/webpack-plugin": "^1.18.1",
"@sentry/webpack-plugin": "^1.18.3",
"patch-package": "^6.4.7",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.2"

View File

@@ -51,7 +51,9 @@ export function EmailOverlayContainer({
const defaultEmailFrom = {
from: {
name: `${currentUser.displayName} @ ${bodyshop.shopname}`,
name: currentUser.displayName
? `${currentUser.displayName} @ ${bodyshop.shopname}`
: bodyshop.shopname,
address: EmailSettings.fromAddress,
},
ReplyTo: {

View File

@@ -135,7 +135,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
label={t("jobs.fields.referral_source_extra")}
name="referral_source_extra"
>
<Input />
<Input disabled={jobRO}/>
</Form.Item>
<Form.Item label={t("jobs.fields.alt_transport")} name="alt_transport">
<Select disabled={jobRO} allowClear>

View File

@@ -147,7 +147,7 @@ export function JobsDetailHeaderCsi({
replyTo: bodyshop.email,
},
template: {
name: TemplateList("job").csi_invitation.key,
name: TemplateList("job_special").csi_invitation_action.key,
variables: {
id: job.csiinvites[0].id,
},

View File

@@ -3,6 +3,7 @@ import { Button, Card, Col, PageHeader, Row, Space } from "antd";
import React from "react";
import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
import ScheduleModal from "../schedule-job-modal/schedule-job-modal.container";
//import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
import ScheduleProductionList from "../schedule-production-list/schedule-production-list.component";
export default function ScheduleCalendarComponent({ data, refetch }) {
@@ -21,8 +22,10 @@ export default function ScheduleCalendarComponent({ data, refetch }) {
>
<SyncOutlined />
</Button>
<ScheduleProductionList />
{
// <ScheduleManualEvent />
}
</Space>
}
/>

View File

@@ -5,9 +5,8 @@ import {
Input,
Row,
Select,
Space,
Switch,
Typography,
Space, Switch,
Typography
} from "antd";
import axios from "axios";
import moment from "moment";
@@ -75,6 +74,12 @@ export function ScheduleJobModalComponent({
return (
<Row gutter={[16, 16]}>
<Col span={12}>
<Space>
<Typography.Title level={3}>{lbrHrsData?.jobs_by_pk?.ro_number}</Typography.Title>
<Typography.Title
level={4}
>{`B/R Hrs:${lbrHrsData?.jobs_by_pk.labhrs?.aggregate.sum.mod_lb_hrs}/${lbrHrsData?.jobs_by_pk.larhrs?.aggregate.sum.mod_lb_hrs}`}</Typography.Title>
</Space>
<LayoutFormRow grow>
<Form.Item
name="start"

View File

@@ -0,0 +1,119 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Form, Input, Popover, Space } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
import {
INSERT_APPOINTMENT,
UPDATE_APPOINTMENT,
} from "../../graphql/appointments.queries";
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
export default function ScheduleManualEvent({ event }) {
const { t } = useTranslation();
const [insertAppointment] = useMutation(INSERT_APPOINTMENT);
const [updateAppointment] = useMutation(UPDATE_APPOINTMENT);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const [visibility, setVisibility] = useState(false);
// const [callQuery, { loading: entryLoading, data: entryData }] = useLazyQuery(
// QUERY_SCOREBOARD_ENTRY
// );
useEffect(() => {
if (visibility && event) {
form.setFieldsValue({ event });
}
}, [visibility, form, event]);
useEffect(() => {
// if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
// console.log("Setting FOrm");
// // form.setFieldsValue(entryData.scoreboard[0]);
// }
}, [form]);
const handleFinish = async (values) => {
logImEXEvent("job_close_add_to_scoreboard");
setLoading(true);
try {
if (event && event.id) {
updateAppointment();
} else {
insertAppointment();
}
} catch (error) {
console.log(error);
} finally {
setLoading(false);
setVisibility(false);
}
};
const overlay = (
<Card>
<div>
<Form form={form} layout="vertical" onFinish={handleFinish}>
<Form.Item
label={t("schedule.fields.note")}
name="note"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("schedule.fields.start")}
name="start"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<FormDateTimePickerComponent />
</Form.Item>
<Form.Item
label={t("schedule.fields.end")}
name="end"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<FormDateTimePickerComponent />
</Form.Item>
<Space wrap>
<Button type="primary" htmlType="submit">
{t("general.actions.save")}
</Button>
<Button onClick={() => setVisibility(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
</div>
</Card>
);
const handleClick = (e) => {
setVisibility(true);
};
return (
<Popover content={overlay} visible={visibility}>
<Button loading={loading} onClick={handleClick}>
{t("schedule.labels.manualevent")}
</Button>
</Popover>
);
}

View File

@@ -208,6 +208,7 @@ export const QUERY_LBR_HRS_BY_PK = gql`
query QUERY_LBR_HRS_BY_PK($id: uuid!) {
jobs_by_pk(id: $id) {
id
ro_number
labhrs: joblines_aggregate(
where: {
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
@@ -535,6 +536,7 @@ export const GET_JOB_BY_PK = gql`
unq_seq
line_ind
line_desc
line_ref
part_type
oem_partno
db_price

View File

@@ -1991,6 +1991,9 @@
"job_costing_ro": "Job Costing",
"job_notes": "Job Notes",
"key_tag": "Key Tag",
"mpi_animal_checklist": "MPI - Animal Checklist",
"mpi_eglass_auth": "MPI - eGlass Auth",
"mpi_final_acct_sheet": "MPI - Final Accounting Sheet",
"paint_grid": "Paint Grid",
"parts_label_single": "Parts Label - Single",
"parts_list": "Parts List",
@@ -2204,6 +2207,11 @@
"work_in_progress_payables": "Work in Progress - Payables"
}
},
"schedule": {
"labels": {
"manualevent": "Add Manual Event"
}
},
"scoreboard": {
"actions": {
"edit": "Edit"

View File

@@ -1991,6 +1991,9 @@
"job_costing_ro": "",
"job_notes": "",
"key_tag": "",
"mpi_animal_checklist": "",
"mpi_eglass_auth": "",
"mpi_final_acct_sheet": "",
"paint_grid": "",
"parts_label_single": "",
"parts_list": "",
@@ -2204,6 +2207,11 @@
"work_in_progress_payables": ""
}
},
"schedule": {
"labels": {
"manualevent": ""
}
},
"scoreboard": {
"actions": {
"edit": ""

View File

@@ -1991,6 +1991,9 @@
"job_costing_ro": "",
"job_notes": "",
"key_tag": "",
"mpi_animal_checklist": "",
"mpi_eglass_auth": "",
"mpi_final_acct_sheet": "",
"paint_grid": "",
"parts_label_single": "",
"parts_list": "",
@@ -2204,6 +2207,11 @@
"work_in_progress_payables": ""
}
},
"schedule": {
"labels": {
"manualevent": ""
}
},
"scoreboard": {
"actions": {
"edit": ""

View File

@@ -374,6 +374,39 @@ export const TemplateList = (type, context) => {
CA_SK: true,
},
},
mpi_final_acct_sheet: {
title: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
description: "Thank You Letter by RO",
key: "mpi_final_acct_sheet",
subject: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
disabled: false,
group: "post",
regions: {
CA_MB: true,
},
},
mpi_eglass_auth: {
title: i18n.t("printcenter.jobs.mpi_eglass_auth"),
description: "Thank You Letter by RO",
key: "mpi_eglass_auth",
subject: i18n.t("printcenter.jobs.mpi_eglass_auth"),
disabled: false,
group: "pre",
regions: {
CA_MB: true,
},
},
mpi_animal_checklist: {
title: i18n.t("printcenter.jobs.mpi_animal_checklist"),
description: "Thank You Letter by RO",
key: "mpi_animal_checklist",
subject: i18n.t("printcenter.jobs.mpi_animal_checklist"),
disabled: false,
group: "pre",
regions: {
CA_MB: true,
},
},
// parts_label_multi: {
// title: i18n.t("printcenter.jobs.parts_label_multi"),
// description: "Thank You Letter by RO",

View File

@@ -1261,11 +1261,13 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@craco/craco@^6.3.0":
version "6.3.0"
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-6.3.0.tgz#157ff6387dab526390b47b12e890542c7e7c6437"
integrity sha512-SCnfEQxT/6NAbU/3sIWw7gQXtzjjiTp/EZFdJTd8inPURILIy0YajrC2p8qBG2KhFo5cwgOrEDyaGyAFvvuyuA==
"@craco/craco@^6.4.0":
version "6.4.0"
resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-6.4.0.tgz#449ca141c4af5751999e8c91764c0e1d3576b420"
integrity sha512-puLp+pSL5B2tpoIPUYlWjKd0VDBPNF16BJIKEKrwg0x/9XC/4h8XPcVGNr6pd27pj8sahiH5QUdoBxB5AE9++g==
dependencies:
"@endemolshinegroup/cosmiconfig-typescript-loader" "^3.0.2"
cosmiconfig "^7.0.1"
cross-spawn "^7.0.0"
lodash "^4.17.15"
semver "^7.3.2"
@@ -1308,6 +1310,16 @@
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@endemolshinegroup/cosmiconfig-typescript-loader@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d"
integrity sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==
dependencies:
lodash.get "^4"
make-error "^1"
ts-node "^9"
tslib "^2"
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@@ -2191,10 +2203,10 @@
"@sentry/utils" "6.13.3"
tslib "^1.9.3"
"@sentry/cli@^1.68.0":
version "1.69.1"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.69.1.tgz#0a6de12346c0f2347d610835a18ff554f2d65adc"
integrity sha512-HxO7vjqSvWfc9L5A/ib3UB1mXKFNiORY9BXwtYTo38jv4ROrKDFz36IzHsD6nPFuv8+6iDVyNlEujK/n9NvRyw==
"@sentry/cli@^1.70.1":
version "1.70.1"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.70.1.tgz#908517b699c0714eff88bedb68c6ea72e94945e8"
integrity sha512-pab3nU3rNsq1HKKmJP2ITDl5cGi+QbQ5eLX6ELaeAbN2eAzfndHu2rTqlnjJAKcYQg6l9gFBn8vvY2xAeRJb6Q==
dependencies:
https-proxy-agent "^5.0.0"
mkdirp "^0.5.5"
@@ -2268,12 +2280,12 @@
"@sentry/types" "6.13.3"
tslib "^1.9.3"
"@sentry/webpack-plugin@^1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.18.1.tgz#0fa24297043305057111d85a7154d4b8b24d43a6"
integrity sha512-maEnHC0nxRnVgAz0qvKvhTGy+SxneR8MFjpgNMvh9CyAB6GEM9VQI1hzxTcAd7Qk90qGW8W4eUmB+ZX8nMrM1w==
"@sentry/webpack-plugin@^1.18.3":
version "1.18.3"
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.18.3.tgz#1cd3401f84f561b4a451dac5f42465ee5102f5d6"
integrity sha512-Qk3Jevislc5DZK0X/WwRVcOtO7iatnWARsEgTV/TuXvDN+fUDDpD/2MytAWAbpLaLy3xEB/cXGeLsbv6d1XNkQ==
dependencies:
"@sentry/cli" "^1.68.0"
"@sentry/cli" "^1.70.1"
"@sinonjs/commons@^1.7.0":
version "1.8.3"
@@ -3302,6 +3314,11 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.6"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -4653,7 +4670,7 @@ cosmiconfig@^6.0.0:
path-type "^4.0.0"
yaml "^1.7.2"
cosmiconfig@^7.0.0:
cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
@@ -4703,6 +4720,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -5305,6 +5327,11 @@ diff-sequences@^26.6.2:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -7112,10 +7139,10 @@ i18next-browser-languagedetector@^6.1.2:
dependencies:
"@babel/runtime" "^7.14.6"
i18next@^21.3.2:
version "21.3.2"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.3.2.tgz#8a83593e764fe19b81565737fbf78eed8a70ab00"
integrity sha512-ojsp2GYeXaPNkMaG2p4Ot2bNZjvCFpTGT5ffnDLyMaLQovLEtTjv66X9riP0vkq1W3+Ici2cty77So+bfyDjSQ==
i18next@^21.3.3:
version "21.3.3"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.3.3.tgz#1065d557328db29a2e1f33526ed37608cdb0242c"
integrity sha512-Wv5arCT9pK35nfhOzTdS64T7JpPcoqnkOEidxc4zF0DZ8KetpvmnkO+uWkXy+DFz6zWzPX7U9bIemwBqpFRprw==
dependencies:
"@babel/runtime" "^7.12.0"
@@ -8638,6 +8665,11 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.get@^4:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash.isequal@^4.0.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@@ -8753,6 +8785,11 @@ make-dir@^3.0.0, make-dir@^3.0.2:
dependencies:
semver "^6.0.0"
make-error@^1, make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
makeerror@1.0.x:
version "1.0.11"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
@@ -11331,10 +11368,10 @@ react-beautiful-dnd@^13.0.0:
redux "^4.0.4"
use-memo-one "^1.1.1"
react-big-calendar@^0.36.1:
version "0.36.1"
resolved "https://registry.yarnpkg.com/react-big-calendar/-/react-big-calendar-0.36.1.tgz#3a74db72dc293de899759e01bfb72ec1715f8787"
integrity sha512-pzg8X/Tc1szg//KoV2GP9YnPPRhE3uCIXSP10Jlr46jMcBiMZ/wP7WGhpgaGVKEL30rR/BDLz7rhXaAYDX/UuQ==
react-big-calendar@^0.38.0:
version "0.38.0"
resolved "https://registry.yarnpkg.com/react-big-calendar/-/react-big-calendar-0.38.0.tgz#53fd1f69046fdff72d1c2311ace4655797936fb1"
integrity sha512-eoVkt9gTo+f1HBL09+o7dYLxp6QxHv52fcn50P5PfaWp3S98uGLQqoqsvghT85koMKvGfDVa5V0+J7yHcaF07Q==
dependencies:
"@babel/runtime" "^7.1.5"
clsx "^1.0.4"
@@ -12269,10 +12306,10 @@ sass-loader@^10.0.5:
schema-utils "^3.0.0"
semver "^7.3.2"
sass@^1.43.2:
version "1.43.2"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.43.2.tgz#c02501520c624ad6622529a8b3724eb08da82d65"
integrity sha512-DncYhjl3wBaPMMJR0kIUaH3sF536rVrOcqqVGmTZHQRRzj7LQlyGV7Mb8aCKFyILMr5VsPHwRYtyKpnKYlmQSQ==
sass@^1.43.3:
version "1.43.3"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.43.3.tgz#aa16a69131b84f0cd23189a242571e8905f1ce43"
integrity sha512-BJnLngqWpMeS65UvlYYEuCb3/fLxDxhHtOB/gWPxs6NKrslTxGt3ZxwIvOe/0Jm4tWwM/+tIpE3wj4dLEhPDeQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
@@ -12704,7 +12741,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20:
source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20:
version "0.5.20"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9"
integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==
@@ -13100,10 +13137,10 @@ style-utils@~0.2.0:
resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.2.1.tgz#c78fe6696214f4ab12701959f09553e9d81dd45b"
integrity sha512-eKRIfWnUSdBqe2ko+qisUwBSlfWpHru89geRqzmScpDhkPW1ksmE04d//nDcXeF+TVK5cnBG90mMmHgxyxXleQ==
styled-components@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.1.tgz#8a86dcd31bff7049c2ed408bae36fa23f03f071a"
integrity sha512-JThv2JRzyH0NOIURrk9iskdxMSAAtCfj/b2Sf1WJaCUsloQkblepy1jaCLX/bYE+mhYo3unmwVSI9I5d9ncSiQ==
styled-components@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743"
integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/traverse" "^7.4.5"
@@ -13511,6 +13548,18 @@ ts-invariant@^0.9.0:
dependencies:
tslib "^2.1.0"
ts-node@^9:
version "9.1.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
dependencies:
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.17"
yn "3.1.1"
ts-pnp@1.2.0, ts-pnp@^1.1.6:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
@@ -13531,7 +13580,7 @@ tslib@^1.8.1, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0:
tslib@^2, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
@@ -14675,6 +14724,11 @@ yeast@0.1.2:
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"

File diff suppressed because one or more lines are too long

View File

@@ -17,7 +17,7 @@
"start": "node server.js"
},
"dependencies": {
"aws-sdk": "^2.1009.0",
"aws-sdk": "^2.1013.0",
"bluebird": "^3.7.2",
"body-parser": "^1.18.3",
"cloudinary": "^1.27.1",
@@ -45,8 +45,8 @@
"soap": "^0.42.0",
"socket.io": "^4.3.1",
"ssh2-sftp-client": "^7.1.0",
"stripe": "^8.183.0",
"twilio": "^3.69.0",
"stripe": "^8.184.0",
"twilio": "^3.70.0",
"uuid": "^8.3.2",
"xmlbuilder2": "^3.0.2"
},

View File

@@ -76,7 +76,7 @@ exports.default = function ({
{
local: false,
federal: true,
state: jobline.tax_part,
state: (jobline.db_ref === "900511" || jobline.db_ref === "900510") ? true: jobline.tax_part,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);

View File

@@ -1,4 +1,5 @@
const urlBuilder = require("./qbo").urlBuilder;
const StandardizeName = require("./qbo").StandardizeName;
const path = require("path");
require("dotenv").config({
path: path.resolve(
@@ -114,7 +115,9 @@ async function QueryVendorRecord(oauthClient, qbo_realmId, req, bill) {
url: urlBuilder(
qbo_realmId,
"query",
`select * From vendor where DisplayName = '${bill.vendor.name}'`
`select * From vendor where DisplayName = '${StandardizeName(
bill.vendor.name
)}'`
),
method: "POST",
headers: {
@@ -152,7 +155,7 @@ async function InsertVendorRecord(oauthClient, qbo_realmId, req, bill) {
body: JSON.stringify(Vendor),
});
setNewRefreshToken(req.user.email, result);
return result && result.Vendor;
return result && result.json && result.json.Vendor;
} catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
error:
@@ -180,9 +183,9 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
DocNumber: bill.invoice_number,
...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}),
Memo: `RO ${bill.job.ro_number || ""} OWNER ${bill.job.ownr_fn || ""} ${
bill.job.ownr_ln || ""
} ${bill.job.ownr_co_nm || ""}`,
PrivateNote: `RO ${bill.job.ro_number || ""} OWNER ${
bill.job.ownr_fn || ""
} ${bill.job.ownr_ln || ""} ${bill.job.ownr_co_nm || ""}`,
Line: bill.billlines.map((il) =>
generateBillLine(
il,
@@ -211,7 +214,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
body: JSON.stringify(billQbo),
});
setNewRefreshToken(req.user.email, result);
return result && result.Bill;
return result && result.json && result.json.Bill;
} catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
error:
@@ -245,6 +248,8 @@ const generateBillLine = (
costCenters
) => {
const account = costCenters.find((c) => c.name === billLine.cost_center);
console.log(account.accountname, accounts[account.accountname]);
return {
DetailType: "AccountBasedExpenseLineDetail",

View File

@@ -27,6 +27,7 @@ const {
} = require("../qbo/qbo-receivables");
const { urlBuilder } = require("./qbo");
const { DineroQbFormat } = require("../accounting-constants");
const { findTaxCode } = require("../qb-receivables-lines");
exports.default = async (req, res) => {
const oauthClient = new OAuthClient({
@@ -135,7 +136,17 @@ exports.default = async (req, res) => {
);
}
await InsertPayment(oauthClient, qbo_realmId, req, payment, jobTier);
if (payment.amount > 0) {
await InsertPayment(oauthClient, qbo_realmId, req, payment, jobTier);
} else {
await InsertCreditMemo(
oauthClient,
qbo_realmId,
req,
payment,
jobTier
);
}
ret.push({ paymentid: payment.id, success: true });
} catch (error) {
logger.log("qbo-payment-create-error", "ERROR", req.user.email, {
@@ -173,7 +184,8 @@ async function InsertPayment(
oauthClient,
qbo_realmId,
req,
payment.job.ro_number
payment.job.ro_number,
false
);
if (invoices && invoices.length !== 1) {
@@ -235,7 +247,13 @@ async function InsertPayment(
throw error;
}
}
async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
async function QueryMetaData(
oauthClient,
qbo_realmId,
req,
ro_number,
isCreditMemo
) {
const invoice = await oauthClient.makeApiCall({
url: urlBuilder(
qbo_realmId,
@@ -288,8 +306,50 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
// classes.json.QueryResponse.Class.forEach((t) => {
// accountMapping[t.Name] = t.Id;
// });
let ret = {};
if (isCreditMemo) {
const taxCodes = await oauthClient.makeApiCall({
url: urlBuilder(qbo_realmId, "query", `select * From TaxCode`),
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
const items = await oauthClient.makeApiCall({
url: urlBuilder(qbo_realmId, "query", `select * From Item`),
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
setNewRefreshToken(req.user.email, items);
const itemMapping = {};
items.json &&
items.json.QueryResponse &&
items.json.QueryResponse.Item &&
items.json.QueryResponse.Item.forEach((t) => {
itemMapping[t.Name] = t.Id;
});
const taxCodeMapping = {};
taxCodes.json &&
taxCodes.json.QueryResponse &&
taxCodes.json.QueryResponse.TaxCode &&
taxCodes.json.QueryResponse.TaxCode.forEach((t) => {
taxCodeMapping[t.Name] = t.Id;
});
ret = {
...ret,
items: itemMapping,
taxCodes: taxCodeMapping,
};
}
return {
...ret,
paymentMethods: paymentMethodMapping,
invoices:
invoice.json &&
@@ -297,3 +357,87 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
invoice.json.QueryResponse.Invoice,
};
}
async function InsertCreditMemo(
oauthClient,
qbo_realmId,
req,
payment,
parentRef
) {
const { paymentMethods, invoices, items, taxCodes } = await QueryMetaData(
oauthClient,
qbo_realmId,
req,
payment.job.ro_number,
true
);
if (invoices && invoices.length !== 1) {
throw new Error(
`More than 1 invoice with DocNumber ${payment.ro_number} found.`
);
}
const paymentQbo = {
CustomerRef: {
value: parentRef.Id,
},
TxnDate: moment(payment.date).format("YYYY-MM-DD"),
DocNumber: payment.paymentnum,
...(invoices && invoices[0]
? { InvoiceRef: { value: invoices[0].Id } }
: {}),
Line: [
{
DetailType: "SalesItemLineDetail",
Amount: Dinero({ amount: Math.round(payment.amount * -100) }).toFormat(
DineroQbFormat
),
SalesItemLineDetail: {
ItemRef: {
value:
items[
payment.job.bodyshop.md_responsibility_centers.refund
.accountitem
],
},
Qty: 1,
TaxCodeRef: {
value:
taxCodes[
findTaxCode(
{
local: false,
federal: false,
state: false,
},
payment.job.bodyshop.md_responsibility_centers.sales_tax_codes
)
],
},
},
},
],
};
logger.log("qbo-payments-objectlog", "DEBUG", req.user.email, payment.id, {
paymentQbo,
});
try {
const result = await oauthClient.makeApiCall({
url: urlBuilder(qbo_realmId, "creditmemo"),
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(paymentQbo),
});
setNewRefreshToken(req.user.email, result);
return result && result.Bill;
} catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, {
error: error && error.message,
method: "InsertCreditMemo",
});
throw error;
}
}

View File

@@ -1,4 +1,6 @@
const urlBuilder = require("./qbo").urlBuilder;
const StandardizeName = require("./qbo").StandardizeName;
const path = require("path");
require("dotenv").config({
path: path.resolve(
@@ -166,7 +168,9 @@ async function QueryInsuranceCo(oauthClient, qbo_realmId, req, job) {
url: urlBuilder(
qbo_realmId,
"query",
`select * From Customer where DisplayName = '${job.ins_co_nm}'`
`select * From Customer where DisplayName = '${StandardizeName(
job.ins_co_nm
)}'`
),
method: "POST",
headers: {
@@ -228,7 +232,9 @@ async function QueryOwner(oauthClient, qbo_realmId, req, job) {
url: urlBuilder(
qbo_realmId,
"query",
`select * From Customer where DisplayName = '${ownerName}'`
`select * From Customer where DisplayName = '${StandardizeName(
ownerName
)}'`
),
method: "POST",
headers: {
@@ -458,7 +464,7 @@ async function InsertInvoice(
body: JSON.stringify(invoiceObj),
});
setNewRefreshToken(req.user.email, result);
return result && result.Invoice;
return result && result.json && result.json.Invoice;
} catch (error) {
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
error,

View File

@@ -14,7 +14,12 @@ function urlBuilder(realmId, object, query = null) {
}`;
}
function StandardizeName(str) {
return str.replace(new RegExp(/'/g), "\\'");
}
exports.urlBuilder = urlBuilder;
exports.StandardizeName = StandardizeName;
exports.callback = require("./qbo-callback").default;
exports.authorize = require("./qbo-authorize").default;
exports.refresh = require("./qbo-callback").refresh;

View File

@@ -152,7 +152,7 @@ const generatePayment = (payment, isThreeTier, twoTierPref) => {
QBXML: {
QBXMLMsgsRq: {
"@onError": "continueOnError",
CreditMemoAddRq: {
wMemoAddRq: {
CreditMemoAdd: {
CustomerRef: {
FullName: (payment.job.bodyshop.accountingconfig.tiers === 3

View File

@@ -15,7 +15,7 @@ const CalcualteAllocations = require("./cdk-calculate-allocations").default;
const moment = require("moment");
const replaceSpecialRegex = `[^a-zA-Z0-9 .,\n #]+/g`;
const replaceSpecialRegex = /[^a-zA-Z0-9 .,\n #]+/g;
exports.default = async function (socket, { txEnvelope, jobid }) {
socket.logEvents = [];
@@ -584,15 +584,21 @@ async function InsertDmsCustomer(socket, newCustomerNumber) {
addressLine:
socket.JobData.ownr_addr1 &&
socket.JobData.ownr_addr1.replace(replaceSpecialRegex, ""),
city: socket.JobData.ownr_city.replace(replaceSpecialRegex, ""),
country: null,
city:
socket.JobData.ownr_city &&
socket.JobData.ownr_city.replace(replaceSpecialRegex, ""),
country:
socket.JobData.ownr_ctry &&
socket.JobData.ownr_ctry.replace(replaceSpecialRegex, ""),
postalCode:
socket.JobData.ownr_zip &&
socket.JobData.ownr_zip //TODO Need to remove for US Based customers.
.toUpperCase()
.replace(/\W/g, "")
.replace(/(...)/, "$1 "),
stateOrProvince: socket.JobData.ownr_st,
stateOrProvince:
socket.JobData.ownr_st &&
socket.JobData.ownr_st.replace(replaceSpecialRegex, ""),
},
contactInfo: {
mainTelephoneNumber: {
@@ -1090,18 +1096,6 @@ async function GenerateTransWips(socket) {
wips.push(item);
});
//should validate that the wips = 0
console.log(
"WIPS TOTAL",
wips.reduce((acc, val) => {
console.log(val);
console.log(acc + val.postAmt);
return acc + val.postAmt;
}, 0)
);
return wips;
}

View File

@@ -20,6 +20,28 @@ mutation UNARCHIVE_CONVERSATION($id: uuid!) {
}
`;
exports.RECEIVE_MESSAGE = `
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
insert_messages(objects: $msg) {
returning {
conversation {
id
archived
bodyshop {
associations(where: {active: {_eq: true}}) {
user {
fcmtokens
}
}
}
}
}
}
}
`;
exports.INSERT_MESSAGE = `
mutation INSERT_MESSAGE($msg: [messages_insert_input!]!, $conversationid: uuid!) {
update_conversations_by_pk(pk_columns: {id: $conversationid}, _set: {archived: false}) {
@@ -152,6 +174,7 @@ query QUERY_JOBS_FOR_CDK_EXPORT($id: uuid!) {
ownr_ph2
ownr_zip
ownr_city
ownr_ctry
ownr_st
ownr_ea
ins_co_nm
@@ -775,6 +798,7 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
line_ind
line_desc
part_type
line_ref
oem_partno
db_price
act_price

View File

@@ -486,7 +486,9 @@ function CalculateTaxesTotals(job, otherTotals) {
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
.multiply(val.part_qty || 0)
.add(
val.prt_dsmk_m && val.prt_dsmk_m !== 0
val.prt_dsmk_m &&
val.prt_dsmk_m !== 0 &&
DiscountNotAlreadyCounted(val, job.joblines)
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
: Dinero({
amount: Math.round(val.act_price * 100),
@@ -566,3 +568,9 @@ function CalculateTaxesTotals(job, otherTotals) {
}
exports.default = Totals;
function DiscountNotAlreadyCounted(jobline, joblines) {
if (jobline.db_ref !== "900510") return true;
const ParentLine = joblines.find((j) => j.unq_seq === jobline.line_ref);
return ParentLine && !(ParentLine.prt_dsmk_m && ParentLine.prt_dsmk_m !== 0);
}

View File

@@ -26,7 +26,7 @@ exports.job = async (req, res) => {
const result = await client
.setHeaders({ Authorization: BearerToken })
.request(queries.QUERY_UPCOMING_APPOINTMENTS, {
now: new Date(),
now: moment().startOf("day"),
jobId: jobId,
});
@@ -42,6 +42,7 @@ exports.job = async (req, res) => {
const bucketMatrix = {};
const yesterday = moment().subtract(1, "day");
//Get latest date + add 5 days to allow for back end adding..
const totalMatrixDays = moment
.max([
...appointments.map((a) => moment(a.start)),
@@ -53,7 +54,7 @@ exports.job = async (req, res) => {
.diff(moment(), "days");
//Initialize the bucket matrix
for (i = 0; i < totalMatrixDays; i++) {
for (var i = 0; i < totalMatrixDays; i++) {
const theDate = moment().add(i, "days").format("yyyy-MM-DD");
//Only need to create a matrix for jobs of the same bucket.
bucketMatrix[theDate] = { in: 0, out: 0 };
@@ -146,7 +147,7 @@ exports.job = async (req, res) => {
}
} catch (error) {
logger.log("smart-scheduling-error", "ERROR", req.user.email, jobId, {
error,
error: JSON.stringify(error),
});
res.status(400).send(error);
}

View File

@@ -11,7 +11,7 @@ const queries = require("../graphql-client/queries");
const { phone } = require("phone");
const admin = require("../firebase/firebase-handler").admin;
const logger = require("../utils/logger");
exports.receive = (req, res) => {
exports.receive = async (req, res) => {
//Perform request validation
logger.log("sms-inbound", "DEBUG", "api", null, {
@@ -36,114 +36,80 @@ exports.receive = (req, res) => {
res.status(400);
res.json({ success: false, error: "Malformed Request" });
} else {
client
.request(queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, {
mssid: req.body.MessagingServiceSid,
phone: phone(req.body.From).phoneNumber,
})
.then((response) => {
let newMessage = {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
};
if (response.bodyshops[0]) {
//Found a bodyshop - should always happen.
if (response.bodyshops[0].conversations.length === 0) {
//No conversation Found, create one.
console.log("[SMS Receive] No conversation found. Creating one.");
newMessage.conversation = {
data: {
bodyshopid: response.bodyshops[0].id,
phone_num: phone(req.body.From).phoneNumber,
},
};
} else if (response.bodyshops[0].conversations.length === 1) {
//Just add it to the conversation
console.log("[SMS Receive] Conversation found. Added ID.");
newMessage.conversationid =
response.bodyshops[0].conversations[0].id;
} else {
//We should never get here.
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
type: "duplicate-phone",
try {
const response = await client.request(
queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID,
{
mssid: req.body.MessagingServiceSid,
phone: phone(req.body.From).phoneNumber,
}
);
let newMessage = {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
};
if (response.bodyshops[0]) {
//Found a bodyshop - should always happen.
if (response.bodyshops[0].conversations.length === 0) {
//No conversation Found, create one.
console.log("[SMS Receive] No conversation found. Creating one.");
newMessage.conversation = {
data: {
bodyshopid: response.bodyshops[0].id,
phone_num: phone(req.body.From).phoneNumber,
},
};
} else if (response.bodyshops[0].conversations.length === 1) {
//Just add it to the conversation
console.log("[SMS Receive] Conversation found. Added ID.");
newMessage.conversationid = response.bodyshops[0].conversations[0].id;
} else {
//We should never get here.
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
type: "duplicate-phone",
});
}
try {
const r2 = await client.request(queries.RECEIVE_MESSAGE, {
msg: newMessage,
});
if (response.bodyshops[0].conversations[0]) {
const r3 = await client.request(queries.INSERT_MESSAGE, {
id:
response.bodyshops[0].conversations[0] &&
response.bodyshops[0].conversations[0].id,
});
}
client
.request(queries.INSERT_MESSAGE, {
msg: newMessage,
conversationid: response.bodyshops[0].conversations[0].id,
})
.then((r2) => {
logger.log("sms-inbound-success", "DEBUG", "api", null, {
newMessage,
});
res.status(200).send("");
logger.log("sms-inbound-success", "DEBUG", "api", null, {
newMessage,
});
res.status(200).send("");
} catch (e2) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
error: e2,
});
const arrayOfAllUserFcmTokens =
r2.insert_messages.returning[0].conversation.bodyshop.associations.map(
(a) => a.user.fcmtokens
);
const allTokens = [];
arrayOfAllUserFcmTokens.map((i) =>
Object.keys(i).map((k) => allTokens.push(k))
);
const uniqueTokens = [...new Set(allTokens)];
var message = {
notification: {
title: `SMS - ${phone(req.body.From).phoneNumber}`,
body: req.body.Body,
click_action: "TEST CLICK ACTION",
},
data: {
jobid: "1234",
title: `New SMS From ${phone(req.body.From).phoneNumber}`,
body: req.body.Body,
},
tokens: uniqueTokens,
};
// Send a message to the device corresponding to the provided
// registration token.
// admin
// .messaging()
// .sendMulticast(message)
// .then((response) => {
// // Response is a message ID string.
// console.log(
// "[SMS Receive] Successfully sent FCM Broadcast.:"
// //JSON.stringify(response)
// );
// })
// .catch((error) => {
// console.log("Error sending message:", error);
// });
})
.catch((e2) => {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
error: e2,
});
res.sendStatus(500).json(e2);
});
res.sendStatus(500).json(e2);
}
})
.catch((e1) => {
console.log("e1", e1);
res.sendStatus(500).json(e1);
});
}
} catch (e1) {
console.log("e1", e1);
res.sendStatus(500).json(e1);
}
}
};

View File

@@ -600,10 +600,10 @@ atob@2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
aws-sdk@^2.1009.0:
version "2.1009.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1009.0.tgz#d96217a19f259c2448f91cf24973d390de16f8e0"
integrity sha512-qKbmt+vzQ7ZSnfEvA+u6d7CkV09AcAGnxZAiNgOAEn8GFFEtERy6C39VoAuWfON/B2avJDYvtRocjVmAxWpgjQ==
aws-sdk@^2.1013.0:
version "2.1013.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1013.0.tgz#85babc473b0bc90cc1160eb48baf616ddb86e346"
integrity sha512-TXxkp/meAdofpC15goFpNuur7fvh/mcMRfHJoP1jYzTtD0wcoB4FK16GLcny0uDYgkQgZuiO9QYv3Rq5bhGCqQ==
dependencies:
buffer "4.9.2"
events "1.1.1"
@@ -639,6 +639,13 @@ axios@^0.21.1:
dependencies:
follow-redirects "^1.10.0"
axios@^0.21.4:
version "0.21.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
dependencies:
follow-redirects "^1.14.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -1731,6 +1738,11 @@ follow-redirects@^1.10.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e"
integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==
follow-redirects@^1.14.0:
version "1.14.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -3739,10 +3751,10 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
stripe@^8.183.0:
version "8.183.0"
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.183.0.tgz#3dc183fafff618526a576a0d9972483b08075e06"
integrity sha512-QcM3nimH1CuP49VPPRt36Wgfu4QoS+Wm0eyGMis7Ej+seWFKqMffMdx7TE2gn8dVsJIOA1kDuIbAQGqpZHozGA==
stripe@^8.184.0:
version "8.184.0"
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.184.0.tgz#ea68470ca6045bb47516c4fea3b775fd6ce15a36"
integrity sha512-ZUdvyX+sizTxXLEbUjgTShrulSWSkMIt7hIKdAkhnajYrHdzVtdmhBJl8sQbR9chMVox3Ig5ohilyeIrvcCE2g==
dependencies:
"@types/node" ">=8.1.0"
qs "^6.6.0"
@@ -3906,12 +3918,12 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
twilio@^3.69.0:
version "3.69.0"
resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.69.0.tgz#641d1c16f647f5f091e253345e7983c7306bffdd"
integrity sha512-mm330UFTlFh6GyLZUPVSLO0uVCigW7JdX/wyyV3VuBJ4Z8ie/aNmgztd3xWQr6RBB98gCwJ+UtumqIfixVUm8A==
twilio@^3.70.0:
version "3.70.0"
resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.70.0.tgz#9e6a96f0c46e8256d74bce918baeb7e678c4c1aa"
integrity sha512-GhohvQfP3aHEwiCb6MWqDJ/KeSyFmFwCQtoSuHEwevE7GCxCq6spK36HlCNg3UyTTZNvfdIhN9Sf1wDWeDIbOg==
dependencies:
axios "^0.21.1"
axios "^0.21.4"
dayjs "^1.8.29"
https-proxy-agent "^5.0.0"
jsonwebtoken "^8.5.1"