Merged in development (pull request #28)
Reorder totals table IO-734 Resolve null parts status reference. IO-737 Allow time ticket entry for RO jobs IO-741 Technician clock issues IO-731 Updates for audatex claims & mapa/mash calculations IO-718 Partial fixes to jobline upsert & totals calculation. IO-730 Clear Errors & Update CI
This commit is contained in:
@@ -22603,6 +22603,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>shiftclockin</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>
|
||||
@@ -25619,7 +25640,7 @@
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>filing_coverhseet_portrait</name>
|
||||
<name>filing_coversheet_portrait</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
|
||||
@@ -47,13 +47,14 @@ export function JobLinesComponent({
|
||||
form,
|
||||
}) {
|
||||
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
|
||||
|
||||
const {
|
||||
loading: billLinesLoading,
|
||||
error: billLinesError,
|
||||
data: billLinesData,
|
||||
} = useQuery(QUERY_BILLS_BY_JOB_REF, {
|
||||
variables: { jobId: job.id },
|
||||
skip: loading,
|
||||
variables: { jobId: job && job.id },
|
||||
skip: loading || !job,
|
||||
});
|
||||
|
||||
const billLinesDataObj = useMemo(() => {
|
||||
@@ -299,40 +300,43 @@ export function JobLinesComponent({
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Space>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
setJobLineEditContext({
|
||||
actions: { refetch: refetch, submit: form && form.submit },
|
||||
context: record,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("general.actions.edit")}
|
||||
</Button>
|
||||
<div>
|
||||
{record.manual_line && (
|
||||
<Button
|
||||
onClick={() =>
|
||||
deleteJobLine({
|
||||
variables: { joblineId: record.id },
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
id: cache.identify(job),
|
||||
fields: {
|
||||
joblines(existingJobLines, { readField }) {
|
||||
return existingJobLines.filter(
|
||||
(jlRef) => record.id !== readField("id", jlRef)
|
||||
);
|
||||
<Space >
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
setJobLineEditContext({
|
||||
actions: { refetch: refetch, submit: form && form.submit },
|
||||
context: record,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("general.actions.edit")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() =>
|
||||
deleteJobLine({
|
||||
variables: { joblineId: record.id },
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
id: cache.identify(job),
|
||||
fields: {
|
||||
joblines(existingJobLines, { readField }) {
|
||||
return existingJobLines.filter(
|
||||
(jlRef) => record.id !== readField("id", jlRef)
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
<DeleteFilled />
|
||||
</Button>
|
||||
});
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
<DeleteFilled />
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
{
|
||||
// <AllocationsAssignmentContainer
|
||||
@@ -342,7 +346,7 @@ export function JobLinesComponent({
|
||||
// hours={record.mod_lb_hrs}
|
||||
// />
|
||||
}
|
||||
</Space>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -61,7 +61,7 @@ export function JobLineStatusPopup({ bodyshop, jobline, disabled }) {
|
||||
onSelect={handleChange}
|
||||
onBlur={handleSave}
|
||||
>
|
||||
{bodyshop.md_order_statuses.statuses.map((s, idx) => (
|
||||
{Object.values(bodyshop.md_order_statuses).map((s, idx) => (
|
||||
<Select.Option key={idx} value={s}>
|
||||
{s}
|
||||
</Select.Option>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "../../graphql/jobs-lines.queries";
|
||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -39,7 +40,7 @@ function JobLinesUpsertModalContainer({
|
||||
manual_line: !(
|
||||
jobLineEditModal.context && jobLineEditModal.context.id
|
||||
),
|
||||
...values,
|
||||
...UndefinedToNull(values),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -267,6 +267,14 @@ export function JobsTotalsTableComponent({ bodyshop, jobRO, job }) {
|
||||
</Typography.Title>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.subtotal")}</td>
|
||||
<td className="currency">
|
||||
<strong>
|
||||
{Dinero(job.job_totals.totals.subtotal).toFormat()}
|
||||
</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.local_tax_amt")}</td>
|
||||
<td className="currency">
|
||||
@@ -317,26 +325,18 @@ export function JobsTotalsTableComponent({ bodyshop, jobRO, job }) {
|
||||
).toFormat()}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.total_cust_payable")}</td>
|
||||
<td className="currency">
|
||||
{Dinero(job.job_totals.totals.custPayable.total).toFormat()}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.subtotal")}</td>
|
||||
<td className="currency">
|
||||
<strong>
|
||||
{Dinero(job.job_totals.totals.subtotal).toFormat()}
|
||||
</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.total_repairs")}</td>
|
||||
<td className="currency">
|
||||
{Dinero(job.job_totals.totals.total_repairs).toFormat()}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.total_cust_payable")}</td>
|
||||
<td className="currency">
|
||||
{Dinero(job.job_totals.totals.custPayable.total).toFormat()}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{t("jobs.labels.net_repairs")}</td>
|
||||
<td className="currency">
|
||||
|
||||
@@ -97,7 +97,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
label={t("jobs.fields.referralsource")}
|
||||
name="referral_source"
|
||||
>
|
||||
<Select disabled={jobRO}>
|
||||
<Select disabled={jobRO} allowClear>
|
||||
{bodyshop.md_referral_sources.map((s) => (
|
||||
<Select.Option key={s} value={s}>
|
||||
{s}
|
||||
@@ -106,7 +106,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.alt_transport")} name="alt_transport">
|
||||
<Select disabled={jobRO}>
|
||||
<Select disabled={jobRO} allowClear>
|
||||
{bodyshop.appt_alt_transport.map((s) => (
|
||||
<Select.Option key={s} value={s}>
|
||||
{s}
|
||||
|
||||
@@ -28,6 +28,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||
setJobCostingContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
|
||||
setTimeTicketContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
||||
});
|
||||
|
||||
export function JobsDetailHeaderActions({
|
||||
@@ -39,6 +41,7 @@ export function JobsDetailHeaderActions({
|
||||
setPaymentContext,
|
||||
setJobCostingContext,
|
||||
jobRO,
|
||||
setTimeTicketContext,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const client = useApolloClient();
|
||||
@@ -110,6 +113,19 @@ export function JobsDetailHeaderActions({
|
||||
{t("jobs.actions.viewchecklist")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="entertimetickets"
|
||||
onClick={() => {
|
||||
logImEXEvent("job_header_enter_time_ticekts");
|
||||
|
||||
setTimeTicketContext({
|
||||
actions: {},
|
||||
context: { jobId: job.id },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("timetickets.actions.enter")}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="enterpayments"
|
||||
disabled={jobRO}
|
||||
|
||||
@@ -27,11 +27,7 @@ export function JobsDetailLaborContainer({
|
||||
return (
|
||||
<div>
|
||||
{techConsole ? null : (
|
||||
<TimeTicketEnterButton
|
||||
disabled={jobRO}
|
||||
actions={{ refetch }}
|
||||
context={{ jobId: jobId }}
|
||||
>
|
||||
<TimeTicketEnterButton actions={{ refetch }} context={{ jobId: jobId }}>
|
||||
{t("timetickets.actions.enter")}
|
||||
</TimeTicketEnterButton>
|
||||
)}
|
||||
|
||||
@@ -86,17 +86,13 @@ export default function JobsFindModalComponent({
|
||||
key: "vehicle",
|
||||
width: "15%",
|
||||
ellipsis: true,
|
||||
render: (text, record) => {
|
||||
return record.vehicle ? (
|
||||
<Link to={"/manage/vehicles/" + record.vehicleid}>
|
||||
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||
record.v_model_desc || ""
|
||||
}`}
|
||||
</Link>
|
||||
) : (
|
||||
t("jobs.errors.novehicle")
|
||||
);
|
||||
},
|
||||
render: (text, record) => (
|
||||
<Link to={"/manage/vehicles/" + record.vehicleid}>
|
||||
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||
record.v_model_desc || ""
|
||||
}`}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("vehicles.fields.plate_no"),
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { Form } from "antd";
|
||||
import { Form, Select } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||
import JobsDetailLaborContainer from "../jobs-detail-labor/jobs-detail-labor.container";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
technician: selectTechnician,
|
||||
});
|
||||
|
||||
export function TechClockInComponent({ form, bodyshop }) {
|
||||
export function TechClockInComponent({ form, bodyshop, technician }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0];
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
@@ -29,6 +31,26 @@ export function TechClockInComponent({ form, bodyshop }) {
|
||||
<JobSearchSelect />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="cost_center"
|
||||
label={t("timetickets.fields.cost_center")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{emps &&
|
||||
emps.rates.map((item) => (
|
||||
<Select.Option key={item.cost_center}>
|
||||
{item.cost_center}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
shouldUpdate={(prevValues, curValues) =>
|
||||
prevValues.jobid !== curValues.jobid
|
||||
|
||||
@@ -35,7 +35,7 @@ export function TechClockInContainer({ technician, bodyshop }) {
|
||||
date: theTime,
|
||||
clockon: theTime,
|
||||
jobid: values.jobid,
|
||||
cost_center: technician.cost_center,
|
||||
cost_center: values.cost_center,
|
||||
ciecacode: Object.keys(
|
||||
bodyshop.md_responsibility_centers.defaults.costs
|
||||
).find((key) => {
|
||||
|
||||
@@ -30,6 +30,7 @@ export function TechClockOffButton({
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const emps = bodyshop.employees.filter((e) => e.id === technician.id)[0];
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("tech_clock_out_job");
|
||||
@@ -120,9 +121,10 @@ export function TechClockOffButton({
|
||||
{t("timetickets.labels.shift")}
|
||||
</Select.Option>
|
||||
) : (
|
||||
bodyshop.md_responsibility_centers.costs.map((i, idx) => (
|
||||
<Select.Option key={idx} value={i.name}>
|
||||
{i.name}
|
||||
emps &&
|
||||
emps.rates.map((item) => (
|
||||
<Select.Option key={item.cost_center}>
|
||||
{item.cost_center}
|
||||
</Select.Option>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -81,6 +81,9 @@ export function TechClockedInList({ technician }) {
|
||||
<DataLabel label={t("timetickets.fields.clockon")}>
|
||||
<DateTimeFormatter>{ticket.clockon}</DateTimeFormatter>
|
||||
</DataLabel>
|
||||
<DataLabel label={t("timetickets.fields.cost_center")}>
|
||||
{ticket.cost_center}{" "}
|
||||
</DataLabel>
|
||||
</Card>
|
||||
</List.Item>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PrinterFilled } from "@ant-design/icons";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Col, Drawer, Grid, PageHeader, Row, Tag, Tabs } from "antd";
|
||||
import { Button, Drawer, Grid, PageHeader, Tabs, Tag } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -9,26 +9,26 @@ import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component";
|
||||
import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component";
|
||||
import JobLinesContainer from "../job-detail-lines/job-lines.container";
|
||||
import JobsDocumentsGalleryContainer from "../jobs-documents-gallery/jobs-documents-gallery.container";
|
||||
import JobNotesContainer from "../jobs-notes/jobs-notes.container";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component";
|
||||
import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPrintCenterContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "printCenter" })),
|
||||
});
|
||||
|
||||
const colBreakPoints = {
|
||||
xs: {
|
||||
span: 24,
|
||||
},
|
||||
sm: {
|
||||
span: 8,
|
||||
},
|
||||
};
|
||||
// const colBreakPoints = {
|
||||
// xs: {
|
||||
// span: 24,
|
||||
// },
|
||||
// sm: {
|
||||
// span: 8,
|
||||
// },
|
||||
// };
|
||||
|
||||
export function JobDetailCards({ setPrintCenterContext }) {
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
@@ -116,16 +116,12 @@ export function JobDetailCards({ setPrintCenterContext }) {
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
<Col {...colBreakPoints}> What would be good to have here?</Col>
|
||||
</Row>
|
||||
<Tabs size="large">
|
||||
<Tabs.TabPane key="lines" tab={t("jobs.labels.lines")}>
|
||||
<JobLinesContainer
|
||||
jobId={selected}
|
||||
joblines={data.jobs_by_pk.joblines}
|
||||
job={data.jobs_by_pk}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
|
||||
@@ -13,10 +13,8 @@ import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
||||
|
||||
export default function TimeTicketModalComponent({
|
||||
form,
|
||||
roAutoCompleteOptions,
|
||||
|
||||
employeeAutoCompleteOptions,
|
||||
loadLineTicketData,
|
||||
lineTicketData,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -33,7 +31,7 @@ export default function TimeTicketModalComponent({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<JobSearchSelect options={roAutoCompleteOptions} />
|
||||
<JobSearchSelect convertedOnly notExported={false} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("timetickets.fields.date")}
|
||||
|
||||
@@ -346,6 +346,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
inproduction
|
||||
vehicleid
|
||||
plate_no
|
||||
plate_st
|
||||
v_vin
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
@@ -357,6 +358,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
vehicle {
|
||||
id
|
||||
plate_no
|
||||
plate_st
|
||||
v_vin
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
@@ -828,7 +830,6 @@ export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql`
|
||||
search_jobs(
|
||||
args: { search: $search }
|
||||
limit: 50
|
||||
order_by: { ro_number: desc_nulls_last }
|
||||
where: {
|
||||
_and: {
|
||||
converted: { _eq: $isConverted }
|
||||
|
||||
@@ -115,6 +115,7 @@ export const QUERY_ACTIVE_TIME_TICKETS = gql`
|
||||
id
|
||||
clockon
|
||||
memo
|
||||
cost_center
|
||||
job {
|
||||
id
|
||||
|
||||
|
||||
@@ -1344,7 +1344,8 @@
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"productionboard": "Production Board - Visual",
|
||||
"productionlist": "Production List"
|
||||
"productionlist": "Production List",
|
||||
"shiftclockin": "Shift Clock"
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1552,7 +1553,7 @@
|
||||
"diagnostic_authorization": "Diagnostic Authorization",
|
||||
"estimate": "Estimate Only",
|
||||
"estimate_detail": "Estimate Details",
|
||||
"filing_coverhseet_portrait": "Filing Coversheet (Portrait)",
|
||||
"filing_coversheet_portrait": "Filing Coversheet (Portrait)",
|
||||
"final_invoice": "Final Invoice",
|
||||
"fippa_authorization": "FIPPA Authorization",
|
||||
"glass_express_checklist": "Glass Express Checklist",
|
||||
|
||||
@@ -1344,7 +1344,8 @@
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"productionboard": "",
|
||||
"productionlist": ""
|
||||
"productionlist": "",
|
||||
"shiftclockin": ""
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1552,7 +1553,7 @@
|
||||
"diagnostic_authorization": "",
|
||||
"estimate": "",
|
||||
"estimate_detail": "",
|
||||
"filing_coverhseet_portrait": "",
|
||||
"filing_coversheet_portrait": "",
|
||||
"final_invoice": "",
|
||||
"fippa_authorization": "",
|
||||
"glass_express_checklist": "",
|
||||
|
||||
@@ -1344,7 +1344,8 @@
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"productionboard": "",
|
||||
"productionlist": ""
|
||||
"productionlist": "",
|
||||
"shiftclockin": ""
|
||||
}
|
||||
},
|
||||
"messaging": {
|
||||
@@ -1552,7 +1553,7 @@
|
||||
"diagnostic_authorization": "",
|
||||
"estimate": "",
|
||||
"estimate_detail": "",
|
||||
"filing_coverhseet_portrait": "",
|
||||
"filing_coversheet_portrait": "",
|
||||
"final_invoice": "",
|
||||
"fippa_authorization": "",
|
||||
"glass_express_checklist": "",
|
||||
|
||||
@@ -42,7 +42,11 @@ export default async function RenderTemplate(
|
||||
try {
|
||||
const render = await jsreport.renderAsync(reportRequest);
|
||||
if (!renderAsHtml) {
|
||||
render.download(Templates[templateObject.name].title || "");
|
||||
render.download(
|
||||
(Templates[templateObject.name] &&
|
||||
Templates[templateObject.name].title) ||
|
||||
""
|
||||
);
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(render.toString());
|
||||
|
||||
@@ -167,11 +167,11 @@ export const TemplateList = (type, context) => {
|
||||
key: "coversheet_portrait",
|
||||
disabled: false,
|
||||
},
|
||||
filing_coverhseet_portrait: {
|
||||
title: i18n.t("printcenter.jobs.filing_coverhseet_portrait"),
|
||||
filing_coversheet_portrait: {
|
||||
title: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
|
||||
description: "All Jobs Notes",
|
||||
subject: i18n.t("printcenter.jobs.filing_coverhseet_portrait"),
|
||||
key: "filing_coverhseet_portrait",
|
||||
subject: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
|
||||
key: "filing_coversheet_portrait",
|
||||
disabled: false,
|
||||
},
|
||||
}
|
||||
|
||||
6
client/src/utils/undefinedtonull.js
Normal file
6
client/src/utils/undefinedtonull.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default function UndefinedToNull(obj) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (obj[key] === undefined) obj[key] = null;
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
@@ -41,10 +41,10 @@ exports.totalsSsu = async function (req, res) {
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200);
|
||||
res.status(200).send();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(503);
|
||||
res.status(503).send();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -269,7 +269,13 @@ function IsAdditionalCost(jobLine) {
|
||||
//936008 is Paint/Materials
|
||||
//936007 is Shop/Materials
|
||||
|
||||
return !jobLine.db_ref || jobLine.db_ref.startsWith("9360");
|
||||
//Remove paint and shop mat lines. They're calculated under rates.
|
||||
const isPaintOrShopMat =
|
||||
jobLine.db_ref === "936008" || jobLine.db_ref === "936007";
|
||||
|
||||
return (
|
||||
!jobLine.db_ref || (jobLine.db_ref.startsWith("9360") && !isPaintOrShopMat)
|
||||
);
|
||||
}
|
||||
|
||||
function CalculateAdditional(job) {
|
||||
@@ -305,7 +311,7 @@ function CalculateAdditional(job) {
|
||||
function CalculateTaxesTotals(job, otherTotals) {
|
||||
const subtotal = otherTotals.parts.parts.subtotal
|
||||
.add(otherTotals.parts.sublets.subtotal)
|
||||
.add(otherTotals.rates.rates_subtotal)
|
||||
.add(otherTotals.rates.subtotal) //No longer using just rates subtotal to include mapa/mash.
|
||||
.add(otherTotals.additional);
|
||||
// .add(Dinero({ amount: (job.towing_payable || 0) * 100 }))
|
||||
// .add(Dinero({ amount: (job.storage_payable || 0) * 100 }));
|
||||
@@ -319,7 +325,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
job.joblines
|
||||
.filter((jl) => !jl.removed)
|
||||
.forEach((val) => {
|
||||
if (!val.tax_part || !val.part_type || IsAdditionalCost(val)) {
|
||||
if (!val.tax_part || (!val.part_type && IsAdditionalCost(val))) {
|
||||
additionalItemsTax = additionalItemsTax.add(
|
||||
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
|
||||
.multiply(val.part_qty || 1)
|
||||
@@ -350,7 +356,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
statePartsTax,
|
||||
state_tax: statePartsTax
|
||||
.add(
|
||||
otherTotals.rates.rates_subtotal.percentage((job.tax_lbr_rt || 0) * 100)
|
||||
otherTotals.rates.subtotal.percentage((job.tax_lbr_rt || 0) * 100) // THis is currently using the lbr tax rate from PFH not PFL.
|
||||
)
|
||||
.add(
|
||||
Dinero({
|
||||
|
||||
Reference in New Issue
Block a user