Time Ticket Task Improvmenets.

This commit is contained in:
Patrick Fic
2023-05-25 11:44:01 -07:00
parent 0849bbbba6
commit a56de72a6b
12 changed files with 449 additions and 222 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project version="1.2" be_version="2.7.1"> <babeledit_project be_version="2.7.1" version="1.2">
<!-- <!--
BabelEdit project file BabelEdit project file
@@ -5608,6 +5608,27 @@
<folder_node> <folder_node>
<name>md_tasks_presets</name> <name>md_tasks_presets</name>
<children> <children>
<concept_node>
<name>enable_tasks</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>hourstype</name> <name>hourstype</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -5692,6 +5713,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>use_approvals</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>
<concept_node> <concept_node>
@@ -8389,6 +8431,27 @@
<folder_node> <folder_node>
<name>ssbuckets</name> <name>ssbuckets</name>
<children> <children>
<concept_node>
<name>color</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>gte</name> <name>gte</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -40461,6 +40524,27 @@
</folder_node> </folder_node>
</children> </children>
</folder_node> </folder_node>
<concept_node>
<name>cardcolor</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>cardsettings</name> <name>cardsettings</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -40671,6 +40755,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>legend</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>note</name> <name>note</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -47825,6 +47930,53 @@
</concept_node> </concept_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>approval_queue_in_use</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>calculate</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> </children>
</folder_node> </folder_node>
<folder_node> <folder_node>

View File

