IO-1157 Add mapa/mash costs to costing.

This commit is contained in:
Patrick Fic
2021-05-27 14:04:52 -07:00
parent 0b21b8d976
commit d91a83a137
17 changed files with 474 additions and 9 deletions

View File

@@ -3339,6 +3339,53 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<folder_node>
<name>jc_hourly_rates</name>
<children>
<concept_node>
<name>mapa</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>mash</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>
<concept_node> <concept_node>
<name>lastnumberworkingdays</name> <name>lastnumberworkingdays</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -16,7 +16,7 @@ import PhoneFormItem, {
} from "../form-items-formatted/phone-form-item.component"; } from "../form-items-formatted/phone-form-item.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
export default function ShopInfoGeneral({ form }) { export default function ShopInfoGeneral({ form }) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@@ -425,6 +425,18 @@ export default function ShopInfoGeneral({ form }) {
> >
<InputNumber min={0} max={1} precision={2} /> <InputNumber min={0} max={1} precision={2} />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.jc_hourly_rates.mapa")}
name={["jc_hourly_rates", "mapa"]}
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.jc_hourly_rates.mash")}
name={["jc_hourly_rates", "mash"]}
>
<CurrencyInput />
</Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}> <LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
<Form.List name={["md_messaging_presets"]}> <Form.List name={["md_messaging_presets"]}>

View File

@@ -87,6 +87,7 @@ export const QUERY_BODYSHOP = gql`
md_ccc_rates md_ccc_rates
enforce_referral enforce_referral
website website
jc_hourly_rates
employees { employees {
id id
active active
@@ -171,6 +172,7 @@ export const UPDATE_SHOP = gql`
md_ccc_rates md_ccc_rates
enforce_referral enforce_referral
website website
jc_hourly_rates
employees { employees {
id id
first_name first_name

View File

@@ -218,6 +218,10 @@
"invoice_federal_tax_rate": "Invoices - Federal Tax Rate", "invoice_federal_tax_rate": "Invoices - Federal Tax Rate",
"invoice_local_tax_rate": "Invoices - Local Tax Rate", "invoice_local_tax_rate": "Invoices - Local Tax Rate",
"invoice_state_tax_rate": "Invoices - Provincial/State Tax Rate", "invoice_state_tax_rate": "Invoices - Provincial/State Tax Rate",
"jc_hourly_rates": {
"mapa": "Job Costing - Paint Materials Hourly Cost Rate",
"mash": "Job Costing - Shop Materials Hourly Cost Rate"
},
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days", "lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
"logo_img_path": "Shop Logo", "logo_img_path": "Shop Logo",
"logo_img_path_height": "Logo Image Height", "logo_img_path_height": "Logo Image Height",

View File

@@ -218,6 +218,10 @@
"invoice_federal_tax_rate": "", "invoice_federal_tax_rate": "",
"invoice_local_tax_rate": "", "invoice_local_tax_rate": "",
"invoice_state_tax_rate": "", "invoice_state_tax_rate": "",
"jc_hourly_rates": {
"mapa": "",
"mash": ""
},
"lastnumberworkingdays": "", "lastnumberworkingdays": "",
"logo_img_path": "", "logo_img_path": "",
"logo_img_path_height": "", "logo_img_path_height": "",

View File

@@ -218,6 +218,10 @@
"invoice_federal_tax_rate": "", "invoice_federal_tax_rate": "",
"invoice_local_tax_rate": "", "invoice_local_tax_rate": "",
"invoice_state_tax_rate": "", "invoice_state_tax_rate": "",
"jc_hourly_rates": {
"mapa": "",
"mash": ""
},
"lastnumberworkingdays": "", "lastnumberworkingdays": "",
"logo_img_path": "", "logo_img_path": "",
"logo_img_path_height": "", "logo_img_path_height": "",

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD CONSTRAINT "bodyshops_autohouseid_key"
UNIQUE ("autohouseid");
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP CONSTRAINT "bodyshops_autohouseid_key";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "jc_hourly_rates";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "jc_hourly_rates" jsonb NULL
DEFAULT jsonb_build_object();
type: run_sql

View File

@@ -0,0 +1,83 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- enforce_referral
- federal_tax_id
- id
- imexshopid
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- jobsizelimit
- logo_img_path
- md_categories
- md_ccc_rates
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- phone
- prodtargethrs
- production_config
- region_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- sub_status
- target_touchtime
- template_header
- textid
- updated_at
- use_fippa
- website
- workingdays
- zip_post
computed_fields: []
filter:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,84 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- enforce_referral
- federal_tax_id
- id
- imexshopid
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- jc_hourly_rates
- jobsizelimit
- logo_img_path
- md_categories
- md_ccc_rates
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- phone
- prodtargethrs
- production_config
- region_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- sub_status
- target_touchtime
- template_header
- textid
- updated_at
- use_fippa
- website
- workingdays
- zip_post
computed_fields: []
filter:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,77 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- enforce_referral
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- logo_img_path
- md_categories
- md_ccc_rates
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- phone
- prodtargethrs
- production_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- target_touchtime
- updated_at
- use_fippa
- website
- workingdays
- zip_post
filter:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -0,0 +1,78 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- enforce_referral
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- jc_hourly_rates
- logo_img_path
- md_categories
- md_ccc_rates
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- phone
- prodtargethrs
- production_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- target_touchtime
- updated_at
- use_fippa
- website
- workingdays
- zip_post
filter:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -771,6 +771,7 @@ tables:
- inhousevendorid - inhousevendorid
- insurance_vendor_id - insurance_vendor_id
- intakechecklist - intakechecklist
- jc_hourly_rates
- jobsizelimit - jobsizelimit
- logo_img_path - logo_img_path
- md_categories - md_categories
@@ -841,6 +842,7 @@ tables:
- inhousevendorid - inhousevendorid
- insurance_vendor_id - insurance_vendor_id
- intakechecklist - intakechecklist
- jc_hourly_rates
- logo_img_path - logo_img_path
- md_categories - md_categories
- md_ccc_rates - md_ccc_rates

View File

@@ -680,6 +680,7 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid!
bodyshop{ bodyshop{
id id
md_responsibility_centers md_responsibility_centers
jc_hourly_rates
} }
} }
}`; }`;
@@ -780,6 +781,7 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT
bodyshop { bodyshop {
id id
md_responsibility_centers md_responsibility_centers
jc_hourly_rates
} }
} }
} }

