IO-2278 Begin parts dispatching including basic items and schema.
This commit is contained in:
@@ -19356,6 +19356,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>dispatchparts</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>new</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -37411,6 +37432,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>markexported</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>markforreexport</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>new</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -37542,6 +37605,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>markreexported</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>payment</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -39355,6 +39439,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>mpi_final_repair_acct_sheet</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>paint_grid</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -40433,6 +40538,27 @@
|
||||
<folder_node>
|
||||
<name>jobs</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>individual_job_note</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>parts_order</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -44378,6 +44504,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>estimators</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>ins_co_nm_filter</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -45,6 +45,7 @@ import JobLinesExpander from "./job-lines-expander.component";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import moment from "moment";
|
||||
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
|
||||
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -440,6 +441,11 @@ export function JobLinesComponent({
|
||||
</Space>
|
||||
</Tag>
|
||||
)}
|
||||
<JobLineDispatchButton
|
||||
selectedLines={selectedLines}
|
||||
setSelectedLines={setSelectedLines}
|
||||
job={job}
|
||||
/>
|
||||
<Button
|
||||
disabled={
|
||||
(job && !job.converted) ||
|
||||
@@ -448,15 +454,6 @@ export function JobLinesComponent({
|
||||
technician
|
||||
}
|
||||
onClick={() => {
|
||||
// setPartsOrderContext({
|
||||
// actions: { refetch: refetch },
|
||||
// context: {
|
||||
// jobId: job.id,
|
||||
// job: job,
|
||||
// linesToOrder: selectedLines,
|
||||
// },
|
||||
// });
|
||||
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import { Button, Form, Popover, Select, Space } from "antd";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobLineDispatchButton);
|
||||
|
||||
export function JobLineDispatchButton({
|
||||
setSelectedLines,
|
||||
selectedLines,
|
||||
|
||||
bodyshop,
|
||||
jobRO,
|
||||
job,
|
||||
currentUser,
|
||||
}) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const Templates = TemplateList("job_special", {
|
||||
ro_number: job.ro_number,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const [dispatchLines] = useMutation(UPDATE_JOB_LINE);
|
||||
|
||||
const handleConvert = async (values) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
//THIS HAS NOT YET BEEN TESTED. START BY FINISHING THIS FUNCTION.
|
||||
const result = await dispatchLines({
|
||||
variables: {
|
||||
joblinesids: selectedLines.map((l) => l.id),
|
||||
employeeid: values.employeeid,
|
||||
note: {
|
||||
audit: true,
|
||||
type: "parts",
|
||||
jobid: job.id,
|
||||
created_by: currentUser.email,
|
||||
text: `${t("joblines.labels.dispatchaudit")}
|
||||
${selectedLines.map((line) => `line.line_desc \r\n`)}
|
||||
`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setVisible(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const popMenu = (
|
||||
<div>
|
||||
<Form layout="vertical" form={form} onFinish={handleConvert}>
|
||||
<Form.Item
|
||||
name={"employeeid"}
|
||||
label={t("jobs.fields.employeeid")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
optionFilterProp="children"
|
||||
filterOption={(input, option) =>
|
||||
option.props.children
|
||||
.toLowerCase()
|
||||
.indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{bodyshop.employees
|
||||
.filter((emp) => emp.active)
|
||||
.map((emp) => (
|
||||
<Select.Option
|
||||
value={emp.id}
|
||||
key={emp.id}
|
||||
name={`${emp.first_name} ${emp.last_name}`}
|
||||
>
|
||||
{`${emp.first_name} ${emp.last_name}`}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<PrintWrapperComponent
|
||||
disabled={!form.getFieldValue("employeeid")}
|
||||
templateObject={{
|
||||
name: Templates.parts_dispatch.key,
|
||||
variables: { id: job.id },
|
||||
}}
|
||||
messageObject={{
|
||||
subject: Templates.parts_dispatch.subject,
|
||||
}}
|
||||
id={job.id}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<Button type="danger" onClick={() => form.submit()} loading={loading}>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
{t("general.actions.cancel")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover open={visible} content={popMenu}>
|
||||
<Button
|
||||
disabled={selectedLines.length === 0 || jobRO}
|
||||
loading={loading}
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -9,9 +9,11 @@ export default function PrintWrapperComponent({
|
||||
children,
|
||||
id,
|
||||
emailOnly = false,
|
||||
disabled,
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handlePrint = async (type) => {
|
||||
if (disabled) return;
|
||||
setLoading(true);
|
||||
await GenerateDocument(templateObject, messageObject, type, id);
|
||||
setLoading(false);
|
||||
@@ -20,8 +22,18 @@ export default function PrintWrapperComponent({
|
||||
return (
|
||||
<Space>
|
||||
{children || null}
|
||||
{!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
|
||||
<MailFilled onClick={() => handlePrint("e")} />
|
||||
{!emailOnly && (
|
||||
<PrinterFilled
|
||||
disabled={disabled}
|
||||
onClick={() => handlePrint("p")}
|
||||
style={{ cursor: disabled ? "not-allowed" : null }}
|
||||
/>
|
||||
)}
|
||||
<MailFilled
|
||||
disabled={disabled}
|
||||
onClick={() => handlePrint("e")}
|
||||
style={{ cursor: disabled ? "not-allowed" : null }}
|
||||
/>
|
||||
{loading && <Spin />}
|
||||
</Space>
|
||||
);
|
||||
|
||||
@@ -1208,6 +1208,7 @@
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "Convert amount to Labor.",
|
||||
"dispatchparts": "Dispatch Parts ({{count}})",
|
||||
"new": "New Line"
|
||||
},
|
||||
"errors": {
|
||||
@@ -2214,17 +2215,17 @@
|
||||
"external": "External",
|
||||
"findermodal": "ICBC Payment Finder",
|
||||
"insurance": "Insurance",
|
||||
"markexported": "Mark Exported",
|
||||
"markforreexport": "Mark for Re-export",
|
||||
"new": "New Payment",
|
||||
"signup": "Please contact support to sign up for electronic payments.",
|
||||
"title": "Payments",
|
||||
"totalpayments": "Total Payments",
|
||||
"markexported": "Mark Exported",
|
||||
"markforreexport": "Mark for Re-export"
|
||||
"totalpayments": "Total Payments"
|
||||
},
|
||||
"successes": {
|
||||
"exported": "Payment(s) exported successfully.",
|
||||
"markreexported": "Payment marked for re-export successfully",
|
||||
"markexported": "Payment(s) marked exported.",
|
||||
"markreexported": "Payment marked for re-export successfully",
|
||||
"payment": "Payment created successfully. ",
|
||||
"stripe": "Credit card transaction charged successfully."
|
||||
}
|
||||
@@ -2623,8 +2624,8 @@
|
||||
"labels": {
|
||||
"atssummary": "ATS Summary",
|
||||
"employeevacation": "Employee Vacations",
|
||||
"ins_co_nm_filter": "Filter by Insurance Company",
|
||||
"estimators": "Filter by Writer/Customer Rep.",
|
||||
"ins_co_nm_filter": "Filter by Insurance Company",
|
||||
"intake": "Intake Events",
|
||||
"manual": "Manual Events",
|
||||
"manualevent": "Add Manual Event"
|
||||
|
||||
@@ -1208,6 +1208,7 @@
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "",
|
||||
"dispatchparts": "",
|
||||
"new": ""
|
||||
},
|
||||
"errors": {
|
||||
@@ -2214,6 +2215,8 @@
|
||||
"external": "",
|
||||
"findermodal": "",
|
||||
"insurance": "",
|
||||
"markexported": "",
|
||||
"markforreexport": "",
|
||||
"new": "",
|
||||
"signup": "",
|
||||
"title": "",
|
||||
@@ -2222,6 +2225,7 @@
|
||||
"successes": {
|
||||
"exported": "",
|
||||
"markexported": "",
|
||||
"markreexported": "",
|
||||
"payment": "",
|
||||
"stripe": ""
|
||||
}
|
||||
@@ -2620,6 +2624,7 @@
|
||||
"labels": {
|
||||
"atssummary": "",
|
||||
"employeevacation": "",
|
||||
"estimators": "",
|
||||
"ins_co_nm_filter": "",
|
||||
"intake": "",
|
||||
"manual": "",
|
||||
|
||||
@@ -1208,6 +1208,7 @@
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "",
|
||||
"dispatchparts": "",
|
||||
"new": ""
|
||||
},
|
||||
"errors": {
|
||||
@@ -2214,6 +2215,8 @@
|
||||
"external": "",
|
||||
"findermodal": "",
|
||||
"insurance": "",
|
||||
"markexported": "",
|
||||
"markforreexport": "",
|
||||
"new": "",
|
||||
"signup": "",
|
||||
"title": "",
|
||||
@@ -2222,6 +2225,7 @@
|
||||
"successes": {
|
||||
"exported": "",
|
||||
"markexported": "",
|
||||
"markreexported": "",
|
||||
"payment": "",
|
||||
"stripe": ""
|
||||
}
|
||||
@@ -2620,6 +2624,7 @@
|
||||
"labels": {
|
||||
"atssummary": "",
|
||||
"employeevacation": "",
|
||||
"estimators": "",
|
||||
"ins_co_nm_filter": "",
|
||||
"intake": "",
|
||||
"manual": "",
|
||||
|
||||
@@ -558,6 +558,15 @@ export const TemplateList = (type, context) => {
|
||||
}),
|
||||
disabled: false,
|
||||
},
|
||||
parts_dispatch: {
|
||||
title: i18n.t("printcenter.jobs.parts_dispatch"),
|
||||
description: "",
|
||||
key: "parts_dispatch",
|
||||
subject: i18n.t("printcenter.subjects.jobs.parts_dispatch", {
|
||||
ro_number: (context && context.ro_number) || "",
|
||||
}),
|
||||
disabled: false,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "appointment"
|
||||
|
||||
@@ -4556,6 +4556,12 @@
|
||||
template_engine: Kriti
|
||||
url: '{{$base_url}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: parts_dispatch
|
||||
schema: public
|
||||
- table:
|
||||
name: parts_dispatch_lines
|
||||
schema: public
|
||||
- table:
|
||||
name: parts_order_lines
|
||||
schema: public
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."parts_dispatch";
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE "public"."parts_dispatch" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "jobid" uuid NOT NULL, "number" serial NOT NULL, "employeeid" uuid NOT NULL, "dispatched_at" timestamptz NOT NULL, "dispatched_by" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade);
|
||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
_new record;
|
||||
BEGIN
|
||||
_new := NEW;
|
||||
_new."updated_at" = NOW();
|
||||
RETURN _new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TRIGGER "set_public_parts_dispatch_updated_at"
|
||||
BEFORE UPDATE ON "public"."parts_dispatch"
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||
COMMENT ON TRIGGER "set_public_parts_dispatch_updated_at" ON "public"."parts_dispatch"
|
||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."parts_dispatch_lines";
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE "public"."parts_dispatch_lines" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "partsdispatchid" UUID NOT NULL, "joblineid" uuid NOT NULL, "quantity" numeric NOT NULL DEFAULT 1, "accepted_at" timestamptz NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("joblineid") REFERENCES "public"."joblines"("id") ON UPDATE cascade ON DELETE cascade);
|
||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
_new record;
|
||||
BEGIN
|
||||
_new := NEW;
|
||||
_new."updated_at" = NOW();
|
||||
RETURN _new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TRIGGER "set_public_parts_dispatch_lines_updated_at"
|
||||
BEFORE UPDATE ON "public"."parts_dispatch_lines"
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||
COMMENT ON TRIGGER "set_public_parts_dispatch_lines_updated_at" ON "public"."parts_dispatch_lines"
|
||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
Reference in New Issue
Block a user