Merged in release/2022-05-20 (pull request #486)

release/2022-05-20

Approved-by: Patrick Fic
This commit is contained in:
Patrick Fic
2022-05-19 18:26:10 +00:00
27 changed files with 4500 additions and 4419 deletions

View File

@@ -33533,6 +33533,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>removefrompartsqueue</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>returnpartsorder</name>
<definition_loaded>false</definition_loaded>
@@ -44249,6 +44270,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>notes</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>plate_no</name>
<definition_loaded>false</definition_loaded>

View File

@@ -4,54 +4,54 @@
"private": true,
"proxy": "http://localhost:4000",
"dependencies": {
"@apollo/client": "^3.5.10",
"@apollo/client": "^3.6.2",
"@asseinfo/react-kanban": "^2.2.0",
"@craco/craco": "^6.4.3",
"@fingerprintjs/fingerprintjs": "^3.3.3",
"@sentry/react": "^6.19.6",
"@sentry/tracing": "^6.19.6",
"@splitsoftware/splitio-react": "^1.4.0",
"@stripe/react-stripe-js": "^1.7.1",
"@stripe/stripe-js": "^1.27.0",
"@tanem/react-nprogress": "^4.0.12",
"antd": "^4.19.5",
"@sentry/react": "^6.19.7",
"@sentry/tracing": "^6.19.7",
"@splitsoftware/splitio-react": "^1.4.1",
"@stripe/react-stripe-js": "^1.8.0",
"@stripe/stripe-js": "^1.29.0",
"@tanem/react-nprogress": "^5.0.0",
"antd": "^4.20.5",
"apollo-link-logger": "^2.0.0",
"axios": "^0.26.1",
"axios": "^0.27.2",
"craco-less": "^1.20.0",
"dinero.js": "^1.9.1",
"dotenv": "^16.0.0",
"dotenv": "^16.0.1",
"enquire-js": "^0.2.1",
"env-cmd": "^10.1.0",
"exifr": "^7.1.3",
"firebase": "^9.6.11",
"graphql": "^16.3.0",
"i18next": "^21.6.16",
"firebase": "^9.8.1",
"graphql": "^16.5.0",
"i18next": "^21.8.2",
"i18next-browser-languagedetector": "^6.1.4",
"jsoneditor": "^9.7.4",
"jsreport-browser-client-dist": "^1.3.0",
"libphonenumber-js": "^1.9.51",
"logrocket": "^2.2.1",
"markerjs2": "^2.21.1",
"libphonenumber-js": "^1.9.53",
"logrocket": "^3.0.0",
"markerjs2": "^2.21.4",
"moment-business-days": "^1.2.0",
"moment-timezone": "^0.5.34",
"normalize-url": "^7.0.3",
"phone": "^3.1.15",
"phone": "^3.1.17",
"preval.macro": "^5.0.0",
"prop-types": "^15.8.1",
"query-string": "^7.1.1",
"rc-queue-anim": "^2.0.0",
"rc-scroll-anim": "^2.7.6",
"react": "^17.0.2",
"react-big-calendar": "^0.38.2",
"react-big-calendar": "^0.40.1",
"react-color": "^2.19.3",
"react-cookie": "^4.1.1",
"react-dom": "^17.0.2",
"react-drag-listview": "^0.1.9",
"react-drag-listview": "^0.2.0",
"react-grid-gallery": "^0.5.5",
"react-grid-layout": "^1.3.4",
"react-i18next": "^11.16.6",
"react-i18next": "^11.16.9",
"react-icons": "^4.3.1",
"react-number-format": "^4.9.1",
"react-number-format": "^4.9.3",
"react-redux": "^7.2.8",
"react-resizable": "^3.0.4",
"react-router-dom": "^5.3.0",
@@ -60,28 +60,28 @@
"react-sublime-video": "^0.2.5",
"react-virtualized": "^9.22.3",
"recharts": "^2.1.9",
"redux": "^4.1.2",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"redux-state-sync": "^3.1.2",
"reselect": "^4.1.5",
"sass": "^1.50.0",
"socket.io-client": "^4.4.1",
"sass": "^1.51.0",
"socket.io-client": "^4.5.0",
"styled-components": "^5.3.5",
"subscriptions-transport-ws": "^0.11.0",
"web-vitals": "^2.1.4",
"workbox-background-sync": "^6.5.2",
"workbox-broadcast-update": "^6.5.2",
"workbox-cacheable-response": "^6.5.2",
"workbox-core": "^6.5.2",
"workbox-expiration": "^6.5.2",
"workbox-google-analytics": "^6.5.2",
"workbox-navigation-preload": "^6.5.2",
"workbox-precaching": "^6.5.2",
"workbox-range-requests": "^6.5.2",
"workbox-routing": "^6.5.2",
"workbox-strategies": "^6.5.2",
"workbox-streams": "^6.5.2",
"workbox-background-sync": "^6.5.3",
"workbox-broadcast-update": "^6.5.3",
"workbox-cacheable-response": "^6.5.3",
"workbox-core": "^6.5.3",
"workbox-expiration": "^6.5.3",
"workbox-google-analytics": "^6.5.3",
"workbox-navigation-preload": "^6.5.3",
"workbox-precaching": "^6.5.3",
"workbox-range-requests": "^6.5.3",
"workbox-routing": "^6.5.3",
"workbox-strategies": "^6.5.3",
"workbox-streams": "^6.5.3",
"yauzl": "^2.10.0"
},
"scripts": {
@@ -118,11 +118,11 @@
"react-error-overlay": "6.0.9"
},
"devDependencies": {
"@sentry/webpack-plugin": "^1.18.8",
"@sentry/webpack-plugin": "^1.18.9",
"@testing-library/cypress": "^8.0.2",
"cypress": "^9.5.3",
"cypress": "^9.6.1",
"eslint-plugin-cypress": "^2.12.1",
"react-error-overlay": "6.0.10",
"react-error-overlay": "6.0.11",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.2"
}

View File

@@ -16,15 +16,18 @@ export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_filehandlers.map((est, idx) => (
<Menu.Item value={est} key={idx}>
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
</Menu.Item>
))}
</Menu>
</div>
<Menu
onClick={handleClick}
style={{
columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1,
}}
>
{bodyshop.md_filehandlers.map((est, idx) => (
<Menu.Item value={est} key={idx} style={{ breakInside: "avoid" }}>
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
</Menu.Item>
))}
</Menu>
);
return (

View File

@@ -216,6 +216,22 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} job={job} />
</DataLabel>
{job.vehicle && job.vehicle.notes && (
<DataLabel label={t("vehicles.fields.notes")}>
<span style={{ whiteSpace: "pre" }}>{job.vehicle.notes}</span>
</DataLabel>
)}
{
// job.vehicle && job.vehicle.v_paint_codes && (
// <DataLabel label={t("vehicles.fields.v_paint_codes")}>
// <span style={{ whiteSpace: "pre" }}>
// {Object.keys(job.vehicle.v_paint_codes).map((key, idx) => (
// <Tag key={idx}>{job.vehicle.v_paint_codes[key]}</Tag>
// ))}
// </span>
// </DataLabel>
// )
}
</div>
</Card>
</Col>