@@ -246,11 +246,13 @@ function Header({
{t("menus.header.timetickets")} {t("menus.header.timetickets")}
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="ttapprovals" icon={<FieldTimeOutlined />}> {bodyshop?.md_tasks_presets?.use_approvals && (
<Link to="/manage/ttapprovals"> <Menu.Item key="ttapprovals" icon={<FieldTimeOutlined />}>
{t("menus.header.ttapprovals")} <Link to="/manage/ttapprovals">
</Link> {t("menus.header.ttapprovals")}
</Menu.Item> </Link>
</Menu.Item>
)}
<Menu.Item <Menu.Item
key="entertimetickets" key="entertimetickets"
icon={<Icon component={GiPlayerTime} />} icon={<Icon component={GiPlayerTime} />}

View File

@@ -247,21 +247,24 @@ export function JobsDetailHeaderActions({
> >
{t("timetickets.actions.enter")} {t("timetickets.actions.enter")}
</Menu.Item> </Menu.Item>
<Menu.Item {bodyshop.md_tasks_presets.enable_tasks && (
key="claimtimetickettasks" <Menu.Item
disabled={ key="claimtimetickettasks"
!job.converted || disabled={
(!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced) !job.converted ||
} (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced)
onClick={() => { }
setTimeTicketTaskContext({ onClick={() => {
actions: {}, setTimeTicketTaskContext({
context: { jobid: job.id }, actions: {},
}); context: { jobid: job.id },
}} });
> }}
{t("timetickets.actions.claimtasks")} >
</Menu.Item> {t("timetickets.actions.claimtasks")}
</Menu.Item>
)}
<Menu.Item <Menu.Item
key="enterpayments" key="enterpayments"
disabled={!job.converted} disabled={!job.converted}

View File

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

View File

@@ -205,16 +205,15 @@ export function TimeTicketList({
} }
}, },
}, },
{ // {
title: "Pay", // title: "Pay",
dataIndex: "pay", // dataIndex: "pay",
key: "pay", // key: "pay",
render: (text, record) => // render: (text, record) =>
Dinero({ amount: Math.round(record.rate * 100) }) // Dinero({ amount: Math.round(record.rate * 100) })
.multiply(record.flat_rate ? record.productivehrs : record.actualhrs) // .multiply(record.flat_rate ? record.productivehrs : record.actualhrs)
.toFormat("$0.00"), // .toFormat("$0.00"),
}, // },
{ {
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",
@@ -282,16 +281,18 @@ export function TimeTicketList({
// context={{ jobId: jobId }} // context={{ jobId: jobId }}
// /> // />
} }
<Button {bodyshop.md_tasks_presets.enable_tasks && (
onClick={() => { <Button
setTimeTicketTaskContext({ onClick={() => {
actions: {}, setTimeTicketTaskContext({
context: { jobid: jobId }, actions: {},
}); context: { jobid: jobId },
}} });
> }}
{t("timetickets.actions.claimtasks")} >
</Button> {t("timetickets.actions.claimtasks")}
</Button>
)}
{jobId && {jobId &&
(techConsole ? null : ( (techConsole ? null : (
<TimeTicketEnterButton <TimeTicketEnterButton

View File

@@ -23,6 +23,7 @@ import JobSearchSelectComponent from "../job-search-select/job-search-select.com
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility"; import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component"; import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
import TimeTicketsTasksPresets from "../time-ticket-tasks-presets/time-ticket-tasks-presets.component"; import TimeTicketsTasksPresets from "../time-ticket-tasks-presets/time-ticket-tasks-presets.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -54,7 +55,12 @@ export function TimeTicketTaskModalComponent({
calculateTimeTickets={calculateTimeTickets} calculateTimeTickets={calculateTimeTickets}
/> />
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col lg={12} md={24}> {bodyshop?.md_tasks_presets?.use_approvals && (
<Col span={24}>
<Alert message={t(".tt_approvals.labels.approval_queue_in_use")} />
</Col>
)}
<Col xl={12} lg={24}>
<Form.Item <Form.Item
name="jobid" name="jobid"
label={t("timetickets.fields.ro_number")} label={t("timetickets.fields.ro_number")}
@@ -77,37 +83,37 @@ export function TimeTicketTaskModalComponent({
> >
<EmployeeTeamSearchSelectComponent /> <EmployeeTeamSearchSelectComponent />
</Form.Item> </Form.Item>
<Space wrap>
<Form.Item
name="hourstype"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Checkbox.Group>
<Space wrap>
<Checkbox value="LAB" style={{ display: "flex" }}>
Body
</Checkbox>
<Checkbox value="LAR" style={{ display: "flex" }}>
Refinish
</Checkbox>
<Checkbox value="LAM" style={{ display: "flex" }}>
Mechanical
</Checkbox>
<Checkbox value="LAF" style={{ display: "flex" }}>
Frame
</Checkbox>
<Checkbox value="LAG" style={{ display: "flex" }}>
Glass
</Checkbox>
</Space>
</Checkbox.Group>
</Form.Item>
<Form.Item
name="hourstype"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Checkbox.Group>
<Space wrap>
<Checkbox value="LAB" style={{ display: "flex" }}>
{t("jobs.fields.lab")}
</Checkbox>
<Checkbox value="LAR" style={{ display: "flex" }}>
{t("jobs.fields.lar")}
</Checkbox>
<Checkbox value="LAM" style={{ display: "flex" }}>
{t("jobs.fields.lam")}
</Checkbox>
<Checkbox value="LAF" style={{ display: "flex" }}>
{t("jobs.fields.laf")}
</Checkbox>
<Checkbox value="LAG" style={{ display: "flex" }}>
{t("jobs.fields.lag")}
</Checkbox>
</Space>
</Checkbox.Group>
</Form.Item>
<Space wrap align="start">
<Form.Item <Form.Item
name="percent" name="percent"
rules={[ rules={[
@@ -119,10 +125,13 @@ export function TimeTicketTaskModalComponent({
> >
<InputNumber min={0} max={100} precision={1} addonAfter="%" /> <InputNumber min={0} max={100} precision={1} addonAfter="%" />
</Form.Item> </Form.Item>
<Button onClick={calculateTimeTickets}>
{t("tt_approvals.labels.calculate")}
</Button>
</Space> </Space>
<Button onClick={calculateTimeTickets}>Calculate</Button>
</Col> </Col>
<Col lg={12} md={24}> <Col xl={12} lg={24}>
<Form.Item shouldUpdate> <Form.Item shouldUpdate>
{() => { {() => {
const data = form.getFieldValue("timetickets"); const data = form.getFieldValue("timetickets");
@@ -167,11 +176,11 @@ export function TimeTicketTaskModalComponent({
dataIndex: "rate", dataIndex: "rate",
key: "rate", key: "rate",
}, },
{ // {
title: "Pay", // title: "Pay",
dataIndex: "pay", // dataIndex: "pay",
key: "pay", // key: "pay",
}, // },
]} ]}
/> />
); );
@@ -231,11 +240,9 @@ export function TimeTicketTaskModalComponent({
<Alert key={idx} message={e} /> <Alert key={idx} message={e} />
))} ))}
<div <div
style={ style={{
{ display: "none",
//display: "none" }}
}
}
> >
{fields.map((field, index) => ( {fields.map((field, index) => (
<Form.Item <Form.Item

View File

@@ -52,12 +52,8 @@ 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 (bodyshop.md_tasks_presets.use_approvals) {
const result = await insertTimeTicketApproval({ const result = await insertTimeTicketApproval({
variables: { variables: {
timeTicketInput: values.timetickets.map((ticket) => ({ timeTicketInput: values.timetickets.map((ticket) => ({
@@ -88,6 +84,7 @@ export function TimeTickeTaskModalContainer({
_.omit(ticket, "pay") _.omit(ticket, "pay")
), ),
}, },
refetchQueries: ["GET_LINE_TICKET_BY_PK"]
}); });
if (result.errors) { if (result.errors) {
notification.open({ notification.open({
@@ -105,6 +102,13 @@ export function TimeTickeTaskModalContainer({
} }
} }
} catch (error) { } catch (error) {
console.log("🚀 ~ file: time-ticket-task-modal.container.jsx:104 ~ handleFinish ~ error:", error)
notification.open({
type: "error",
message: t("timetickets.errors.creating", {
message: JSON.stringify(error),
}),
});
} finally { } finally {
} }
} }

View File

@@ -9,13 +9,16 @@ import { createStructuredSelector } from "reselect";
import { INSERT_TIME_TICKET_AND_APPROVE } from "../../graphql/timetickets.queries"; import { INSERT_TIME_TICKET_AND_APPROVE } from "../../graphql/timetickets.queries";
import { QUERY_TT_APPROVALS_BY_IDS } from "../../graphql/tt-approvals.queries"; import { QUERY_TT_APPROVALS_BY_IDS } from "../../graphql/tt-approvals.queries";
import { import {
selectAuthLevel,
selectBodyshop, selectBodyshop,
selectCurrentUser, selectCurrentUser,
} from "../../redux/user/user.selectors"; } from "../../redux/user/user.selectors";
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
authLevel: selectAuthLevel,
}); });
export function TtApproveButton({ export function TtApproveButton({
@@ -23,6 +26,7 @@ export function TtApproveButton({
currentUser, currentUser,
selectedTickets, selectedTickets,
disabled, disabled,
authLevel,
loadingCallback, loadingCallback,
completedCallback, completedCallback,
refetch, refetch,
@@ -83,7 +87,14 @@ export function TtApproveButton({
}; };
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled}> <Button
onClick={handleQbxml}
loading={loading}
disabled={
disabled ||
!HasRbacAccess({ bodyshop, authLevel, action: "ttapprovals:approve" })
}
>
{t("tt_approvals.actions.approveselected")} {t("tt_approvals.actions.approveselected")}
</Button> </Button>
); );

View File

@@ -46,9 +46,12 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
<Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees"> <Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees">
<ShopEmployeesContainer /> <ShopEmployeesContainer />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.employee_teams")} key="teams"> {
<ShopTeamsContainer /> bodyshop.md_tasks_presets.enable_tasks &&
</Tabs.TabPane> <Tabs.TabPane tab={t("bodyshop.labels.employee_teams")} key="teams">
<ShopTeamsContainer />
</Tabs.TabPane>
}
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing"> <Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
<ShopInfoUsersComponent /> <ShopInfoUsersComponent />
</Tabs.TabPane> </Tabs.TabPane>

View File

@@ -341,10 +341,12 @@
"md_payment_types": "Payment Types", "md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources", "md_referral_sources": "Referral Sources",
"md_tasks_presets": { "md_tasks_presets": {
"enable_tasks": "Enable Task Claiming",
"hourstype": "Hour Types", "hourstype": "Hour Types",
"memo": "Time Ticket Memo", "memo": "Time Ticket Memo",
"name": "Preset Name", "name": "Preset Name",
"percent": "Percent" "percent": "Percent",
"use_approvals": "Use Time Ticket Approval Queue"
}, },
"messaginglabel": "Messaging Preset Label", "messaginglabel": "Messaging Preset Label",
"messagingtext": "Messaging Preset Text", "messagingtext": "Messaging Preset Text",
@@ -521,12 +523,12 @@
"dailyhrslimit": "Daily Incoming Hours Limit" "dailyhrslimit": "Daily Incoming Hours Limit"
}, },
"ssbuckets": { "ssbuckets": {
"color": "Job Color",
"gte": "Greater Than/Equal to (hrs)", "gte": "Greater Than/Equal to (hrs)",
"id": "ID", "id": "ID",
"label": "Label", "label": "Label",
"lt": "Less than (hrs)", "lt": "Less than (hrs)",
"target": "Target (count)", "target": "Target (count)"
"color": "Job Color"
}, },
"state": "Province/State", "state": "Province/State",
"state_tax_id": "Provincial/State Tax ID (PST, QST)", "state_tax_id": "Provincial/State Tax ID (PST, QST)",
@@ -2399,6 +2401,7 @@
"qbo_usa": "QBO USA" "qbo_usa": "QBO USA"
} }
}, },
"cardcolor": "Card Colors",
"cardsettings": "Card Settings", "cardsettings": "Card Settings",
"clm_no": "Claim Number", "clm_no": "Claim Number",
"comment": "Comment", "comment": "Comment",
@@ -2409,6 +2412,7 @@
"ins_co_nm": "Insurance Company Name", "ins_co_nm": "Insurance Company Name",
"jobdetail": "Job Details", "jobdetail": "Job Details",
"laborhrs": "Labor Hours", "laborhrs": "Labor Hours",
"legend": "Legend:",
"note": "Production Note", "note": "Production Note",
"ownr_nm": "Owner Name", "ownr_nm": "Owner Name",
"paintpriority": "P/P", "paintpriority": "P/P",
@@ -2421,9 +2425,7 @@
"sublets": "Sublets", "sublets": "Sublets",
"totalhours": "Total Hrs ", "totalhours": "Total Hrs ",
"touchtime": "T/T", "touchtime": "T/T",
"viewname": "View Name", "viewname": "View Name"
"legend": "Legend:",
"cardcolor": "Card Colors"
}, },
"successes": { "successes": {
"removed": "Job removed from production." "removed": "Job removed from production."
@@ -2815,6 +2817,10 @@
"tt_approvals": { "tt_approvals": {
"actions": { "actions": {
"approveselected": "Approve Selected" "approveselected": "Approve Selected"
},
"labels": {
"approval_queue_in_use": "Time tickets will be added to the approval queue.",
"calculate": "Calculate"
} }
}, },
"user": { "user": {

View File

@@ -341,10 +341,12 @@
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
"md_tasks_presets": { "md_tasks_presets": {
"enable_tasks": "",
"hourstype": "", "hourstype": "",
"memo": "", "memo": "",
"name": "", "name": "",
"percent": "" "percent": "",
"use_approvals": ""
}, },
"messaginglabel": "", "messaginglabel": "",
"messagingtext": "", "messagingtext": "",
@@ -521,6 +523,7 @@
"dailyhrslimit": "" "dailyhrslimit": ""
}, },
"ssbuckets": { "ssbuckets": {
"color": "",
"gte": "", "gte": "",
"id": "", "id": "",
"label": "", "label": "",
@@ -2398,6 +2401,7 @@
"qbo_usa": "" "qbo_usa": ""
} }
}, },
"cardcolor": "",
"cardsettings": "", "cardsettings": "",
"clm_no": "", "clm_no": "",
"comment": "", "comment": "",
@@ -2408,6 +2412,7 @@
"ins_co_nm": "", "ins_co_nm": "",
"jobdetail": "", "jobdetail": "",
"laborhrs": "", "laborhrs": "",
"legend": "",
"note": "", "note": "",
"ownr_nm": "", "ownr_nm": "",
"paintpriority": "", "paintpriority": "",
@@ -2812,6 +2817,10 @@
"tt_approvals": { "tt_approvals": {
"actions": { "actions": {
"approveselected": "" "approveselected": ""
},
"labels": {
"approval_queue_in_use": "",
"calculate": ""
} }
}, },
"user": { "user": {

View File

@@ -341,10 +341,12 @@
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
"md_tasks_presets": { "md_tasks_presets": {
"enable_tasks": "",
"hourstype": "", "hourstype": "",
"memo": "", "memo": "",
"name": "", "name": "",
"percent": "" "percent": "",
"use_approvals": ""
}, },
"messaginglabel": "", "messaginglabel": "",
"messagingtext": "", "messagingtext": "",
@@ -521,6 +523,7 @@
"dailyhrslimit": "" "dailyhrslimit": ""
}, },
"ssbuckets": { "ssbuckets": {
"color": "",
"gte": "", "gte": "",
"id": "", "id": "",
"label": "", "label": "",
@@ -2398,6 +2401,7 @@
"qbo_usa": "" "qbo_usa": ""
} }
}, },
"cardcolor": "",
"cardsettings": "", "cardsettings": "",
"clm_no": "", "clm_no": "",
"comment": "", "comment": "",
@@ -2408,6 +2412,7 @@
"ins_co_nm": "", "ins_co_nm": "",
"jobdetail": "", "jobdetail": "",
"laborhrs": "", "laborhrs": "",
"legend": "",
"note": "", "note": "",
"ownr_nm": "", "ownr_nm": "",
"paintpriority": "", "paintpriority": "",
@@ -2812,6 +2817,10 @@
"tt_approvals": { "tt_approvals": {
"actions": { "actions": {
"approveselected": "" "approveselected": ""
},
"labels": {
"approval_queue_in_use": "",
"calculate": ""
} }
}, },
"user": { "user": {