Changed RO Search Select to use RO searching and possible provided job value for options IMEX-129 IMEX-327

This commit is contained in:
Patrick Fic
2020-08-26 16:15:17 -07:00
parent 69f2b66e56
commit 721c938e8a
20 changed files with 193 additions and 109 deletions

View File

@@ -45,12 +45,14 @@ function InvoiceEnterModalContainer({
invoice: [
Object.assign({}, remainingValues, {
invoicelines: {
data: remainingValues.invoicelines.map((i) => {
return {
...i,
joblineid: i.joblineid === "noline" ? null : i.joblineid,
};
}),
data:
remainingValues.invoicelines &&
remainingValues.invoicelines.map((i) => {
return {
...i,
joblineid: i.joblineid === "noline" ? null : i.joblineid,
};
}),
},
}),
],

View File

@@ -12,7 +12,6 @@ import { CalculateInvoiceTotal } from "./invoice-form.totals.utility";
export default function InvoiceFormComponent({
form,
roAutoCompleteOptions,
vendorAutoCompleteOptions,
lineData,
responsibilityCenters,
@@ -57,7 +56,6 @@ export default function InvoiceFormComponent({
]}
>
<JobSearchSelect
options={roAutoCompleteOptions}
disabled={invoiceEdit}
onBlur={() => {
if (form.getFieldValue("jobid") !== null) {

View File

@@ -3,7 +3,6 @@ import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import InvoiceFormComponent from "./invoice-form.component";
@@ -13,10 +12,6 @@ const mapStateToProps = createStructuredSelector({
});
export function InvoiceFormContainer({ bodyshop, form, invoiceEdit }) {
const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
});
const { data: VendorAutoCompleteData } = useQuery(SEARCH_VENDOR_AUTOCOMPLETE);
const [loadLines, { data: lineData }] = useLazyQuery(
@@ -28,7 +23,6 @@ export function InvoiceFormContainer({ bodyshop, form, invoiceEdit }) {
<InvoiceFormComponent
form={form}
invoiceEdit={invoiceEdit}
roAutoCompleteOptions={RoAutoCompleteData && RoAutoCompleteData.jobs}
vendorAutoCompleteOptions={
VendorAutoCompleteData && VendorAutoCompleteData.vendors
}

View File

@@ -1,50 +1,94 @@
import { useLazyQuery } from "@apollo/react-hooks";
import { Select } from "antd";
import React, { useEffect, useState, forwardRef } from "react";
import React, { forwardRef, useEffect, useState } from "react";
import {
SEARCH_JOBS_FOR_AUTOCOMPLETE,
SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE,
} from "../../graphql/jobs.queries";
import { LoadingOutlined } from "@ant-design/icons";
import _ from "lodash";
const { Option } = Select;
//To be used as a form element only.
const JobSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
const [callSearch, { loading, error, data }] = useLazyQuery(
SEARCH_JOBS_FOR_AUTOCOMPLETE
);
const [
callIdSearch,
{ loading: idLoading, error: idError, data: idData },
] = useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE);
const executeSearch = (v) => {
callSearch(v);
};
const debouncedExecuteSearch = _.debounce(executeSearch, 800);
const handleSearch = (value) => {
debouncedExecuteSearch({ variables: { search: value } });
};
const JobSearchSelect = (
{ value, onChange, options, onBlur, disabled, loading },
ref
) => {
const [option, setOption] = useState(value);
useEffect(() => {
if (value === option) {
console.log("Job ID Provided, searching...");
callIdSearch({ variables: { id: value } });
}
}, [value, option, callIdSearch]);
// useEffect(() => {
// if (value !== option && onChange) {
// onChange(option);
// }
// }, [value, option, onChange]);
const handleSelect = (value) => {
setOption(value);
if (value !== option && onChange) {
onChange(option);
}
}, [value, option, onChange]);
};
const theOptions = [
...(idData && idData.jobs_by_pk ? [idData.jobs_by_pk] : []),
...(data && data.search_jobs ? data.search_jobs : []),
];
return (
<Select
ref={ref}
disabled={disabled}
showSearch
autoFocus
value={option}
style={{
width: 300,
}}
loading={loading}
onChange={setOption}
optionFilterProp="children"
onBlur={onBlur}
>
{options
? options.map((o) => (
<Option key={o.id} value={o.id}>
{`${o.ro_number ? o.ro_number : o.est_number} | ${
o.ownr_ln || ""
} ${o.ownr_fn || ""} ${
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
o.v_model_desc || ""
}`}
</Option>
))
: null}
</Select>
<div>
<Select
ref={ref}
disabled={disabled}
showSearch
autoFocus
value={option}
style={{
width: 300,
}}
filterOption={false}
onSearch={handleSearch}
// onChange={setOption}
onSelect={handleSelect}
notFoundContent={loading ? <LoadingOutlined /> : null}
onBlur={onBlur}
>
{theOptions
? theOptions.map((o) => (
<Option key={o.id} value={o.id}>
{`${o.ro_number ? o.ro_number : o.est_number} | ${
o.ownr_ln || ""
} ${o.ownr_fn || ""} ${
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
o.v_model_desc || ""
}`}
</Option>
))
: null}
</Select>
{idLoading || loading ? <LoadingOutlined /> : null}
</div>
);
};
export default forwardRef(JobSearchSelect);

View File

@@ -61,7 +61,7 @@ export function JobsCloseLabmatAllocationButton({
setState({ center: "", amount: 0 });
};
const showAllocation = allocation.total.getAmount() > 0;
const showAllocation = Dinero(allocation.total).getAmount() > 0;
useEffect(() => {
if (remainingAmount === 0) setVisible(false);
}, [remainingAmount, setVisible]);
@@ -73,7 +73,8 @@ export function JobsCloseLabmatAllocationButton({
<Select
style={{ width: "200px" }}
value={state.center}
onSelect={(val) => setState({ ...state, center: val })}>
onSelect={(val) => setState({ ...state, center: val })}
>
{bodyshop.md_responsibility_centers.profits.map((r, idx) => (
<Option key={idx} value={r.name}>
{r.name}
@@ -94,7 +95,8 @@ export function JobsCloseLabmatAllocationButton({
state.center === "" ||
remainingAmount === 0 ||
invoiced
}>
}
>
{t("jobs.actions.allocate")}
</Button>
</div>

View File

@@ -8,7 +8,7 @@ export default function JobCloseLabMatAllocation({
labmatAllocations,
setLabmatAllocations,
labMatTotalAllocation,
invoiced
invoiced,
}) {
const { t } = useTranslation();
@@ -32,15 +32,15 @@ export default function JobCloseLabMatAllocation({
<td>{t(`jobs.fields.${alloc}`)}</td>
<td>
{labmatAllocations[alloc].total &&
labmatAllocations[alloc].total.toFormat()}
Dinero(labmatAllocations[alloc].total).toFormat()}
</td>
<td>
{labmatAllocations[alloc].total
{Dinero(labmatAllocations[alloc].total)
.subtract(
Dinero({
amount: labmatAllocations[alloc].allocations.reduce(
(acc, val) => {
return acc + val.amount.getAmount();
return acc + Dinero(val.amount).getAmount();
},
0
),
@@ -52,12 +52,12 @@ export default function JobCloseLabMatAllocation({
<AllocationButton
allocationKey={alloc}
invoiced={invoiced}
remainingAmount={labmatAllocations[alloc].total
remainingAmount={Dinero(labmatAllocations[alloc].total)
.subtract(
Dinero({
amount: labmatAllocations[alloc].allocations.reduce(
(acc, val) => {
return acc + val.amount.getAmount();
return acc + Dinero(val.amount).getAmount();
},
0
),
@@ -82,10 +82,10 @@ export default function JobCloseLabMatAllocation({
})}
<tr>
<td></td>
<td>{labmatAllocations.subtotal.toFormat()}</td>
<td>{Dinero(labmatAllocations.subtotal).toFormat()}</td>
<td></td>
<td></td>
<td>{labMatTotalAllocation.toFormat()}</td>
<td>{Dinero(labMatTotalAllocation).toFormat()}</td>
</tr>
</tbody>
</table>

View File

@@ -32,15 +32,15 @@ export default function JobsClosePartsAllocation({
<td>{t(`jobs.fields.${alloc.toLowerCase()}`)}</td>
<td>
{partsAllocations[alloc].total &&
partsAllocations[alloc].total.toFormat()}
Dinero(partsAllocations[alloc].total).toFormat()}
</td>
<td>
{partsAllocations[alloc].total
{Dinero(partsAllocations[alloc].total)
.subtract(
Dinero({
amount: partsAllocations[alloc].allocations.reduce(
(acc, val) => {
return acc + val.amount.getAmount();
return acc + Dinero(val.amount).getAmount();
},
0
),
@@ -52,12 +52,12 @@ export default function JobsClosePartsAllocation({
<AllocationButton
allocationKey={alloc}
invoiced={invoiced}
remainingAmount={partsAllocations[alloc].total
remainingAmount={Dinero(partsAllocations[alloc].total)
.subtract(
Dinero({
amount: partsAllocations[alloc].allocations.reduce(
(acc, val) => {
return acc + val.amount.getAmount();
return acc + Dinero(val.amount).getAmount();
},
0
),
@@ -70,7 +70,7 @@ export default function JobsClosePartsAllocation({
</td>
<td>
<AllocationTags
invoiced={invoiced}
invoiced={invoiced}
allocationKey={alloc}
allocation={partsAllocations[alloc]}
setAllocations={setPartsAllocations}
@@ -85,7 +85,7 @@ export default function JobsClosePartsAllocation({
{Dinero({
amount: Object.keys(partsAllocations).reduce((acc, val) => {
return (acc =
acc + partsAllocations[val].total.getAmount());
acc + Dinero(partsAllocations[val].total).getAmount());
}, 0),
}).toFormat()}
</td>

View File

@@ -13,12 +13,7 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function PaymentFormComponent({
form,
roAutoCompleteOptions,
stripeStateArr,
bodyshop,
}) {
export function PaymentFormComponent({ form, stripeStateArr, bodyshop }) {
const [stripeState, setStripeState] = stripeStateArr;
const { t } = useTranslation();
@@ -38,7 +33,7 @@ export function PaymentFormComponent({
},
]}
>
<JobSearchSelect options={roAutoCompleteOptions} />
<JobSearchSelect />
</Form.Item>
<Form.Item
label={t("payments.fields.amount")}

View File

@@ -1,8 +1,6 @@
import { useQuery } from "@apollo/react-hooks";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import PaymentFormComponent from "./payment-form.component";
@@ -10,24 +8,10 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function PaymentFormContainer({
bodyshop,
form,
stripeStateArr,
}) {
const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open*"] },
});
export function PaymentFormContainer({ bodyshop, form, stripeStateArr }) {
return (
<div>
<PaymentFormComponent
form={form}
roAutoCompleteOptions={RoAutoCompleteData && RoAutoCompleteData.jobs}
stripeStateArr={stripeStateArr}
/>
<PaymentFormComponent form={form} stripeStateArr={stripeStateArr} />
</div>
);
}

View File

@@ -1,10 +1,8 @@
import { useQuery } from "@apollo/react-hooks";
import { Form } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
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";
@@ -15,11 +13,6 @@ const mapStateToProps = createStructuredSelector({
export function TechClockInComponent({ form, bodyshop }) {
const { t } = useTranslation();
const { loading, data } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
variables: {
statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"],
},
});
return (
<div>
@@ -33,7 +26,7 @@ export function TechClockInComponent({ form, bodyshop }) {
},
]}
>
<JobSearchSelect loading={loading} options={data ? data.jobs : []} />
<JobSearchSelect />
</Form.Item>
<Form.Item

View File

@@ -1,12 +1,12 @@
import { useLazyQuery, useMutation, useQuery } from "@apollo/react-hooks";
import { Button, Form, Modal, notification } from "antd";
import moment from "moment";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_EMPLOYEES } from "../../graphql/employees.queries";
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
import { ACTIVE_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import {
INSERT_NEW_TIME_TICKET,
UPDATE_TIME_TICKET,
@@ -15,7 +15,6 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import TimeTicketModalComponent from "./time-ticket-modal.component";
import moment from "moment";
const mapStateToProps = createStructuredSelector({
timeTicketModal: selectTimeTicket,
@@ -35,13 +34,11 @@ export function TimeTicketModalContainer({
const [enterAgain, setEnterAgain] = useState(false);
const [insertTicket] = useMutation(INSERT_NEW_TIME_TICKET);
const [updateTicket] = useMutation(UPDATE_TIME_TICKET);
const { data: RoAutoCompleteData } = useQuery(ACTIVE_JOBS_FOR_AUTOCOMPLETE, {
variables: { statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"] },
skip: !timeTicketModal.visible,
});
const { data: EmployeeAutoCompleteData } = useQuery(QUERY_EMPLOYEES, {
skip: !timeTicketModal.visible,
});
const [loadLineTicketData, { data: lineTicketData }] = useLazyQuery(
GET_LINE_TICKET_BY_PK
);
@@ -194,7 +191,6 @@ export function TimeTicketModalContainer({
>
<TimeTicketModalComponent
form={form}
roAutoCompleteOptions={RoAutoCompleteData && RoAutoCompleteData.jobs}
employeeAutoCompleteOptions={
EmployeeAutoCompleteData && EmployeeAutoCompleteData.employees
}

View File

@@ -179,6 +179,9 @@ export const QUERY_INVOICE_BY_PK = gql`
total
updated_at
vendorid
local_tax_rate
state_tax_rate
federal_tax_rate
vendor {
id
name

View File

@@ -674,6 +674,41 @@ export const ACTIVE_JOBS_FOR_AUTOCOMPLETE = gql`
}
`;
export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql`
query SEARCH_JOBS_FOR_AUTOCOMPLETE($search: String) {
search_jobs(
args: { search: $search }
limit: 50
order_by: { ro_number: desc_nulls_last }
) {
id
ownr_fn
ownr_ln
ro_number
est_number
vehicleid
v_make_desc
v_model_desc
v_model_yr
}
}
`;
export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql`
query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) {
jobs_by_pk(id: $id) {
id
ownr_fn
ownr_ln
ro_number
est_number
vehicleid
v_make_desc
v_model_desc
v_model_yr
}
}
`;
export const SEARCH_FOR_JOBS = gql`
query SEARCH_FOR_JOBS($search: String!) {
jobs(where: { ro_number: { _ilike: $search } }) {

View File

@@ -350,8 +350,10 @@ export function Manage({ match, conflict }) {
<ChatAffixContainer />
<BackTop />
<div style={{ textAlign: "center", margin: "1rem 0rem" }}>
<span>{`ImEX Online V.${process.env.NODE_ENV}-${process.env.REACT_APP_GIT_SHA}`}</span>
<span>&copy; 2019 - {new Date().getFullYear} Snapt Software Inc. </span>
<div>{`ImEX Online V.${process.env.NODE_ENV}-${process.env.REACT_APP_GIT_SHA}`}</div>
<div>
&copy; 2019 - {new Date().getFullYear()} Snapt Software Inc.{" "}
</div>
</div>
</Content>
</Layout>

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,11 @@
- args:
cascade: true
read_only: false
sql: "CREATE OR REPLACE FUNCTION public.search_jobs(search text)\n RETURNS SETOF
jobs\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = '' then\n
\ return query select * from jobs j ;\n else \n return query SELECT\n
\ *\nFROM\n jobs\nWHERE\nsearch = id OR\n search <% (ownr_fn) OR\n search
<% (ownr_ln) OR\n search <% (cast(est_number as text)) OR\n search <% (ro_number)
OR\n search <% (clm_no) OR\n search <% (plate_no) OR\n search <% (v_make_desc)
OR\n search <% (v_model_desc) ;\n end if;\n\n\tEND\n\n\n$function$;"
type: run_sql

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,11 @@
- args:
cascade: true
read_only: false
sql: "CREATE OR REPLACE FUNCTION public.search_jobs(search text)\n RETURNS SETOF
jobs\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = '' then\n
\ return query select * from jobs j ;\n else \n return query SELECT\n
\ *\nFROM\n jobs\nWHERE\nUUID(search) = id OR\n search <% (ownr_fn) OR\n search
<% (ownr_ln) OR\n search <% (cast(est_number as text)) OR\n search <% (ro_number)
OR\n search <% (clm_no) OR\n search <% (plate_no) OR\n search <% (v_make_desc)
OR\n search <% (v_model_desc) ;\n end if;\n\n\tEND\n\n\n$function$;"
type: run_sql

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,11 @@
- args:
cascade: true
read_only: false
sql: "CREATE OR REPLACE FUNCTION public.search_jobs(search text)\n RETURNS SETOF
jobs\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = '' then\n
\ return query select * from jobs j ;\n else \n return query SELECT\n
\ *\nFROM\n jobs\nWHERE\n search <% (ownr_fn) OR\n search <% (ownr_ln) OR\n
\ search <% (cast(est_number as text)) OR\n search <% (ro_number) OR\n search
<% (clm_no) OR\n search <% (plate_no) OR\n search <% (v_make_desc) OR\n search
<% (v_model_desc) ;\n end if;\n\n\tEND\n\n\n$function$;"
type: run_sql