@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.7.1">
|
<babeledit_project be_version="2.7.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -2063,6 +2063,32 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<folder_node>
|
||||||
|
<name>validation</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>atleastone</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>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
@@ -8138,6 +8164,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>default_quote</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>
|
<concept_node>
|
||||||
<name>default_received</name>
|
<name>default_received</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -33967,6 +34014,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>is_quote</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>
|
<concept_node>
|
||||||
<name>mark_as_received</name>
|
<name>mark_as_received</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"@asseinfo/react-kanban": "^2.2.0",
|
"@asseinfo/react-kanban": "^2.2.0",
|
||||||
"@craco/craco": "^6.4.3",
|
"@craco/craco": "^6.4.3",
|
||||||
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
||||||
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@sentry/react": "^7.1.1",
|
"@sentry/react": "^7.1.1",
|
||||||
"@sentry/tracing": "^7.1.1",
|
"@sentry/tracing": "^7.1.1",
|
||||||
"@splitsoftware/splitio-react": "^1.4.1",
|
"@splitsoftware/splitio-react": "^1.4.1",
|
||||||
|
|||||||
@@ -552,7 +552,20 @@ export function BillEnterModalLinesComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.List name="billlines">
|
<Form.List
|
||||||
|
name="billlines"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
validator: async (_, billlines) => {
|
||||||
|
if (!billlines || billlines.length < 1) {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error(t("billlines.validation.atleastone"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
{(fields, { add, remove, move }) => {
|
{(fields, { add, remove, move }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -217,21 +217,31 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
|||||||
<JobsRelatedRos jobid={job.id} job={job} />
|
<JobsRelatedRos jobid={job.id} job={job} />
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
{job.vehicle && job.vehicle.notes && (
|
{job.vehicle && job.vehicle.notes && (
|
||||||
<DataLabel label={t("vehicles.fields.notes")}>
|
<DataLabel
|
||||||
<span style={{ whiteSpace: "pre" }}>{job.vehicle.notes}</span>
|
label={t("vehicles.fields.notes")}
|
||||||
|
valueStyle={{ whiteSpace: "pre-wrap" }}
|
||||||
|
>
|
||||||
|
{job.vehicle.notes}
|
||||||
|
</DataLabel>
|
||||||
|
)}
|
||||||
|
{job.vehicle && job.vehicle.v_paint_codes && (
|
||||||
|
<DataLabel
|
||||||
|
label={t("vehicles.fields.v_paint_codes", { number: "" })}
|
||||||
|
>
|
||||||
|
<span style={{ whiteSpace: "pre" }}>
|
||||||
|
{Object.keys(job.vehicle.v_paint_codes)
|
||||||
|
.filter(
|
||||||
|
(key) =>
|
||||||
|
job.vehicle.v_paint_codes[key] !== "" &&
|
||||||
|
job.vehicle.v_paint_codes[key] !== null &&
|
||||||
|
job.vehicle.v_paint_codes[key] !== undefined
|
||||||
|
)
|
||||||
|
.map((key, idx) => (
|
||||||
|
<Tag key={idx}>{job.vehicle.v_paint_codes[key]}</Tag>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
)}
|
)}
|
||||||
{
|
|
||||||
// job.vehicle && job.vehicle.v_paint_codes && (
|
|
||||||
// <DataLabel label={t("vehicles.fields.v_paint_codes")}>
|
|
||||||
// <span style={{ whiteSpace: "pre" }}>
|
|
||||||
// {Object.keys(job.vehicle.v_paint_codes).map((key, idx) => (
|
|
||||||
// <Tag key={idx}>{job.vehicle.v_paint_codes[key]}</Tag>
|
|
||||||
// ))}
|
|
||||||
// </span>
|
|
||||||
// </DataLabel>
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -290,18 +290,42 @@ export function PartsOrderModalComponent({
|
|||||||
>
|
>
|
||||||
<Input.TextArea rows={3} />
|
<Input.TextArea rows={3} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{OEConnection.treatment === "on" && !isReturn && (
|
||||||
|
<Form.Item
|
||||||
|
name="is_quote"
|
||||||
|
label={t("parts_orders.labels.is_quote")}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Checkbox />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
|
||||||
<Radio.Group
|
<Form.Item noStyle shouldUpdate>
|
||||||
defaultValue={sendType}
|
{() => {
|
||||||
onChange={(e) => setSendType(e.target.value)}
|
const is_quote = form.getFieldValue("is_quote");
|
||||||
>
|
if (is_quote) setSendType("oec");
|
||||||
<Radio value={"none"}>{t("general.labels.none")}</Radio>
|
return (
|
||||||
<Radio value={"e"}>{t("parts_orders.labels.email")}</Radio>
|
<Radio.Group
|
||||||
<Radio value={"p"}>{t("parts_orders.labels.print")}</Radio>
|
defaultValue={sendType}
|
||||||
{OEConnection.treatment === "on" && !isReturn && (
|
value={sendType}
|
||||||
<Radio value={"oec"}>{t("parts_orders.labels.oec")}</Radio>
|
onChange={(e) => setSendType(e.target.value)}
|
||||||
)}
|
>
|
||||||
</Radio.Group>
|
<Radio disabled={is_quote} value={"none"}>
|
||||||
|
{t("general.labels.none")}
|
||||||
|
</Radio>
|
||||||
|
<Radio disabled={is_quote} value={"e"}>
|
||||||
|
{t("parts_orders.labels.email")}
|
||||||
|
</Radio>
|
||||||
|
<Radio disabled={is_quote} value={"p"}>
|
||||||
|
{t("parts_orders.labels.print")}
|
||||||
|
</Radio>
|
||||||
|
{OEConnection.treatment === "on" && !isReturn && (
|
||||||
|
<Radio value={"oec"}>{t("parts_orders.labels.oec")}</Radio>
|
||||||
|
)}
|
||||||
|
</Radio.Group>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,31 +93,48 @@ export function PartsOrderModalContainer({
|
|||||||
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
||||||
const [updateJob] = useMutation(UPDATE_JOB);
|
const [updateJob] = useMutation(UPDATE_JOB);
|
||||||
|
|
||||||
const handleFinish = async ({ removefrompartsqueue, ...values }) => {
|
const handleFinish = async ({
|
||||||
|
removefrompartsqueue,
|
||||||
|
is_quote,
|
||||||
|
...values
|
||||||
|
}) => {
|
||||||
logImEXEvent("parts_order_insert");
|
logImEXEvent("parts_order_insert");
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
const insertResult = await insertPartOrder({
|
let insertResult;
|
||||||
variables: {
|
if (!is_quote) {
|
||||||
po: [
|
await insertPartOrder({
|
||||||
{
|
variables: {
|
||||||
...values,
|
po: [
|
||||||
order_date: moment().format("YYYY-MM-DD"),
|
{
|
||||||
orderedby: currentUser.email,
|
...values,
|
||||||
jobid: jobId,
|
order_date: moment().format("YYYY-MM-DD"),
|
||||||
user_email: currentUser.email,
|
orderedby: currentUser.email,
|
||||||
return: isReturn,
|
jobid: jobId,
|
||||||
status: bodyshop.md_order_statuses.default_ordered || "Ordered*",
|
user_email: currentUser.email,
|
||||||
},
|
return: isReturn,
|
||||||
],
|
status: bodyshop.md_order_statuses.default_ordered || "Ordered*",
|
||||||
},
|
},
|
||||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID"],
|
],
|
||||||
});
|
},
|
||||||
if (!!insertResult.error) {
|
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID"],
|
||||||
notification["error"]({
|
});
|
||||||
message: t("parts_orders.errors.creating"),
|
if (!!insertResult.error) {
|
||||||
description: JSON.stringify(insertResult.error),
|
notification["error"]({
|
||||||
|
message: t("parts_orders.errors.creating"),
|
||||||
|
description: JSON.stringify(insertResult.error),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: jobId,
|
||||||
|
operation: isReturn
|
||||||
|
? AuditTrailMapping.jobspartsreturn(
|
||||||
|
insertResult.data.insert_parts_orders.returning[0].order_number
|
||||||
|
)
|
||||||
|
: AuditTrailMapping.jobspartsorder(
|
||||||
|
insertResult.data.insert_parts_orders.returning[0].order_number
|
||||||
|
),
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const jobLinesResult = await updateJobLines({
|
const jobLinesResult = await updateJobLines({
|
||||||
@@ -127,6 +144,8 @@ export function PartsOrderModalContainer({
|
|||||||
.map((item) => item.job_line_id),
|
.map((item) => item.job_line_id),
|
||||||
status: isReturn
|
status: isReturn
|
||||||
? bodyshop.md_order_statuses.default_returned || "Returned*"
|
? bodyshop.md_order_statuses.default_returned || "Returned*"
|
||||||
|
: is_quote
|
||||||
|
? bodyshop.md_order_statuses.default_quote || "Quote"
|
||||||
: bodyshop.md_order_statuses.default_ordered || "Ordered*",
|
: bodyshop.md_order_statuses.default_ordered || "Ordered*",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -142,17 +161,6 @@ export function PartsOrderModalContainer({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
insertAuditTrail({
|
|
||||||
jobid: jobId,
|
|
||||||
operation: isReturn
|
|
||||||
? AuditTrailMapping.jobspartsreturn(
|
|
||||||
insertResult.data.insert_parts_orders.returning[0].order_number
|
|
||||||
)
|
|
||||||
: AuditTrailMapping.jobspartsorder(
|
|
||||||
insertResult.data.insert_parts_orders.returning[0].order_number
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!!jobLinesResult.errors) {
|
if (!!jobLinesResult.errors) {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("parts_orders.errors.creating"),
|
message: t("parts_orders.errors.creating"),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -66,6 +67,9 @@ export function ScheduleCalendarHeaderComponent({
|
|||||||
<td>
|
<td>
|
||||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<OwnerNameDisplay ownerObject={j} />
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{`(${(
|
{`(${(
|
||||||
j.labhrs.aggregate.sum.mod_lb_hrs +
|
j.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
@@ -99,6 +103,9 @@ export function ScheduleCalendarHeaderComponent({
|
|||||||
<td>
|
<td>
|
||||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<OwnerNameDisplay ownerObject={j} />
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{`(${(
|
{`(${(
|
||||||
j.labhrs.aggregate.sum.mod_lb_hrs +
|
j.labhrs.aggregate.sum.mod_lb_hrs +
|
||||||
|
|||||||
@@ -2,9 +2,28 @@ import { Form, Input } from "antd";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
export default function ShopInfoOrderStatusComponent({ form }) {
|
import { connect } from "react-redux";
|
||||||
const { t } = useTranslation();
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ShopInfoOrderStatusComponent);
|
||||||
|
|
||||||
|
export function ShopInfoOrderStatusComponent({ bodyshop, form }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { OEConnection } = useTreatments(
|
||||||
|
["OEConnection"],
|
||||||
|
{},
|
||||||
|
bodyshop.imexshopid
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<LayoutFormRow header={t("bodyshop.labels.orderstatuses")}>
|
<LayoutFormRow header={t("bodyshop.labels.orderstatuses")}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -56,6 +75,20 @@ export default function ShopInfoOrderStatusComponent({ form }) {
|
|||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{OEConnection.treatment === "on" && (
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.statuses.default_quote")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
name={["md_order_statuses", "default_quote"]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,6 +324,9 @@ export const QUERY_SCHEDULE_LOAD_DATA = gql`
|
|||||||
ro_number
|
ro_number
|
||||||
scheduled_completion
|
scheduled_completion
|
||||||
actual_completion
|
actual_completion
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_co_nm
|
||||||
labhrs: joblines_aggregate(
|
labhrs: joblines_aggregate(
|
||||||
where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }
|
where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }
|
||||||
) {
|
) {
|
||||||
@@ -352,6 +355,9 @@ export const QUERY_SCHEDULE_LOAD_DATA = gql`
|
|||||||
id
|
id
|
||||||
scheduled_in
|
scheduled_in
|
||||||
ro_number
|
ro_number
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_co_nm
|
||||||
labhrs: joblines_aggregate(
|
labhrs: joblines_aggregate(
|
||||||
where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }
|
where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
|
import useLocalStorage from "../../utils/useLocalStorage";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -31,6 +32,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
statusFilters,
|
statusFilters,
|
||||||
} = searchParams;
|
} = searchParams;
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const [filter, setFilter] = useLocalStorage("filter_parts_queue", null);
|
||||||
|
|
||||||
const { loading, error, data, refetch } = useQuery(QUERY_PARTS_QUEUE, {
|
const { loading, error, data, refetch } = useQuery(QUERY_PARTS_QUEUE, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -92,7 +94,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
// searchParams.page = pagination.current;
|
// searchParams.page = pagination.current;
|
||||||
searchParams.sortcolumn = sorter.columnKey;
|
searchParams.sortcolumn = sorter.columnKey;
|
||||||
searchParams.sortorder = sorter.order;
|
searchParams.sortorder = sorter.order;
|
||||||
|
setFilter(filters);
|
||||||
history.push({ search: queryString.stringify(searchParams) });
|
history.push({ search: queryString.stringify(searchParams) });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -247,6 +249,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
key: "queued_for_parts",
|
key: "queued_for_parts",
|
||||||
sorter: (a, b) => a.queued_for_parts - b.queued_for_parts,
|
sorter: (a, b) => a.queued_for_parts - b.queued_for_parts,
|
||||||
sortOrder: sortcolumn === "queued_for_parts" && sortorder,
|
sortOrder: sortcolumn === "queued_for_parts" && sortorder,
|
||||||
|
filteredValue: filter.queued_for_parts || null,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
text: "Queued",
|
text: "Queued",
|
||||||
|
|||||||
@@ -136,6 +136,9 @@
|
|||||||
"other": "-- Not On Estimate --",
|
"other": "-- Not On Estimate --",
|
||||||
"reconciled": "Reconciled!",
|
"reconciled": "Reconciled!",
|
||||||
"unreconciled": "Unreconciled"
|
"unreconciled": "Unreconciled"
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"atleastone": "At least one bill line must be entered."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bills": {
|
"bills": {
|
||||||
@@ -502,6 +505,7 @@
|
|||||||
"default_imported": "Default Imported Status",
|
"default_imported": "Default Imported Status",
|
||||||
"default_invoiced": "Default Invoiced Status",
|
"default_invoiced": "Default Invoiced Status",
|
||||||
"default_ordered": "Default Ordered Status",
|
"default_ordered": "Default Ordered Status",
|
||||||
|
"default_quote": "Default Quote Status",
|
||||||
"default_received": "Default Received Status",
|
"default_received": "Default Received Status",
|
||||||
"default_returned": "Default Returned",
|
"default_returned": "Default Returned",
|
||||||
"default_scheduled": "Default Scheduled Status",
|
"default_scheduled": "Default Scheduled Status",
|
||||||
@@ -2013,6 +2017,7 @@
|
|||||||
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ",
|
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ",
|
||||||
"email": "Send by Email",
|
"email": "Send by Email",
|
||||||
"inthisorder": "Parts in this Order",
|
"inthisorder": "Parts in this Order",
|
||||||
|
"is_quote": "Parts Quote?",
|
||||||
"mark_as_received": "Mark as Received?",
|
"mark_as_received": "Mark as Received?",
|
||||||
"newpartsorder": "New Parts Order",
|
"newpartsorder": "New Parts Order",
|
||||||
"notyetordered": "This part has not yet been ordered.",
|
"notyetordered": "This part has not yet been ordered.",
|
||||||
|
|||||||
@@ -136,6 +136,9 @@
|
|||||||
"other": "",
|
"other": "",
|
||||||
"reconciled": "",
|
"reconciled": "",
|
||||||
"unreconciled": ""
|
"unreconciled": ""
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"atleastone": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bills": {
|
"bills": {
|
||||||
@@ -502,6 +505,7 @@
|
|||||||
"default_imported": "",
|
"default_imported": "",
|
||||||
"default_invoiced": "",
|
"default_invoiced": "",
|
||||||
"default_ordered": "",
|
"default_ordered": "",
|
||||||
|
"default_quote": "",
|
||||||
"default_received": "",
|
"default_received": "",
|
||||||
"default_returned": "",
|
"default_returned": "",
|
||||||
"default_scheduled": "",
|
"default_scheduled": "",
|
||||||
@@ -2013,6 +2017,7 @@
|
|||||||
"confirmdelete": "",
|
"confirmdelete": "",
|
||||||
"email": "Enviar por correo electrónico",
|
"email": "Enviar por correo electrónico",
|
||||||
"inthisorder": "Partes en este pedido",
|
"inthisorder": "Partes en este pedido",
|
||||||
|
"is_quote": "",
|
||||||
"mark_as_received": "",
|
"mark_as_received": "",
|
||||||
"newpartsorder": "",
|
"newpartsorder": "",
|
||||||
"notyetordered": "",
|
"notyetordered": "",
|
||||||
|
|||||||
@@ -136,6 +136,9 @@
|
|||||||
"other": "",
|
"other": "",
|
||||||
"reconciled": "",
|
"reconciled": "",
|
||||||
"unreconciled": ""
|
"unreconciled": ""
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"atleastone": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bills": {
|
"bills": {
|
||||||
@@ -502,6 +505,7 @@
|
|||||||
"default_imported": "",
|
"default_imported": "",
|
||||||
"default_invoiced": "",
|
"default_invoiced": "",
|
||||||
"default_ordered": "",
|
"default_ordered": "",
|
||||||
|
"default_quote": "",
|
||||||
"default_received": "",
|
"default_received": "",
|
||||||
"default_returned": "",
|
"default_returned": "",
|
||||||
"default_scheduled": "",
|
"default_scheduled": "",
|
||||||
@@ -2013,6 +2017,7 @@
|
|||||||
"confirmdelete": "",
|
"confirmdelete": "",
|
||||||
"email": "Envoyé par email",
|
"email": "Envoyé par email",
|
||||||
"inthisorder": "Pièces dans cette commande",
|
"inthisorder": "Pièces dans cette commande",
|
||||||
|
"is_quote": "",
|
||||||
"mark_as_received": "",
|
"mark_as_received": "",
|
||||||
"newpartsorder": "",
|
"newpartsorder": "",
|
||||||
"notyetordered": "",
|
"notyetordered": "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { gql } from "@apollo/client";
|
import { gql } from "@apollo/client";
|
||||||
import { notification } from "antd";
|
import { notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import jsreport from "jsreport-browser-client-dist";
|
import jsreport from "@jsreport/browser-client";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { auth } from "../firebase/firebase.utils";
|
import { auth } from "../firebase/firebase.utils";
|
||||||
@@ -9,7 +9,9 @@ import { setEmailOptions } from "../redux/email/email.actions";
|
|||||||
import { store } from "../redux/store";
|
import { store } from "../redux/store";
|
||||||
import client from "../utils/GraphQLClient";
|
import client from "../utils/GraphQLClient";
|
||||||
import { TemplateList } from "./TemplateConstants";
|
import { TemplateList } from "./TemplateConstants";
|
||||||
|
|
||||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||||
|
|
||||||
jsreport.serverUrl = server;
|
jsreport.serverUrl = server;
|
||||||
|
|
||||||
const Templates = TemplateList();
|
const Templates = TemplateList();
|
||||||
@@ -21,6 +23,10 @@ export default async function RenderTemplate(
|
|||||||
renderAsExcel = false,
|
renderAsExcel = false,
|
||||||
renderAsText = false
|
renderAsText = false
|
||||||
) {
|
) {
|
||||||
|
if (window.jsr3) {
|
||||||
|
jsreport.serverUrl = "https://reports3.test.imex.online/";
|
||||||
|
}
|
||||||
|
|
||||||
//Query assets that match the template name. Must be in format <<templateName>>.query
|
//Query assets that match the template name. Must be in format <<templateName>>.query
|
||||||
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
||||||
templateObject
|
templateObject
|
||||||
@@ -69,7 +75,7 @@ export default async function RenderTemplate(
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const render = await jsreport.renderAsync(reportRequest);
|
const render = await jsreport.render(reportRequest);
|
||||||
|
|
||||||
if (!renderAsHtml) {
|
if (!renderAsHtml) {
|
||||||
render.download(
|
render.download(
|
||||||
@@ -104,7 +110,7 @@ export default async function RenderTemplate(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const pdfRender = await jsreport.renderAsync(pdfRequest);
|
const pdfRender = await jsreport.render(pdfRequest);
|
||||||
pdf = pdfRender.toDataURI();
|
pdf = pdfRender.toDataURI();
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -152,6 +158,9 @@ export async function RenderTemplates(
|
|||||||
// (template) => template.name === item.templateObject.name
|
// (template) => template.name === item.templateObject.name
|
||||||
// );
|
// );
|
||||||
// });
|
// });
|
||||||
|
if (window.jsr3) {
|
||||||
|
jsreport.serverUrl = "https://reports3.test.imex.online/";
|
||||||
|
}
|
||||||
|
|
||||||
unsortedTemplatesAndData.sort(function (a, b) {
|
unsortedTemplatesAndData.sort(function (a, b) {
|
||||||
return (
|
return (
|
||||||
@@ -242,7 +251,7 @@ export async function RenderTemplates(
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const render = await jsreport.renderAsync(reportRequest);
|
const render = await jsreport.render(reportRequest);
|
||||||
if (!renderAsHtml) {
|
if (!renderAsHtml) {
|
||||||
render.download("Speed Print");
|
render.download("Speed Print");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
40
client/src/utils/useLocalStorage.js
Normal file
40
client/src/utils/useLocalStorage.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function useLocalStorage(key, initialValue) {
|
||||||
|
// State to store our value
|
||||||
|
// Pass initial state function to useState so logic is only executed once
|
||||||
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Get from local storage by key
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
// Parse stored json or if none return initialValue
|
||||||
|
return item ? JSON.parse(item) : initialValue;
|
||||||
|
} catch (error) {
|
||||||
|
// If error also return initialValue
|
||||||
|
console.log(error);
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Return a wrapped version of useState's setter function that ...
|
||||||
|
// ... persists the new value to localStorage.
|
||||||
|
const setValue = (value) => {
|
||||||
|
try {
|
||||||
|
// Allow value to be a function so we have same API as useState
|
||||||
|
const valueToStore =
|
||||||
|
value instanceof Function ? value(storedValue) : value;
|
||||||
|
// Save state
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
// Save to local storage
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// A more advanced implementation would handle the error case
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return [storedValue, setValue];
|
||||||
|
}
|
||||||
@@ -1918,6 +1918,11 @@
|
|||||||
"@types/yargs" "^16.0.0"
|
"@types/yargs" "^16.0.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
|
||||||
|
"@jsreport/browser-client@^3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@jsreport/browser-client/-/browser-client-3.1.0.tgz#a84011087ca8a29a6dc6a852fa05ffaf1983a679"
|
||||||
|
integrity sha512-ZElwn2KRIzkUzAyD5UKGxULZUhokWuPOlMzrmiur4WirqH3yoiHlOJEdnRGkjjE/fhZzCR8gBFZ/TuOW/fsOIw==
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.5":
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
version "2.1.5"
|
version "2.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ exports.default = async (req, res) => {
|
|||||||
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
||||||
|
|
||||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
||||||
const { start, end } = req.body; //YYYY-MM-DD
|
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||||
const allxmlsToUpload = [];
|
const allxmlsToUpload = [];
|
||||||
const allErrors = [];
|
const allErrors = [];
|
||||||
try {
|
try {
|
||||||
@@ -107,7 +107,7 @@ exports.default = async (req, res) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
//Error at the shop level.
|
//Error at the shop level.
|
||||||
logger.log("autohouse-error-shop", "ERROR", "api", bodyshop.id, {
|
logger.log("autohouse-error-shop", "ERROR", "api", bodyshop.id, {
|
||||||
error,
|
...error,
|
||||||
});
|
});
|
||||||
|
|
||||||
allErrors.push({
|
allErrors.push({
|
||||||
@@ -125,17 +125,29 @@ exports.default = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (const xmlObj of allxmlsToUpload) {
|
if (skipUpload) {
|
||||||
// fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
for (const xmlObj of allxmlsToUpload) {
|
||||||
// }
|
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||||
|
}
|
||||||
|
|
||||||
// res.json(allxmlsToUpload);
|
res.json(allxmlsToUpload);
|
||||||
// return;
|
sendServerEmail({
|
||||||
|
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
||||||
|
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||||
|
Uploaded: ${JSON.stringify(
|
||||||
|
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let sftp = new Client();
|
let sftp = new Client();
|
||||||
sftp.on("error", (errors) =>
|
sftp.on("error", (errors) =>
|
||||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
||||||
errors,
|
...errors,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
@@ -160,7 +172,7 @@ exports.default = async (req, res) => {
|
|||||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
||||||
error,
|
...error,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
sftp.end();
|
sftp.end();
|
||||||
@@ -169,7 +181,7 @@ exports.default = async (req, res) => {
|
|||||||
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
||||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||||
Uploaded: ${JSON.stringify(
|
Uploaded: ${JSON.stringify(
|
||||||
allxmlsToUpload.map((x) => x.filename),
|
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||||
null,
|
null,
|
||||||
2
|
2
|
||||||
)}
|
)}
|
||||||
@@ -185,7 +197,11 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
|||||||
//Level 2
|
//Level 2
|
||||||
|
|
||||||
if (!job.job_totals) {
|
if (!job.job_totals) {
|
||||||
errorCallback({ job, error: { toString: () => "No job totals for RO." } });
|
errorCallback({
|
||||||
|
jobid: jobid,
|
||||||
|
ro_number: job.ro_number,
|
||||||
|
error: { toString: () => "No job totals for RO." },
|
||||||
|
});
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +674,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
|||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
|
||||||
errorCallback({ job, error });
|
errorCallback({ jobid: jobid, ro_number: job.ro_number, error });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -889,7 +905,9 @@ const GenerateDetailLines = (job, line, statuses) => {
|
|||||||
OriginalCost: null,
|
OriginalCost: null,
|
||||||
OriginalInvoiceNumber: null,
|
OriginalInvoiceNumber: null,
|
||||||
PriceEach: line.act_price || 0,
|
PriceEach: line.act_price || 0,
|
||||||
PartNumber: _.escape(line.oem_partno.replace(/[^\x00-\x7F]/g, "")),
|
PartNumber: line.oem_partno
|
||||||
|
? line.oem_partno.replace(/[^\x00-\x7F]/g, "")
|
||||||
|
: "",
|
||||||
ProfitPercent: null,
|
ProfitPercent: null,
|
||||||
PurchaseOrderNumber: null,
|
PurchaseOrderNumber: null,
|
||||||
Qty: line.part_qty || 0,
|
Qty: line.part_qty || 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user