Add tax rates to shop config, resolve rate population on job detail.

This commit is contained in:
Patrick Fic
2023-09-19 15:23:47 -07:00
parent fef680fb99
commit eff4f82ad7
9 changed files with 665 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -1009,6 +1009,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>smspaymentreminder</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>suggesteddates</name>
<definition_loaded>false</definition_loaded>
@@ -7526,6 +7547,111 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>responsibilitycenter_tax_rate</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>responsibilitycenter_tax_sur</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>responsibilitycenter_tax_thres</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>responsibilitycenter_tax_tier</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>responsibilitycenter_tax_type</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>
<folder_node>
<name>responsibilitycenters</name>
<children>
@@ -10133,6 +10259,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>md_parts_scan</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>md_tasks_presets</name>
<definition_loaded>false</definition_loaded>
@@ -17839,6 +17986,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>reports</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>required</name>
<definition_loaded>false</definition_loaded>
@@ -39411,6 +39579,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>committed_timetickets_ro</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>coversheet_landscape</name>
<definition_loaded>false</definition_loaded>
@@ -40151,6 +40340,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>parts_dispatch</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>parts_invoice_label_single</name>
<definition_loaded>false</definition_loaded>
@@ -40886,6 +41096,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>worksheet_sorted_by_team</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>
<folder_node>
@@ -41229,6 +41460,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>parts_dispatch</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>parts_order</name>
<definition_loaded>false</definition_loaded>
@@ -43064,6 +43316,69 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>committed_timetickets</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>committed_timetickets_employee</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>committed_timetickets_summary</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>credits_not_received_date</name>
<definition_loaded>false</definition_loaded>
@@ -45122,6 +45437,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>work_in_progress_committed_labour</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>work_in_progress_jobs</name>
<definition_loaded>false</definition_loaded>
@@ -46682,6 +47018,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>committed_at</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_center</name>
<definition_loaded>false</definition_loaded>
@@ -46703,6 +47060,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>created_by</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>date</name>
<definition_loaded>false</definition_loaded>

View File