View File

@@ -10,8 +10,7 @@ Dinero.globalRoundingMode = "HALF_EVEN";
async function JobCosting(req, res) { async function JobCosting(req, res) {
const { jobid } = req.body; const { jobid } = req.body;
console.log("🚀 ~ file: job-costing.js ~ line 13 ~ jobid", jobid); console.time("Query for Data");
console.time("querydata");
const BearerToken = req.headers.authorization; const BearerToken = req.headers.authorization;
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, { const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
@@ -209,6 +208,8 @@ function GenerateCostingData(job) {
job.bodyshop.md_responsibility_centers.costs.map((p) => p.name) job.bodyshop.md_responsibility_centers.costs.map((p) => p.name)
); );
const materialsHours = { mapaHrs: 0, mashHrs: 0 };
//Massage the data. //Massage the data.
const jobLineTotalsByProfitCenter = const jobLineTotalsByProfitCenter =
job && job &&
@@ -234,6 +235,7 @@ function GenerateCostingData(job) {
if (!acc.labor[defaultProfits["MAPA"]]) if (!acc.labor[defaultProfits["MAPA"]])
acc.labor[defaultProfits["MAPA"]] = Dinero(); acc.labor[defaultProfits["MAPA"]] = Dinero();
materialsHours.mapaHrs += val.mod_lb_hrs || 0;
acc.labor[defaultProfits["MAPA"]] = acc.labor[ acc.labor[defaultProfits["MAPA"]] = acc.labor[
defaultProfits["MAPA"] defaultProfits["MAPA"]
].add( ].add(
@@ -253,6 +255,7 @@ function GenerateCostingData(job) {
amount: Math.round((job.rate_mash || 0) * 100), amount: Math.round((job.rate_mash || 0) * 100),
}).multiply(val.mod_lb_hrs || 0) }).multiply(val.mod_lb_hrs || 0)
); );
materialsHours.mashHrs += val.mod_lb_hrs || 0;
} }
//If labor line, add to paint and shop materials. //If labor line, add to paint and shop materials.
} }
@@ -309,12 +312,7 @@ function GenerateCostingData(job) {
.multiply(val.part_qty || 0) .multiply(val.part_qty || 0)
.percentage(val.prt_dsmk_p) .percentage(val.prt_dsmk_p)
); );
console.log(
`*** partsAmount`,
val.line_desc,
partsProfitCenter,
partsAmount.toJSON()
);
if (!acc.parts[partsProfitCenter]) if (!acc.parts[partsProfitCenter])
acc.parts[partsProfitCenter] = Dinero(); acc.parts[partsProfitCenter] = Dinero();
acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter] =
@@ -348,6 +346,52 @@ function GenerateCostingData(job) {
return bill_acc; return bill_acc;
}, {}); }, {});
//If the hourly rates for job costing are set, add them in.
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mapa) {
if (
!billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
]
)
billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
] = Dinero();
billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
] = billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
].add(
Dinero({
amount:
(job.bodyshop.jc_hourly_rates &&
job.bodyshop.jc_hourly_rates.mapa * 100) ||
0,
}).multiply(materialsHours.mapaHrs)
);
}
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mash) {
if (
!billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
]
)
billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
] = Dinero();
billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
] = billTotalsByCostCenters[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
].add(
Dinero({
amount:
(job.bodyshop.jc_hourly_rates &&
job.bodyshop.jc_hourly_rates.mash * 100) ||
0,
}).multiply(materialsHours.mashHrs)
);
}
const ticketTotalsByCostCenter = job.timetickets.reduce( const ticketTotalsByCostCenter = job.timetickets.reduce(
(ticket_acc, ticket_val) => { (ticket_acc, ticket_val) => {
//At the invoice level. //At the invoice level.