Merge branch 'feature/payroll' into feature/america

This commit is contained in:
Patrick Fic
2023-05-17 07:51:57 -07:00
15 changed files with 470 additions and 32 deletions

View File

@@ -3602,6 +3602,27 @@
<folder_node> <folder_node>
<name>actions</name> <name>actions</name>
<children> <children>
<concept_node>
<name>add_task_preset</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>addapptcolor</name> <name>addapptcolor</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -5584,6 +5605,95 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<folder_node>
<name>md_tasks_presets</name>
<children>
<concept_node>
<name>hourstype</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>memo</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>name</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>percent</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>messaginglabel</name> <name>messaginglabel</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -9771,6 +9881,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>md_tasks_presets</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>md_to_emails</name> <name>md_to_emails</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -10280,6 +10411,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>task-presets</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>workingdays</name> <name>workingdays</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -14809,6 +14961,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>newmember</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> </children>
</folder_node> </folder_node>
<folder_node> <folder_node>
@@ -14835,6 +15008,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>employeeid</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>name</name> <name>name</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -14856,6 +15050,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>percentage</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> </children>
</folder_node> </folder_node>
</children> </children>

View File

@@ -1,5 +1,6 @@
import Dinero from "dinero.js";
import { Card } from "antd"; import { Card } from "antd";
import Dinero from "dinero.js";
import _ from "lodash";
import moment from "moment"; import moment from "moment";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -18,7 +19,6 @@ import {
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util"; import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
import _ from "lodash";
import CustomTooltip from "./chart-custom-tooltip"; import CustomTooltip from "./chart-custom-tooltip";
const graphProps = { const graphProps = {
@@ -71,7 +71,9 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
bodyshop.scoreboard_target.dailyBodyTarget + bodyshop.scoreboard_target.dailyBodyTarget +
bodyshop.scoreboard_target.dailyPaintTarget, bodyshop.scoreboard_target.dailyPaintTarget,
val val
), ) +
bodyshop.scoreboard_target.dailyBodyTarget +
bodyshop.scoreboard_target.dailyPaintTarget,
1 1
), ),
accHrs: _.round( accHrs: _.round(

View File

@@ -15,6 +15,7 @@ import ShopInfoResponsibilityCenterComponent from "./shop-info.responsibilitycen
import ShopInfoROStatusComponent from "./shop-info.rostatus.component"; import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component"; import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
import ShopInfoSpeedPrint from "./shop-info.speedprint.component"; import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -83,6 +84,12 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
<ShopInfoPartsScan form={form} /> <ShopInfoPartsScan form={form} />
</Tabs.TabPane> </Tabs.TabPane>
)} )}
<Tabs.TabPane
key="task-presets"
tab={t("bodyshop.labels.task-presets")}
>
<ShopInfoTaskPresets form={form} />
</Tabs.TabPane>
</Tabs> </Tabs>
</Card> </Card>
); );

View File