@@ -28,26 +28,36 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
total: job.job_totals.totals.subtotal,
bold: true,
},
{
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"
...(job.job_totals.totals.us_sales_tax_breakdown
? [
{
key: t("jobs.fields.ca_bc_pvrt"),
total: job.job_totals.additional.pvrt,
key: bodyshop.md_responsibility_centers.taxes.tax_ty1.tax_type1,
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
},
{
key: bodyshop.md_responsibility_centers.taxes.tax_ty2.tax_type2,
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
},
{
key: bodyshop.md_responsibility_centers.taxes.tax_ty3.tax_type3,
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
},
{
key: bodyshop.md_responsibility_centers.taxes.tax_ty4.tax_type4,
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
},
{
key: bodyshop.md_responsibility_centers.taxes.tax_ty5.tax_type5,
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
},
]
: []),
{
key: t("jobs.labels.federal_tax_amt"),
total: job.job_totals.totals.federal_tax,
},
: [
{
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
]),
{
key: t("jobs.labels.total_repairs"),
total: job.job_totals.totals.total_repairs,
@@ -81,7 +91,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
bold: true,
},
];
}, [job.job_totals, t, bodyshop.region_config]);
}, [job.job_totals, t, bodyshop.md_responsibility_centers]);
const columns = [
{

View File

@@ -17,6 +17,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { useTreatments } from "@splitsoftware/splitio-react";
import ShopInfoResponsibilitycentersTaxesComponent from "./shop-info.responsibilitycenters.taxes.component";
const SelectorDiv = styled.div`
.ant-form-item .ant-select {
@@ -4445,6 +4446,7 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
<InputNumber precision={2} />
</Form.Item>
</LayoutFormRow>
<ShopInfoResponsibilitycentersTaxesComponent />
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.itemexemptcode")}
rules={[

View File

@@ -0,0 +1,232 @@
import { Divider, Form, Input, InputNumber, Space } from "antd";
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";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ShopInfoResponsibilityCenters);
export function ShopInfoResponsibilityCenters({ bodyshop }) {
//Iteratively build the form items.
const formItems = [];
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
const section = [];
section.push(
TaxFormItems({
typeNum: tyCounter,
rootElements: true,
bodyshop,
})
);
for (let iterator = 1; iterator <= 5; iterator++) {
section.push(
TaxFormItems({
typeNum: tyCounter,
typeNumIterator: iterator,
rootElements: false,
})
);
}
formItems.push(Space({ children: section, wrap: true }));
formItems.push(<Divider />);
}
return formItems;
}
function TaxFormItems({ typeNum, typeNumIterator, rootElements, bodyshop }) {
const { t } = useTranslation();
if (rootElements)
return (
<>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_type", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
`tax_type${typeNum}`,
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.state_tax")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
"name",
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountdesc")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
"accountdesc",
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_accountitem")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
"accountitem",
]}
>
<Input />
</Form.Item>
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Form.Item
label={t("bodyshop.fields.dms.dms_acctnumber")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
"dms_acctnumber",
]}
>
<Input />
</Form.Item>
)}
</>
);
return (
<>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_tier", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
`ty${typeNum}_tier${typeNumIterator}`,
]}
>
<InputNumber precision={0} min={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_thres", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
`ty${typeNum}_thres${typeNumIterator}`,
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_rate", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
`ty${typeNum}_rate${typeNumIterator}`,
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenter_tax_sur", {
typeNum,
typeNumIterator,
})}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name={[
"md_responsibility_centers",
"taxes",
`tax_ty${typeNum}`,
`ty${typeNum}_sur${typeNumIterator}`,
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
</>
);
}

View File

@@ -392,7 +392,7 @@ const transormJobToForm = (job) => {
Object.keys(job.parts_tax_rates).forEach((parttype) => {
Object.keys(job.parts_tax_rates[parttype]).forEach((key) => {
if (key.includes("tx_in")) {
if (job.parts_tax_rates[parttype][key] === "Y") {
if (job.parts_tax_rates[parttype][key] === "Y" || job.parts_tax_rates[parttype][key] === true) {
job.parts_tax_rates[parttype][key] = true;
} else {
job.parts_tax_rates[parttype][key] = false;

View File

@@ -473,6 +473,11 @@
"responsibilitycenter_accountname": "Account Name",
"responsibilitycenter_accountnumber": "Account Number",
"responsibilitycenter_rate": "Rate",
"responsibilitycenter_tax_rate": "Tax {{typeNum}} Tier {{typeNumIterator}} Rate",
"responsibilitycenter_tax_sur": "Tax {{typeNum}} Tier {{typeNumIterator}} Surcharge",
"responsibilitycenter_tax_thres": "Tax {{typeNum}} Tier {{typeNumIterator}} Threshold",
"responsibilitycenter_tax_tier": "Tax {{typeNum}} Tier {{typeNumIterator}}",
"responsibilitycenter_tax_type": "Tax {{typeNum}} Type",
"responsibilitycenters": {
"ap": "Accounts Payable",
"ar": "Accounts Receivable",
@@ -613,8 +618,8 @@
"jobstatuses": "Job Statuses",
"laborrates": "Labor Rates",
"licensing": "Licensing",
"md_tasks_presets": "Tasks Presets",
"md_parts_scan": "Parts Scan Rules",
"md_tasks_presets": "Tasks Presets",
"md_to_emails": "Preset To Emails",
"md_to_emails_emails": "Emails",
"messagingpresets": "Messaging Presets",

View File

@@ -63,6 +63,7 @@
"scheduledfor": "Cita programada para:",
"severalerrorsfound": "",
"smartscheduling": "",
"smspaymentreminder": "",
"suggesteddates": ""
},
"successes": {
@@ -472,6 +473,11 @@
"responsibilitycenter_accountname": "",
"responsibilitycenter_accountnumber": "",
"responsibilitycenter_rate": "",
"responsibilitycenter_tax_rate": "",
"responsibilitycenter_tax_sur": "",
"responsibilitycenter_tax_thres": "",
"responsibilitycenter_tax_tier": "",
"responsibilitycenter_tax_type": "",
"responsibilitycenters": {
"ap": "",
"ar": "",

View File

@@ -63,6 +63,7 @@
"scheduledfor": "Rendez-vous prévu pour:",
"severalerrorsfound": "",
"smartscheduling": "",
"smspaymentreminder": "",
"suggesteddates": ""
},
"successes": {
@@ -472,6 +473,11 @@
"responsibilitycenter_accountname": "",
"responsibilitycenter_accountnumber": "",
"responsibilitycenter_rate": "",
"responsibilitycenter_tax_rate": "",
"responsibilitycenter_tax_sur": "",
"responsibilitycenter_tax_thres": "",
"responsibilitycenter_tax_tier": "",
"responsibilitycenter_tax_type": "",
"responsibilitycenters": {
"ap": "",
"ar": "",

View File

@@ -767,6 +767,7 @@ function CalculateTaxesTotals(job, otherTotals) {
let statePartsTax = Dinero();
let additionalItemsTax = Dinero();
let us_sales_tax_breakdown;
//Audatex sends additional glass part types. IO-774
const BackupGlassTax =
@@ -977,8 +978,8 @@ function CalculateTaxesTotals(job, otherTotals) {
.add(totalTaxByTier.ty4Tax)
.add(totalTaxByTier.ty5Tax)
.add(totalTaxByTier.ty6Tax);
console.log("Tiered Taxes Total for Parts", statePartsTax.toFormat());
us_sales_tax_breakdown = totalTaxByTier;
console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
} else {
//Use the old thing.
job.joblines
@@ -1037,6 +1038,8 @@ function CalculateTaxesTotals(job, otherTotals) {
let laborTaxTotal = Dinero();
if (Object.keys(job.cieca_pfl).length > 0) {
//Ignore it now, we have calculated it above.
//This was previously used for JCS before parts were also calculated at a different rate.
} else {
//We don't have it, just add in how it was before.
laborTaxTotal = otherTotals.rates.subtotal.percentage(
@@ -1055,6 +1058,7 @@ function CalculateTaxesTotals(job, otherTotals) {
)
),
statePartsTax,
us_sales_tax_breakdown,
state_tax: statePartsTax
.add(laborTaxTotal)
.add(
@@ -1083,7 +1087,6 @@ function CalculateTaxesTotals(job, otherTotals) {
)
: Dinero()
),
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100),
};
ret.total_repairs = ret.subtotal