Merged in feature/IO-3214-Job-Status-Card-Extension (pull request #2304)

feature/IO-3214-Job-Status-Card-Extension - Complete
This commit is contained in:
Dave Richer
2025-05-06 21:10:52 +00:00
12 changed files with 127 additions and 50 deletions

View File

@@ -106,7 +106,12 @@ export function JobsAdminDatesChange({ insertAuditTrail, job }) {
<Form.Item label={t("jobs.fields.date_open")} name="date_open">
<DateTimePicker />
</Form.Item>
<Form.Item label={t("jobs.fields.estimate_sent_approval")} name="estimate_sent_approval">
<DateTimePicker />
</Form.Item>
<Form.Item label={t("jobs.fields.estimate_approved")} name="estimate_approved">
<DateTimePicker />
</Form.Item>
<Form.Item label={t("jobs.fields.date_scheduled")} name="date_scheduled">
<DateTimePicker />
</Form.Item>

View File

@@ -7,6 +7,7 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
import { selectBodyshop } from "../../redux/user/user.selectors";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import FormRow from "../layout-form-row/layout-form-row.component";
import dayjs from "../../utils/day";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -40,6 +41,20 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
<Form.Item label={t("jobs.fields.date_rentalresp")} name="date_rentalresp">
<DateTimePicker disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.estimate_sent_approval")} name="estimate_sent_approval">
<DateTimePicker
disabled={true}
value={job.estimate_sent_approval ? dayjs(job.estimate_sent_approval) : null}
placeholder={t("general.labels.na")}
/>
</Form.Item>
<Form.Item label={t("jobs.fields.estimate_approved")} name="estimate_approved">
<DateTimePicker
disabled={true}
value={job.estimate_approved ? dayjs(job.estimate_approved) : null}
placeholder={t("general.labels.na")}
/>
</Form.Item>
</FormRow>
<FormRow header={t("jobs.forms.scheddates")}>
@@ -76,21 +91,15 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
<DateTimePicker disabled={jobRO} />
</Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item
label={t("jobs.fields.actual_completion")}
name="actual_completion"
rules={[
{
required: jobInPostProduction
}
]}
>
<DateTimePicker disabled={jobRO} />
</Form.Item>
);
}}
{() => (
<Form.Item
label={t("jobs.fields.actual_completion")}
name="actual_completion"
rules={[{ required: jobInPostProduction }]}
>
<DateTimePicker disabled={jobRO} />
</Form.Item>
)}
</Form.Item>
<Form.Item label={t("jobs.fields.scheduled_delivery")} name="scheduled_delivery">
<DateTimePicker disabled={jobRO} />
@@ -103,15 +112,12 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
<Form.Item label={t("jobs.fields.date_invoiced")} name="date_invoiced">
<DateTimePicker disabled={true || jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.date_exported")} name="date_exported">
<DateTimePicker disabled={true || jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.date_void")} name="date_void">
<DateTimePicker disabled={true || jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.date_lost_sale")} name="date_lost_sale">
<DateTimePicker disabled={true || jobRO} />
</Form.Item>

View File

@@ -1,13 +1,15 @@
import { BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, WarningFilled } from "@ant-design/icons";
import { Card, Col, Divider, Row, Space, Tag, Tooltip } from "antd";
import React, { useState } from "react";
import { Card, Checkbox, Col, Divider, Row, Space, Tag, Tooltip } from "antd";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { useMutation } from "@apollo/client";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
@@ -22,6 +24,7 @@ import ProductionListColumnComment from "../production-list-columns/production-l
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
import "./jobs-detail-header.styles.scss";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -29,41 +32,55 @@ const mapStateToProps = createStructuredSelector({
});
const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) => dispatch(setModalContext({ context: context, modal: "printCenter" }))
setPrintCenterContext: (context) =>
dispatch(
setModalContext({
context: context,
modal: "printCenter"
})
)
});
const colSpan = {
xs: {
span: 24
},
sm: {
span: 24
},
md: {
span: 12
},
lg: {
span: 6
},
xl: {
span: 6
}
xs: { span: 24 },
sm: { span: 24 },
md: { span: 12 },
lg: { span: 6 },
xl: { span: 6 }
};
export function JobsDetailHeader({ job, bodyshop, disabled }) {
const { t } = useTranslation();
const { notification } = useNotification();
const [notesClamped, setNotesClamped] = useState(true);
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`.trim();
const [updateJob] = useMutation(UPDATE_JOB);
const vehicleTitle =
`${job.v_model_yr || ""} ${job.v_color || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim();
const bodyHrs = job.joblines.filter((j) => j.mod_lbr_ty !== "LAR").reduce((acc, val) => acc + val.mod_lb_hrs, 0);
const refinishHrs = job.joblines
.filter((line) => line.mod_lbr_ty === "LAR")
.reduce((acc, val) => acc + val.mod_lb_hrs, 0);
const ownerTitle = OwnerNameDisplayFunction(job).trim();
// Handle checkbox changes
const handleCheckboxChange = async (field, checked) => {
const value = checked ? dayjs().toISOString() : null;
try {
await updateJob({
variables: {
jobId: job.id,
job: { [field]: value }
},
refetchQueries: ["GET_JOB_BY_PK"],
awaitRefetchQueries: true
});
} catch (error) {
notification.error({
message: t("jobs.errors.saving", { error: error.message })
});
}
};
return (
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
<Col {...colSpan}>
@@ -72,11 +89,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<DataLabel label={t("jobs.fields.status")}>
<Space wrap>
{job.status}
{job.inproduction && (
<Tag color="#f50" key="production">
{t("jobs.labels.inproduction")}
</Tag>
)}
{job.inproduction && <Tag color="#f50">{t("jobs.labels.inproduction")}</Tag>}
{job.suspended && <PauseCircleOutlined style={{ color: "orangered" }} />}
{job.iouparent && (
<Link to={`/manage/jobs/${job.iouparent}`}>
@@ -110,7 +123,6 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<span style={{ margin: "0rem .5rem" }}>/</span>
<CurrencyFormatter>{job.owner_owing}</CurrencyFormatter>
</DataLabel>
<DataLabel label={t("jobs.fields.alt_transport")}>
{job.alt_transport}
<JobAltTransportChange job={job} />
@@ -127,11 +139,27 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
))}
</DataLabel>
)}
<DataLabel label={t("jobs.fields.production_vars.note")}>
<ProductionListColumnProductionNote record={job} />
</DataLabel>
<DataLabel label={t("jobs.fields.estimate_sent_approval")}>
<Checkbox
checked={!!job.estimate_sent_approval}
onChange={(e) => handleCheckboxChange("estimate_sent_approval", e.target.checked)}
disabled={disabled}
>
{t("jobs.labels.sent")}
</Checkbox>
</DataLabel>
<DataLabel label={t("jobs.fields.estimate_approved")}>
<Checkbox
checked={!!job.estimate_approved}
onChange={(e) => handleCheckboxChange("estimate_approved", e.target.checked)}
disabled={disabled}
>
{t("jobs.labels.approved")}
</Checkbox>
</DataLabel>
<Space wrap>
{job.special_coverage_policy && (
<Tag color="tomato">

View File

@@ -685,6 +685,8 @@ export const GET_JOB_BY_PK = gql`
scheduled_delivery
scheduled_in
selling_dealer
estimate_approved
estimate_sent_approval
selling_dealer_contact
servicing_dealer
servicing_dealer_contact
@@ -929,6 +931,8 @@ export const QUERY_JOB_CARD_DETAILS = gql`
date_exported
date_repairstarted
date_scheduled
estimate_sent_approval
estimate_approved
date_estimated
employee_body_rel {
id
@@ -1077,6 +1081,8 @@ export const UPDATE_JOB = gql`
date_repairstarted
date_void
date_lost_sale
estimate_sent_approval
estimate_approved
}
}
}
@@ -2431,6 +2437,8 @@ export const QUERY_PARTS_QUEUE_CARD_DETAILS = gql`
plate_st
po_number
production_vars
estimate_sent_approval
estimate_approved
ro_number
scheduled_completion
scheduled_delivery

View File

@@ -1650,6 +1650,8 @@
"adjustment_bottom_line": "Adjustments",
"adjustmenthours": "Adjustment Hours",
"alt_transport": "Alt. Trans.",
"estimate_sent_approval": "Estimate Sent for Approval",
"estimate_approved": "Estimate Approved",
"area_of_damage_impact": {
"10": "Left Front Side",
"11": "Left Front Corner",
@@ -1955,6 +1957,8 @@
"scheddates": "Schedule Dates"
},
"labels": {
"sent": "",
"approved": "",
"accountsreceivable": "Accounts Receivable",
"act_price_ppc": "New Part Price",
"actual_completion_inferred": "$t(jobs.fields.actual_completion) inferred using $t(jobs.fields.scheduled_completion).",

View File

@@ -1642,6 +1642,8 @@
"voiding": ""
},
"fields": {
"estimate_sent_approval": "",
"estimate_approved": "",
"active_tasks": "",
"actual_completion": "Realización real",
"actual_delivery": "Entrega real",
@@ -1955,6 +1957,8 @@
"scheddates": ""
},
"labels": {
"sent": "",
"approved": "",
"accountsreceivable": "",
"act_price_ppc": "",
"actual_completion_inferred": "",

View File

@@ -1642,6 +1642,8 @@
"voiding": ""
},
"fields": {
"estimate_sent_approval": "",
"estimate_approved": "",
"active_tasks": "",
"actual_completion": "Achèvement réel",
"actual_delivery": "Livraison réelle",
@@ -1955,6 +1957,8 @@
"scheddates": ""
},
"labels": {
"sent": "",
"approved": "",
"accountsreceivable": "",
"act_price_ppc": "",
"actual_completion_inferred": "",

View File

@@ -3702,6 +3702,8 @@
- est_ph1
- est_st
- est_zip
- estimate_approved
- estimate_sent_approval
- federal_tax_rate
- flat_rate_ats
- g_bett_amt
@@ -3976,6 +3978,8 @@
- est_ph1
- est_st
- est_zip
- estimate_approved
- estimate_sent_approval
- federal_tax_rate
- flat_rate_ats
- g_bett_amt
@@ -4262,6 +4266,8 @@
- est_ph1
- est_st
- est_zip
- estimate_approved
- estimate_sent_approval
- federal_tax_rate
- flat_rate_ats
- g_bett_amt

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"."jobs" add column "estimate_sent_approval" timestamptz
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."jobs" add column "estimate_sent_approval" timestamptz
null;

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"."jobs" add column "estimate_approved" timestamptz
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."jobs" add column "estimate_approved" timestamptz
null;