Merge branch 'master-AIO' into feature/IO-2458-RO-Closer
This commit is contained in:
@@ -12,6 +12,12 @@ import App from "./App";
|
||||
import * as Sentry from "@sentry/react";
|
||||
|
||||
import themeProvider from "./themeProvider";
|
||||
import { Userpilot } from 'userpilot'
|
||||
|
||||
// Initialize Userpilot
|
||||
if(import.meta.env.DEV){
|
||||
Userpilot.initialize('NX-69145f08');
|
||||
}
|
||||
|
||||
dayjs.locale("en");
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import "./App.styles.scss";
|
||||
import handleBeta from "../utils/betaHandler";
|
||||
import Eula from "../components/eula/eula.component";
|
||||
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
||||
import { ProductFruits } from 'react-product-fruits';
|
||||
|
||||
const ResetPassword = lazy(() =>
|
||||
import("../pages/reset-password/reset-password.component")
|
||||
);
|
||||
@@ -149,6 +151,7 @@ export function App({
|
||||
|
||||
// Any route that is not assigned and matched will default to the Landing Page component
|
||||
return (
|
||||
|
||||
<Suspense
|
||||
fallback={
|
||||
<LoadingSpinner
|
||||
@@ -159,7 +162,13 @@ export function App({
|
||||
})}
|
||||
/>
|
||||
}
|
||||
>
|
||||
>
|
||||
<ProductFruits //workspaceCode="aoJoEifvezYI0Z0P"
|
||||
language="en" user={{
|
||||
email: currentUser.email,
|
||||
username: currentUser.email,
|
||||
}} />
|
||||
|
||||
<Routes>
|
||||
<Route
|
||||
path="*"
|
||||
|
||||
BIN
client/src/assets/promanager/ProManagerLogo.gif
Normal file
BIN
client/src/assets/promanager/ProManagerLogo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -1,5 +1,5 @@
|
||||
import {useMutation, useQuery} from "@apollo/client";
|
||||
import {Button, Form, Popconfirm, Space} from "antd";
|
||||
import {Button, Divider, Form, Popconfirm, Space} from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import queryString from "query-string";
|
||||
import React, {useState} from "react";
|
||||
@@ -203,7 +203,7 @@ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail,
|
||||
layout="vertical"
|
||||
>
|
||||
<BillFormContainer form={form} billEdit disabled={exported}/>
|
||||
|
||||
<Divider orientation="left">{t("general.labels.media")}</Divider>
|
||||
{bodyshop.uselocalmediaserver ? (
|
||||
<JobsDocumentsLocalGallery
|
||||
job={{id: data ? data.bills_by_pk.jobid : null}}
|
||||
|
||||
@@ -173,7 +173,11 @@ export function BillDetailEditReturn({
|
||||
</Form>
|
||||
</Modal>
|
||||
<Button
|
||||
disabled={data.bills_by_pk.is_credit_memo || disabled}
|
||||
disabled={
|
||||
data.bills_by_pk.is_credit_memo ||
|
||||
data.bills_by_pk.isinhouse ||
|
||||
disabled
|
||||
}
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
|
||||
@@ -172,6 +172,7 @@ function BillEnterModalContainer({
|
||||
],
|
||||
},
|
||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
@@ -239,6 +240,7 @@ function BillEnterModalContainer({
|
||||
if (markPolReceived && markPolReceived.length > 0) {
|
||||
const r2 = await updatePartsOrderLines({
|
||||
variables: {partsLineIds: markPolReceived.map((p) => p.id)},
|
||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID" ],
|
||||
});
|
||||
if (!!r2.errors) {
|
||||
setLoading(false);
|
||||
@@ -373,12 +375,13 @@ function BillEnterModalContainer({
|
||||
});
|
||||
|
||||
if (enterAgain) {
|
||||
// form.resetFields();
|
||||
form.setFieldsValue({
|
||||
...formValues,
|
||||
billlines: [],
|
||||
});
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
form.setFieldsValue({
|
||||
...formValues,
|
||||
vendorid:values.vendorid,
|
||||
billlines: [],
|
||||
});
|
||||
// form.resetFields();
|
||||
} else {
|
||||
toggleModalVisible();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -689,14 +689,14 @@ export function BillEnterModalLinesComponent({
|
||||
|
||||
formItemProps: (field) => {
|
||||
return {
|
||||
key: `${field.index}fedtax`,
|
||||
valuePropName: "checked",
|
||||
// initialValue: true,
|
||||
name: [
|
||||
field.name,
|
||||
"applicable_taxes",
|
||||
"federal",
|
||||
],
|
||||
key: `${field.index}fedtax`,
|
||||
valuePropName: 'checked',
|
||||
initialValue: InstanceRenderManager({
|
||||
imex: true,
|
||||
rome: false,
|
||||
promanager: false,
|
||||
}),
|
||||
name: [field.name, 'applicable_taxes', 'federal'],
|
||||
};
|
||||
},
|
||||
formInput: (record, index) => (
|
||||
|
||||
@@ -12,6 +12,7 @@ import "./chat-affix.styles.scss";
|
||||
export function ChatAffixContainer({bodyshop, chatVisible}) {
|
||||
const {t} = useTranslation();
|
||||
const client = useApolloClient();
|
||||
|
||||
useEffect(() => {
|
||||
if (!bodyshop || !bodyshop.messagingservicesid) return;
|
||||
|
||||
@@ -31,6 +32,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
|
||||
error
|
||||
);
|
||||
notification.open({
|
||||
key: 'fcm',
|
||||
type: "warning",
|
||||
message: t("general.errors.fcm"),
|
||||
btn: (
|
||||
@@ -62,7 +64,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
|
||||
|
||||
SubscribeToTopic();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [bodyshop]);
|
||||
|
||||
useEffect(() => {
|
||||
function handleMessage(payload) {
|
||||
|
||||
@@ -61,6 +61,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
value: "courtesycars.status.in",
|
||||
},
|
||||
{
|
||||
text: t("courtesycars.status.inservice"),
|
||||
value: "courtesycars.status.inservice",
|
||||
},
|
||||
{
|
||||
text: t("courtesycars.status.out"),
|
||||
value: "courtesycars.status.out",
|
||||
},
|
||||
@@ -73,7 +77,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
value: "courtesycars.status.leasereturn",
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => value.includes(record.status),
|
||||
onFilter: (value, record) => record.status === value,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
@@ -176,7 +180,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
title: t("courtesycars.fields.fuel"),
|
||||
dataIndex: "fuel",
|
||||
key: "fuel",
|
||||
sorter: (a, b) => alphaSort(a.fuel, b.fuel),
|
||||
sorter: (a, b) => a.fuel - b.fuel,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
@@ -185,12 +189,14 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
return t("courtesycars.labels.fuel.full");
|
||||
case 88:
|
||||
return t("courtesycars.labels.fuel.78");
|
||||
case 63:
|
||||
case 75:
|
||||
return t("courtesycars.labels.fuel.34");
|
||||
case 63:
|
||||
return t("courtesycars.labels.fuel.58");
|
||||
case 50:
|
||||
return t("courtesycars.labels.fuel.12");
|
||||
case 38:
|
||||
return t("courtesycars.labels.fuel.34");
|
||||
return t("courtesycars.labels.fuel.38");
|
||||
case 25:
|
||||
return t("courtesycars.labels.fuel.14");
|
||||
case 13:
|
||||
|
||||
@@ -9,6 +9,7 @@ import axios from "axios";
|
||||
const fortyFiveDaysAgo = () => dayjs().subtract(45, 'day').toLocaleString();
|
||||
|
||||
export default function JobLifecycleDashboardComponent({data, bodyshop, ...cardProps}) {
|
||||
console.log("🚀 ~ JobLifecycleDashboardComponent ~ bodyshop:", bodyshop)
|
||||
const {t} = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [lifecycleData, setLifecycleData] = useState(null);
|
||||
@@ -19,7 +20,7 @@ export default function JobLifecycleDashboardComponent({data, bodyshop, ...cardP
|
||||
setLoading(true);
|
||||
const response = await axios.post("/job/lifecycle", {
|
||||
jobids: data.job_lifecycle.map(x => x.id),
|
||||
statuses: bodyshop.md_order_statuses
|
||||
statuses: bodyshop.md_ro_statuses
|
||||
});
|
||||
setLifecycleData(response.data.durations);
|
||||
setLoading(false);
|
||||
@@ -166,4 +167,4 @@ job_lifecycle: jobs(where: {
|
||||
}) {
|
||||
id
|
||||
actual_in
|
||||
} `;
|
||||
} `;
|
||||
|
||||
@@ -184,7 +184,7 @@ export function DashboardGridComponent({currentUser, bodyshop}) {
|
||||
}}
|
||||
onClick={() => handleRemoveComponent(item.i)}
|
||||
/>
|
||||
<TheComponent className="dashboard-card" data={dashboarddata}/>
|
||||
<TheComponent className="dashboard-card" bodyshop={bodyshop} data={dashboarddata}/>
|
||||
</LoadingSkeleton>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import dayjs from "../../utils/day";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import dayjs from '../../utils/day';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||
import AlertComponent from '../alert/alert.component';
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
function FeatureWrapper({
|
||||
bodyshop,
|
||||
featureName,
|
||||
noauth,
|
||||
children,
|
||||
...restProps
|
||||
}) {
|
||||
function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (HasFeatureAccess({ featureName, bodyshop })) return children;
|
||||
@@ -25,7 +19,13 @@ function FeatureWrapper({
|
||||
return (
|
||||
noauth || (
|
||||
<AlertComponent
|
||||
message={t("general.messages.nofeatureaccess", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}
|
||||
message={t('general.messages.nofeatureaccess', {
|
||||
app: InstanceRenderManager({
|
||||
imex: '$t(titles.imexonline)',
|
||||
rome: '$t(titles.romeonline)',
|
||||
promanager: '$t(titles.promanager)',
|
||||
}),
|
||||
})}
|
||||
type="warning"
|
||||
/>
|
||||
)
|
||||
@@ -33,10 +33,7 @@ function FeatureWrapper({
|
||||
}
|
||||
|
||||
export function HasFeatureAccess({ featureName, bodyshop }) {
|
||||
return (
|
||||
bodyshop?.features.allAccess ||
|
||||
dayjs(bodyshop?.features[featureName]).isAfter(dayjs())
|
||||
);
|
||||
return bodyshop?.features.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(FeatureWrapper);
|
||||
|
||||
@@ -5,6 +5,7 @@ import {useTranslation} from "react-i18next";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import "./job-bills-total.styles.scss";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
export default function JobBillsTotalComponent({
|
||||
loading,
|
||||
@@ -89,7 +90,7 @@ export default function JobBillsTotalComponent({
|
||||
.add(Dinero(totals.parts.sublets.total))
|
||||
.add(Dinero(totals.additional.shipping))
|
||||
.add(Dinero(totals.additional.towing))
|
||||
.add(Dinero(totals.additional.additionalCosts)); //TODO:AIO Additional costs were captured for Rome, but not imex. This may need to be evaluated?
|
||||
.add( InstanceRenderManager({imex: Dinero(), rome: Dinero(totals.additional.additionalCosts),promanager: "USE_ROME" })) ; // Additional costs were captured for Rome, but not imex.
|
||||
|
||||
const discrepancy = totalPartsSublet.subtract(billTotals);
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ export function JobLinesComponent({
|
||||
key: 'location',
|
||||
render: (text, record) => <JobLineLocationPopup jobline={record} disabled={jobRO} />,
|
||||
},
|
||||
...(HasFeatureAccess({ featureName: 'bills' })
|
||||
...(HasFeatureAccess({ featureName: 'bills', bodyshop })
|
||||
? [
|
||||
{
|
||||
title: t('joblines.labels.billref'),
|
||||
|
||||
@@ -23,7 +23,6 @@ export function JobEmployeeAssignments({
|
||||
jobRO,
|
||||
body,
|
||||
refinish,
|
||||
|
||||
prep,
|
||||
csr,
|
||||
handleAdd,
|
||||
@@ -78,7 +77,7 @@ export function JobEmployeeAssignments({
|
||||
setVisibility(false);
|
||||
}}
|
||||
>
|
||||
Assign
|
||||
{t("allocations.actions.assign")}
|
||||
</Button>
|
||||
<Button onClick={() => setVisibility(false)}>Close</Button>
|
||||
</Space>
|
||||
|
||||
@@ -44,13 +44,13 @@ export function JobEmployeeAssignmentsContainer({
|
||||
});
|
||||
if (refetch) refetch();
|
||||
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobassignmentchange(operation, name),
|
||||
type: "jobassignmentchange",
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
if (!!!result.errors) {
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobassignmentchange(operation, name),
|
||||
type: "jobassignmentchange",
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.assigning", {
|
||||
message: JSON.stringify(result.errors),
|
||||
@@ -68,19 +68,21 @@ export function JobEmployeeAssignmentsContainer({
|
||||
variables: {jobId: job.id, job: {[empAssignment]: null}},
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.assigning", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobassignmentremoved(operation),
|
||||
type: "jobassignmentremoved",});
|
||||
setLoading(false);
|
||||
};
|
||||
if (!!!result.errors) {
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobassignmentremoved(operation),
|
||||
type: "jobassignmentremoved",
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.assigning", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function JobReconciliationBillsTable({
|
||||
state.sortedInfo.order,
|
||||
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.bill.is_credit_memo}/>
|
||||
<Checkbox checked={record.bill.is_credit_memo}/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -6,6 +6,7 @@ import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -29,108 +30,130 @@ export function JobTotalsTableTotals({bodyshop, job}) {
|
||||
total: job.job_totals.totals.subtotal,
|
||||
bold: true,
|
||||
},
|
||||
|
||||
...(job.job_totals.totals.us_sales_tax_breakdown
|
||||
? [
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
|
||||
"T1"
|
||||
} - ${[
|
||||
job.cieca_pft.ty1_rate1,
|
||||
job.cieca_pft.ty1_rate2,
|
||||
job.cieca_pft.ty1_rate3,
|
||||
job.cieca_pft.ty1_rate4,
|
||||
job.cieca_pft.ty1_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
|
||||
"T2"
|
||||
} - ${[
|
||||
job.cieca_pft.ty2_rate1,
|
||||
job.cieca_pft.ty2_rate2,
|
||||
job.cieca_pft.ty2_rate3,
|
||||
job.cieca_pft.ty2_rate4,
|
||||
job.cieca_pft.ty2_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
|
||||
"T3"
|
||||
} - ${[
|
||||
job.cieca_pft.ty3_rate1,
|
||||
job.cieca_pft.ty3_rate2,
|
||||
job.cieca_pft.ty3_rate3,
|
||||
job.cieca_pft.ty3_rate4,
|
||||
job.cieca_pft.ty3_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
|
||||
"T4"
|
||||
} - ${[
|
||||
job.cieca_pft.ty4_rate1,
|
||||
job.cieca_pft.ty4_rate2,
|
||||
job.cieca_pft.ty4_rate3,
|
||||
job.cieca_pft.ty4_rate4,
|
||||
job.cieca_pft.ty4_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
|
||||
"TT"
|
||||
} - ${[
|
||||
job.cieca_pft.ty5_rate1,
|
||||
job.cieca_pft.ty5_rate2,
|
||||
job.cieca_pft.ty5_rate3,
|
||||
job.cieca_pft.ty5_rate4,
|
||||
job.cieca_pft.ty5_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
|
||||
},
|
||||
{
|
||||
key: t("jobs.labels.total_sales_tax"),
|
||||
bold: true,
|
||||
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
|
||||
).toJSON(),
|
||||
},
|
||||
].filter((item) => item.total.amount !== 0)
|
||||
: [
|
||||
{
|
||||
key: t("jobs.labels.state_tax_amt"),
|
||||
total: job.job_totals.totals.state_tax,
|
||||
},
|
||||
]),
|
||||
...InstanceRenderManager({imex: [ {
|
||||
key: t("jobs.labels.local_tax_amt"),
|
||||
total: job.job_totals.totals.local_tax,
|
||||
},
|
||||
{
|
||||
key: t("jobs.labels.state_tax_amt"),
|
||||
total: job.job_totals.totals.state_tax,
|
||||
},
|
||||
...(bodyshop.region_config === "CA_BC"
|
||||
? [
|
||||
{
|
||||
key: t("jobs.fields.ca_bc_pvrt"),
|
||||
total: job.job_totals.additional.pvrt,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: t("jobs.labels.federal_tax_amt"),
|
||||
total: job.job_totals.totals.federal_tax,
|
||||
},],
|
||||
promanager: "USE_ROME",
|
||||
rome: [(job.job_totals.totals.us_sales_tax_breakdown
|
||||
? [
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
|
||||
"T1"
|
||||
} - ${[
|
||||
job.cieca_pft.ty1_rate1,
|
||||
job.cieca_pft.ty1_rate2,
|
||||
job.cieca_pft.ty1_rate3,
|
||||
job.cieca_pft.ty1_rate4,
|
||||
job.cieca_pft.ty1_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
|
||||
"T2"
|
||||
} - ${[
|
||||
job.cieca_pft.ty2_rate1,
|
||||
job.cieca_pft.ty2_rate2,
|
||||
job.cieca_pft.ty2_rate3,
|
||||
job.cieca_pft.ty2_rate4,
|
||||
job.cieca_pft.ty2_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
|
||||
"T3"
|
||||
} - ${[
|
||||
job.cieca_pft.ty3_rate1,
|
||||
job.cieca_pft.ty3_rate2,
|
||||
job.cieca_pft.ty3_rate3,
|
||||
job.cieca_pft.ty3_rate4,
|
||||
job.cieca_pft.ty3_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
|
||||
"T4"
|
||||
} - ${[
|
||||
job.cieca_pft.ty4_rate1,
|
||||
job.cieca_pft.ty4_rate2,
|
||||
job.cieca_pft.ty4_rate3,
|
||||
job.cieca_pft.ty4_rate4,
|
||||
job.cieca_pft.ty4_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
|
||||
},
|
||||
{
|
||||
key: `${
|
||||
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
|
||||
"TT"
|
||||
} - ${[
|
||||
job.cieca_pft.ty5_rate1,
|
||||
job.cieca_pft.ty5_rate2,
|
||||
job.cieca_pft.ty5_rate3,
|
||||
job.cieca_pft.ty5_rate4,
|
||||
job.cieca_pft.ty5_rate5,
|
||||
]
|
||||
.filter((i) => i > 0)
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
|
||||
},
|
||||
{
|
||||
key: t("jobs.labels.total_sales_tax"),
|
||||
bold: true,
|
||||
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
|
||||
)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
|
||||
).toJSON(),
|
||||
},
|
||||
].filter((item) => item.total.amount !== 0)
|
||||
: [
|
||||
{
|
||||
key: t("jobs.labels.state_tax_amt"),
|
||||
total: job.job_totals.totals.state_tax,
|
||||
},
|
||||
])]
|
||||
}),
|
||||
|
||||
|
||||
{
|
||||
key: t("jobs.labels.total_repairs"),
|
||||
|
||||
@@ -6,6 +6,7 @@ import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -29,19 +30,25 @@ export function JobsCloseAutoAllocate({bodyshop, joblines, form, disabled}) {
|
||||
ret.profitcenter_labor = null;
|
||||
}
|
||||
//Verify that this is also manually updated in server/job-costing
|
||||
if (!jl.part_type && !jl.mod_lbr_ty) {
|
||||
const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : "";
|
||||
if (lineDesc.includes("shop materials")) {
|
||||
ret.profitcenter_part = defaults.profits["MASH"];
|
||||
} else if (lineDesc.includes("paint/materials")) {
|
||||
ret.profitcenter_part = defaults.profits["MAPA"];
|
||||
} else if (lineDesc.includes("ats amount")) {
|
||||
ret.profitcenter_part = defaults.profits["ATS"];
|
||||
} else if (jl.act_price > 0) {
|
||||
ret.profitcenter_part = defaults.profits["PAO"];
|
||||
} else {
|
||||
ret.profitcenter_part = null;
|
||||
}
|
||||
if (
|
||||
InstanceRenderManager({
|
||||
imex: !jl.part_type && !jl.mod_lbr_ty,
|
||||
rome: !ret.profitcenter_part,
|
||||
promanager: 'USE_ROME',
|
||||
})
|
||||
) {
|
||||
const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : '';
|
||||
if (lineDesc.includes('shop materials')) {
|
||||
ret.profitcenter_part = defaults.profits['MASH'];
|
||||
} else if (lineDesc.includes('paint/materials')) {
|
||||
ret.profitcenter_part = defaults.profits['MAPA'];
|
||||
} else if (lineDesc.includes('ats amount')) {
|
||||
ret.profitcenter_part = defaults.profits['ATS'];
|
||||
} else if (jl.act_price > 0) {
|
||||
ret.profitcenter_part = defaults.profits['PAO'];
|
||||
} else {
|
||||
ret.profitcenter_part = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}),
|
||||
|
||||
@@ -1,261 +1,225 @@
|
||||
import {Divider, Form, Input, InputNumber, Select, Space, Switch, Tooltip,} from "antd";
|
||||
import React from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {selectJobReadOnly} from "../../redux/application/application.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import CABCpvrtCalculator from "../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
import JobsDetailRatesLabor from "./jobs-detail-rates.labor.component";
|
||||
import JobsDetailRatesMaterials from "./jobs-detail-rates.materials.component";
|
||||
import JobsDetailRatesOther from "./jobs-detail-rates.other.component";
|
||||
import JobsDetailRatesParts from "./jobs-detail-rates.parts.component";
|
||||
import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component";
|
||||
import JobsDetailRatesProfileOVerride from "./jobs-detail-rates.profile-override.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { Divider, Form, Input, InputNumber, Select, Space, Switch, Tooltip } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import { selectJobReadOnly } from '../../redux/application/application.selectors';
|
||||
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||
import CABCpvrtCalculator from '../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component';
|
||||
import CurrencyInput from '../form-items-formatted/currency-form-item.component';
|
||||
import JobsDetailRatesChangeButton from '../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component';
|
||||
import JobsMarkPstExempt from '../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component';
|
||||
import FormRow from '../layout-form-row/layout-form-row.component';
|
||||
import JobsDetailRatesLabor from './jobs-detail-rates.labor.component';
|
||||
import JobsDetailRatesMaterials from './jobs-detail-rates.materials.component';
|
||||
import JobsDetailRatesOther from './jobs-detail-rates.other.component';
|
||||
import JobsDetailRatesParts from './jobs-detail-rates.parts.component';
|
||||
import JobsDetailRatesTaxes from './jobs-detail-rates.taxes.component';
|
||||
import JobsDetailRatesProfileOVerride from './jobs-detail-rates.profile-override.component';
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
export function JobsDetailRates({jobRO, form, job, bodyshop}) {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<FormRow>
|
||||
<Form.Item label={t("jobs.fields.class")} name="class">
|
||||
<Select disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.depreciation_taxes")}
|
||||
name="depreciation_taxes"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} min={0}/>
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_customer_gst")}
|
||||
name="ca_customer_gst"
|
||||
>
|
||||
<CurrencyInput
|
||||
disabled={jobRO}
|
||||
min={0}
|
||||
max={
|
||||
Math.round(
|
||||
(job.job_totals &&
|
||||
job.job_totals.totals.federal_tax.amount) ||
|
||||
0
|
||||
) / 100
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.other_amount_payable")}
|
||||
name="other_amount_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} min={0}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.towing_payable")}
|
||||
name="towing_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} min={0}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.storage_payable")}
|
||||
name="storage_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} min={0}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.adjustment_bottom_line")}
|
||||
name="adjustment_bottom_line"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid}/>
|
||||
</Form.Item>
|
||||
{bodyshop.region_config === "CA_BC" && (
|
||||
<Space align="center">
|
||||
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
|
||||
<CurrencyInput disabled={jobRO} min={0}/>
|
||||
</Form.Item>
|
||||
<CABCpvrtCalculator form={form} disabled={jobRO}/>
|
||||
</Space>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.auto_add_ats")}
|
||||
name="auto_add_ats"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}
|
||||
>
|
||||
{() => {
|
||||
if (form.getFieldValue("auto_add_ats"))
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_ats")}
|
||||
name="rate_ats"
|
||||
initialValue={bodyshop.shoprates.rate_atp}
|
||||
>
|
||||
<CurrencyInput disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
);
|
||||
|
||||
return null;
|
||||
}}
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
{
|
||||
InstanceRenderManager({imex:
|
||||
<FormRow>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.federal_tax_rate")}
|
||||
name="federal_tax_rate"
|
||||
>
|
||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO}/>
|
||||
export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<FormRow>
|
||||
<Form.Item label={t('jobs.fields.class')} name="class">
|
||||
<Select disabled={true} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.depreciation_taxes')} name="depreciation_taxes">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith('ca') && (
|
||||
<Tooltip title={t('jobs.labels.ca_gst_all_if_null')}>
|
||||
<Form.Item label={t('jobs.fields.ca_customer_gst')} name="ca_customer_gst">
|
||||
<CurrencyInput
|
||||
disabled={jobRO}
|
||||
min={0}
|
||||
max={
|
||||
Math.round((job.job_totals && job.job_totals.totals.federal_tax.amount) || 0) /
|
||||
100
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Form.Item label={t('jobs.fields.other_amount_payable')} name="other_amount_payable">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.towing_payable')} name="towing_payable">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.storage_payable')} name="storage_payable">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.adjustment_bottom_line')} name="adjustment_bottom_line">
|
||||
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config === 'CA_BC' && (
|
||||
<Space align="center">
|
||||
<Form.Item label={t('jobs.fields.ca_bc_pvrt')} name="ca_bc_pvrt">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.state_tax_rate")}
|
||||
name="state_tax_rate"
|
||||
label={t('jobs.fields.auto_add_ats')}
|
||||
name="auto_add_ats"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<InputNumber
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}>
|
||||
{() => {
|
||||
if (form.getFieldValue('auto_add_ats'))
|
||||
return (
|
||||
<Form.Item
|
||||
label={t('jobs.fields.rate_ats')}
|
||||
name="rate_ats"
|
||||
initialValue={bodyshop.shoprates.rate_atp}
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
</Form.Item>
|
||||
);
|
||||
|
||||
return null;
|
||||
}}
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
{InstanceRenderManager({
|
||||
imex: (
|
||||
<FormRow>
|
||||
<Form.Item label={t('jobs.fields.federal_tax_rate')} name="federal_tax_rate">
|
||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.state_tax_rate')} name="state_tax_rate">
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={1}
|
||||
precision={2}
|
||||
disabled={jobRO}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.local_tax_rate")}
|
||||
name="local_tax_rate"
|
||||
>
|
||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.local_tax_rate')} name="local_tax_rate">
|
||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith('ca') && (
|
||||
<Form.Item
|
||||
label={t('jobs.fields.ca_gst_registrant')}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</FormRow>})
|
||||
}
|
||||
<Divider
|
||||
orientation="left"
|
||||
type="horizontal"
|
||||
style={{marginTop: ".8rem", float: "right"}}
|
||||
>
|
||||
{t("jobs.forms.laborrates")}
|
||||
</Divider>
|
||||
<Space>
|
||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO}/>
|
||||
<JobsMarkPstExempt form={form}/>
|
||||
</Space>
|
||||
<FormRow noDivider>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.labor_rate_desc")}
|
||||
name="labor_rate_desc"
|
||||
>
|
||||
<Input disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_laa")} name="rate_laa">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lad")} name="rate_lad">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lae")} name="rate_lae">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lar")} name="rate_lar">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_las")} name="rate_las">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_laf")} name="rate_laf">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lam")} name="rate_lam">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lag")} name="rate_lag">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la1")} name="rate_la1">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la2")} name="rate_la2">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la3")} name="rate_la3">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la4")} name="rate_la4">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lau")} name="rate_lau">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mapa")} name="rate_mapa">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mash")} name="rate_mash">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mahw")} name="rate_mahw">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_ma2s")} name="rate_ma2s">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_ma3s")} name="rate_ma3s">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
{
|
||||
// <Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
// <Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
}
|
||||
<Form.Item label={t("jobs.fields.rate_matd")} name="rate_matd">
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
{
|
||||
InstanceRenderManager({rome: <>
|
||||
<Divider orientation="left">Tax Profile</Divider>
|
||||
<JobsDetailRatesProfileOVerride form={form}/>
|
||||
<JobsDetailRatesParts form={form}/>
|
||||
<JobsDetailRatesLabor form={form}/>
|
||||
<JobsDetailRatesMaterials form={form}/>
|
||||
<JobsDetailRatesOther form={form}/>
|
||||
<JobsDetailRatesTaxes form={form}/>
|
||||
|
||||
</>})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
>
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
</FormRow>
|
||||
),
|
||||
})}
|
||||
<Divider orientation="left" type="horizontal" style={{ marginTop: '.8rem', float: 'right' }}>
|
||||
{t('jobs.forms.laborrates')}
|
||||
</Divider>
|
||||
<Space>
|
||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO} />
|
||||
<JobsMarkPstExempt form={form} />
|
||||
</Space>
|
||||
<FormRow noDivider>
|
||||
<Form.Item label={t('jobs.fields.labor_rate_desc')} name="labor_rate_desc">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_laa')} name="rate_laa">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lab')} name="rate_lab">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lad')} name="rate_lad">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lae')} name="rate_lae">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lar')} name="rate_lar">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_las')} name="rate_las">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_laf')} name="rate_laf">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lam')} name="rate_lam">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lag')} name="rate_lag">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_la1')} name="rate_la1">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_la2')} name="rate_la2">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_la3')} name="rate_la3">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_la4')} name="rate_la4">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_lau')} name="rate_lau">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_mapa')} name="rate_mapa">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_mash')} name="rate_mash">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_mahw')} name="rate_mahw">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_ma2s')} name="rate_ma2s">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('jobs.fields.rate_ma3s')} name="rate_ma3s">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
{
|
||||
// <Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
// <Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
}
|
||||
<Form.Item label={t('jobs.fields.rate_matd')} name="rate_matd">
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
{InstanceRenderManager({
|
||||
imex: <JobsDetailRatesParts form={form} />,
|
||||
rome: (
|
||||
<>
|
||||
<Divider orientation="left">Tax Profile</Divider>
|
||||
<JobsDetailRatesProfileOVerride form={form} />
|
||||
<JobsDetailRatesParts form={form} />
|
||||
<JobsDetailRatesLabor form={form} />
|
||||
<JobsDetailRatesMaterials form={form} />
|
||||
<JobsDetailRatesOther form={form} />
|
||||
<JobsDetailRatesTaxes form={form} />
|
||||
</>
|
||||
),
|
||||
promanager: "USE_ROME"
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(JobsDetailRates);
|
||||
|
||||
@@ -34,19 +34,20 @@ export function PartDispatchTableComponent({
|
||||
// const selectedBill = search.billid;
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const Templates = TemplateList("job_special");
|
||||
const Templates = TemplateList("job_special", job);
|
||||
|
||||
const {refetch} = billsQuery;
|
||||
|
||||
const recordActions = (record) => (
|
||||
<Space wrap>
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: Templates.parts_dispatch.key,
|
||||
variables: {id: record.id},
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
<Space wrap>
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: Templates.parts_dispatch.key,
|
||||
variables: { id: record.id },
|
||||
}}
|
||||
messageObject={{ subject: Templates.parts_dispatch.subject }}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
const columns = [
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -31,7 +32,13 @@ export function ProductionColumnsComponent({
|
||||
}) {
|
||||
const [columns, setColumns] = columnState;
|
||||
const {t} = useTranslation();
|
||||
|
||||
const {
|
||||
treatments: { Enhanced_Payroll },
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ['Enhanced_Payroll'],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
});
|
||||
const handleAdd = (e) => {
|
||||
setColumns([
|
||||
...columns,
|
||||
@@ -41,6 +48,7 @@ export function ProductionColumnsComponent({
|
||||
state: tableState,
|
||||
data,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
treatments:{Enhanced_Payroll}
|
||||
}).filter((i) => i.key === e.key),
|
||||
]);
|
||||
};
|
||||
@@ -52,6 +60,7 @@ export function ProductionColumnsComponent({
|
||||
state: tableState,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
refetch,
|
||||
treatments:{Enhanced_Payroll}
|
||||
});
|
||||
|
||||
const menu = {
|
||||
|
||||
@@ -29,7 +29,8 @@ import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.co
|
||||
import {store} from "../../redux/store";
|
||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
|
||||
const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
||||
const r = ({technician, state, activeStatuses, data, bodyshop, refetch, treatments}) => {
|
||||
const {Enhanced_Payroll} = treatments;
|
||||
return [
|
||||
{
|
||||
title: i18n.t("jobs.actions.viewdetail"),
|
||||
@@ -42,7 +43,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
...Enhanced_Payroll.treatment === "on" ? [ {
|
||||
title: i18n.t("timetickets.actions.claimtasks"),
|
||||
dataIndex: "claimtasks",
|
||||
key: "claimtasks",
|
||||
@@ -64,7 +65,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
||||
{i18n.t("timetickets.actions.claimtasks")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
},] : [],
|
||||
{
|
||||
title: i18n.t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
@@ -326,7 +327,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
||||
onFilter: (value, record) =>
|
||||
value.includes(record.special_coverage_policy),
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.special_coverage_policy} />
|
||||
<Checkbox checked={record.special_coverage_policy} />
|
||||
),
|
||||
},
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {UPDATE_SHOP} from "../../graphql/bodyshop.queries";
|
||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||
import ProductionListColumns from "../production-list-columns/production-list-columns.data";
|
||||
import {useSplitTreatments} from '@splitsoftware/splitio-react';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -31,6 +32,12 @@ export function ProductionListTable({
|
||||
const [updateDefaultProdView] = useMutation(UPDATE_ACTIVE_PROD_LIST_VIEW);
|
||||
const [updateShop] = useMutation(UPDATE_SHOP);
|
||||
|
||||
const {treatments: {Enhanced_Payroll}} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Enhanced_Payroll"],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
});
|
||||
|
||||
const handleSelect = async (value, option) => {
|
||||
setColumns(
|
||||
bodyshop.production_config
|
||||
@@ -44,6 +51,7 @@ export function ProductionListTable({
|
||||
state,
|
||||
data: data,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
treatments:{Enhanced_Payroll}
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
};
|
||||
@@ -100,6 +108,7 @@ export function ProductionListTable({
|
||||
refetch,
|
||||
data: data,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
treatments: {Enhanced_Payroll}
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
};
|
||||
|
||||
@@ -28,13 +28,12 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
||||
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const {treatments: {Production_List_Status_Colors}} = useSplitTreatments({
|
||||
const {treatments: {Production_List_Status_Colors, Enhanced_Payroll}} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Production_List_Status_Colors"],
|
||||
names: ["Production_List_Status_Colors","Enhanced_Payroll"],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
});
|
||||
|
||||
|
||||
const assoc = bodyshop.associations.find(
|
||||
(a) => a.useremail === currentUser.email
|
||||
);
|
||||
@@ -69,6 +68,7 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
||||
state,
|
||||
data,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
treatments: {Production_List_Status_Colors, Enhanced_Payroll}
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width ?? 100,
|
||||
};
|
||||
@@ -88,7 +88,8 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
||||
refetch,
|
||||
state,
|
||||
data: data,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
treatments: {Production_List_Status_Colors, Enhanced_Payroll}
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width ?? 100,
|
||||
};
|
||||
|
||||
@@ -141,9 +141,10 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
||||
|
||||
const grouped = _.groupBy(FilteredReportsList, "group");
|
||||
|
||||
const groupExcludeKeyFilter = [...!HasFeatureAccess({featureName: 'bills'})? ["purchases"]:[],
|
||||
...!HasFeatureAccess({featureName: 'timetickets'})? ["payroll"]:[],
|
||||
]
|
||||
const groupExcludeKeyFilter = [
|
||||
...(!HasFeatureAccess({ featureName: 'bills', bodyshop }) ? ['purchases'] : []),
|
||||
...(!HasFeatureAccess({ featureName: 'timetickets', bodyshop }) ? ['payroll'] : []),
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -18,7 +18,6 @@ import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
|
||||
import queryString from "query-string";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
|
||||
@@ -241,17 +241,17 @@ export function ShopInfoResponsibilityCenterComponent({bodyshop, form}) {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Space align="center">
|
||||
d
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
<Space align="center">
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</Space>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
|
||||
@@ -8,6 +8,7 @@ import {Link, useLocation, useNavigate} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import RomeLogo from "../../assets/RomeOnlineBlue.png";
|
||||
import ImEXOnlineLogo from "../../assets/logo192.png";
|
||||
import ProManagerLogo from '../../assets/promanager/ProManagerLogo.gif';
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import {emailSignInStart, sendPasswordReset,} from "../../redux/user/user.actions";
|
||||
import {selectCurrentUser, selectLoginLoading, selectSignInError,} from "../../redux/user/user.selectors";
|
||||
@@ -53,9 +54,9 @@ export function SignInComponent({
|
||||
return (
|
||||
<div className="login-container">
|
||||
<div className="login-logo-container">
|
||||
<img src={InstanceRenderManager({imex:ImEXOnlineLogo, rome:RomeLogo, promanager:'https://www.web-est.com/img/web_est_logo_software.gif'})} width={200} alt={InstanceRenderManager({imex:t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})}/>
|
||||
<img src={InstanceRenderManager({imex:ImEXOnlineLogo, rome:RomeLogo, promanager:ProManagerLogo})} width={InstanceRenderManager({imex:200, rome:200,promanager:450})} alt={InstanceRenderManager({imex:t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})}/>
|
||||
<Typography.Title>{
|
||||
InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:null})
|
||||
}</Typography.Title>
|
||||
</div>
|
||||
<Form onFinish={handleFinish} form={form} size="large">
|
||||
|
||||
@@ -65,14 +65,19 @@ export function TimeTicketList({
|
||||
}, [timetickets]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("timetickets.fields.committed"),
|
||||
dataIndex: "committed_at",
|
||||
key: "committed_at",
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.committed_at}/>
|
||||
),
|
||||
},
|
||||
...(Enhanced_Payroll.treatment === "on"
|
||||
? [{
|
||||
title: t("timetickets.fields.committed"),
|
||||
dataIndex: "committed_at",
|
||||
key: "committed_at",
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.committed_at}/>
|
||||
),
|
||||
},]
|
||||
: [
|
||||
|
||||
]),
|
||||
|
||||
{
|
||||
title: t("timetickets.fields.date"),
|
||||
dataIndex: "date",
|
||||
|
||||
@@ -16,7 +16,6 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
||||
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
||||
import TimeTicketCalculatorComponent from "../time-ticket-calculator/time-ticket-calculator.component";
|
||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
|
||||
@@ -178,7 +178,7 @@ export function TimeTicketModalContainer({
|
||||
onCancel={handleCancel}
|
||||
afterClose={() => form.resetFields()}
|
||||
footer={
|
||||
<span>
|
||||
<Space>
|
||||
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
|
||||
<Button
|
||||
loading={loading}
|
||||
@@ -198,7 +198,7 @@ export function TimeTicketModalContainer({
|
||||
{t("general.actions.saveandnew")}
|
||||
</Button>
|
||||
)}
|
||||
</span>
|
||||
</Space>
|
||||
}
|
||||
destroyOnClose
|
||||
>
|
||||
@@ -229,9 +229,12 @@ export function TimeTicketModalContainer({
|
||||
<PageHeader
|
||||
extra={
|
||||
<Space>
|
||||
{
|
||||
Enhanced_Payroll.treatment === 'on' &&
|
||||
<TimeTicketsCommitToggleComponent
|
||||
timeticket={timeTicketModal.context?.timeticket}
|
||||
/>
|
||||
}
|
||||
<Button onClick={handleCancel}>
|
||||
{t("general.actions.cancel")}
|
||||
</Button>
|
||||
|
||||
@@ -1,92 +1,91 @@
|
||||
import {HeartOutlined} from "@ant-design/icons";
|
||||
import {Select, Space, Tag} from "antd";
|
||||
import React, {forwardRef, useEffect, useState} from "react";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import { HeartOutlined } from '@ant-design/icons';
|
||||
import { Select, Space, Tag } from 'antd';
|
||||
import React, { forwardRef, useEffect, useState } from 'react';
|
||||
import PhoneNumberFormatter from '../../utils/PhoneFormatter';
|
||||
|
||||
const {Option} = Select;
|
||||
const { Option } = Select;
|
||||
|
||||
//To be used as a form element only.
|
||||
|
||||
const VendorSearchSelect = (
|
||||
{value, onChange, options, onSelect, disabled, preferredMake, showPhone},
|
||||
ref
|
||||
{ value, onChange, options, onSelect, disabled, preferredMake, showPhone },
|
||||
ref
|
||||
) => {
|
||||
const [option, setOption] = useState(value);
|
||||
const [option, setOption] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
if (value !== option && onChange) {
|
||||
onChange(option);
|
||||
}
|
||||
}, [value, option, onChange]);
|
||||
useEffect(() => {
|
||||
if (value !== option && onChange) {
|
||||
onChange(option);
|
||||
}
|
||||
}, [value, option, onChange]);
|
||||
|
||||
const favorites =
|
||||
preferredMake && options
|
||||
? options.filter(
|
||||
(o) =>
|
||||
o.favorite.filter(
|
||||
(f) => f.toLowerCase() === preferredMake.toLowerCase()
|
||||
).length > 0
|
||||
)
|
||||
: [];
|
||||
const favorites =
|
||||
preferredMake && options
|
||||
? options.filter(
|
||||
(o) =>
|
||||
o.favorite.filter((f) => f.toLowerCase() === preferredMake.toLowerCase()).length > 0
|
||||
)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Select
|
||||
ref={ref}
|
||||
showSearch
|
||||
value={option}
|
||||
style={{
|
||||
width: "100%",
|
||||
}}
|
||||
popupMatchSelectWidth={false}
|
||||
onChange={setOption}
|
||||
optionFilterProp="name"
|
||||
onSelect={onSelect}
|
||||
disabled={disabled || false}
|
||||
optionLabelProp={"name"}
|
||||
>
|
||||
{favorites
|
||||
? favorites.map((o) => (
|
||||
<Option
|
||||
key={`favorite-${o.id}`}
|
||||
value={o.id}
|
||||
name={o.name}
|
||||
discount={o.discount}
|
||||
>
|
||||
<div className="imex-flex-row">
|
||||
<div style={{flex: 1}}>{o.name}</div>
|
||||
<Space style={{marginLeft: "1rem"}}>
|
||||
<HeartOutlined style={{color: "red"}}/>
|
||||
{o.phone && showPhone && (
|
||||
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
|
||||
)}
|
||||
{o.discount && o.discount !== 0 ? (
|
||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
{options
|
||||
? options.map((o) => (
|
||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div className="imex-flex-row" style={{width: "100%"}}>
|
||||
<div style={{flex: 1}}>{o.name}</div>
|
||||
return (
|
||||
<Select
|
||||
ref={ref}
|
||||
showSearch
|
||||
value={option}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
labelRender={({ label, value, ...rest }) => {
|
||||
if (!value || !options) return label;
|
||||
const discount = options?.find((o) => o.id === value)?.discount;
|
||||
return (
|
||||
<div className="imex-flex-row" style={{ width: '100%' }}>
|
||||
<div style={{ flex: 1 }}>{label}</div>
|
||||
|
||||
<Space style={{marginLeft: "1rem"}}>
|
||||
{o.phone && showPhone && (
|
||||
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
|
||||
)}
|
||||
{o.discount && o.discount !== 0 ? (
|
||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
popupMatchSelectWidth={false}
|
||||
onChange={setOption}
|
||||
optionFilterProp="name"
|
||||
onSelect={onSelect}
|
||||
disabled={disabled || false}
|
||||
optionLabelProp={'name'}
|
||||
>
|
||||
{favorites
|
||||
? favorites.map((o) => (
|
||||
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div className="imex-flex-row">
|
||||
<div style={{ flex: 1 }}>{o.name}</div>
|
||||
<Space style={{ marginLeft: '1rem' }}>
|
||||
<HeartOutlined style={{ color: 'red' }} />
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? (
|
||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
{options
|
||||
? options.map((o) => (
|
||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div className="imex-flex-row" style={{ width: '100%' }}>
|
||||
<div style={{ flex: 1 }}>{o.name}</div>
|
||||
|
||||
))
|
||||
: null}
|
||||
</Select>
|
||||
);
|
||||
<Space style={{ marginLeft: '1rem' }}>
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? (
|
||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
export default forwardRef(VendorSearchSelect);
|
||||
|
||||
@@ -126,7 +126,7 @@ export function BillsListPage({
|
||||
state.sortedInfo.columnKey === "is_credit_memo" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.is_credit_memo}/>
|
||||
<Checkbox checked={record.is_credit_memo}/>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -136,7 +136,7 @@ export function BillsListPage({
|
||||
sorter: (a, b) => a.exported - b.exported,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
|
||||
render: (text, record) => <Checkbox disabled checked={record.exported}/>,
|
||||
render: (text, record) => <Checkbox checked={record.exported}/>,
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
|
||||
@@ -41,8 +41,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
||||
export const socket = SocketIO(
|
||||
import.meta.env.PROD
|
||||
? import.meta.env.VITE_APP_AXIOS_BASE_API_URL
|
||||
: window.location.origin,
|
||||
// "http://localhost:4000", // for dev testing,
|
||||
: "http://localhost:4000", // for dev testing,
|
||||
{
|
||||
path: "/ws",
|
||||
withCredentials: true,
|
||||
|
||||
@@ -162,26 +162,24 @@ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
{ text: "False", value: false },
|
||||
],
|
||||
onFilter: (value, record) => record.successful === value,
|
||||
render: (text, record) => (
|
||||
<Checkbox disabled checked={record.successful}/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("general.labels.message"),
|
||||
dataIndex: "message",
|
||||
key: "message",
|
||||
render: (text, record) =>
|
||||
record.message && (
|
||||
<div>
|
||||
<ul>
|
||||
{JSON.parse(record.message).map((m, idx) => (
|
||||
<li key={idx}>{m}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
render: (text, record) => <Checkbox checked={record.successful} />,
|
||||
},
|
||||
{
|
||||
title: t("general.labels.message"),
|
||||
dataIndex: "message",
|
||||
key: "message",
|
||||
render: (text, record) =>
|
||||
record.message && (
|
||||
<div>
|
||||
<ul>
|
||||
{JSON.parse(record.message).map((m, idx) => (
|
||||
<li key={idx}>{m}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Card
|
||||
|
||||
@@ -372,8 +372,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
<Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<><Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col lg={8} md={24}>
|
||||
<Form.List
|
||||
@@ -452,7 +453,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
||||
<DeleteFilled
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
if(!jobRO){
|
||||
remove(field.name);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
@@ -530,6 +533,7 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
<Divider/>
|
||||
<JobsCloseLines job={job}/>
|
||||
|
||||
@@ -332,7 +332,7 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "partssublet",
|
||||
icon: <ToolFilled/>,
|
||||
label: t("menus.jobsdetail.partssublet"),
|
||||
label: HasFeatureAccess({featureName: "bills", bodyshop}) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"),
|
||||
children: <JobsDetailPliContainer job={job}/>,
|
||||
},
|
||||
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ {
|
||||
|
||||
@@ -521,13 +521,12 @@ export function Manage({conflict, bodyshop,enableJoyRide,joyRideSteps,setJoyRide
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex' }}>
|
||||
{`Joy Ride Status: ${enableJoyRide}`}
|
||||
<div>
|
||||
{`${InstanceRenderManager({
|
||||
imex: t('titles.imexonline'),
|
||||
rome: t('titles.romeonline'),
|
||||
promanager: t('titles.promanager'),
|
||||
})} ${import.meta.env.VITE_APP_GIT_SHA || 'Local Build'} - ${
|
||||
})} - ${
|
||||
import.meta.env.VITE_APP_GIT_SHA_DATE
|
||||
}`}
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@ export function ShopPage({bodyshop, setSelectedHeader, setBreadcrumbs}) {
|
||||
},
|
||||
);
|
||||
|
||||
if(HasFeatureAccess("csi")){
|
||||
if(HasFeatureAccess({featureName:"csi", bodyshop})){
|
||||
items.push({
|
||||
key: "csiq",
|
||||
label: t("bodyshop.labels.csiq"),
|
||||
|
||||
@@ -1,103 +1,110 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Col, Row, Space} from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useSearchParams} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TimeTicketsDatesSelector
|
||||
from "../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component";
|
||||
import TimeTicketList from "../../components/time-ticket-list/time-ticket-list.component";
|
||||
import TimeTicketsPayrollTable from "../../components/time-tickets-payroll-table/time-tickets-payroll-table.component";
|
||||
import TimeTicketsSummaryEmployees
|
||||
from "../../components/time-tickets-summary-employees/time-tickets-summary-employees.component";
|
||||
import {QUERY_TIME_TICKETS_IN_RANGE} from "../../graphql/timetickets.queries";
|
||||
import TimeTicketsAttendanceTable
|
||||
from "../../components/time-tickets-attendance-table/time-tickets-attendance-table.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import TimeTicketsCommit from "../../components/time-tickets-commit/time-tickets-commit.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { Col, Row, Space } from 'antd';
|
||||
import dayjs from '../../utils/day';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import AlertComponent from '../../components/alert/alert.component';
|
||||
import RbacWrapper from '../../components/rbac-wrapper/rbac-wrapper.component';
|
||||
import TimeTicketsDatesSelector from '../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component';
|
||||
import TimeTicketList from '../../components/time-ticket-list/time-ticket-list.component';
|
||||
import TimeTicketsPayrollTable from '../../components/time-tickets-payroll-table/time-tickets-payroll-table.component';
|
||||
import TimeTicketsSummaryEmployees from '../../components/time-tickets-summary-employees/time-tickets-summary-employees.component';
|
||||
import { QUERY_TIME_TICKETS_IN_RANGE } from '../../graphql/timetickets.queries';
|
||||
import TimeTicketsAttendanceTable from '../../components/time-tickets-attendance-table/time-tickets-attendance-table.component';
|
||||
import { setBreadcrumbs, setSelectedHeader } from '../../redux/application/application.actions';
|
||||
import TimeTicketsCommit from '../../components/time-tickets-commit/time-tickets-commit.component';
|
||||
import FeatureWrapperComponent from '../../components/feature-wrapper/feature-wrapper.component';
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { useSplitTreatments } from '@splitsoftware/splitio-react';
|
||||
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop:selectBodyshop
|
||||
});
|
||||
|
||||
export function TimeTicketsContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const [searchParams] = useSearchParams();
|
||||
const {start, end} = Object.fromEntries(searchParams);
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
});
|
||||
|
||||
const startDate = start
|
||||
? dayjs(start)
|
||||
: dayjs().startOf("week").subtract(7, "day");
|
||||
const endDate = end ? dayjs(end) : dayjs().endOf("week");
|
||||
export function TimeTicketsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const {
|
||||
treatments: { Enhanced_Payroll },
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ['Enhanced_Payroll'],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { start, end } = Object.fromEntries(searchParams);
|
||||
|
||||
const {loading, error, data} = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
|
||||
variables: {
|
||||
start: startDate,
|
||||
end: endDate,
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
const startDate = start ? dayjs(start) : dayjs().startOf('week').subtract(7, 'day');
|
||||
const endDate = end ? dayjs(end) : dayjs().endOf('week');
|
||||
|
||||
const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
|
||||
variables: {
|
||||
start: startDate,
|
||||
end: endDate,
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
nextFetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t('titles.timetickets', {
|
||||
app: InstanceRenderManager({
|
||||
imex: '$t(titles.imexonline)',
|
||||
rome: '$t(titles.romeonline)',
|
||||
promanager: '$t(titles.promanager)',
|
||||
}),
|
||||
});
|
||||
setSelectedHeader('timetickets');
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: '/manage/timetickets',
|
||||
label: t('titles.bc.timetickets'),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.timetickets",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("timetickets");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/timetickets",
|
||||
label: t("titles.bc.timetickets"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='timetickets'>
|
||||
<RbacWrapper action="timetickets:list">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<TimeTicketList
|
||||
loading={loading}
|
||||
timetickets={data ? data.timetickets : []}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<TimeTicketsAttendanceTable/>
|
||||
<TimeTicketsPayrollTable/>
|
||||
<TimeTicketsCommit timetickets={data ? data.timetickets : []}/>
|
||||
<TimeTicketsDatesSelector/>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<TimeTicketsSummaryEmployees
|
||||
loading={loading}
|
||||
timetickets={data ? data.timetickets : []}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="timetickets">
|
||||
<RbacWrapper action="timetickets:list">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<TimeTicketList
|
||||
loading={loading}
|
||||
timetickets={data ? data.timetickets : []}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<TimeTicketsAttendanceTable />
|
||||
<TimeTicketsPayrollTable />
|
||||
{Enhanced_Payroll.treatment === 'on' && (
|
||||
<TimeTicketsCommit timetickets={data ? data.timetickets : []} />
|
||||
)}
|
||||
<TimeTicketsDatesSelector />
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<TimeTicketsSummaryEmployees
|
||||
loading={loading}
|
||||
timetickets={data ? data.timetickets : []}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TimeTicketsContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketsContainer);
|
||||
|
||||
@@ -47,6 +47,7 @@ import client from "../../utils/GraphQLClient";
|
||||
import {QUERY_EULA} from "../../graphql/bodyshop.queries";
|
||||
import day from "../../utils/day";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { Userpilot } from "userpilot";
|
||||
|
||||
const fpPromise = FingerprintJS.load();
|
||||
|
||||
@@ -227,6 +228,15 @@ export function* signInSuccessSaga({payload}) {
|
||||
window.$crisp.push(['set', 'user:nickname', [payload.displayName || payload.email]]);
|
||||
window.$crisp.push(['set', 'session:segments', [['user']]]);
|
||||
},
|
||||
promanager: () =>{
|
||||
Userpilot.identify(
|
||||
payload.email,
|
||||
{
|
||||
email: payload.email,
|
||||
}
|
||||
);
|
||||
console.log("*** Userpilot identified.")
|
||||
}
|
||||
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -749,7 +749,7 @@
|
||||
"refuelcharge": "Refuel Charge (per liter/gallon)",
|
||||
"scheduledreturn": "Scheduled Return",
|
||||
"start": "Contract Start",
|
||||
"statetax": "State Taxes",
|
||||
"statetax": "Provincial/State Taxes",
|
||||
"status": "Status"
|
||||
},
|
||||
"labels": {
|
||||
@@ -899,6 +899,7 @@
|
||||
"refhrs": "Refinish Hrs"
|
||||
},
|
||||
"titles": {
|
||||
"joblifecycle": "Job Life Cycles",
|
||||
"labhours": "Total Body Hours",
|
||||
"larhours": "Total Refinish Hours",
|
||||
"monthlyemployeeefficiency": "Monthly Employee Efficiency",
|
||||
@@ -1164,6 +1165,7 @@
|
||||
"loadingshop": "Loading shop data...",
|
||||
"loggingin": "Authorizing...",
|
||||
"markedexported": "Manually marked as exported.",
|
||||
"media": "Media",
|
||||
"message": "Message",
|
||||
"monday": "Monday",
|
||||
"na": "N/A",
|
||||
@@ -2002,7 +2004,7 @@
|
||||
"savebeforeconversion": "You have unsaved changes on the Job. Please save them before converting it. ",
|
||||
"scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the Job. ",
|
||||
"specialcoveragepolicy": "Special Coverage Policy Applies",
|
||||
"state_tax_amt": "State Taxes",
|
||||
"state_tax_amt": "Provincial/State Taxes",
|
||||
"subletstotal": "Sublets Total",
|
||||
"subtotal": "Subtotal",
|
||||
"supplementnote": "The Job had a supplement imported.",
|
||||
@@ -2174,6 +2176,7 @@
|
||||
"insurance": "Insurance Information",
|
||||
"labor": "Labor",
|
||||
"lifecycle": "Lifecycle",
|
||||
"parts": "Parts",
|
||||
"partssublet": "Parts & Bills",
|
||||
"rates": "Rates",
|
||||
"repairdata": "Repair Data",
|
||||
@@ -2558,7 +2561,7 @@
|
||||
"invoice_total_payable": "Invoice (Total Payable)",
|
||||
"iou_form": "IOU Form",
|
||||
"job_costing_ro": "Job Costing",
|
||||
"job_lifecycle_ro": "",
|
||||
"job_lifecycle_ro": "Job Lifecycle",
|
||||
"job_notes": "Job Notes",
|
||||
"key_tag": "Key Tag",
|
||||
"labels": {
|
||||
|
||||
@@ -899,6 +899,7 @@
|
||||
"refhrs": ""
|
||||
},
|
||||
"titles": {
|
||||
"joblifecycle": "",
|
||||
"labhours": "",
|
||||
"larhours": "",
|
||||
"monthlyemployeeefficiency": "",
|
||||
@@ -2174,6 +2175,7 @@
|
||||
"insurance": "",
|
||||
"labor": "Labor",
|
||||
"lifecycle": "",
|
||||
"parts": "",
|
||||
"partssublet": "Piezas / Subarrendamiento",
|
||||
"rates": "",
|
||||
"repairdata": "Datos de reparación",
|
||||
|
||||
@@ -899,6 +899,7 @@
|
||||
"refhrs": ""
|
||||
},
|
||||
"titles": {
|
||||
"joblifecycle": "",
|
||||
"labhours": "",
|
||||
"larhours": "",
|
||||
"monthlyemployeeefficiency": "",
|
||||
@@ -2174,6 +2175,7 @@
|
||||
"insurance": "",
|
||||
"labor": "La main d'oeuvre",
|
||||
"lifecycle": "",
|
||||
"parts": "",
|
||||
"partssublet": "Pièces / Sous-location",
|
||||
"rates": "",
|
||||
"repairdata": "Données de réparation",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { initReactI18next } from 'react-i18next';
|
||||
import en_Translation from './en_us/common.json';
|
||||
import es_Translation from './es/common.json';
|
||||
import fr_Translation from './fr/common.json';
|
||||
import { GenerateTemplates } from '../utils/RenderTemplate';
|
||||
|
||||
// the translations
|
||||
// (tip move them in a JSON file and import them)
|
||||
@@ -13,19 +14,27 @@ const resources = {
|
||||
'es-MX': es_Translation,
|
||||
};
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(LanguageDetector) // passes i18n down to react-i18next
|
||||
.init({
|
||||
resources,
|
||||
//lng: "en",
|
||||
detection: {},
|
||||
fallbackLng: 'en-US',
|
||||
debug: import.meta.env.DEV,
|
||||
//keySeparator: false, // we do not use keys in form messages.welcome
|
||||
interpolation: {
|
||||
escapeValue: false, // react already safes from xss
|
||||
skipOnVariables: false,
|
||||
.use(initReactI18next)
|
||||
.init(
|
||||
{
|
||||
resources,
|
||||
//lng: "en",
|
||||
detection: {},
|
||||
fallbackLng: 'en-US',
|
||||
debug: import.meta.env.DEV,
|
||||
react: {
|
||||
useSuspense: true,
|
||||
},
|
||||
//keySeparator: false, // we do not use keys in form messages.welcome
|
||||
interpolation: {
|
||||
escapeValue: false, // react already safes from xss
|
||||
skipOnVariables: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
(error) => {
|
||||
GenerateTemplates();
|
||||
}
|
||||
);
|
||||
|
||||
export default i18n;
|
||||
|
||||
@@ -14,7 +14,12 @@ const server = import.meta.env.VITE_APP_REPORTS_SERVER_URL;
|
||||
|
||||
jsreport.serverUrl = server;
|
||||
|
||||
const Templates = TemplateList();
|
||||
let Templates;
|
||||
export function GenerateTemplates(){
|
||||
//Required as a part of the transition to Vite.
|
||||
//Previous method had the template hash generating before translations loaded, resulting in empty files.
|
||||
Templates = TemplateList()
|
||||
}
|
||||
|
||||
export default async function RenderTemplate(
|
||||
templateObject,
|
||||
|
||||
Reference in New Issue
Block a user