From 0f8fe525a48786e110a20b804c25422b32c05b8c Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 23 Mar 2021 12:58:27 -0700 Subject: [PATCH] IO-795 Resolve parts reconciliation issues. --- bodyshop_translations.babel | 21 +++++++ client/.env.development2 | 13 ++++ .../job-reconciliation.modal.container.jsx | 21 ++++++- ...b-reconciliation-parts-table.component.jsx | 5 ++ ...job-reconciliation-parts-table.styles.scss | 3 + .../job-reconciliation-totals.component.jsx | 5 +- .../job-reconciliation-totals.utility.js | 5 -- client/src/graphql/jobs.queries.js | 61 ++++++++++++++++++- client/src/translations/en_us/common.json | 3 +- client/src/translations/es/common.json | 3 +- client/src/translations/fr/common.json | 3 +- 11 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 client/.env.development2 create mode 100644 client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.styles.scss diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 465de8c3b..cefdf5565 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -20503,6 +20503,27 @@ + + removedpartsstrikethrough + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/.env.development2 b/client/.env.development2 new file mode 100644 index 000000000..96ee2121d --- /dev/null +++ b/client/.env.development2 @@ -0,0 +1,13 @@ +FAST_REFRESH=false +REACT_APP_GRAPHQL_ENDPOINT=https://bodyshop-dev-db.herokuapp.com/v1/graphql +REACT_APP_GRAPHQL_ENDPOINT_WS=wss://bodyshop-dev-db.herokuapp.com/v1/graphql +REACT_APP_GA_CODE=231099835 +REACT_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"} +REACT_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/bodyshop +REACT_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/bodyshop +REACT_APP_CLOUDINARY_API_KEY=473322739956866 +REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,f_auto,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_REPORTS_SERVER_URL=https://reports.bodyshop.app \ No newline at end of file diff --git a/client/src/components/job-reconciliation-modal/job-reconciliation.modal.container.jsx b/client/src/components/job-reconciliation-modal/job-reconciliation.modal.container.jsx index cd45c8722..3850cf359 100644 --- a/client/src/components/job-reconciliation-modal/job-reconciliation.modal.container.jsx +++ b/client/src/components/job-reconciliation-modal/job-reconciliation.modal.container.jsx @@ -1,11 +1,15 @@ +import { useQuery } from "@apollo/client"; import { Modal } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { GET_JOB_RECONCILIATION_BY_PK } from "../../graphql/jobs.queries"; import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectReconciliation } from "../../redux/modals/modals.selectors"; import JobReconciliationModalComponent from "./job-reconciliation-modal.component"; +import LoadingSpinner from "../loading-spinner/loading-spinner.component"; +import AlertComponent from "../alert/alert.component"; const mapStateToProps = createStructuredSelector({ reconciliationModal: selectReconciliation, @@ -20,7 +24,12 @@ function JobReconciliationModalContainer({ }) { const { t } = useTranslation(); const { context, visible } = reconciliationModal; - const { job, bills } = context; + const { job } = context; + + const { loading, error, data } = useQuery(GET_JOB_RECONCILIATION_BY_PK, { + variables: { id: job && job.id }, + skip: !(job && job.id) || !visible, + }); const handleCancel = () => { toggleModalVisible(); @@ -37,7 +46,15 @@ function JobReconciliationModalContainer({ cancelButtonProps={{ display: "none" }} destroyOnClose > - + + {error && } + {data && ( + + )} + ); } diff --git a/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.component.jsx b/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.component.jsx index 089dfe1d4..4c35fdd94 100644 --- a/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.component.jsx +++ b/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.component.jsx @@ -3,6 +3,7 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { alphaSort } from "../../utils/sorters"; +import "./job-reconciliation-parts-table.styles.scss"; export default function JobReconcilitionPartsTable({ jobLineState, @@ -114,7 +115,11 @@ export default function JobReconcilitionPartsTable({ onChange: handleOnRowClick, selectedRowKeys: selectedLines, }} + rowClassName={(record) => record.removed && "text-strikethrough"} /> +
+ {t("jobs.labels.reconciliation.removedpartsstrikethrough")} +
); } diff --git a/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.styles.scss b/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.styles.scss new file mode 100644 index 000000000..fffdb8790 --- /dev/null +++ b/client/src/components/job-reconciliation-parts-table/job-reconciliation-parts-table.styles.scss @@ -0,0 +1,3 @@ +.text-strikethrough { + text-decoration: line-through; +} diff --git a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx index 4f3474750..11330c5b9 100644 --- a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx +++ b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.component.jsx @@ -39,7 +39,9 @@ export default function JobReconciliationTotals({ return acc.add( Dinero({ amount: Math.round((val.actual_price || 0) * 100), - }).multiply(val.quantity || 1) + }) + .multiply(val.quantity || 1) + .multiply(val.bill.is_credit_memo ? -1 : 1) ); }, Dinero()), }; @@ -97,6 +99,7 @@ export default function JobReconciliationTotals({ onClick={() => { jobLineState[1]([]); billLineState[1]([]); + setErrors([]); }} > {t("jobs.labels.reconciliation.clear")} diff --git a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js index e679b1102..cb4b9fc82 100644 --- a/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js +++ b/client/src/components/job-reconciliation-totals/job-reconciliation-totals.utility.js @@ -23,11 +23,6 @@ export const reconcileByAssocLine = ( setErrors((errors) => [ ...errors, ..._.uniqBy(duplicatedJobLinesbyInvoiceId).map((dupedId) => { - console.log( - "dupedId", - dupedId, - billLines.find((b) => b.id === dupedId) - ); return i18next.t("jobs.labels.reconciliation.multiplebilllines", { line_desc: jobLines.find((j) => j.id === dupedId)?.line_desc, }); diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index f7b6b8730..68d7ae507 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -580,7 +580,66 @@ export const GET_JOB_BY_PK = gql` } } `; - +export const GET_JOB_RECONCILIATION_BY_PK = gql` + query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) { + bills(where: { jobid: { _eq: $id } }) { + id + vendorid + vendor { + id + name + } + total + invoice_number + date + federal_tax_rate + state_tax_rate + local_tax_rate + is_credit_memo + isinhouse + exported + billlines { + actual_price + quantity + actual_cost + cost_center + id + joblineid + line_desc + applicable_taxes + deductedfromlbr + } + } + jobs_by_pk(id: $id) { + id + joblines(order_by: { line_no: asc }) { + id + removed + line_no + unq_seq + line_ind + line_desc + part_type + oem_partno + db_price + act_price + part_qty + mod_lbr_ty + db_hrs + mod_lb_hrs + lbr_op + lbr_amt + op_code_desc + status + notes + location + tax_part + db_ref + manual_line + } + } + } +`; export const QUERY_JOB_CARD_DETAILS = gql` query QUERY_JOB_CARD_DETAILS($id: uuid!) { jobs_by_pk(id: $id) { diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 92313b507..eba3ba4f0 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1229,7 +1229,8 @@ "joblinestotal": "Job Lines Total", "multipleactprices": "${{act_price}} is the price for multiple job lines.", "multiplebilllines": "{{line_desc}} has 2 or more bill lines associated to it.", - "multiplebillsforactprice": "Found more than 1 bill matching ${{act_price}} retail price." + "multiplebillsforactprice": "Found more than 1 bill matching ${{act_price}} retail price.", + "removedpartsstrikethrough": "Strike through lines represent parts that have been removed from the estimate. They are included for completeness of reconciliation." }, "reconciliationheader": "Parts & Sublet Reconciliation", "rosaletotal": "Total RO Sale", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index be2219678..0fe165865 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1229,7 +1229,8 @@ "joblinestotal": "", "multipleactprices": "", "multiplebilllines": "", - "multiplebillsforactprice": "" + "multiplebillsforactprice": "", + "removedpartsstrikethrough": "" }, "reconciliationheader": "", "rosaletotal": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index b70d37225..526459af3 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1229,7 +1229,8 @@ "joblinestotal": "", "multipleactprices": "", "multiplebilllines": "", - "multiplebillsforactprice": "" + "multiplebillsforactprice": "", + "removedpartsstrikethrough": "" }, "reconciliationheader": "", "rosaletotal": "",