BOD-52 #comment Implemented job updating based on owner fields. Currently, which fields are updated are hardcoded.

This commit is contained in:
Patrick Fic
2020-03-23 15:35:59 -07:00
parent edba734605
commit f04ba766ad
9 changed files with 376 additions and 43 deletions

View File

@@ -11,7 +11,7 @@
<preset_collections/>
<framework>react-intl</framework>
<filename>bodyshop_translations.babel</filename>
<source_root_dir></source_root_dir>
<source_root_dir>client</source_root_dir>
<folder_node>
<name></name>
<children>
@@ -1723,6 +1723,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>open_statuses</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>
</children>
</folder_node>
<concept_node>
@@ -1751,6 +1772,48 @@
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>alljobstatuses</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>allopenjobstatuses</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>jobstatuses</name>
<definition_loaded>false</definition_loaded>
@@ -7986,6 +8049,32 @@
<folder_node>
<name>owners</name>
<children>
<folder_node>
<name>actions</name>
<children>
<concept_node>
<name>update</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>
</children>
</folder_node>
<folder_node>
<name>errors</name>
<children>
@@ -8398,6 +8487,69 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>fromclaim</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>fromowner</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>updateowner</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>
</children>
</folder_node>
<folder_node>
@@ -10266,7 +10418,7 @@
</editor_configuration>
<primary_language>en-US</primary_language>
<configuration>
<definitions></definitions>
<definitions>client/src</definitions>
<indent>tab</indent>
<format>namespaced-json</format>
<support_arrays>true</support_arrays>

View File

