Merged in release/2022-06-30 (pull request #534)
release/2022-06-30 Approved-by: Patrick Fic
This commit is contained in:
@@ -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>
|
||||||
@@ -17779,6 +17826,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>actions</name>
|
<name>actions</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>converttolabor</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>new</name>
|
<name>new</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -18959,6 +19027,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>labels</name>
|
<name>labels</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>adjustmenttobeadded</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>billref</name>
|
<name>billref</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -18980,6 +19069,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>convertedtolabor</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>edit</name>
|
<name>edit</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -33967,6 +34077,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",
|
||||||
|
|||||||
@@ -144,6 +144,14 @@ function BillEnterModalContainer({
|
|||||||
adjKeys.forEach((key) => {
|
adjKeys.forEach((key) => {
|
||||||
newAdjustments[key] =
|
newAdjustments[key] =
|
||||||
(newAdjustments[key] || 0) + adjustmentsToInsert[key];
|
(newAdjustments[key] || 0) + adjustmentsToInsert[key];
|
||||||
|
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: values.jobid,
|
||||||
|
operation: AuditTrailMapping.jobmodifylbradj({
|
||||||
|
mod_lbr_ty: key,
|
||||||
|
hours: adjustmentsToInsert[key].toFixed(1),
|
||||||
|
}),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const jobUpdate = client.mutate({
|
const jobUpdate = client.mutate({
|
||||||
@@ -161,10 +169,6 @@ function BillEnterModalContainer({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
insertAuditTrail({
|
|
||||||
jobid: values.jobid,
|
|
||||||
operation: AuditTrailMapping.jobmodifylbradj(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const markPolReceived =
|
const markPolReceived =
|
||||||
|
|||||||
@@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -38,12 +38,6 @@ export function EmailDocumentsComponent({
|
|||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(
|
|
||||||
selectedMedia &&
|
|
||||||
selectedMedia
|
|
||||||
.filter((s) => s.isSelected)
|
|
||||||
.reduce((acc, val) => (acc = acc + val.size), 0)
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{loading && <LoadingSpinner />}
|
{loading && <LoadingSpinner />}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
|||||||
import JobLinesExpander from "./job-lines-expander.component";
|
import JobLinesExpander from "./job-lines-expander.component";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -175,7 +176,7 @@ export function JobLinesComponent({
|
|||||||
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<>
|
<JobLineConvertToLabor jobline={record} job={job}>
|
||||||
<CurrencyFormatter>
|
<CurrencyFormatter>
|
||||||
{record.db_ref === "900510" || record.db_ref === "900511"
|
{record.db_ref === "900510" || record.db_ref === "900511"
|
||||||
? record.prt_dsmk_m
|
? record.prt_dsmk_m
|
||||||
@@ -188,7 +189,7 @@ export function JobLinesComponent({
|
|||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
</>
|
</JobLineConvertToLabor>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -295,9 +296,9 @@ export function JobLinesComponent({
|
|||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<Space>
|
||||||
{(record.manual_line || jobIsPrivate) && (
|
{(record.manual_line || jobIsPrivate) && (
|
||||||
<Space>
|
<>
|
||||||
<Button
|
<Button
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -334,9 +335,9 @@ export function JobLinesComponent({
|
|||||||
>
|
>
|
||||||
<DeleteFilled />
|
<DeleteFilled />
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
import { ClockCircleOutlined } from "@ant-design/icons";
|
||||||
|
import { useApolloClient } from "@apollo/client";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Form,
|
||||||
|
notification,
|
||||||
|
Popover,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Tooltip,
|
||||||
|
} from "antd";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import {
|
||||||
|
QUERY_JOB_LBR_ADJUSTMENTS,
|
||||||
|
UPDATE_JOB,
|
||||||
|
} from "../../graphql/jobs.queries";
|
||||||
|
|
||||||
|
import _ from "lodash";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
//currentUser: selectCurrentUser
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(JobLineConvertToLabor);
|
||||||
|
|
||||||
|
export function JobLineConvertToLabor({
|
||||||
|
children,
|
||||||
|
jobline,
|
||||||
|
job,
|
||||||
|
insertAuditTrail,
|
||||||
|
...otherBtnProps
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [visibility, setVisibility] = useState(false);
|
||||||
|
const client = useApolloClient();
|
||||||
|
|
||||||
|
const handleFinish = async (values) => {
|
||||||
|
const { mod_lbr_ty } = values;
|
||||||
|
logImEXEvent("job_convert_dollar_to_labor");
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const existingAdjustments = await client.query({
|
||||||
|
query: QUERY_JOB_LBR_ADJUSTMENTS,
|
||||||
|
variables: {
|
||||||
|
id: job.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const newAdjustments = _.cloneDeep(
|
||||||
|
existingAdjustments.data.jobs_by_pk.lbr_adjustments
|
||||||
|
);
|
||||||
|
|
||||||
|
newAdjustments[mod_lbr_ty] =
|
||||||
|
(newAdjustments[mod_lbr_ty] || 0) +
|
||||||
|
calculateAdjustment({ mod_lbr_ty, job, jobline });
|
||||||
|
|
||||||
|
const jobUpdate = client.mutate({
|
||||||
|
mutation: UPDATE_JOB,
|
||||||
|
variables: {
|
||||||
|
jobId: job.id,
|
||||||
|
job: { lbr_adjustments: newAdjustments },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const lineUpdate = client.mutate({
|
||||||
|
mutation: UPDATE_JOB_LINE,
|
||||||
|
variables: {
|
||||||
|
lineId: jobline.id,
|
||||||
|
line: { convertedtolbr: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!!jobUpdate.errors) {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.saving", {
|
||||||
|
message: JSON.stringify(jobUpdate.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!!lineUpdate.errors) {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("joblines.errors.saving", {
|
||||||
|
message: JSON.stringify(lineUpdate.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: job.id,
|
||||||
|
operation: AuditTrailMapping.jobmodifylbradj({
|
||||||
|
hours: calculateAdjustment({ mod_lbr_ty, job, jobline }).toFixed(1),
|
||||||
|
mod_lbr_ty,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
setVisibility(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const overlay = (
|
||||||
|
<Card>
|
||||||
|
<Form form={form} layout="vertical" onFinish={handleFinish}>
|
||||||
|
<Form.Item
|
||||||
|
label={t("joblines.fields.mod_lbr_ty")}
|
||||||
|
name="mod_lbr_ty"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select allowClear optionFilterProp="children" showSearch>
|
||||||
|
<Select.Option value="LAA">
|
||||||
|
{t("joblines.fields.lbr_types.LAA")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAB">
|
||||||
|
{t("joblines.fields.lbr_types.LAB")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAD">
|
||||||
|
{t("joblines.fields.lbr_types.LAD")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAE">
|
||||||
|
{t("joblines.fields.lbr_types.LAE")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAF">
|
||||||
|
{t("joblines.fields.lbr_types.LAF")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAG">
|
||||||
|
{t("joblines.fields.lbr_types.LAG")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAM">
|
||||||
|
{t("joblines.fields.lbr_types.LAM")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAR">
|
||||||
|
{t("joblines.fields.lbr_types.LAR")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAS">
|
||||||
|
{t("joblines.fields.lbr_types.LAS")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LAU">
|
||||||
|
{t("joblines.fields.lbr_types.LAU")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LA1">
|
||||||
|
{t("joblines.fields.lbr_types.LA1")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LA2">
|
||||||
|
{t("joblines.fields.lbr_types.LA2")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LA3">
|
||||||
|
{t("joblines.fields.lbr_types.LA3")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option value="LA4">
|
||||||
|
{t("joblines.fields.lbr_types.LA4")}
|
||||||
|
</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
const { mod_lbr_ty } = form.getFieldsValue();
|
||||||
|
return t("joblines.labels.adjustmenttobeadded", {
|
||||||
|
adjustment: calculateAdjustment({
|
||||||
|
mod_lbr_ty,
|
||||||
|
job,
|
||||||
|
jobline,
|
||||||
|
}).toFixed(1),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Space wrap>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
disabled={jobline.convertedtolbr}
|
||||||
|
htmlType="submit"
|
||||||
|
>
|
||||||
|
{t("general.actions.save")}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => setVisibility(false)}>
|
||||||
|
{t("general.actions.cancel")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClick = (e) => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
form.setFieldsValue({
|
||||||
|
// date: new moment(),
|
||||||
|
// bodyhrs: Math.round(v.bodyhrs * 10) / 10,
|
||||||
|
// painthrs: Math.round(v.painthrs * 10) / 10,
|
||||||
|
});
|
||||||
|
setVisibility(true);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{children}
|
||||||
|
{jobline.act_price !== 0 && (
|
||||||
|
<Popover
|
||||||
|
disabled={jobline.convertedtolbr}
|
||||||
|
content={overlay}
|
||||||
|
visible={visibility}
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<Tooltip title={t("joblines.actions.converttolabor")}>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
disabled={jobline.convertedtolbr}
|
||||||
|
loading={loading}
|
||||||
|
onClick={handleClick}
|
||||||
|
{...otherBtnProps}
|
||||||
|
>
|
||||||
|
<ClockCircleOutlined />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateAdjustment({ mod_lbr_ty, job, jobline }) {
|
||||||
|
if (!mod_lbr_ty) return 0;
|
||||||
|
const rate = job[`rate_${mod_lbr_ty.toLowerCase()}`];
|
||||||
|
|
||||||
|
if (rate === 0 || rate === null || rate === undefined) return 0;
|
||||||
|
const adj = jobline.act_price / job[`rate_${mod_lbr_ty.toLowerCase()}`];
|
||||||
|
|
||||||
|
return adj;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Form, Select } from "antd";
|
import { Form, Select, Space, Tooltip } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -8,6 +8,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import LaborTypeFormItem from "../form-items-formatted/labor-type-form-item.component";
|
import LaborTypeFormItem from "../form-items-formatted/labor-type-form-item.component";
|
||||||
import PartTypeFormItem from "../form-items-formatted/part-type-form-item.component";
|
import PartTypeFormItem from "../form-items-formatted/part-type-form-item.component";
|
||||||
import ReadOnlyFormItem from "../form-items-formatted/read-only-form-item.component";
|
import ReadOnlyFormItem from "../form-items-formatted/read-only-form-item.component";
|
||||||
|
import { WarningOutlined } from "@ant-design/icons";
|
||||||
import "./jobs-close-lines.styles.scss";
|
import "./jobs-close-lines.styles.scss";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -62,14 +63,23 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Form.Item
|
<Space>
|
||||||
span={2}
|
<Form.Item
|
||||||
// label={t("joblines.fields.act_price")}
|
span={2}
|
||||||
key={`${index}act_price`}
|
// label={t("joblines.fields.act_price")}
|
||||||
name={[field.name, "act_price"]}
|
key={`${index}act_price`}
|
||||||
>
|
name={[field.name, "act_price"]}
|
||||||
<ReadOnlyFormItem type="currency" />
|
>
|
||||||
</Form.Item>
|
<ReadOnlyFormItem type="currency" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
key={`${index}convertedtolbr`}
|
||||||
|
name={[field.name, "convertedtolbr"]}
|
||||||
|
>
|
||||||
|
<HasBeenConvertedTolabor />
|
||||||
|
</Form.Item>
|
||||||
|
</Space>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -192,3 +202,14 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseLines);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseLines);
|
||||||
|
|
||||||
|
const HasBeenConvertedTolabor = ({ value }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
console.log(value);
|
||||||
|
if (!value) return null;
|
||||||
|
return (
|
||||||
|
<Tooltip title={t("joblines.labels.convertedtolabor")}>
|
||||||
|
<WarningOutlined style={{ color: "tomato" }} />
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -12,7 +12,24 @@ import React, { useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
|
|
||||||
export default function LaborAllocationsAdjustmentEdit({
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
//currentUser: selectCurrentUser
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(LaborAllocationsAdjustmentEdit);
|
||||||
|
|
||||||
|
export function LaborAllocationsAdjustmentEdit({
|
||||||
|
insertAuditTrail,
|
||||||
jobId,
|
jobId,
|
||||||
mod_lbr_ty,
|
mod_lbr_ty,
|
||||||
adjustments,
|
adjustments,
|
||||||
@@ -51,6 +68,15 @@ export default function LaborAllocationsAdjustmentEdit({
|
|||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.save"),
|
message: t("jobs.successes.save"),
|
||||||
});
|
});
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: jobId,
|
||||||
|
operation: AuditTrailMapping.jobmodifylbradj({
|
||||||
|
mod_lbr_ty: values.mod_lbr_ty,
|
||||||
|
hours:
|
||||||
|
values.hours -
|
||||||
|
((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1),
|
||||||
|
}),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|||||||
@@ -124,6 +124,15 @@ export function PartsOrderModalComponent({
|
|||||||
<Checkbox />
|
<Checkbox />
|
||||||
</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>
|
||||||
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<Divider orientation="left">
|
<Divider orientation="left">
|
||||||
{t("parts_orders.labels.inthisorder")}
|
{t("parts_orders.labels.inthisorder")}
|
||||||
@@ -291,17 +300,32 @@ export function PartsOrderModalComponent({
|
|||||||
<Input.TextArea rows={3} />
|
<Input.TextArea rows={3} />
|
||||||
</Form.Item>
|
</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,53 @@ 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: [
|
insertResult = 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;
|
||||||
|
}
|
||||||
|
notification["success"]({
|
||||||
|
message: values.isReturn
|
||||||
|
? t("parts_orders.successes.return_created")
|
||||||
|
: t("parts_orders.successes.created"),
|
||||||
|
});
|
||||||
|
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 +149,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 +166,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"),
|
||||||
@@ -160,12 +173,6 @@ export function PartsOrderModalContainer({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
notification["success"]({
|
|
||||||
message: values.isReturn
|
|
||||||
? t("parts_orders.successes.return_created")
|
|
||||||
: t("parts_orders.successes.created"),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (values.vendorid === bodyshop.inhousevendorid) {
|
if (values.vendorid === bodyshop.inhousevendorid) {
|
||||||
setBillEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { PauseCircleOutlined } from "@ant-design/icons";
|
|||||||
import { Space } from "antd";
|
import { Space } from "antd";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React from "react";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { TimeFormatter } from "../../utils/DateFormatter";
|
import { TimeFormatter } from "../../utils/DateFormatter";
|
||||||
@@ -530,6 +529,27 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
<JobPartsQueueCount parts={record.joblines_status} record={record} />
|
<JobPartsQueueCount parts={record.joblines_status} record={record} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
//Added as a place holder for St Claude. Not implemented as it requires another join for a field used by only 1 client.
|
||||||
|
// {
|
||||||
|
// title: i18n.t("vehicles.fields.v_paint_codes", { number: "" }),
|
||||||
|
// dataIndex: "v_paint_codes",
|
||||||
|
// key: "v_paint_codes",
|
||||||
|
// render: (text, record) =>
|
||||||
|
// record.vehicle?.v_paint_codes ? (
|
||||||
|
// <span style={{ whiteSpace: "pre" }}>
|
||||||
|
// {Object.keys(record.vehicle.v_paint_codes)
|
||||||
|
// .filter(
|
||||||
|
// (key) =>
|
||||||
|
// record.vehicle.v_paint_codes[key] !== "" &&
|
||||||
|
// record.vehicle.v_paint_codes[key] !== null &&
|
||||||
|
// record.vehicle.v_paint_codes[key] !== undefined
|
||||||
|
// )
|
||||||
|
// .map((key, idx) => (
|
||||||
|
// <Tag key={idx}>{record.vehicle.v_paint_codes[key]}</Tag>
|
||||||
|
// ))}
|
||||||
|
// </span>
|
||||||
|
// ) : null,
|
||||||
|
// },
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
export default r;
|
export default r;
|
||||||
|
|||||||
@@ -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 } }
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ export const UPDATE_JOB_LINE = gql`
|
|||||||
location
|
location
|
||||||
status
|
status
|
||||||
removed
|
removed
|
||||||
|
convertedtolbr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -702,6 +702,7 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
prt_dsmk_p
|
prt_dsmk_p
|
||||||
prt_dsmk_m
|
prt_dsmk_m
|
||||||
ioucreated
|
ioucreated
|
||||||
|
convertedtolbr
|
||||||
billlines(limit: 1, order_by: { bill: { date: desc } }) {
|
billlines(limit: 1, order_by: { bill: { date: desc } }) {
|
||||||
id
|
id
|
||||||
quantity
|
quantity
|
||||||
@@ -1905,6 +1906,7 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
|||||||
profitcenter_labor
|
profitcenter_labor
|
||||||
profitcenter_part
|
profitcenter_part
|
||||||
prt_dsmk_p
|
prt_dsmk_p
|
||||||
|
convertedtolbr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
"jobimported": "Job imported.",
|
"jobimported": "Job imported.",
|
||||||
"jobinproductionchange": "Job production status set to {{inproduction}}",
|
"jobinproductionchange": "Job production status set to {{inproduction}}",
|
||||||
"jobioucreated": "IOU Created.",
|
"jobioucreated": "IOU Created.",
|
||||||
"jobmodifylbradj": "Labor adjustments modified.",
|
"jobmodifylbradj": "Labor adjustments modified {{mod_lbr_ty}} / {{hours}}.",
|
||||||
"jobnoteadded": "Note added to job.",
|
"jobnoteadded": "Note added to job.",
|
||||||
"jobnotedeleted": "Note deleted from job.",
|
"jobnotedeleted": "Note deleted from job.",
|
||||||
"jobnoteupdated": "Note updated on job.",
|
"jobnoteupdated": "Note updated on job.",
|
||||||
@@ -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",
|
||||||
@@ -1110,6 +1114,7 @@
|
|||||||
},
|
},
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"converttolabor": "Convert amount to Labor.",
|
||||||
"new": "New Line"
|
"new": "New Line"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1175,7 +1180,9 @@
|
|||||||
"unq_seq": "Seq #"
|
"unq_seq": "Seq #"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"adjustmenttobeadded": "Adjustment to be added: {{adjustment}}",
|
||||||
"billref": "Latest Bill",
|
"billref": "Latest Bill",
|
||||||
|
"convertedtolabor": "This line has been converted to labor. Ensure you adjust the profit center for the amount accordingly.",
|
||||||
"edit": "Edit Line",
|
"edit": "Edit Line",
|
||||||
"ioucreated": "IOU",
|
"ioucreated": "IOU",
|
||||||
"new": "New Line",
|
"new": "New Line",
|
||||||
@@ -2013,6 +2020,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": "",
|
||||||
@@ -1110,6 +1114,7 @@
|
|||||||
},
|
},
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"converttolabor": "",
|
||||||
"new": ""
|
"new": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1175,7 +1180,9 @@
|
|||||||
"unq_seq": "Seq #"
|
"unq_seq": "Seq #"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"adjustmenttobeadded": "",
|
||||||
"billref": "",
|
"billref": "",
|
||||||
|
"convertedtolabor": "",
|
||||||
"edit": "Línea de edición",
|
"edit": "Línea de edición",
|
||||||
"ioucreated": "",
|
"ioucreated": "",
|
||||||
"new": "Nueva línea",
|
"new": "Nueva línea",
|
||||||
@@ -2013,6 +2020,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": "",
|
||||||
@@ -1110,6 +1114,7 @@
|
|||||||
},
|
},
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"converttolabor": "",
|
||||||
"new": ""
|
"new": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1175,7 +1180,9 @@
|
|||||||
"unq_seq": "Seq #"
|
"unq_seq": "Seq #"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"adjustmenttobeadded": "",
|
||||||
"billref": "",
|
"billref": "",
|
||||||
|
"convertedtolabor": "",
|
||||||
"edit": "Ligne d'édition",
|
"edit": "Ligne d'édition",
|
||||||
"ioucreated": "",
|
"ioucreated": "",
|
||||||
"new": "Nouvelle ligne",
|
"new": "Nouvelle ligne",
|
||||||
@@ -2013,6 +2020,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": "",
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ const AuditTrailMapping = {
|
|||||||
i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
|
i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
|
||||||
jobspartsreturn: (order_number) =>
|
jobspartsreturn: (order_number) =>
|
||||||
i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
|
i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
|
||||||
jobmodifylbradj: () => i18n.t("audit_trail.messages.jobmodifylbradj", {}),
|
jobmodifylbradj: ({ mod_lbr_ty, hours }) =>
|
||||||
|
i18n.t("audit_trail.messages.jobmodifylbradj", { mod_lbr_ty, hours }),
|
||||||
billposted: (invoice_number) =>
|
billposted: (invoice_number) =>
|
||||||
i18n.t("audit_trail.messages.billposted", { invoice_number }),
|
i18n.t("audit_trail.messages.billposted", { invoice_number }),
|
||||||
billupdated: (invoice_number) =>
|
billupdated: (invoice_number) =>
|
||||||
|
|||||||
@@ -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,16 +110,17 @@ export default async function RenderTemplate(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const pdfRender = await jsreport.renderAsync(pdfRequest);
|
const pdfRender = await jsreport.render(pdfRequest);
|
||||||
pdf = pdfRender.toDataURI();
|
pdf = await pdfRender.toDataURI();
|
||||||
}
|
}
|
||||||
|
const html = await render.toString();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
resolve({
|
resolve({
|
||||||
pdf,
|
pdf,
|
||||||
filename:
|
filename:
|
||||||
Templates[templateObject.name] &&
|
Templates[templateObject.name] &&
|
||||||
Templates[templateObject.name].title,
|
Templates[templateObject.name].title,
|
||||||
html: render.toString(),
|
html,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -152,6 +159,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,13 +252,11 @@ 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 {
|
||||||
return new Promise((resolve, reject) => {
|
return render.toString();
|
||||||
resolve(render.toString());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notification["error"]({ message: JSON.stringify(error) });
|
notification["error"]({ message: JSON.stringify(error) });
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ export default async function FcmHandler({ client, payload }) {
|
|||||||
updated_at(oldupdated0) {
|
updated_at(oldupdated0) {
|
||||||
return new Date();
|
return new Date();
|
||||||
},
|
},
|
||||||
messages_aggregate(cached) {
|
// messages_aggregate(cached) {
|
||||||
return { aggregate: { count: cached.aggregate.count + 1 } };
|
// return { aggregate: { count: cached.aggregate.count + 1 } };
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|||||||
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"
|
||||||
|
|||||||
@@ -2384,6 +2384,7 @@
|
|||||||
- bett_tax
|
- bett_tax
|
||||||
- bett_type
|
- bett_type
|
||||||
- cert_part
|
- cert_part
|
||||||
|
- convertedtolbr
|
||||||
- created_at
|
- created_at
|
||||||
- db_hrs
|
- db_hrs
|
||||||
- db_price
|
- db_price
|
||||||
@@ -2447,6 +2448,7 @@
|
|||||||
- bett_tax
|
- bett_tax
|
||||||
- bett_type
|
- bett_type
|
||||||
- cert_part
|
- cert_part
|
||||||
|
- convertedtolbr
|
||||||
- created_at
|
- created_at
|
||||||
- db_hrs
|
- db_hrs
|
||||||
- db_price
|
- db_price
|
||||||
@@ -2521,6 +2523,7 @@
|
|||||||
- bett_tax
|
- bett_tax
|
||||||
- bett_type
|
- bett_type
|
||||||
- cert_part
|
- cert_part
|
||||||
|
- convertedtolbr
|
||||||
- created_at
|
- created_at
|
||||||
- db_hrs
|
- db_hrs
|
||||||
- db_price
|
- db_price
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."joblines" add column "convertedtolbr" boolean
|
||||||
|
-- not null default 'false';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."joblines" add column "convertedtolbr" boolean
|
||||||
|
not null default 'false';
|
||||||
@@ -257,12 +257,14 @@ exports.validateFirebaseIdToken = async (req, res, next) => {
|
|||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("api-unauthorized-call", "WARN", null, null, {
|
logger.log("api-unauthorized-call", "WARN", null, null, {
|
||||||
req,
|
path: req.path,
|
||||||
|
body: req.body,
|
||||||
|
|
||||||
type: "unauthroized",
|
type: "unauthroized",
|
||||||
error,
|
...error,
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(403).send("Unauthorized");
|
res.status(401).send("Unauthorized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ exports.mixdataUpload = async (req, res) => {
|
|||||||
explicitArray: false,
|
explicitArray: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
logger.log("job-mixdata-parse", "DEBUG", req.user.email, inboundRequest);
|
||||||
|
|
||||||
const ScaleType = DetermineScaleType(inboundRequest);
|
const ScaleType = DetermineScaleType(inboundRequest);
|
||||||
const RoNumbersFromInboundRequest = GetListOfRos(
|
const RoNumbersFromInboundRequest = GetListOfRos(
|
||||||
inboundRequest,
|
inboundRequest,
|
||||||
@@ -76,6 +78,7 @@ exports.mixdataUpload = async (req, res) => {
|
|||||||
res.status(500).JSON(error);
|
res.status(500).JSON(error);
|
||||||
logger.log("job-mixdata-upload-error", "ERROR", null, null, {
|
logger.log("job-mixdata-upload-error", "ERROR", null, null, {
|
||||||
error: error.message,
|
error: error.message,
|
||||||
|
...error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user