diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 500460478..81b0ae9c9 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -22603,6 +22603,27 @@ + + shiftclockin + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + @@ -25619,7 +25640,7 @@ - filing_coverhseet_portrait + filing_coversheet_portrait false diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx index 8f5ce8a2e..b5ef60cd8 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -47,13 +47,14 @@ export function JobLinesComponent({ form, }) { const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK); + const { loading: billLinesLoading, error: billLinesError, data: billLinesData, } = useQuery(QUERY_BILLS_BY_JOB_REF, { - variables: { jobId: job.id }, - skip: loading, + variables: { jobId: job && job.id }, + skip: loading || !job, }); const billLinesDataObj = useMemo(() => { @@ -299,40 +300,43 @@ export function JobLinesComponent({ dataIndex: "actions", key: "actions", render: (text, record) => ( - - +
{record.manual_line && ( - + + }); + }, + }) + } + > + + + )} { // } - +
), }, ]; diff --git a/client/src/components/job-line-status-popup/job-line-status-popup.component.jsx b/client/src/components/job-line-status-popup/job-line-status-popup.component.jsx index 4f5710bc7..e948aadd8 100644 --- a/client/src/components/job-line-status-popup/job-line-status-popup.component.jsx +++ b/client/src/components/job-line-status-popup/job-line-status-popup.component.jsx @@ -61,7 +61,7 @@ export function JobLineStatusPopup({ bodyshop, jobline, disabled }) { onSelect={handleChange} onBlur={handleSave} > - {bodyshop.md_order_statuses.statuses.map((s, idx) => ( + {Object.values(bodyshop.md_order_statuses).map((s, idx) => ( {s} diff --git a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx index c83ed1764..3e2ac88ef 100644 --- a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx +++ b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx @@ -10,6 +10,7 @@ import { } from "../../graphql/jobs-lines.queries"; import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectJobLineEditModal } from "../../redux/modals/modals.selectors"; +import UndefinedToNull from "../../utils/undefinedtonull"; import JobLinesUpdsertModal from "./job-lines-upsert-modal.component"; const mapStateToProps = createStructuredSelector({ @@ -39,7 +40,7 @@ function JobLinesUpsertModalContainer({ manual_line: !( jobLineEditModal.context && jobLineEditModal.context.id ), - ...values, + ...UndefinedToNull(values), }, ], }, diff --git a/client/src/components/job-totals-table/job-totals-table.component.jsx b/client/src/components/job-totals-table/job-totals-table.component.jsx index feccaeb4b..7da4b2bfb 100644 --- a/client/src/components/job-totals-table/job-totals-table.component.jsx +++ b/client/src/components/job-totals-table/job-totals-table.component.jsx @@ -267,6 +267,14 @@ export function JobsTotalsTableComponent({ bodyshop, jobRO, job }) { + + + + - - - - - - - - + + + + What would be good to have here? - What would be good to have here? - What would be good to have here? - diff --git a/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx b/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx index 8be13a059..cb5859a54 100644 --- a/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx +++ b/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx @@ -13,10 +13,8 @@ import TimeTicketList from "../time-ticket-list/time-ticket-list.component"; export default function TimeTicketModalComponent({ form, - roAutoCompleteOptions, + employeeAutoCompleteOptions, - loadLineTicketData, - lineTicketData, }) { const { t } = useTranslation(); @@ -33,7 +31,7 @@ export default function TimeTicketModalComponent({ }, ]} > - + { resolve(render.toString()); diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 0867d1784..47a4e5054 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -167,11 +167,11 @@ export const TemplateList = (type, context) => { key: "coversheet_portrait", disabled: false, }, - filing_coverhseet_portrait: { - title: i18n.t("printcenter.jobs.filing_coverhseet_portrait"), + filing_coversheet_portrait: { + title: i18n.t("printcenter.jobs.filing_coversheet_portrait"), description: "All Jobs Notes", - subject: i18n.t("printcenter.jobs.filing_coverhseet_portrait"), - key: "filing_coverhseet_portrait", + subject: i18n.t("printcenter.jobs.filing_coversheet_portrait"), + key: "filing_coversheet_portrait", disabled: false, }, } diff --git a/client/src/utils/undefinedtonull.js b/client/src/utils/undefinedtonull.js new file mode 100644 index 000000000..841701c8c --- /dev/null +++ b/client/src/utils/undefinedtonull.js @@ -0,0 +1,6 @@ +export default function UndefinedToNull(obj) { + Object.keys(obj).forEach((key) => { + if (obj[key] === undefined) obj[key] = null; + }); + return obj; +} diff --git a/server/job/job-totals.js b/server/job/job-totals.js index ec2e7be9d..9ab41acf9 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -41,10 +41,10 @@ exports.totalsSsu = async function (req, res) { }, }); - res.status(200); + res.status(200).send(); } catch (error) { console.log(error); - res.status(503); + res.status(503).send(); } }; @@ -269,7 +269,13 @@ function IsAdditionalCost(jobLine) { //936008 is Paint/Materials //936007 is Shop/Materials - return !jobLine.db_ref || jobLine.db_ref.startsWith("9360"); + //Remove paint and shop mat lines. They're calculated under rates. + const isPaintOrShopMat = + jobLine.db_ref === "936008" || jobLine.db_ref === "936007"; + + return ( + !jobLine.db_ref || (jobLine.db_ref.startsWith("9360") && !isPaintOrShopMat) + ); } function CalculateAdditional(job) { @@ -305,7 +311,7 @@ function CalculateAdditional(job) { function CalculateTaxesTotals(job, otherTotals) { const subtotal = otherTotals.parts.parts.subtotal .add(otherTotals.parts.sublets.subtotal) - .add(otherTotals.rates.rates_subtotal) + .add(otherTotals.rates.subtotal) //No longer using just rates subtotal to include mapa/mash. .add(otherTotals.additional); // .add(Dinero({ amount: (job.towing_payable || 0) * 100 })) // .add(Dinero({ amount: (job.storage_payable || 0) * 100 })); @@ -319,7 +325,7 @@ function CalculateTaxesTotals(job, otherTotals) { job.joblines .filter((jl) => !jl.removed) .forEach((val) => { - if (!val.tax_part || !val.part_type || IsAdditionalCost(val)) { + if (!val.tax_part || (!val.part_type && IsAdditionalCost(val))) { additionalItemsTax = additionalItemsTax.add( Dinero({ amount: Math.round((val.act_price || 0) * 100) }) .multiply(val.part_qty || 1) @@ -350,7 +356,7 @@ function CalculateTaxesTotals(job, otherTotals) { statePartsTax, state_tax: statePartsTax .add( - otherTotals.rates.rates_subtotal.percentage((job.tax_lbr_rt || 0) * 100) + otherTotals.rates.subtotal.percentage((job.tax_lbr_rt || 0) * 100) // THis is currently using the lbr tax rate from PFH not PFL. ) .add( Dinero({
{t("jobs.labels.subtotal")} + + {Dinero(job.job_totals.totals.subtotal).toFormat()} + +
{t("jobs.labels.local_tax_amt")} @@ -317,26 +325,18 @@ export function JobsTotalsTableComponent({ bodyshop, jobRO, job }) { ).toFormat()}
{t("jobs.labels.total_cust_payable")} - {Dinero(job.job_totals.totals.custPayable.total).toFormat()} -
{t("jobs.labels.subtotal")} - - {Dinero(job.job_totals.totals.subtotal).toFormat()} - -
{t("jobs.labels.total_repairs")} {Dinero(job.job_totals.totals.total_repairs).toFormat()}
{t("jobs.labels.total_cust_payable")} + {Dinero(job.job_totals.totals.custPayable.total).toFormat()} +
{t("jobs.labels.net_repairs")} diff --git a/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx b/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx index 326a3e8b8..385fd21bd 100644 --- a/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx +++ b/client/src/components/jobs-detail-general/jobs-detail-general.component.jsx @@ -97,7 +97,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) { label={t("jobs.fields.referralsource")} name="referral_source" > - {bodyshop.md_referral_sources.map((s) => ( {s} @@ -106,7 +106,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) { - {bodyshop.appt_alt_transport.map((s) => ( {s} 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 219dc6cc5..2e06b48a4 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 @@ -28,6 +28,8 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(setModalContext({ context: context, modal: "payment" })), setJobCostingContext: (context) => dispatch(setModalContext({ context: context, modal: "jobCosting" })), + setTimeTicketContext: (context) => + dispatch(setModalContext({ context: context, modal: "timeTicket" })), }); export function JobsDetailHeaderActions({ @@ -39,6 +41,7 @@ export function JobsDetailHeaderActions({ setPaymentContext, setJobCostingContext, jobRO, + setTimeTicketContext, }) { const { t } = useTranslation(); const client = useApolloClient(); @@ -110,6 +113,19 @@ export function JobsDetailHeaderActions({ {t("jobs.actions.viewchecklist")} + { + logImEXEvent("job_header_enter_time_ticekts"); + + setTimeTicketContext({ + actions: {}, + context: { jobId: job.id }, + }); + }} + > + {t("timetickets.actions.enter")} + {techConsole ? null : ( - + {t("timetickets.actions.enter")} )} diff --git a/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx b/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx index c770590f1..ce3106117 100644 --- a/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx +++ b/client/src/components/jobs-find-modal/jobs-find-modal.component.jsx @@ -86,17 +86,13 @@ export default function JobsFindModalComponent({ key: "vehicle", width: "15%", ellipsis: true, - render: (text, record) => { - return record.vehicle ? ( - - {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ - record.v_model_desc || "" - }`} - - ) : ( - t("jobs.errors.novehicle") - ); - }, + render: (text, record) => ( + + {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ + record.v_model_desc || "" + }`} + + ), }, { title: t("vehicles.fields.plate_no"), diff --git a/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx index 163d30772..fadd6e39e 100644 --- a/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx +++ b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.component.jsx @@ -1,19 +1,21 @@ -import { Form } from "antd"; +import { Form, Select } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { selectTechnician } from "../../redux/tech/tech.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import JobSearchSelect from "../job-search-select/job-search-select.component"; import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, + technician: selectTechnician, }); -export function TechClockInComponent({ form, bodyshop }) { +export function TechClockInComponent({ form, bodyshop, technician }) { const { t } = useTranslation(); - + const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0]; return (
+ + + + prevValues.jobid !== curValues.jobid diff --git a/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx index 920cc3744..6aa69f208 100644 --- a/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx +++ b/client/src/components/tech-job-clock-in-form/tech-job-clock-in-form.container.jsx @@ -35,7 +35,7 @@ export function TechClockInContainer({ technician, bodyshop }) { date: theTime, clockon: theTime, jobid: values.jobid, - cost_center: technician.cost_center, + cost_center: values.cost_center, ciecacode: Object.keys( bodyshop.md_responsibility_centers.defaults.costs ).find((key) => { diff --git a/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx b/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx index d88791562..2ebbf2b14 100644 --- a/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx +++ b/client/src/components/tech-job-clock-out-button/tech-job-clock-out-button.component.jsx @@ -30,6 +30,7 @@ export function TechClockOffButton({ const [form] = Form.useForm(); const { t } = useTranslation(); + const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0]; const handleFinish = async (values) => { logImEXEvent("tech_clock_out_job"); @@ -120,9 +121,10 @@ export function TechClockOffButton({ {t("timetickets.labels.shift")} ) : ( - bodyshop.md_responsibility_centers.costs.map((i, idx) => ( - - {i.name} + emps && + emps.rates.map((item) => ( + + {item.cost_center} )) )} diff --git a/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx b/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx index c959e2fd7..e028a29c5 100644 --- a/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx +++ b/client/src/components/tech-job-clocked-in-list/tech-job-clocked-in-list.component.jsx @@ -81,6 +81,9 @@ export function TechClockedInList({ technician }) { {ticket.clockon} + + {ticket.cost_center}{" "} + )} diff --git a/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx index 6607115dd..d16c59f56 100644 --- a/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx +++ b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx @@ -1,6 +1,6 @@ import { PrinterFilled } from "@ant-design/icons"; import { useQuery } from "@apollo/client"; -import { Button, Col, Drawer, Grid, PageHeader, Row, Tag, Tabs } from "antd"; +import { Button, Drawer, Grid, PageHeader, Tabs, Tag } from "antd"; import queryString from "query-string"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -9,26 +9,26 @@ import { Link, useHistory, useLocation } from "react-router-dom"; import { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { setModalContext } from "../../redux/modals/modals.actions"; import AlertComponent from "../alert/alert.component"; -import LoadingSpinner from "../loading-spinner/loading-spinner.component"; -import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component"; -import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component"; import JobLinesContainer from "../job-detail-lines/job-lines.container"; import JobsDocumentsGalleryContainer from "../jobs-documents-gallery/jobs-documents-gallery.container"; import JobNotesContainer from "../jobs-notes/jobs-notes.container"; +import LoadingSpinner from "../loading-spinner/loading-spinner.component"; +import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component"; +import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component"; const mapDispatchToProps = (dispatch) => ({ setPrintCenterContext: (context) => dispatch(setModalContext({ context: context, modal: "printCenter" })), }); -const colBreakPoints = { - xs: { - span: 24, - }, - sm: { - span: 8, - }, -}; +// const colBreakPoints = { +// xs: { +// span: 24, +// }, +// sm: { +// span: 8, +// }, +// }; export function JobDetailCards({ setPrintCenterContext }) { const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) @@ -116,16 +116,12 @@ export function JobDetailCards({ setPrintCenterContext }) { } > - -