@@ -0,0 +1,144 @@
import { DeleteFilled } from "@ant-design/icons";
import {
Button,
Checkbox,
Col,
Form,
Input,
InputNumber,
Row,
Space,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function ShopInfoTaskPresets({ form }) {
const { t } = useTranslation();
return (
<LayoutFormRow header={t("bodyshop.labels.md_tasks_presets")}>
<Form.List name={["md_tasks_presets", "presets"]}>
{(fields, { add, remove, move }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key}>
<LayoutFormRow noDivider>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.name")}
key={`${index}name`}
name={[field.name, "name"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.hourstype")}
key={`${index}hourstype`}
name={[field.name, "hourstype"]}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Checkbox.Group>
<Row>
<Col span={8}>
<Checkbox
value="LAB"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAB")}
</Checkbox>
</Col>
<Col span={8}>
<Checkbox
value="LAR"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAR")}
</Checkbox>
</Col>
<Col span={8}>
<Checkbox
value="LAM"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAM")}
</Checkbox>
</Col>
<Col span={8}>
<Checkbox
value="LAF"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAF")}
</Checkbox>
</Col>
<Col span={8}>
<Checkbox
value="LAG"
style={{ lineHeight: "32px" }}
>
{t("joblines.fields.lbr_types.LAG")}
</Checkbox>
</Col>
</Row>
</Checkbox.Group>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.percent")}
key={`${index}percent`}
name={[field.name, "percent"]}
>
<InputNumber min={0} max={100} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_tasks_presets.memo")}
key={`${index}memo`}
name={[field.name, "memo"]}
>
<Input />
</Form.Item>
<Space wrap>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
</Space>
</LayoutFormRow>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
{t("bodyshop.actions.add_task_preset")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</LayoutFormRow>
);
}

View File

@@ -52,6 +52,10 @@ export function TimeTickeTaskModalContainer({
}); });
async function handleFinish(values) { async function handleFinish(values) {
console.log(
"🚀 ~ file: time-ticket-task-modal.container.jsx:55 ~ handleFinish ~ values:",
values
);
try { try {
if (true) { if (true) {
const result = await insertTimeTicketApproval({ const result = await insertTimeTicketApproval({
@@ -112,7 +116,6 @@ export function TimeTickeTaskModalContainer({
}, [context.jobid, queryJobInfo, visible]); }, [context.jobid, queryJobInfo, visible]);
const calculateTimeTickets = (presetMemo) => { const calculateTimeTickets = (presetMemo) => {
console.log("🚀 ~ file: time-ticket-task-modal.container.jsx:115 ~ calculateTimeTickets ~ presetMemo:", presetMemo)
const formData = form.getFieldsValue(); const formData = form.getFieldsValue();
if ( if (
!formData.jobid || !formData.jobid ||
@@ -147,7 +150,7 @@ export function TimeTickeTaskModalContainer({
jobid: formData.jobid, jobid: formData.jobid,
rate: e.labor_rates[hourstype], rate: e.labor_rates[hourstype],
actualhrs: 0, actualhrs: 0,
memo: presetMemo, memo: typeof presetMemo === "string" ? presetMemo : "",
flat_rate: true, flat_rate: true,
ciecacode: hourstype, ciecacode: hourstype,
cost_center: cost_center:

View File

@@ -1,12 +1,28 @@
import { Button, Dropdown } from "antd"; import { Button, Dropdown } from "antd";
import React from "react"; import React from "react";
export default function TimeTicketsTasksPresets({ 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
)(TimeTicketsTasksPresets);
export function TimeTicketsTasksPresets({
bodyshop,
form, form,
calculateTimeTickets, calculateTimeTickets,
}) { }) {
const handleClick = (props) => { const handleClick = (props) => {
const preset = samplePresets.find((p) => { const preset = bodyshop.md_tasks_presets?.presets?.find((p) => {
return p.name === props.key; return p.name === props.key;
}); });
@@ -24,7 +40,12 @@ export default function TimeTicketsTasksPresets({
<Dropdown <Dropdown
trigger="click" trigger="click"
menu={{ menu={{
items: samplePresets.map((p) => ({ label: p.name, key: p.name })), items: bodyshop.md_tasks_presets?.presets
? bodyshop.md_tasks_presets?.presets?.map((p) => ({
label: p.name,
key: p.name,
}))
: [],
onClick: handleClick, onClick: handleClick,
}} }}
> >
@@ -33,19 +54,19 @@ export default function TimeTicketsTasksPresets({
); );
} }
const samplePresets = [ // const samplePresets = [
{ // {
name: "Teardown", // name: "Teardown",
hourstype: ["LAB", "LAM"], // hourstype: ["LAB", "LAM"],
percent: 10, // percent: 10,
memo: "Teardown Preset Task", // memo: "Teardown Preset Task",
}, // },
{ // {
name: "Disassembly", // name: "Disassembly",
hourstype: ["LAB", "LAD"], // hourstype: ["LAB", "LAD"],
percent: 20, // percent: 20,
memo: "Disassy Preset Claim", // memo: "Disassy Preset Claim",
}, // },
{ name: "Body", hourstype: ["LAB", "LAD"], percent: 20 }, // { name: "Body", hourstype: ["LAB", "LAD"], percent: 20 },
{ name: "Prep", hourstype: ["LAR"], percent: 20 }, // { name: "Prep", hourstype: ["LAR"], percent: 20 },
]; // ];

View File

@@ -117,6 +117,7 @@ export const QUERY_BODYSHOP = gql`
md_parts_scan md_parts_scan
enforce_conversion_category enforce_conversion_category
tt_enforce_hours_for_tech_console tt_enforce_hours_for_tech_console
md_tasks_presets
use_paint_scale_data use_paint_scale_data
employees { employees {
user_email user_email
@@ -233,6 +234,7 @@ export const UPDATE_SHOP = gql`
md_parts_scan md_parts_scan
enforce_conversion_category enforce_conversion_category
tt_enforce_hours_for_tech_console tt_enforce_hours_for_tech_console
md_tasks_presets
employees { employees {
id id
first_name first_name

View File

@@ -67,7 +67,7 @@ export const GET_LINE_TICKET_BY_PK = gql`
clockoff clockoff
rate rate
committed_at committed_at
committed_by commited_by
employee { employee {
id id
first_name first_name

View File

@@ -159,7 +159,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
memo memo
jobid jobid
committed_at committed_at
committed_by commited_by
flat_rate flat_rate
job { job {
id id

View File

@@ -227,6 +227,7 @@
}, },
"bodyshop": { "bodyshop": {
"actions": { "actions": {
"add_task_preset": "Add Task Preset",
"addapptcolor": "Add Appointment Color", "addapptcolor": "Add Appointment Color",
"addbucket": "Add Definition", "addbucket": "Add Definition",
"addpartslocation": "Add Parts Location", "addpartslocation": "Add Parts Location",
@@ -339,6 +340,12 @@
}, },
"md_payment_types": "Payment Types", "md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources", "md_referral_sources": "Referral Sources",
"md_tasks_presets": {
"hourstype": "Hour Types",
"memo": "Time Ticket Memo",
"name": "Preset Name",
"percent": "Percent"
},
"messaginglabel": "Messaging Preset Label", "messaginglabel": "Messaging Preset Label",
"messagingtext": "Messaging Preset Text", "messagingtext": "Messaging Preset Text",
"noteslabel": "Note Label", "noteslabel": "Note Label",
@@ -594,6 +601,7 @@
"jobstatuses": "Job Statuses", "jobstatuses": "Job Statuses",
"laborrates": "Labor Rates", "laborrates": "Labor Rates",
"licensing": "Licensing", "licensing": "Licensing",
"md_tasks_presets": "Tasks Presets",
"md_to_emails": "Preset To Emails", "md_to_emails": "Preset To Emails",
"md_to_emails_emails": "Emails", "md_to_emails_emails": "Emails",
"messagingpresets": "Messaging Presets", "messagingpresets": "Messaging Presets",
@@ -620,6 +628,7 @@
"speedprint": "Speed Print Configuration", "speedprint": "Speed Print Configuration",
"ssbuckets": "Job Size Definitions", "ssbuckets": "Job Size Definitions",
"systemsettings": "System Settings", "systemsettings": "System Settings",
"task-presets": "Task Presets",
"workingdays": "Working Days" "workingdays": "Working Days"
}, },
"successes": { "successes": {
@@ -921,11 +930,14 @@
}, },
"employee_teams": { "employee_teams": {
"actions": { "actions": {
"new": "New Team" "new": "New Team",
"newmember": "New Team Member"
}, },
"fields": { "fields": {
"active": "Active", "active": "Active",
"name": "Team Name" "employeeid": "Employee",
"name": "Team Name",
"percentage": "Percent"
} }
}, },
"employees": { "employees": {

View File

@@ -227,6 +227,7 @@
}, },
"bodyshop": { "bodyshop": {
"actions": { "actions": {
"add_task_preset": "",
"addapptcolor": "", "addapptcolor": "",
"addbucket": "", "addbucket": "",
"addpartslocation": "", "addpartslocation": "",
@@ -339,6 +340,12 @@
}, },
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
"md_tasks_presets": {
"hourstype": "",
"memo": "",
"name": "",
"percent": ""
},
"messaginglabel": "", "messaginglabel": "",
"messagingtext": "", "messagingtext": "",
"noteslabel": "", "noteslabel": "",
@@ -593,6 +600,7 @@
"jobstatuses": "", "jobstatuses": "",
"laborrates": "", "laborrates": "",
"licensing": "", "licensing": "",
"md_tasks_presets": "",
"md_to_emails": "", "md_to_emails": "",
"md_to_emails_emails": "", "md_to_emails_emails": "",
"messagingpresets": "", "messagingpresets": "",
@@ -619,6 +627,7 @@
"speedprint": "", "speedprint": "",
"ssbuckets": "", "ssbuckets": "",
"systemsettings": "", "systemsettings": "",
"task-presets": "",
"workingdays": "" "workingdays": ""
}, },
"successes": { "successes": {
@@ -920,11 +929,14 @@
}, },
"employee_teams": { "employee_teams": {
"actions": { "actions": {
"new": "" "new": "",
"newmember": ""
}, },
"fields": { "fields": {
"active": "", "active": "",
"name": "" "employeeid": "",
"name": "",
"percentage": ""
} }
}, },
"employees": { "employees": {

View File

@@ -227,6 +227,7 @@
}, },
"bodyshop": { "bodyshop": {
"actions": { "actions": {
"add_task_preset": "",
"addapptcolor": "", "addapptcolor": "",
"addbucket": "", "addbucket": "",
"addpartslocation": "", "addpartslocation": "",
@@ -339,6 +340,12 @@
}, },
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
"md_tasks_presets": {
"hourstype": "",
"memo": "",
"name": "",
"percent": ""
},
"messaginglabel": "", "messaginglabel": "",
"messagingtext": "", "messagingtext": "",
"noteslabel": "", "noteslabel": "",
@@ -593,6 +600,7 @@
"jobstatuses": "", "jobstatuses": "",
"laborrates": "", "laborrates": "",
"licensing": "", "licensing": "",
"md_tasks_presets": "",
"md_to_emails": "", "md_to_emails": "",
"md_to_emails_emails": "", "md_to_emails_emails": "",
"messagingpresets": "", "messagingpresets": "",
@@ -619,6 +627,7 @@
"speedprint": "", "speedprint": "",
"ssbuckets": "", "ssbuckets": "",
"systemsettings": "", "systemsettings": "",
"task-presets": "",
"workingdays": "" "workingdays": ""
}, },
"successes": { "successes": {
@@ -920,11 +929,14 @@
}, },
"employee_teams": { "employee_teams": {
"actions": { "actions": {
"new": "" "new": "",
"newmember": ""
}, },
"fields": { "fields": {
"active": "", "active": "",
"name": "" "employeeid": "",
"name": "",
"percentage": ""
} }
}, },
"employees": { "employees": {

View File

@@ -941,6 +941,7 @@
- md_referral_sources - md_referral_sources
- md_responsibility_centers - md_responsibility_centers
- md_ro_statuses - md_ro_statuses
- md_tasks_presets
- md_to_emails - md_to_emails
- messagingservicesid - messagingservicesid
- pbs_configuration - pbs_configuration
@@ -1038,6 +1039,7 @@
- md_referral_sources - md_referral_sources
- md_responsibility_centers - md_responsibility_centers
- md_ro_statuses - md_ro_statuses
- md_tasks_presets
- md_to_emails - md_to_emails
- pbs_configuration - pbs_configuration
- phone - phone

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "md_tasks_presets" jsonb
-- not null default jsonb_build_object();

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "md_tasks_presets" jsonb
not null default jsonb_build_object();