From 4fb9c37c0d91644f52c6078fb8136caa537f4f59 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 22 Apr 2024 09:15:59 -0700 Subject: [PATCH 1/4] IO-2761 Actual Completion in Vehicle and Owners Job Details lists Signed-off-by: Allan Carr --- .../owner-detail-jobs.component.jsx | 16 ++++++++++++++-- .../vehicle-detail-jobs.component.jsx | 16 ++++++++++++++-- client/src/graphql/owners.queries.js | 1 + client/src/graphql/vehicles.queries.js | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx b/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx index d47be4d1f..d62d849a1 100644 --- a/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx +++ b/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx @@ -6,7 +6,8 @@ import { Link } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; -import { alphaSort, statusSort } from "../../utils/sorters"; +import { DateTimeFormatter } from "../../utils/DateFormatter"; +import { alphaSort, dateSort, statusSort } from "../../utils/sorters"; import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component"; const mapStateToProps = createStructuredSelector({ @@ -86,7 +87,18 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) { })), onFilter: (value, record) => value.includes(record.status), }, - + { + title: t("jobs.fields.actual_completion"), + dataIndex: "actual_completion", + key: "actual_completion", + render: (text, record) => ( + {record.actual_completion} + ), + sorter: (a, b) => dateSort(a.actual_completion, b.actual_completion), + sortOrder: + state.sortedInfo.columnKey === "actual_completion" && + state.sortedInfo.order, + }, { title: t("jobs.fields.clm_total"), dataIndex: "clm_total", diff --git a/client/src/components/vehicle-detail-jobs/vehicle-detail-jobs.component.jsx b/client/src/components/vehicle-detail-jobs/vehicle-detail-jobs.component.jsx index 370142a2a..98be8d233 100644 --- a/client/src/components/vehicle-detail-jobs/vehicle-detail-jobs.component.jsx +++ b/client/src/components/vehicle-detail-jobs/vehicle-detail-jobs.component.jsx @@ -6,7 +6,8 @@ import { Link } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; -import { alphaSort, statusSort } from "../../utils/sorters"; +import { DateTimeFormatter } from "../../utils/DateFormatter"; +import { alphaSort, dateSort, statusSort } from "../../utils/sorters"; import OwnerNameDisplay, { OwnerNameDisplayFunction, } from "../owner-name-display/owner-name-display.component"; @@ -79,7 +80,18 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) { })), onFilter: (value, record) => value.includes(record.status), }, - + { + title: t("jobs.fields.actual_completion"), + dataIndex: "actual_completion", + key: "actual_completion", + render: (text, record) => ( + {record.actual_completion} + ), + sorter: (a, b) => dateSort(a.actual_completion, b.actual_completion), + sortOrder: + state.sortedInfo.columnKey === "actual_completion" && + state.sortedInfo.order, + }, { title: t("jobs.fields.clm_total"), dataIndex: "clm_total", diff --git a/client/src/graphql/owners.queries.js b/client/src/graphql/owners.queries.js index ea0062cd5..aba6d2dfa 100644 --- a/client/src/graphql/owners.queries.js +++ b/client/src/graphql/owners.queries.js @@ -71,6 +71,7 @@ export const QUERY_OWNER_BY_ID = gql` tax_number jobs(order_by: { date_open: desc }) { id + actual_completion ro_number clm_no status diff --git a/client/src/graphql/vehicles.queries.js b/client/src/graphql/vehicles.queries.js index 1daccc7f5..930af12e5 100644 --- a/client/src/graphql/vehicles.queries.js +++ b/client/src/graphql/vehicles.queries.js @@ -30,6 +30,7 @@ export const QUERY_VEHICLE_BY_ID = gql` notes jobs(order_by: { date_open: desc }) { id + actual_completion ro_number ownr_co_nm ownr_fn From 02a49efbea03c864a1b917cec65468def1d03fd4 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 22 Apr 2024 14:14:54 -0700 Subject: [PATCH 2/4] IO-2762 Return from Bill Reference in Parts Return Drawer Signed-off-by: Allan Carr --- .../parts-order-list-table.component.jsx | 42 ++++++++++++++++--- client/src/graphql/bills.queries.js | 1 + client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx index e27d6ee4f..859b23c6a 100644 --- a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx +++ b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx @@ -1,5 +1,5 @@ import { DeleteFilled, EyeFilled, SyncOutlined } from "@ant-design/icons"; -import { useMutation } from "@apollo/client"; +import { useLazyQuery, useMutation } from "@apollo/client"; import { Button, Card, @@ -13,20 +13,21 @@ import { Table, } from "antd"; import queryString from "query-string"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useLocation } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { logImEXEvent } from "../../firebase/firebase.utils"; +import { QUERY_BILL_BY_PK } from "../../graphql/bills.queries"; import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateFormatter } from "../../utils/DateFormatter"; -import { alphaSort } from "../../utils/sorters"; import { TemplateList } from "../../utils/TemplateConstants"; +import { alphaSort } from "../../utils/sorters"; import DataLabel from "../data-label/data-label.component"; import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component"; import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component"; @@ -78,19 +79,46 @@ export function PartsOrderListTableComponent({ const [state, setState] = useState({ sortedInfo: {}, }); + + const [returnfrombill, setReturnFromBill] = useState(); + const [billData, setBillData] = useState(); const search = queryString.parse(useLocation().search); const selectedpartsorder = search.partsorderid; const [searchText, setSearchText] = useState(""); + const [billQuery] = useLazyQuery(QUERY_BILL_BY_PK); const [deletePartsOrder] = useMutation(DELETE_PARTS_ORDER); const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : []; const { refetch } = billsQuery; + useEffect(() => { + if (returnfrombill === null) { + setBillData(null); + } else { + const fetchData = async () => { + const result = await billQuery({ + variables: { billid: returnfrombill }, + }); + setBillData(result.data); + }; + fetchData(); + } + }, [returnfrombill, billQuery]); + const recordActions = (record, showView = false) => ( {showView && ( - )} @@ -417,7 +445,11 @@ export function PartsOrderListTableComponent({ return (
Date: Mon, 22 Apr 2024 15:18:13 -0700 Subject: [PATCH 3/4] IO-2763 Job Action Button Create Courtesy Car and Create Task items added Signed-off-by: Allan Carr --- .../jobs-detail-header-actions.component.jsx | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx index 902dc0dc4..6c3c1dce0 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx @@ -1,6 +1,9 @@ import { DownCircleFilled } from "@ant-design/icons"; import { useApolloClient, useMutation } from "@apollo/client"; -import { Button, Card, Dropdown, Form, Input, Modal, notification, Popconfirm, Popover, Select, Space } from "antd"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import { Button, Card, Dropdown, Form, Input, Modal, Popconfirm, Popover, Select, Space, notification } from "antd"; +import axios from "axios"; +import parsePhoneNumber from "libphonenumber-js"; import React, { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -8,27 +11,24 @@ import { Link, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { auth, logImEXEvent } from "../../firebase/firebase.utils"; import { CANCEL_APPOINTMENTS_BY_JOB_ID, INSERT_MANUAL_APPT } from "../../graphql/appointments.queries"; +import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries"; import { DELETE_JOB, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; +import { setEmailOptions } from "../../redux/email/email.actions"; +import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; import { setModalContext } from "../../redux/modals/modals.actions"; import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; +import { DateTimeFormatter } from "../../utils/DateFormatter"; +import { TemplateList } from "../../utils/TemplateConstants"; +import dayjs from "../../utils/day"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; +import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component"; +import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component"; import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component"; import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util"; import DuplicateJob from "./jobs-detail-header-actions.duplicate.util"; -import axios from "axios"; -import { setEmailOptions } from "../../redux/email/email.actions"; -import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; -import { GET_CURRENT_QUESTIONSET_ID, INSERT_CSI } from "../../graphql/csi.queries"; -import { TemplateList } from "../../utils/TemplateConstants"; -import parsePhoneNumber from "libphonenumber-js"; -import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component"; -import { DateTimeFormatter } from "../../utils/DateFormatter"; -import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component"; -import dayjs from "../../utils/day"; -import { useSplitTreatments } from "@splitsoftware/splitio-react"; -import InstanceRenderManager from "../../utils/instanceRenderMgr"; import JobsDetailHeaderActionsToggleProduction from "./jobs-detail-header-actions.toggle-production"; const mapStateToProps = createStructuredSelector({ @@ -83,6 +83,13 @@ const mapDispatchToProps = (dispatch) => ({ modal: "timeTicketTask" }) ), + setTaskUpsertContext: (context) => + dispatch( + setModalContext({ + context: context, + modal: "taskUpsert" + }) + ), setEmailOptions: (e) => dispatch(setEmailOptions(e)), openChatByPhone: (phone) => dispatch(openChatByPhone(phone)), setMessage: (text) => dispatch(setMessage(text)) @@ -104,7 +111,8 @@ export function JobsDetailHeaderActions({ setEmailOptions, openChatByPhone, setMessage, - setTimeTicketTaskContext + setTimeTicketTaskContext, + setTaskUpsertContext }) { const { t } = useTranslation(); const client = useApolloClient(); @@ -766,7 +774,7 @@ export function JobsDetailHeaderActions({ }); } - if (HasFeatureAccess({ featureName: "courtesycars" })) { + if (HasFeatureAccess({ featureName: "courtesycars", bodyshop })) { menuItems.push({ key: "cccontract", disabled: jobRO || !job.converted, @@ -778,6 +786,16 @@ export function JobsDetailHeaderActions({ }); } + menuItems.push({ + key: "createtask", + label: t("menus.header.create_task"), + onClick: () => + setTaskUpsertContext({ + actions: {}, + context: { jobid: job.id } + }) + }); + menuItems.push( job.inproduction ? { From a6b825ffdfe73e8afc9899a89a550c6a6a5dc843 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 25 Apr 2024 16:43:49 -0700 Subject: [PATCH 4/4] Move intellipay to server side processing. --- bodyshop_translations.babel | 364 +++++++++++++++++- .../card-payment-modal.component..jsx | 83 +--- .../jobs-detail-header-actions.component.jsx | 2 +- .../payment-expanded-row.component.jsx | 6 +- client/src/translations/en_us/common.json | 28 +- client/src/translations/es/common.json | 30 +- client/src/translations/fr/common.json | 28 +- server/graphql-client/queries.js | 10 +- server/intellipay/intellipay.js | 164 ++++---- 9 files changed, 536 insertions(+), 179 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 17ebd2af4..09552c8e2 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1,4 +1,4 @@ - +