View File

@@ -61,7 +61,9 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) {
jobId={jobId}
loading={loading}
data={data ? data.jobs_by_pk.notes : null}
relatedRos={data ? data.jobs_by_pk.vehicle.jobs : null}
relatedRos={
data ? data.jobs_by_pk.vehicle && data.jobs_by_pk.vehicle.jobs : null
}
refetch={refetch}
deleteLoading={deleteLoading}
handleNoteDelete={handleNoteDelete}

View File

@@ -72,13 +72,9 @@ export function NoteUpsertModalContainer({
toggleModalVisible();
} else {
logImEXEvent("job_note_insert");
const AdditionalNoteInserts = Object.keys(relatedros).filter(
(key) => relatedros[key]
);
console.log(
"🚀 ~ file: note-upsert-modal.container.jsx ~ line 78 ~ handleFinish ~ AdditionalNoteInserts",
AdditionalNoteInserts
);
const AdditionalNoteInserts = relatedros
? Object.keys(relatedros).filter((key) => relatedros[key])
: [];
await insertNote({
variables: {

View File

@@ -22,9 +22,17 @@ export function NotesPresetButton({ bodyshop, form }) {
};
const menu = (
<Menu>
<Menu
style={{
columnCount: Math.floor(bodyshop.md_notes_presets.length / 10) + 1,
}}
>
{bodyshop.md_notes_presets.map((i, idx) => (
<Menu.Item onClick={() => handleSelect(i)} key={idx}>
<Menu.Item
onClick={() => handleSelect(i)}
key={idx}
style={{ breakInside: "avoid" }}
>
{i.label}
</Menu.Item>
))}

View File

@@ -11,6 +11,7 @@ import {
Select,
Menu,
Dropdown,
Checkbox,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -114,6 +115,15 @@ export function PartsOrderModalComponent({
</Space>
</Tag>
)}
{!isReturn && (
<Form.Item
name="removefrompartsqueue"
label={t("parts_orders.labels.removefrompartsqueue")}
valuePropName="checked"
>
<Checkbox />
</Form.Item>
)}
</LayoutFormRow>
<Divider orientation="left">
{t("parts_orders.labels.inthisorder")}
@@ -280,6 +290,7 @@ export function PartsOrderModalComponent({
>
<Input.TextArea rows={3} />
</Form.Item>
<Radio.Group
defaultValue={sendType}
onChange={(e) => setSendType(e.target.value)}

View File

@@ -32,6 +32,7 @@ import PartsOrderModalComponent from "./parts-order-modal.component";
import axios from "axios";
import { useTreatments } from "@splitsoftware/splitio-react";
import _ from "lodash";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -90,8 +91,9 @@ export function PartsOrderModalContainer({
const [insertPartOrder] = useMutation(INSERT_NEW_PARTS_ORDERS);
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async (values) => {
const handleFinish = async ({ removefrompartsqueue, ...values }) => {
logImEXEvent("parts_order_insert");
setSaving(true);
const insertResult = await insertPartOrder({
@@ -128,6 +130,17 @@ export function PartsOrderModalContainer({
},
});
if (!isReturn && removefrompartsqueue) {
await updateJob({
variables: {
jobId: jobId,
job: {
queued_for_parts: false,
},
},
});
}
insertAuditTrail({
jobid: jobId,
operation: isReturn

View File

@@ -8,8 +8,11 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import moment from "moment";
import { useApolloClient } from "@apollo/client";
import { GET_BLOCKED_DAYS } from "../../graphql/scoreboard.queries";
import { useApolloClient, useQuery } from "@apollo/client";
import {
GET_BLOCKED_DAYS,
QUERY_SCOREBOARD,
} from "../../graphql/scoreboard.queries";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -22,10 +25,15 @@ export default connect(
mapDispatchToProps
)(ScoreboardDisplayComponent);
export function ScoreboardDisplayComponent({
bodyshop,
scoreboardSubscription,
}) {
export function ScoreboardDisplayComponent({ bodyshop }) {
const scoreboardSubscription = useQuery(QUERY_SCOREBOARD, {
variables: {
start: moment().startOf("month"),
end: moment().endOf("month"),
},
pollInterval: 60000,
});
const { data } = scoreboardSubscription;
const client = useApolloClient();
const scoreBoardlist = (data && data.scoreboard) || [];

View File

@@ -139,6 +139,9 @@ export default function VehicleDetailFormComponent({ form, loading }) {
<Input />
</Form.Item>
</LayoutFormRow>
<Form.Item label={t("vehicles.fields.notes")} name="notes">
<Input.TextArea rows={4} />
</Form.Item>
</div>
);
}

View File

@@ -75,13 +75,9 @@ export const QUERY_PARTS_QUEUE = gql`
v_make_desc
v_color
vehicleid
actual_completion
actual_delivery
actual_in
scheduled_in
id
clm_no
clm_total
owner_owing
ro_number
status
updated_at
@@ -534,6 +530,8 @@ export const GET_JOB_BY_PK = gql`
v_model_desc
v_make_desc
v_color
notes
v_paint_codes
jobs {
id
ro_number

View File

@@ -1,7 +1,7 @@
import { gql } from "@apollo/client";
export const SUBSCRIPTION_SCOREBOARD = gql`
subscription SUBSCRIPTION_SCOREBOARD($start: date!, $end: date!) {
export const QUERY_SCOREBOARD = gql`
query QUERY_SCOREBOARD($start: date!, $end: date!) {
scoreboard(
where: { _and: { date: { _gte: $start, _lte: $end } } }
order_by: { date: asc }

View File

@@ -27,6 +27,7 @@ export const QUERY_VEHICLE_BY_ID = gql`
v_bstyle
updated_at
trim_color
notes
jobs {
id
ro_number

View File

@@ -15,7 +15,7 @@ import OwnerNameDisplay from "../../components/owner-name-display/owner-name-dis
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter";
import { alphaSort, dateSort } from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({
@@ -158,6 +158,17 @@ export function PartsQueuePageComponent({ bodyshop }) {
},
},
{
title: t("jobs.fields.scheduled_in"),
dataIndex: "scheduled_in",
key: "scheduled_in",
ellipsis: true,
sorter: (a, b) => dateSort(a.scheduled_in, b.scheduled_in),
sortOrder: sortcolumn === "scheduled_in" && sortorder,
render: (text, record) => (
<DateTimeFormatter>{record.scheduled_in}</DateTimeFormatter>
),
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",

View File

@@ -160,6 +160,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
<Button
onClick={() => {
delete searchParams.search;
searchParams.page = 1;
history.push({ search: queryString.stringify(searchParams) });
}}
>

View File

@@ -2,17 +2,14 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
import { useSubscription } from "@apollo/client";
import { SUBSCRIPTION_SCOREBOARD } from "../../graphql/scoreboard.queries";
import moment from "moment";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -26,13 +23,6 @@ const mapDispatchToProps = (dispatch) => ({
export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const scoreboardSubscription = useSubscription(SUBSCRIPTION_SCOREBOARD, {
variables: {
start: moment().startOf("month"),
end: moment().endOf("month"),
},
});
useEffect(() => {
document.title = t("titles.scoreboard");
setSelectedHeader("scoreboard");
@@ -47,7 +37,7 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
return (
<FeatureWrapper featureName="scoreboard">
<RbacWrapper action="scoreboard:view">
<ScoreboardDisplay scoreboardSubscription={scoreboardSubscription} />
<ScoreboardDisplay />
</RbacWrapper>
</FeatureWrapper>
);

View File

@@ -1980,6 +1980,7 @@
"parts_orders": "Parts Orders",
"print": "Show Printed Form",
"receive": "Receive Parts Order",
"removefrompartsqueue": "Remove from Parts Queue?",
"returnpartsorder": "Return Parts Order"
},
"successes": {
@@ -2633,6 +2634,7 @@
},
"fields": {
"description": "Vehicle Description",
"notes": "Vehicle Notes",
"plate_no": "License Plate",
"plate_st": "Plate Jurisdiction",
"trim_color": "Trim Color",

View File

@@ -1980,6 +1980,7 @@
"parts_orders": "",
"print": "Mostrar formulario impreso",
"receive": "",
"removefrompartsqueue": "",
"returnpartsorder": ""
},
"successes": {
@@ -2633,6 +2634,7 @@
},
"fields": {
"description": "Descripcion del vehiculo",
"notes": "",
"plate_no": "Placa",
"plate_st": "Jurisdicción de placas",
"trim_color": "Recortar color",

View File

@@ -1980,6 +1980,7 @@
"parts_orders": "",
"print": "Afficher le formulaire imprimé",
"receive": "",
"removefrompartsqueue": "",
"returnpartsorder": ""
},
"successes": {
@@ -2633,6 +2634,7 @@
},
"fields": {
"description": "Description du véhicule",
"notes": "",
"plate_no": "Plaque d'immatriculation",
"plate_st": "Juridiction de la plaque",
"trim_color": "Couleur de garniture",

File diff suppressed because it is too large Load Diff

View File

@@ -4925,60 +4925,62 @@
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- v_vin
- v_make_desc
- v_model_desc
- v_model_yr
- v_color
- v_paint_codes
- v_bstyle
- v_engine
- shopid
- db_v_code
- id
- notes
- plate_no
- plate_st
- v_cond
- v_prod_dt
- v_type
- v_trimcode
- shopid
- trim_color
- v_mldgcode
- v_options
- v_tone
- v_stage
- updated_at
- v_bstyle
- v_color
- v_cond
- v_engine
- v_make_desc
- v_makecode
- v_mldgcode
- v_model_desc
- v_model_yr
- v_options
- v_paint_codes
- v_prod_dt
- v_stage
- v_tone
- v_trimcode
- v_type
- v_vin
select_permissions:
- role: user
permission:
columns:
- v_paint_codes
- created_at
- db_v_code
- id
- notes
- plate_no
- plate_st
- shopid
- trim_color
- updated_at
- v_bstyle
- v_color
- v_cond
- v_engine
- v_makecode
- v_make_desc
- v_makecode
- v_mldgcode
- v_model_desc
- v_model_yr
- v_options
- v_paint_codes
- v_prod_dt
- v_stage
- v_tone
- v_trimcode
- v_type
- v_vin
- created_at
- updated_at
- id
- shopid
filter:
bodyshop:
associations:
@@ -4993,31 +4995,32 @@
- role: user
permission:
columns:
- v_paint_codes
- created_at
- db_v_code
- id
- notes
- plate_no
- plate_st
- shopid
- trim_color
- updated_at
- v_bstyle
- v_color
- v_cond
- v_engine
- v_makecode
- v_make_desc
- v_makecode
- v_mldgcode
- v_model_desc
- v_model_yr
- v_options
- v_paint_codes
- v_prod_dt
- v_stage
- v_tone
- v_trimcode
- v_type
- v_vin
- created_at
- updated_at
- id
- shopid
filter:
bodyshop:
associations:

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."vehicles" add column "notes" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."vehicles" add column "notes" text
null;

View File

@@ -4,7 +4,7 @@
"license": "UNLICENSED",
"engines": {
"node": ">=16.0.0",
"npm": ">=7.0.0"
"npm": ">=8.0.0"
},
"scripts": {
"setup": "yarn && cd client && yarn",
@@ -17,21 +17,21 @@
"start": "node server.js"
},
"dependencies": {
"aws-sdk": "^2.1116.0",
"axios": "^0.24.0",
"aws-sdk": "^2.1136.0",
"axios": "^0.27.2",
"bluebird": "^3.7.2",
"body-parser": "^1.20.0",
"cloudinary": "^1.29.1",
"cloudinary": "^1.30.0",
"compression": "^1.7.4",
"cookie-parser": "^1.4.6",
"cors": "2.8.5",
"csrf": "^3.1.0",
"dinero.js": "^1.9.1",
"dotenv": "10.0.0",
"express": "^4.17.3",
"firebase-admin": "^10.0.2",
"graphql": "^16.3.0",
"graphql-request": "^3.7.0",
"dotenv": "16.0.1",
"express": "^4.18.1",
"firebase-admin": "^10.2.0",
"graphql": "^16.5.0",
"graphql-request": "^4.2.0",
"graylog2": "^0.2.1",
"inline-css": "^3.0.0",
"intuit-oauth": "^4.0.0",
@@ -40,16 +40,16 @@
"moment": "^2.29.3",
"moment-timezone": "^0.5.34",
"multer": "^1.4.4",
"node-mailjet": "^3.3.10",
"node-mailjet": "^3.4.1",
"node-quickbooks": "^2.0.39",
"nodemailer": "^6.7.3",
"phone": "^3.1.15",
"nodemailer": "^6.7.5",
"phone": "^3.1.17",
"query-string": "^7.1.1",
"soap": "^0.43.0",
"socket.io": "^4.4.1",
"socket.io": "^4.5.0",
"ssh2-sftp-client": "^8.0.0",
"stripe": "^8.217.0",
"twilio": "^3.76.1",
"stripe": "^9.1.0",
"twilio": "^3.77.0",
"uuid": "^8.3.2",
"xml2js": "^0.4.23",
"xmlbuilder2": "^3.0.2"

View File

@@ -917,7 +917,10 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
est_co_nm
est_ct_fn
est_ct_ln
vehicle{
id
notes
}
est_ph1
est_ea
selling_dealer

7266
yarn.lock

File diff suppressed because it is too large Load Diff