@@ -1,10 +1,20 @@
import React from "react";
import { Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
export default function OwnerDetailJobsComponent({ owner }) {
import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
function OwnerDetailJobsComponent({ bodyshop, owner }) {
const { t } = useTranslation();
const [selectedJobs, setSelectedJobs] = useState([]);
const columns = [
{
title: t("jobs.fields.ro_number"),
@@ -50,10 +60,31 @@ export default function OwnerDetailJobsComponent({ owner }) {
return (
<Table
title={() => (
<div>
<OwnerDetailUpdateJobsComponent
selectedJobs={selectedJobs}
owner={owner}
/>
</div>
)}
pagination={{ position: "bottom" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
rowKey='id'
dataSource={owner.jobs}
rowSelection={{
onSelect: props => {
setSelectedJobs([...selectedJobs, props.id]);
},
// type: "radio",
selectedRowKeys: selectedJobs,
getCheckboxProps: record => ({
disabled: bodyshop.md_ro_statuses.open_statuses
? !bodyshop.md_ro_statuses.open_statuses.includes(record.status)
: true
})
}}
/>
);
}
export default connect(mapStateToProps, null)(OwnerDetailJobsComponent);

View File

@@ -0,0 +1,37 @@
import React from "react";
import { Button } from "antd";
import { useTranslation } from "react-i18next";
import { useMutation } from "@apollo/react-hooks";
import { UPDATE_JOBS } from "../../graphql/jobs.queries";
export default function OwnerDetailUpdateJobsComponent({
owner,
selectedJobs
}) {
const { t } = useTranslation();
const [updateJobs] = useMutation(UPDATE_JOBS);
const handlecClick = e => {
updateJobs({
variables: {
jobIds: selectedJobs,
fields: {
ownr_addr1: owner["ownr_addr1"],
ownr_addr2: owner["ownr_addr2"],
ownr_co_nm: owner["ownr_co_nm"],
ownr_city: owner["ownr_city"],
ownr_ctry: owner["ownr_ctry"],
ownr_ea: owner["ownr_ea"],
ownr_fn: owner["ownr_fn"],
ownr_ph1: owner["ownr_ph1"],
ownr_ln: owner["ownr_ln"],
ownr_ph2: owner["ownr_ph2"],
ownr_st: owner["ownr_st"],
ownr_title: owner["ownr_title"],
ownr_zip: owner["ownr_zip"]
}
}
});
};
return <Button onClick={handlecClick}>{t("owners.actions.update")}</Button>;
}

View File

@@ -1,26 +1,75 @@
import { Button, Col, Popover, Row, Tag } from "antd";
import { Button, Col, Popover, Row, Tag, Descriptions } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import PhoneFormatter from "../../utils/PhoneFormatter";
export default function OwnerTagPopoverComponent({ job }) {
const { t } = useTranslation();
const content = (
<div>
The Content
<div style={{ width: "400px" }}>
<Row>
<Col span={12}>Claim Info</Col>
<Col span={12}>Owner Info</Col>
<Col span={12}>
<Descriptions
title={t("owners.labels.fromclaim")}
size='small'
column={1}>
<Descriptions.Item
key='1'
label={t("jobs.fields.owner")}>{`${job.ownr_fn ||
""} ${job.ownr_ln || ""} ${job.ownr_co_nm ||
""}`}</Descriptions.Item>
<Descriptions.Item key='2' label={t("jobs.fields.ownr_ph1")}>
<PhoneFormatter>{job.ownr_ph1 || ""}</PhoneFormatter>
</Descriptions.Item>
<Descriptions.Item key='3' label={t("owners.fields.address")}>
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 ||
""} ${job.ownr_city || ""} ${job.ownr_st ||
""} ${job.ownr_zip || ""} ${job.ownr_ctry ||
""} ${job.ownr_city || ""}`}
</Descriptions.Item>
<Descriptions.Item key='4' label={t("owners.fields.ownr_ea")}>
{job.ownr_ea || ""}
{
//TODO Should add an email formatter.
}
</Descriptions.Item>
</Descriptions>
</Col>
<Col span={12}>
<Descriptions
title={t("owners.labels.fromowner")}
size='small'
column={1}>
<Descriptions.Item key='1' label={t("jobs.fields.owner")}>{`${job
.owner.ownr_fn || ""} ${job.owner.ownr_ln || ""} ${job.owner
.ownr_co_nm || ""}`}</Descriptions.Item>
<Descriptions.Item key='2' label={t("jobs.fields.ownr_ph1")}>
<PhoneFormatter>{job.owner.ownr_ph1 || ""}</PhoneFormatter>
</Descriptions.Item>
<Descriptions.Item key='3' label={t("owners.fields.address")}>
{`${job.owner.ownr_addr1 || ""} ${job.owner.ownr_addr2 ||
""} ${job.owner.ownr_city || ""} ${job.owner.ownr_st ||
""} ${job.owner.ownr_zip || ""} ${job.owner.ownr_ctry ||
""} ${job.owner.ownr_city || ""}`}
</Descriptions.Item>
<Descriptions.Item key='4' label={t("owners.fields.ownr_ea")}>
{job.owner.ownr_ea || ""}
{
//TODO Should add an email formatter.
}
</Descriptions.Item>
</Descriptions>
</Col>
</Row>
<Link to={`/manage/owners/${job.owner.id}`}>
<Button>{t("owners.actions.update")}</Button>
<Button>{t("owners.labels.updateowner")}</Button>
</Link>
</div>
);
return (
<Popover placement="bottom" content={content}>
<Tag color="red">
<Popover placement='bottom' content={content}>
<Tag color='red'>
{job.owner
? `${job.ownr_co_nm || ""}${job.ownr_fn || ""} ${job.ownr_ln || ""}`
: t("jobs.errors.noowner")}

View File

@@ -6,7 +6,7 @@ import styled from "styled-components";
const SelectorDiv = styled.div`
.ant-form-item .ant-select {
width: 125px;
width: 200px;
}
`;
//TODO Fix up styles.
@@ -24,7 +24,8 @@ export default function ShopInfoROStatusComponent({ form }) {
return (
<div>
<Row>
<Col span={12}>
<Col span={8}>
{t("bodyshop.labels.alljobstatuses")}
<Form.List name={["md_ro_statuses", "statuses"]}>
{(fields, { add, remove }) => {
return (
@@ -32,8 +33,7 @@ export default function ShopInfoROStatusComponent({ form }) {
{fields.map((field, index) => (
<Form.Item
key={field.key}
style={{ padding: 0, margin: 2 }}
>
style={{ padding: 0, margin: 2 }}>
<div style={{ display: "flex" }}>
<Form.Item
style={{ padding: 0, margin: 2 }}
@@ -45,8 +45,7 @@ export default function ShopInfoROStatusComponent({ form }) {
required: true,
message: t("general.validation.required")
}
]}
>
]}>
<Input onBlur={handleBlur} />
</Form.Item>
<DeleteFilled
@@ -59,12 +58,11 @@ export default function ShopInfoROStatusComponent({ form }) {
))}
<Form.Item>
<Button
type="dashed"
type='dashed'
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
style={{ width: "100%" }}>
{t("bodyshop.actions.newstatus")}
</Button>
</Form.Item>
@@ -75,6 +73,24 @@ export default function ShopInfoROStatusComponent({ form }) {
</Col>
<Col span={12}>
<SelectorDiv>
<Form.Item
name={["md_ro_statuses", "open_statuses"]}
label={t("bodyshop.fields.statuses.open_statuses")}
rules={[
{
required: true,
message: t("general.validation.required"),
type: "array"
}
]}>
<Select mode='multiple'>
{options.map((item, idx) => (
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.statuses.default_scheduled")}
rules={[
@@ -83,8 +99,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_scheduled"]}
>
name={["md_ro_statuses", "default_scheduled"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -99,8 +114,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_arrived"]}
>
name={["md_ro_statuses", "default_arrived"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -115,8 +129,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_exported"]}
>
name={["md_ro_statuses", "default_exported"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -131,8 +144,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_imported"]}
>
name={["md_ro_statuses", "default_imported"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -147,8 +159,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_invoiced"]}
>
name={["md_ro_statuses", "default_invoiced"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -163,8 +174,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_completed"]}
>
name={["md_ro_statuses", "default_completed"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
@@ -179,8 +189,7 @@ export default function ShopInfoROStatusComponent({ form }) {
message: t("general.validation.required")
}
]}
name={["md_ro_statuses", "default_delivered"]}
>
name={["md_ro_statuses", "default_delivered"]}>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>

View File

@@ -153,10 +153,26 @@ export const GET_JOB_BY_PK = gql`
adjustment_bottom_line
ownr_fn
ownr_ln
ownr_ea
ownr_addr1
ownr_addr2
ownr_city
ownr_st
ownr_zip
ownr_ctry
ownr_ph1
owner {
id
ownr_fn
ownr_ln
ownr_ea
ownr_addr1
ownr_addr2
ownr_city
ownr_st
ownr_zip
ownr_ctry
ownr_ph1
}
labor_rate_desc
rate_lab
@@ -303,6 +319,18 @@ export const UPDATE_JOB = gql`
}
`;
export const UPDATE_JOBS = gql`
mutation UPDATE_JOBS($jobIds: [uuid!]!, $fields: jobs_set_input!) {
update_jobs(where: { id: { _in: $jobIds } }, _set: $fields) {
returning {
id
est_ph1
est_ea
}
}
}
`;
export const CONVERT_JOB_TO_RO = gql`
mutation CONVERT_JOB_TO_RO($jobId: uuid!) {
update_jobs(where: { id: { _eq: $jobId } }, _set: { converted: true }) {

View File

@@ -118,11 +118,14 @@
"default_invoiced": "Default Invoiced Status",
"default_ordered": "Default Ordered Status",
"default_received": "Default Received Status",
"default_scheduled": "Default Scheduled Status"
"default_scheduled": "Default Scheduled Status",
"open_statuses": "Open Statuses"
},
"zip_post": "Zip/Postal Code"
},
"labels": {
"alljobstatuses": "All Job Statuses",
"allopenjobstatuses": "All Open Job Statuses",
"jobstatuses": "Job Statuses",
"orderstatuses": "Order Statuses",
"responsibilitycenters": {
@@ -523,6 +526,9 @@
}
},
"owners": {
"actions": {
"update": "Update Selected Records"
},
"errors": {
"noaccess": "The record does not exist or you do not have access to it. ",
"selectexistingornew": "Select an existing owner record or create a new one. "
@@ -546,7 +552,10 @@
},
"labels": {
"create_new": "Create a new owner record.",
"existing_owners": "Existing Owners"
"existing_owners": "Existing Owners",
"fromclaim": "Info From Claim",
"fromowner": "Info From Previous",
"updateowner": "Update Owner"
},
"successes": {
"save": "Owner saved successfully."

View File

@@ -118,11 +118,14 @@
"default_invoiced": "",
"default_ordered": "",
"default_received": "",
"default_scheduled": ""
"default_scheduled": "",
"open_statuses": ""
},
"zip_post": ""
},
"labels": {
"alljobstatuses": "",
"allopenjobstatuses": "",
"jobstatuses": "",
"orderstatuses": "",
"responsibilitycenters": {
@@ -523,6 +526,9 @@
}
},
"owners": {
"actions": {
"update": ""
},
"errors": {
"noaccess": "El registro no existe o no tiene acceso a él.",
"selectexistingornew": ""
@@ -546,7 +552,10 @@
},
"labels": {
"create_new": "Crea un nuevo registro de propietario.",
"existing_owners": "Propietarios existentes"
"existing_owners": "Propietarios existentes",
"fromclaim": "",
"fromowner": "",
"updateowner": ""
},
"successes": {
"save": "Propietario guardado con éxito."

View File

@@ -118,11 +118,14 @@
"default_invoiced": "",
"default_ordered": "",
"default_received": "",
"default_scheduled": ""
"default_scheduled": "",
"open_statuses": ""
},
"zip_post": ""
},
"labels": {
"alljobstatuses": "",
"allopenjobstatuses": "",
"jobstatuses": "",
"orderstatuses": "",
"responsibilitycenters": {
@@ -523,6 +526,9 @@
}
},
"owners": {
"actions": {
"update": ""
},
"errors": {
"noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès.",
"selectexistingornew": ""
@@ -546,7 +552,10 @@
},
"labels": {
"create_new": "Créez un nouvel enregistrement de propriétaire.",
"existing_owners": "Propriétaires existants"
"existing_owners": "Propriétaires existants",
"fromclaim": "",
"fromowner": "",
"updateowner": ""
},
"successes": {
"save": "Le propriétaire a bien enregistré."