diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 7e79e45eb..20252a51f 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -7550,6 +7550,32 @@ dms + + cdk + + + payers + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + cdk_dealerid false @@ -23006,6 +23032,32 @@ + + dms + + + kmoutnotgreaterthankmin + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + documents false diff --git a/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx b/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx index 79ba67527..142ca8671 100644 --- a/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx +++ b/client/src/components/dms-allocations-summary/dms-allocations-summary.component.jsx @@ -1,17 +1,21 @@ -import { Button, Table } from "antd"; -import React, { useState } from "react"; +import { Button, Table, Typography } from "antd"; +import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import Dinero from "dinero.js"; +import { SyncOutlined } from "@ant-design/icons"; + const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, }); + const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); + export default connect( mapStateToProps, mapDispatchToProps @@ -20,6 +24,15 @@ export default connect( export function DmsAllocationsSummary({ socket, bodyshop, jobId }) { const { t } = useTranslation(); const [allocationsSummary, setAllocationsSummary] = useState([]); + + useEffect(() => { + if (socket.connected) { + socket.emit("cdk-calculate-allocations", jobId, (ack) => + setAllocationsSummary(ack) + ); + } + }, [socket, socket.connected, jobId]); + const columns = [ { title: t("jobs.fields.dms.center"), @@ -71,13 +84,45 @@ export function DmsAllocationsSummary({ socket, bodyshop, jobId }) { ); }} > - Get + )} pagination={{ position: "top", defaultPageSize: 50 }} columns={columns} rowKey="center" dataSource={allocationsSummary} + summary={() => { + const totals = allocationsSummary.reduce( + (acc, val) => { + return { + totalSale: acc.totalSale.add(Dinero(val.sale)), + totalCost: acc.totalCost.add(Dinero(val.cost)), + }; + }, + { + totalSale: Dinero(), + totalCost: Dinero(), + } + ); + + return ( + + + + {t("general.labels.totals")} + + + + {totals.totalSale.toFormat()} + + + {totals.totalCost.toFormat()} + + + + + ); + }} /> ); } diff --git a/client/src/components/dms-cdk-makes/dms-cdk-makes.component.jsx b/client/src/components/dms-cdk-makes/dms-cdk-makes.component.jsx index c972178b1..89ad19179 100644 --- a/client/src/components/dms-cdk-makes/dms-cdk-makes.component.jsx +++ b/client/src/components/dms-cdk-makes/dms-cdk-makes.component.jsx @@ -4,6 +4,9 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { useTranslation } from "react-i18next"; +import { useLazyQuery } from "@apollo/client"; +import { SEARCH_DMS_VEHICLES } from "../../graphql/dms.queries"; +import AlertComponent from "../alert/alert.component"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser @@ -12,83 +15,75 @@ const mapStateToProps = createStructuredSelector({ const mapDispatchToProps = (dispatch) => ({ //setUserLanguage: language => dispatch(setUserLanguage(language)) }); -export default connect(mapStateToProps, mapDispatchToProps)(DmsCdkMakes); +export default connect(mapStateToProps, mapDispatchToProps)(DmsCdkVehicles); -export function DmsCdkMakes({ bodyshop, form, socket }) { - const [makesList, setMakesList] = useState([]); - const [searchText, setSearchText] = useState(""); - const [loading, setLoading] = useState(false); +export function DmsCdkVehicles({ bodyshop, form, socket, job }) { const [visible, setVisible] = useState(false); const [selectedModel, setSelectedModel] = useState(null); const { t } = useTranslation(); + + const [callSearch, { loading, error, data }] = + useLazyQuery(SEARCH_DMS_VEHICLES); const columns = [ { - title: t("jobs.fields.dms.makeFullName"), - dataIndex: "makeFullName", - key: "makeFullName", + title: t("jobs.fields.dms.make"), + dataIndex: "make", + key: "make", }, { - title: t("jobs.fields.dms.modelFullName"), - dataIndex: "modelFullName", - key: "modelFullName", + title: t("jobs.fields.dms.model"), + dataIndex: "model", + key: "model", }, { - title: t("jobs.fields.dms.makeCode"), - dataIndex: "makeCode", - key: "makeCode", + title: t("jobs.fields.dms.makecode"), + dataIndex: "makecode", + key: "makecode", }, { - title: t("jobs.fields.dms.modelCode"), - dataIndex: "modelCode", - key: "modelCode", + title: t("jobs.fields.dms.modelcode"), + dataIndex: "modelcode", + key: "modelcode", }, ]; - const filteredMakes = - searchText !== "" && searchText - ? makesList.filter( - (make) => - searchText - .split(" ") - .some((v) => - make.makeFullName.toLowerCase().includes(v.toLowerCase()) - ) || - searchText - .split(" ") - .some((v) => - make.modelFullName.toLowerCase().includes(v.toLowerCase()) - ) - ) - : makesList; - + console.log( + "🚀 ~ file: dms-cdk-makes.component.jsx ~ line 95 ~ selectedModel", + selectedModel + ); return (
- setVisible(false)}> + setVisible(false)} + onOk={() => { + form.setFieldsValue({ + dms_make: selectedModel.makecode, + dms_model: selectedModel.modelcode, + }); + setVisible(false); + }} + > + {error && } ( setSearchText(val)} + onSearch={(val) => callSearch({ variables: { search: val } })} placeholder={t("general.labels.search")} /> )} columns={columns} loading={loading} - id="id" - dataSource={filteredMakes} + rowKey="id" + dataSource={data ? data.search_dms_vehicles : []} onRow={(record) => { return { - onClick: setSelectedModel(record), + onClick: () => setSelectedModel(record), }; }} rowSelection={{ - onSelect: (record, selected, ...props) => { - console.log( - "🚀 ~ file: dms-cdk-makes.component.jsx ~ line 85 ~ record, selected, ...props", - record, - selected, - ...props - ); - + onSelect: (record) => { setSelectedModel(record); }, @@ -100,15 +95,14 @@ export function DmsCdkMakes({ bodyshop, form, socket }) { ); diff --git a/client/src/components/dms-cdk-makes/dms-cdk-makes.refetch.component.jsx b/client/src/components/dms-cdk-makes/dms-cdk-makes.refetch.component.jsx new file mode 100644 index 000000000..a154e819d --- /dev/null +++ b/client/src/components/dms-cdk-makes/dms-cdk-makes.refetch.component.jsx @@ -0,0 +1,32 @@ +import { Button } from "antd"; +import axios from "axios"; +import React, { useState } from "react"; +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)(DmsCdkMakesRefetch); + +export function DmsCdkMakesRefetch({ bodyshop, form, socket }) { + const [loading, setLoading] = useState(false); + const handleRefetch = async () => { + setLoading(true); + const response = await axios.post("/cdk/getvehicles", { + cdk_dealerid: bodyshop.cdk_dealerid, + bodyshopid: bodyshop.id, + }); + console.log(response); + setLoading(false); + }; + return ( + + ); +} diff --git a/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx index b85d1ff38..46be3d6d3 100644 --- a/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx +++ b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx @@ -1,10 +1,24 @@ import { Button, Table } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; import { socket } from "../../pages/dms/dms.container"; -import PhoneFormatter from "../../utils/PhoneFormatter"; +import { selectBodyshop } from "../../redux/user/user.selectors"; import { alphaSort } from "../../utils/sorters"; -export default function DmsCustomerSelector() { + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect( + mapStateToProps, + mapDispatchToProps +)(DmsCustomerSelector); + +export function DmsCustomerSelector({ bodyshop }) { const { t } = useTranslation(); const [customerList, setcustomerList] = useState([]); const [visible, setVisible] = useState(false); @@ -15,11 +29,24 @@ export default function DmsCustomerSelector() { setcustomerList(customerList); }); - const onOk = () => { + const onUseSelected = () => { setVisible(false); socket.emit("cdk-selected-customer", selectedCustomer); }; + const onUseGeneric = () => { + setVisible(false); + socket.emit( + "cdk-selected-customer", + bodyshop.cdk_configuration.generic_customer_number + ); + }; + + const onCreateNew = () => { + setVisible(false); + socket.emit("cdk-selected-customer", null); + }; + const columns = [ { title: t("dms.fields.name1"), @@ -27,28 +54,13 @@ export default function DmsCustomerSelector() { key: "name1", sorter: (a, b) => alphaSort(a.name1?.fullName, b.name1?.fullName), }, - { - title: t("dms.fields.name2"), - dataIndex: ["name2", "fullName"], - key: "name2", - sorter: (a, b) => alphaSort(a.name2?.fullName, b.name2?.fullName), - }, - { - title: t("dms.fields.phone"), - dataIndex: ["contactInfo", "mainTelephoneNumber", "value"], - key: "phone", - render: (record, value) => ( - - {record.contactInfo?.mainTelephoneNumber?.value} - - ), - }, + { title: t("dms.fields.address"), //dataIndex: ["name2", "fullName"], key: "address", render: (record, value) => - `${record.address?.addressLine[0]}, ${record.address?.city} ${record.address?.stateOrProvince} ${record.address?.postalCode}`, + `${record?.address?.addressLine[0]}, ${record.address?.city} ${record.address?.stateOrProvince} ${record.address?.postalCode}`, }, ]; @@ -57,7 +69,23 @@ export default function DmsCustomerSelector() {
(
- + + +
)} pagination={{ position: "top" }} diff --git a/client/src/components/dms-post-form/dms-post-form.component.jsx b/client/src/components/dms-post-form/dms-post-form.component.jsx index 8bef25c4b..783f4749c 100644 --- a/client/src/components/dms-post-form/dms-post-form.component.jsx +++ b/client/src/components/dms-post-form/dms-post-form.component.jsx @@ -1,5 +1,13 @@ import { DeleteFilled } from "@ant-design/icons"; -import { Button, Form, Input } from "antd"; +import { + Button, + Form, + Input, + InputNumber, + Select, + Space, + Statistic, +} from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -8,7 +16,9 @@ import { selectBodyshop } from "../../redux/user/user.selectors"; import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component"; - +import Dinero from "dinero.js"; +import { determineDmsType } from "../../pages/dms/dms.container"; +import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); @@ -17,11 +27,38 @@ const mapDispatchToProps = (dispatch) => ({ }); export default connect(mapStateToProps, mapDispatchToProps)(DmsPostForm); -export function DmsPostForm({ bodyshop, socket, jobId }) { +export function DmsPostForm({ bodyshop, socket, job }) { const [form] = Form.useForm(); const { t } = useTranslation(); + + const handlePayerSelect = (value, index) => { + form.setFieldsValue({ + payers: form.getFieldValue("payers").map((payer, mapIndex) => { + if (index !== mapIndex) return payer; + const cdkPayer = + bodyshop.cdk_configuration.payers && + bodyshop.cdk_configuration.payers.find((i) => i.name === value); + + if (!cdkPayer) return payer; + + return { + ...cdkPayer, + dms_acctnumber: cdkPayer.dms_acctnumber, + controlnumber: job && job[cdkPayer.control_type], + }; + }), + }); + }; + + const handleFinish = (values) => { + socket.emit(`${determineDmsType(bodyshop)}-export-job`, { + jobid: job.id, + txEnvelope: values, + }); + }; + return ( - + - + + + + + + + - + - + + + + + @@ -81,20 +156,30 @@ export function DmsPostForm({ bodyshop, socket, jobId }) { }, ]} > - + - + - + + + + {() => { + const payers = form.getFieldValue("payers"); + + const row = payers && payers[index]; + + const cdkPayer = + bodyshop.cdk_configuration.payers && + bodyshop.cdk_configuration.payers.find( + (i) => i && row && i.name === row.name + ); + + return ( +
+ {cdkPayer && + t(`jobs.fields.${cdkPayer.control_type}`)} +
+ ); + }} +
+ { remove(field.name); @@ -133,18 +240,69 @@ export function DmsPostForm({ bodyshop, socket, jobId }) { ); }}
+ + {() => { + //Perform Calculation to determine discrepancy. + let totalAllocated = Dinero(); + + const payers = form.getFieldValue("payers"); + payers && + payers.forEach((payer) => { + totalAllocated = totalAllocated.add( + Dinero({ amount: Math.round((payer?.amount || 0) * 100) }) + ); + }); + const discrep = Dinero(job.job_totals.totals.total_repairs).subtract( + totalAllocated + ); + return ( + + + + + + + + ); + }} + ); } diff --git a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx index 37a9213fa..c50b7b9b0 100644 --- a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx +++ b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx @@ -91,6 +91,99 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) { > + + + + + + + + + + {(fields, { add, remove }) => { + return ( +
+ {fields.map((field, index) => ( + + + + + + + + + + + + + { + remove(field.name); + }} + /> + + + ))} + + + +
+ ); + }} +
)} @@ -1335,926 +1428,802 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) { )} - {!bodyshop.cdk_dealerid && ( - <> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { document.title = t("titles.dms"); @@ -73,7 +73,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { console.log("Connected again."); }); socket.on("reconnect", () => { - console.log("Connected again."); setLogs((logs) => { return [ ...logs, @@ -102,48 +101,42 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - if (!jobId || !bodyshop.cdk_dealerid) return ; + if (!jobId || !bodyshop.cdk_dealerid || !(data && data.jobs_by_pk)) + return ; - const dmsType = determineDmsType(bodyshop); - - // if (loading) return ; - // if (error) return ; + if (loading) return ; + if (error) return ; return (
- - - - -
+ {data && data.jobs_by_pk && data.jobs_by_pk.ro_number} - + + + + +
@@ -155,7 +148,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { ); } -const determineDmsType = (bodyshop) => { +export const determineDmsType = (bodyshop) => { if (bodyshop.cdk_dealerid) return "cdk"; else { return "pbs"; diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index bf57b554a..49b3d8e27 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -8,6 +8,7 @@ import { Alert, Divider, PageHeader, + InputNumber, } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; @@ -56,6 +57,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { actual_in: values.actual_in, actual_completion: values.actual_completion, actual_delivery: values.actual_delivery, + kmin: values.kmin, + kmout: values.kmout, }, }, refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"], @@ -112,6 +115,8 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { actual_delivery: job.actual_delivery ? moment(job.actual_delivery) : job.scheduled_delivery && moment(job.scheduled_delivery), + kmin: job.kmin, + kmout: job.kmout, }} scrollToFirstError > @@ -203,6 +208,45 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { > + {bodyshop.cdk_dealerid && ( + + + + )} + {bodyshop.cdk_dealerid && ( + ({ + validator(_, value) { + if (!value || getFieldValue("kmin") <= value) { + return Promise.resolve(); + } + + return Promise.reject( + new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin")) + ); + }, + }), + ]} + > + + + )} diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 2d24eb84d..e9cb2d679 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1,2402 +1,2408 @@ { - "translation": { - "allocations": { - "actions": { - "assign": "Assign" - }, - "errors": { - "deleting": "Error encountered while deleting allocation. {{message}}", - "saving": "Error while allocating. {{message}}", - "validation": "Please ensure all fields are entered correctly. " - }, - "fields": { - "employee": "Allocated To" - }, - "successes": { - "deleted": "Allocation deleted successfully.", - "save": "Allocated successfully. " - } - }, - "appointments": { - "actions": { - "block": "Block Day", - "calculate": "Calculate SMART Dates", - "cancel": "Cancel", - "intake": "Intake", - "new": "New Appointment", - "preview": "Preview", - "reschedule": "Reschedule", - "sendreminder": "Send Reminder", - "viewjob": "View Job" - }, - "errors": { - "blocking": "Error creating block {{message}}.", - "canceling": "Error canceling appointment. {{message}}", - "saving": "Error scheduling appointment. {{message}}" - }, - "fields": { - "alt_transport": "Alt. Trans.", - "color": "Appointment Color", - "note": "Appt. Note", - "time": "Appointment Time", - "title": "Title" - }, - "labels": { - "arrivedon": "Arrived on: ", - "arrivingjobs": "Arriving Jobs", - "blocked": "Blocked", - "cancelledappointment": "Canceled appointment for: ", - "completingjobs": "Completing Jobs", - "history": "History", - "inproduction": "Jobs In Production", - "noarrivingjobs": "No jobs are arriving.", - "nocompletingjobs": "No jobs scheduled for completion.", - "nodateselected": "No date has been selected.", - "priorappointments": "Previous Appointments", - "reminder": "This is {{shopname}} reminding you about an appointment on {{date}} at {{time}}. Please let us know if you are not able to make the appointment. We look forward to seeing you soon. ", - "scheduledfor": "Scheduled appointment for: ", - "smartscheduling": "Smart Scheduling", - "suggesteddates": "Suggested Dates" - }, - "successes": { - "canceled": "Appointment canceled successfully.", - "created": "Appointment scheduled successfully.", - "saved": "Appointment saved successfully." - } - }, - "associations": { - "actions": { - "activate": "Activate" - }, - "fields": { - "active": "Active?", - "shopname": "Shop Name" - }, - "labels": { - "actions": "Actions" - } - }, - "audit": { - "fields": { - "created": "Time", - "operation": "Operation", - "useremail": "User", - "values": "Values" - } - }, - "audit_trail": { - "messages": { - "billposted": "Bill with invoice number {{invoice_number}} posted.", - "billupdated": "Bill with invoice number {{invoice_number}} updated.", - "jobassignmentchange": "Employee {{name}} assigned to {{operation}}", - "jobassignmentremoved": "Employee assignment removed for {{operation}}", - "jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.", - "jobconverted": "Job converted and assigned number {{ro_number}}.", - "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", - "jobimported": "Job imported.", - "jobinproductionchange": "Job production status set to {{inproduction}}", - "jobmodifylbradj": "Labor adjustments modified.", - "jobspartsorder": "Parts order {{order_number}} added to job.", - "jobspartsreturn": "Parts return {{order_number}} added to job.", - "jobstatuschange": "Job status changed to {{status}}.", - "jobsupplement": "Job supplement imported." - } - }, - "billlines": { - "actions": { - "newline": "New Line" - }, - "fields": { - "actual_cost": "Actual Cost", - "actual_price": "Retail", - "cost_center": "Cost Center", - "federal_tax_applicable": "Fed. Tax?", - "jobline": "Job Line", - "line_desc": "Line Description", - "local_tax_applicable": "Loc. Tax?", - "location": "Location", - "quantity": "Quantity", - "state_tax_applicable": "St. Tax?" - }, - "labels": { - "deductedfromlbr": "Deduct from Labor?", - "entered": "Entered", - "from": "From", - "other": "-- Not On Estimate --", - "reconciled": "Reconciled!", - "unreconciled": "Unreconciled" - } - }, - "bills": { - "actions": { - "edit": "Edit", - "receive": "Receive Part", - "return": "Return Items" - }, - "errors": { - "creating": "Error adding bill. {{error}}", - "deleting": "Error deleting bill. {{error}}", - "exporting": "Error exporting payable(s). {{error}}", - "exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.", - "invalidro": "Not a valid RO.", - "invalidvendor": "Not a valid vendor.", - "validation": "Please ensure all fields are entered correctly. " - }, - "fields": { - "allpartslocation": "Parts Bin", - "date": "Bill Date", - "exported": "Exported", - "federal_tax_rate": "Federal Tax Rate", - "invoice_number": "Invoice Number", - "is_credit_memo": "Credit Memo?", - "local_tax_rate": "Local Tax Rate", - "ro_number": "RO Number", - "state_tax_rate": "Provincial/State Tax Rate", - "total": "Bill Total", - "vendor": "Vendor", - "vendorname": "Vendor Name" - }, - "labels": { - "actions": "Actions", - "bill_lines": "Bill Lines", - "bill_total": "Bill Total Amount", - "billcmtotal": "Credit Memos", - "bills": "Bills", - "creditsnotreceived": "Credits Not Received", - "creditsreceived": "Credits Received", - "dedfromlbr": "Labor Adjustments", - "deleteconfirm": "Are you sure you want to delete this bill? It cannot be undone. If this bill has deductions from labors, manual changes may be required.", - "discrepancy": "Discrepancy", - "discrepwithcms": "Discrepancy including Credit Memos", - "discrepwithlbradj": "Discrepancy including Lbr. Adj.", - "editadjwarning": "This bill had lines which resulted in labor adjustments. Manual correction to adjustments may be required.", - "entered_total": "Total of Entered Lines", - "enteringcreditmemo": "You are entering a credit memo. Please ensure you are also entering positive values.", - "federal_tax": "Federal Tax", - "local_tax": "Local Tax", - "markforreexport": "Mark for Re-export", - "new": "New Bill", - "noneselected": "No bill selected.", - "onlycmforinvoiced": "Only credit memos can be entered for any job that has been invoiced, exported, or voided.", - "retailtotal": "Bills Retail Total", - "state_tax": "Provincial/State Tax", - "subtotal": "Subtotal", - "totalreturns": "Total Returns" - }, - "successes": { - "created": "Invoice added successfully.", - "deleted": "Bill deleted successfully.", - "exported": "Bill(s) exported successfully.", - "reexport": "Bill marked for re-export." - }, - "validation": { - "manualinhouse": "Manual posting to the in house vendor is restricted. ", - "unique_invoice_number": "This invoice number has already been entered for this vendor." - } - }, - "bodyshop": { - "actions": { - "addapptcolor": "Add Appointment Color", - "addbucket": "Add Definition", - "addpartslocation": "Add Parts Location", - "addspeedprint": "Add Speed Print", - "addtemplate": "Add Template", - "newlaborrate": "New Labor Rate", - "newsalestaxcode": "New Sales Tax Code", - "newstatus": "Add Status", - "testrender": "Test Render" - }, - "errors": { - "loading": "Unable to load shop details. Please call technical support.", - "saving": "Error encountered while saving. {{message}}" - }, - "fields": { - "address1": "Address 1", - "address2": "Address 2", - "appt_alt_transport": "Appointment Alternative Transportation Options", - "appt_colors": { - "color": "Color", - "label": "Label" - }, - "appt_length": "Default Appointment Length", - "attach_pdf_to_email": "Attach PDF copy to sent emails?", - "bill_federal_tax_rate": "Bills - Federal Tax Rate %", - "bill_local_tax_rate": "Bill - Provincial/State Tax Rate %", - "bill_state_tax_rate": "Bill - Provincial/State Tax Rate %", - "city": "City", - "country": "Country", - "dailybodytarget": "Scoreboard - Daily Body Target", - "dailypainttarget": "Scoreboard - Daily Paint Target", - "default_adjustment_rate": "Default Labor Deduction Adjustment Rate", - "deliver": { - "templates": "Delivery Templates" - }, - "dms": { - "default_journal": "Default Journal", - "dms_acctnumber": "DMS Account #", - "dms_wip_acctnumber": "DMS W.I.P. Account #", - "mappingname": "DMS Mapping Name" - }, - "email": "General Shop Email", - "enforce_class": "Enforce Class on Conversion?", - "enforce_referral": "Enforce Referrals", - "federal_tax_id": "Federal Tax ID (GST/HST)", - "inhousevendorid": "In House Vendor ID", - "insurance_vendor_id": "Insurance Vendor ID", - "intake": { - "templates": "Intake Templates" - }, - "invoice_federal_tax_rate": "Invoices - Federal Tax Rate", - "invoice_local_tax_rate": "Invoices - Local 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", - "logo_img_path": "Shop Logo", - "logo_img_path_height": "Logo Image Height", - "logo_img_path_width": "Logo Image Width", - "md_categories": "Categories", - "md_ccc_rates": "Courtesy Car Contract Rate Presets", - "md_classes": "Classes", - "md_hour_split": { - "paint": "Paint Hour Split", - "prep": "Prep Hour Split" - }, - "md_ins_co": { - "city": "City", - "name": "Insurance Company Name", - "state": "Province/State", - "street1": "Street 1", - "street2": "Street 2", - "zip": "Zip/Postal Code" - }, - "md_jobline_presets": "Jobline Presets", - "md_payment_types": "Payment Types", - "md_referral_sources": "Referral Sources", - "messaginglabel": "Messaging Preset Label", - "messagingtext": "Messaging Preset Text", - "noteslabel": "Note Label", - "notestext": "Note Text", - "partslocation": "Parts Location", - "phone": "Phone", - "prodtargethrs": "Production Target Hours", - "rbac": { - "accounting": { - "exportlog": "Accounting -> Export Log", - "payables": "Accounting -> Payables", - "payments": "Accounting -> Payments", - "receivables": "Accounting -> Receivables" - }, - "bills": { - "delete": "Bills -> Delete", - "enter": "Bills -> Enter", - "list": "Bills -> List", - "reexport": "Bills -> Re-export", - "view": "Bills -> View" - }, - "contracts": { - "create": "Contracts -> Create", - "detail": "Contracts -> Detail", - "list": "Contracts -> List" - }, - "courtesycar": { - "create": "Courtesy Car -> Create", - "detail": "Courtesy Car -> Detail", - "list": "Courtesy Car -> List" - }, - "csi": { - "export": "CSI -> Export", - "page": "CSI -> Page" - }, - "employees": { - "page": "Employees -> List" - }, - "jobs": { - "admin": "Jobs -> Admin", - "available-list": "Jobs -> Available List", - "checklist-view": "Jobs -> Checklist View", - "close": "Jobs -> Close", - "create": "Jobs -> Create", - "deliver": "Jobs -> Deliver", - "detail": "Jobs -> Detail", - "intake": "Jobs -> Intake", - "list-active": "Jobs -> List Active", - "list-all": "Jobs -> List All", - "partsqueue": "Jobs -> Parts Queue" - }, - "owners": { - "detail": "Owners -> Detail", - "list": "Owners -> List" - }, - "payments": { - "enter": "Payments -> Enter", - "list": "Payments -> List" - }, - "phonebook": { - "edit": "Phonebook -> Edit", - "view": "Phonebook -> View" - }, - "production": { - "board": "Production -> Board", - "list": "Production -> List" - }, - "schedule": { - "view": "Schedule -> View" - }, - "scoreboard": { - "view": "Scoreboard -> View" - }, - "shiftclock": { - "view": "Shift Clock -> View" - }, - "shop": { - "dashboard": "Shop -> Dashboard", - "rbac": "Shop -> RBAC", - "templates": "Shop -> Templates", - "vendors": "Shop -> Vendors" - }, - "temporarydocs": { - "view": "Temporary Docs -> View" - }, - "timetickets": { - "edit": "Time Tickets -> Edit", - "enter": "Time Tickets -> Enter", - "list": "Time Tickets -> List", - "shiftedit": "Time Tickets -> Shift Edit" - }, - "users": { - "editaccess": "Users -> Edit access" - } - }, - "responsibilitycenter": "Responsibility Center", - "responsibilitycenter_accountdesc": "Account Description", - "responsibilitycenter_accountitem": "Item", - "responsibilitycenter_accountname": "Account Name", - "responsibilitycenter_accountnumber": "Account Number", - "responsibilitycenter_rate": "Rate", - "responsibilitycenters": { - "ap": "Accounts Payable", - "ar": "Accounts Receivable", - "ats": "ATS", - "federal_tax": "Federal Tax", - "lab": "Body", - "lad": "Diagnostic", - "lae": "Electrical", - "laf": "Frame", - "lag": "Glass", - "lam": "Mechanical", - "lar": "Refinish", - "las": "Structural", - "lau": "Detail", - "local_tax": "Local Tax", - "mapa": "Paint Materials", - "mash": "Shop Materials", - "paa": "Aftermarket", - "pac": "Chrome", - "pal": "LKQ", - "pam": "Remanufactured", - "pan": "OEM", - "pao": "Other", - "pap": "OEM Partial", - "par": "Recored", - "pas": "Sublet", - "refund": "Refund", - "sales_tax_codes": { - "code": "Code", - "description": "Description", - "federal": "Federal Tax Applies", - "local": "Local Tax Applies", - "state": "Provincial/State Tax Applies" - }, - "state_tax": "Provincial/State Tax", - "tow": "Towing" - }, - "schedule_end_time": "Schedule Ending Time", - "schedule_start_time": "Schedule Starting Time", - "shopname": "Shop Name", - "speedprint": { - "id": "Id", - "label": "Label", - "templates": "Templates" - }, - "ssbuckets": { - "gte": "Greater Than/Equal to (hrs)", - "id": "ID", - "label": "Label", - "lt": "Less than (hrs)", - "target": "Target (count)" - }, - "state": "Province/State", - "state_tax_id": "Provincial/State Tax ID (PST, QST)", - "status": "Status Label", - "statuses": { - "active_statuses": "Active Statuses (Filtering for Active Jobs throughout system)", - "default_arrived": "Default Arrived Status (Transition to Production)", - "default_bo": "Default Backordered Status", - "default_canceled": "Default Canceled Status", - "default_completed": "Default Completed Status", - "default_delivered": "Default Delivered Status (Transition to Post-Production)", - "default_exported": "Default Exported Status", - "default_imported": "Default Imported Status", - "default_invoiced": "Default Invoiced Status", - "default_ordered": "Default Ordered Status", - "default_received": "Default Received Status", - "default_returned": "Default Returned", - "default_scheduled": "Default Scheduled Status", - "default_void": "Default Void", - "open_statuses": "Open Statuses", - "post_production_statuses": "Post-Production Statuses", - "pre_production_statuses": "Pre-Production Statuses", - "production_statuses": "Production Statuses" - }, - "target_touchtime": "Target Touch Time", - "tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs", - "use_fippa": "Use FIPPA for Names on Generated Documents?", - "website": "Website", - "zip_post": "Zip/Postal Code" - }, - "labels": { - "2tiername": "Name => RO", - "2tiersetup": "2 Tier Setup", - "2tiersource": "Source => RO", - "accountingsetup": "Accounting Setup", - "accountingtiers": "Number of Tiers to Use for Export", - "alljobstatuses": "All Job Statuses", - "allopenjobstatuses": "All Open Job Statuses", - "apptcolors": "Appointment Colors", - "businessinformation": "Business Information", - "checklists": "Checklists", - "csiq": "CSI Questions", - "customtemplates": "Custom Templates", - "defaultcostsmapping": "Default Costs Mapping", - "defaultprofitsmapping": "Default Profits Mapping", - "deliverchecklist": "Delivery Checklist", - "dms": { - "cdk_dealerid": "CDK Dealer ID", - "title": "DMS" - }, - "emaillater": "Email Later", - "employees": "Employees", - "insurancecos": "Insurance Companies", - "intakechecklist": "Intake Checklist", - "jobstatuses": "Job Statuses", - "laborrates": "Labor Rates", - "licensing": "Licensing", - "messagingpresets": "Messaging Presets", - "notemplatesavailable": "No templates available to add.", - "notespresets": "Notes Presets", - "orderstatuses": "Order Statuses", - "partslocations": "Parts Locations", - "printlater": "Print Later", - "rbac": "Role Based Access Control", - "responsibilitycenters": { - "costs": "Cost Centers", - "profits": "Profit Centers", - "sales_tax_codes": "Sales Tax Codes", - "tax_accounts": "Tax Accounts", - "title": "Responsibility Centers" - }, - "scheduling": "SMART Scheduling", - "scoreboardsetup": "Scoreboard Setup", - "shopinfo": "Shop Information", - "speedprint": "Speed Print Configuration", - "ssbuckets": "Job Size Definitions", - "systemsettings": "System Settings", - "workingdays": "Working Days" - }, - "successes": { - "save": "Shop configuration saved successfully. " - }, - "validation": { - "larsplit": "Refinish hour split must add up to 1.", - "useremailmustexist": "This email is not a valid user." - } - }, - "checklist": { - "actions": { - "printall": "Print All Documents" - }, - "errors": { - "complete": "Error during job checklist completion. {{error}}", - "nochecklist": "No checklist has been configured for your shop. " - }, - "labels": { - "addtoproduction": "Add Job to Production?", - "allow_text_message": "Permission to Text?", - "checklist": "Checklist", - "printpack": "Job Intake Print Pack", - "removefromproduction": "Remove job from production?" - }, - "successes": { - "completed": "Job checklist completed." - } - }, - "contracts": { - "actions": { - "changerate": "Change Contract Rates", - "convertoro": "Convert to RO", - "decodelicense": "Decode License", - "find": "Find Contract", - "printcontract": "Print Contract", - "senddltoform": "Insert Driver's License Information" - }, - "errors": { - "fetchingjobinfo": "Error fetching job info. {{error}}.", - "returning": "Error returning courtesy car. {{error}}", - "saving": "Error saving contract. {{error}}", - "selectjobandcar": "Please ensure both a car and job are selected." - }, - "fields": { - "actax": "A/C Tax", - "actualreturn": "Actual Return Date", - "agreementnumber": "Agreement Number", - "cc_cardholder": "Cardholder Name", - "cc_expiry": "Credit Card Expiry Date", - "cc_num": "Credit Card Number", - "cleanupcharge": "Clean Up Charge", - "coverage": "Coverage", - "dailyfreekm": "Daily Free Mileage", - "dailyrate": "Daily Rate", - "damage": "Existing Damage", - "damagewaiver": "Damage Waiver", - "driver": "Driver", - "driver_addr1": "Driver Address 1", - "driver_addr2": "Driver Address 2", - "driver_city": "Driver City", - "driver_dlexpiry": "Driver's License Expiration Date", - "driver_dlnumber": "Driver's License Number", - "driver_dlst": "Driver's License Province/State", - "driver_dob": "Driver's DOB", - "driver_fn": "Driver's First Name", - "driver_ln": "Driver's Last Name", - "driver_ph1": "Driver's Phone", - "driver_state": "Driver's Province/State ", - "driver_zip": "Driver's Postal/ZIP Code", - "excesskmrate": "Excess Mileage", - "federaltax": "Federal Taxes", - "fuelin": "Fuel In", - "fuelout": "Fuel Out", - "kmend": "Mileage End", - "kmstart": "Mileage Start", - "localtax": "Local Taxes", - "refuelcharge": "Refuel Charge (per liter/gallon)", - "scheduledreturn": "Scheduled Return", - "start": "Contract Start", - "statetax": "Provincial/State Taxes", - "status": "Status" - }, - "labels": { - "agreement": "Agreement {{agreement_num}} - {{status}}", - "availablecars": "Available Cars", - "cardueforservice": "The courtesy car is due for servicing.", - "convertform": { - "applycleanupcharge": "Apply cleanup charge?", - "refuelqty": "Refuel qty.?" - }, - "correctdataonform": "Please review the information above. If any of it is not correct, you can fix it later.", - "dlexpirebeforereturn": "The driver's license expires before the car is expected to return. ", - "driverinformation": "Driver's Information", - "findcontract": "Find Contract", - "findermodal": "Contract Finder", - "noteconvertedfrom": "R.O. created from converted Courtesy Car Contract {{agreementnumber}}.", - "populatefromjob": "Populate from Job", - "rates": "Contract Rates", - "time": "Time", - "vehicle": "Vehicle", - "waitingforscan": "Please scan driver's license barcode..." - }, - "status": { - "new": "New Contract", - "out": "Out", - "returned": "Returned" - }, - "successes": { - "saved": "Contract saved successfully. " - } - }, - "courtesycars": { - "actions": { - "new": "New Courtesy Car", - "return": "Return Car" - }, - "errors": { - "saving": "Error saving courtesy card. {{error}}" - }, - "fields": { - "color": "Color", - "dailycost": "Daily Cost to Rent", - "damage": "Damage", - "fleetnumber": "Fleet Number", - "fuel": "Fuel Level", - "insuranceexpires": "Insurance Expires On", - "leaseenddate": "Lease Ends On", - "make": "Make", - "mileage": "Mileage", - "model": "Model", - "nextservicedate": "Next Service Date", - "nextservicekm": "Next Service KMs", - "notes": "Notes", - "plate": "Plate Number", - "purchasedate": "Purchase Date", - "registrationexpires": "Registration Expires On", - "serviceenddate": "Usage End Date", - "servicestartdate": "Usage Start Date", - "status": "Status", - "vin": "VIN", - "year": "Year" - }, - "labels": { - "courtesycar": "Courtesy Car", - "fuel": { - "12": "1/2", - "14": "1/4", - "18": "1/8", - "34": "3/4", - "38": "3/8", - "58": "5/8", - "78": "7/8", - "empty": "Empty", - "full": "Full" - }, - "outwith": "Out With", - "return": "Return Courtesy Car", - "status": "Status", - "uniquefleet": "Enter a unique fleet number.", - "usage": "Usage", - "vehicle": "Vehicle Description" - }, - "status": { - "in": "Available", - "inservice": "In Service", - "out": "Rented" - }, - "successes": { - "saved": "Courtesy Car saved successfully." - } - }, - "csi": { - "actions": { - "activate": "Activate" - }, - "errors": { - "creating": "Error creating survey {{message}}", - "notconfigured": "You do not have any current CSI Question Sets configured.", - "notfoundsubtitle": "We were unable to find a survey using the link you provided. Please ensure the URL is correct or reach out to your shop for more help.", - "notfoundtitle": "No survey found." - }, - "fields": { - "completedon": "Completed On" - }, - "labels": { - "nologgedinuser": "Please log out of ImEX Online", - "nologgedinuser_sub": "Users of ImEX Online cannot complete CSI surveys while logged in. Please log out and try again.", - "noneselected": "No response selected.", - "title": "Customer Satisfaction Survey" - }, - "successes": { - "created": "CSI created successfully. ", - "submitted": "Your responses have been submitted successfully.", - "submittedsub": "Your input is highly appreciated." - } - }, - "dashboard": { - "actions": { - "addcomponent": "Add Component" - }, - "errors": { - "refreshrequired": "You must refresh the dashboard data to see this component.", - "updatinglayout": "Error saving updated layout {{message}}" - }, - "labels": { - "bodyhrs": "Body Hrs", - "dollarsinproduction": "Dollars in Production", - "prodhrs": "Production Hrs", - "refhrs": "Refinish Hrs" - }, - "titles": { - "monthlyemployeeefficiency": "Monthly Employee Efficiency", - "monthlyjobcosting": "Monthly Job Costing ", - "monthlylaborsales": "Monthly Labor Sales", - "monthlypartssales": "Monthly Parts Sales", - "monthlyrevenuegraph": "Monthly Revenue Graph", - "prodhrssummary": "Production Hours Summary", - "productiondollars": "Total dollars in Production", - "productionhours": "Total hours in Production", - "projectedmonthlysales": "Projected Monthly Sales" - } - }, - "documents": { - "actions": { - "delete": "Delete Selected Documents", - "download": "Download Selected Images", - "reassign": "Reassign to another Job", - "selectallimages": "Select All Images", - "selectallotherdocuments": "Select All Other Documents" - }, - "errors": { - "deletes3": "Error deleting document from storage. ", - "deleting_cloudinary": "Error deleting document from storage. {{message}}", - "getpresignurl": "Error obtaining presigned URL for document. {{message}}", - "insert": "Unable to upload file. {{message}}", - "nodocuments": "There are no documents.", - "updating": "Error updating document. {{error}}" - }, - "labels": { - "confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.", - "doctype": "Document Type", - "newjobid": "Assign to Job", - "reassign_limitexceeded": "Reassigning all selected documents will exceed the job storage limit for your shop. ", - "reassign_limitexceeded_title": "Unable to reassign document(s)", - "storageexceeded": "You've exceeded your storage limit for this job. Please remove documents, or increase your storage plan.", - "storageexceeded_title": "Storage Limit Exceeded", - "upload": "Upload", - "upload_limitexceeded": "Uploading all selected documents will exceed the job storage limit for your shop. ", - "upload_limitexceeded_title": "Unable to upload document(s)", - "uploading": "Uploading...", - "usage": "of job storage used. ({{used}} / {{total}})" - }, - "successes": { - "delete": "Document(s) deleted successfully.", - "edituploaded": "Edited document uploaded successfully. Please close this window and refresh the documents list.", - "insert": "Uploaded document successfully. ", - "updated": "Document updated successfully. " - } - }, - "emails": { - "errors": { - "notsent": "Email not sent. Error encountered while sending {{message}}" - }, - "fields": { - "cc": "CC", - "subject": "Subject", - "to": "To" - }, - "labels": { - "attachments": "Attachments", - "documents": "Documents", - "generatingemail": "Generating email...", - "pdfcopywillbeattached": "A PDF copy of this email will be attached when it is sent.", - "preview": "Email Preview" - }, - "successes": { - "sent": "Email sent successfully." - } - }, - "employees": { - "actions": { - "new": "New Employee", - "newrate": "New Rate" - }, - "errors": { - "delete": "Error encountered while deleting employee. {{message}}", - "save": "Error encountered saving employee. {{message}}", - "validation": "Please check all fields.", - "validationtitle": "Unable to save employee." - }, - "fields": { - "active": "Active?", - "base_rate": "Base Rate", - "cost_center": "Cost Center", - "employee_number": "Employee Number", - "first_name": "First Name", - "flat_rate": "Flat Rate (Disabled is Straight Time)", - "hire_date": "Hire Date", - "last_name": "Last Name", - "pin": "Tech Console PIN", - "rate": "Rate", - "termination_date": "Termination Date", - "user_email": "User Email" - }, - "labels": { - "actions": "Actions", - "flat_rate": "Flat Rate", - "name": "Name", - "rate_type": "Rate Type", - "straight_time": "Straight Time" - }, - "successes": { - "delete": "Employee deleted successfully.", - "save": "Employee saved successfully." - }, - "validation": { - "unique_employee_number": "You must enter a unique employee number." - } - }, - "exportlogs": { - "fields": { - "createdat": "Created At" - }, - "labels": { - "attempts": "Export Attempts" - } - }, - "general": { - "actions": { - "add": "Add", - "calculate": "Calculate", - "cancel": "Cancel", - "clear": "Clear", - "close": "Close", - "copylink": "Copy Link", - "create": "Create", - "delete": "Delete", - "deleteall": "Delete All", - "deselectall": "Deselect All", - "edit": "Edit", - "login": "Login", - "refresh": "Refresh", - "remove": "Remove", - "reset": "Reset your changes.", - "resetpassword": "Reset Password", - "save": "Save", - "saveandnew": "Save and New", - "selectall": "Select All", - "senderrortosupport": "Send Error to Support", - "submit": "Submit", - "view": "View", - "viewreleasenotes": "See What's Changed" - }, - "errors": { - "notfound": "No record was found." - }, - "itemtypes": { - "contract": "CC Contract", - "courtesycar": "Courtesy Car", - "job": "Job", - "owner": "Owner", - "vehicle": "Vehicle" - }, - "labels": { - "actions": "Actions", - "areyousure": "Are you sure?", - "barcode": "Barcode", - "cancel": "Are you sure you want to cancel? Your changes will not be saved.", - "clear": "Clear", - "confirmpassword": "Confirm Password", - "created_at": "Created At", - "email": "Email", - "errors": "Errors", - "exceptiontitle": "An error has occurred.", - "friday": "Friday", - "globalsearch": "Global Search", - "hours": "hrs", - "in": "In", - "instanceconflictext": "Your $t(titles.app) account can only be used on one device at any given time. Refresh your session to take control.", - "instanceconflictitle": "Your account is being used elsewhere.", - "item": "Item", - "label": "Label", - "loading": "Loading...", - "loadingapp": "Loading $t(titles.app)", - "loadingshop": "Loading shop data...", - "loggingin": "Authorizing...", - "message": "Message", - "monday": "Monday", - "na": "N/A", - "newpassword": "New Password", - "no": "No", - "nointernet": "It looks like you're not connected to the internet.", - "nointernet_sub": "Please check your connection and try again. ", - "none": "None", - "out": "Out", - "password": "Password", - "passwordresetsuccess": "A password reset link has been sent to you.", - "passwordresetsuccess_sub": "You should receive this email in the next few minutes. Please check your email including any junk or spam folders. ", - "passwordresetvalidatesuccess": "Password successfully reset. ", - "passwordresetvalidatesuccess_sub": "You may now sign in again using your new password. ", - "passwordsdonotmatch": "The passwords you have entered do not match.", - "print": "Print", - "required": "Required", - "saturday": "Saturday", - "search": "Search...", - "searchresults": "Results for {{search}}", - "selectdate": "Select date...", - "sendagain": "Send Again", - "sendby": "Send By", - "signin": "Sign In", - "sms": "SMS", - "sub_status": { - "expired": "The subscription for this shop has expired. Please contact technical support to reactivate the subscription. " - }, - "successful": "Successful", - "sunday": "Sunday", - "text": "Text", - "thursday": "Thursday", - "totals": "Totals", - "tuesday": "Tuesday", - "unknown": "Unknown", - "username": "Username", - "view": "View", - "wednesday": "Wednesday", - "yes": "Yes" - }, - "languages": { - "english": "English", - "french": "French", - "spanish": "Spanish" - }, - "messages": { - "exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.", - "newversionmessage": "Click refresh below to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.", - "newversiontitle": "New version of ImEX Online Available", - "noacctfilepath": "There is no accounting file path set. You will not be able to export any items.", - "nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.", - "noshop": "You do not have access to any shops. Please reach out to your shop manager or technical support. ", - "notfoundsub": "Please make sure that you have access to the data or that the link is correct.", - "notfoundtitle": "We couldn't find what you're looking for...", - "partnernotrunning": "ImEX Online has detected that the partner is not running. Please ensure it is running to enable full functionality.", - "rbacunauth": "You are not authorized to view this content. Please reach out to your shop manager to change your access level.", - "unsavedchanges": "You have unsaved changes.", - "unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?" - }, - "validation": { - "invalidemail": "Please enter a valid email.", - "invalidphone": "Please enter a valid phone number.", - "required": "{{label}} is required. " - } - }, - "help": { - "actions": { - "connect": "Connect" - }, - "labels": { - "codeplacholder": "6 digit PIN code", - "rescuedesc": "Enter the 6 digit code provided by ImEX Online Support below and click connect.", - "rescuetitle": "Rescue Me!" - } - }, - "intake": { - "labels": { - "printpack": "Intake Print Pack" - } - }, - "joblines": { - "actions": { - "new": "New Line" - }, - "errors": { - "creating": "Error encountered while creating job line. {{message}}", - "updating": "Error encountered updating job line. {{message}}" - }, - "fields": { - "act_price": "Retail Price", - "db_price": "List Price", - "lbr_types": { - "LA1": "LA1", - "LA2": "LA2", - "LA3": "LA3", - "LA4": "LA4", - "LAA": "Aluminum", - "LAB": "Body", - "LAD": "Diagnostic", - "LAE": "Electrical", - "LAF": "Frame", - "LAG": "Glass", - "LAM": "Mechanical", - "LAR": "Refinish", - "LAS": "Structural", - "LAU": "User Defined" - }, - "line_desc": "Line Desc.", - "line_ind": "S#", - "line_no": "Line #", - "location": "Location", - "mod_lb_hrs": "Hrs", - "mod_lbr_ty": "Labor Type", - "notes": "Notes", - "oem_partno": "OEM Part #", - "op_code_desc": "Operation Code Description", - "part_qty": "Qty.", - "part_type": "Part Type", - "part_types": { - "CCC": "CC Cleaning", - "CCD": "CC Damage Waiver", - "CCDR": "CC Daily Rate", - "CCF": "CC Refuel", - "CCM": "CC Mileage", - "PAA": "Aftermarket", - "PAC": "Rechromed", - "PAE": "Existing", - "PAG": "Glass", - "PAL": "LKQ", - "PAM": "Remanufactured", - "PAN": "New/OEM", - "PAO": "Other", - "PAP": "OEM Partial", - "PAR": "Recored", - "PAS": "Sublet", - "PASL": "Sublet" - }, - "profitcenter_labor": "Profit Center: Labor", - "profitcenter_part": "Profit Center: Part", - "prt_dsmk_p": "Line Markup %", - "status": "Status", - "total": "Total", - "unq_seq": "Seq #" - }, - "labels": { - "billref": "Latest Bill", - "edit": "Edit Line", - "new": "New Line", - "nostatus": "No Status", - "presets": "Jobline Presets" - }, - "successes": { - "created": "Job line created successfully.", - "saved": "Job line saved.", - "updated": "Job line updated successfully." - }, - "validations": { - "hrsrequirediflbrtyp": "Labor hours are required if a labor type is selected. Clear the labor type if there are no labor hours.", - "requiredifparttype": "Required if a part type has been specified.", - "zeropriceexistingpart": "This line cannot have any price since it uses an existing part." - } - }, - "jobs": { - "actions": { - "addDocuments": "Add Job Documents", - "addNote": "Add Note", - "addtopartsqueue": "Add to Parts Queue", - "addtoproduction": "Add to Production", - "addtoscoreboard": "Add to Scoreboard", - "allocate": "Allocate", - "autoallocate": "Auto Allocate", - "changelaborrate": "Change Labor Rate", - "changestatus": "Change Status", - "convert": "Convert", - "deliver": "Deliver", - "dmsautoallocate": "DMS Auto Allocate", - "export": "Export", - "exportcustdata": "Export Customer Data", - "exportselected": "Export Selected", - "filterpartsonly": "Filter Parts Only", - "generatecsi": "Generate CSI & Copy Link", - "gotojob": "Go to Job", - "intake": "Intake", - "manualnew": "Create New Job Manually", - "mark": "Mark", - "markasexported": "Mark as Exported", - "markpstexempt": "Mark Job PST Exempt", - "markpstexemptconfirm": "Are you sure you want to do this? To undo this, you must manually update all PST rates.", - "postbills": "Post Bills", - "printCenter": "Print Center", - "recalculate": "Recalculate", - "reconcile": "Reconcile", - "removefromproduction": "Remove from Production", - "schedule": "Schedule", - "sendcsi": "Send CSI", - "sync": "Sync", - "uninvoice": "Uninvoice", - "unvoid": "Unvoid Job", - "viewchecklist": "View Checklists", - "viewdetail": "View Details" - }, - "errors": { - "addingtoproduction": "Error adding to production. {{error}}", - "cannotintake": "Intake cannot be completed for this job. It has either already been completed or the job is already here.", - "closing": "Error closing job. {{error}}", - "creating": "Error encountered while creating job. {{error}}", - "deleted": "Error deleting job. {{error}}", - "exporting": "Error exporting job. {{error}}", - "exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.", - "invoicing": "Error invoicing job. {{error}}", - "noaccess": "This job does not exist or you do not have access to it.", - "nodamage": "No damage points on estimate.", - "nodates": "No dates specified for this job.", - "nofinancial": "No financial data has been calculated yet for this job. Please save it again.", - "nojobselected": "No job is selected.", - "noowner": "No owner associated.", - "novehicle": "No vehicle associated.", - "saving": "Error encountered while saving record.", - "scanimport": "Error importing job. {{message}}", - "totalscalc": "Error while calculating new job totals.", - "updating": "Error while updating job(s). {{error}}", - "validation": "Please ensure all fields are entered correctly.", - "validationtitle": "Validation Error", - "voiding": "Error voiding job. {{error}}" - }, - "fields": { - "actual_completion": "Actual Completion", - "actual_delivery": "Actual Delivery", - "actual_in": "Actual In", - "adjustment_bottom_line": "Adjustments", - "adjustmenthours": "Adjustment Hours", - "alt_transport": "Alt. Trans.", - "ca_bc_pvrt": "PVRT", - "ca_customer_gst": "Customer Portion of GST", - "ca_gst_registrant": "GST Registrant", - "category": "Category", - "ccc": "CC Cleaning", - "ccd": "CC Damage Waiver", - "ccdr": "CC Daily Rate", - "ccf": "CC Refuel", - "ccm": "CC Mileage", - "cieca_id": "CIECA ID", - "claim_total": "Claim Total", - "class": "Class", - "clm_no": "Claim #", - "clm_total": "Claim Total", - "customerowing": "Customer Owing", - "date_estimated": "Date Estimated", - "date_exported": "Exported", - "date_invoiced": "Invoiced", - "date_open": "Open", - "date_scheduled": "Scheduled", - "ded_amt": "Deductible", - "ded_status": "Deductible Status", - "depreciation_taxes": "Depreciation/Taxes", - "dms": { - "center": "Center", - "cost": "Cost", - "cost_dms_acctnumber": "Cost DMS Acct #", - "dms_wip_acctnumber": "Cost WIP DMS Acct #", - "sale": "Sale", - "sale_dms_acctnumber": "Sale DMS Acct #" - }, - "driveable": "Driveable", - "employee_body": "Body", - "employee_csr": "Customer Service Rep.", - "employee_prep": "Prep", - "employee_refinish": "Refinish", - "est_addr1": "Estimator Address", - "est_co_nm": "Estimator Company", - "est_ct_fn": "Estimator First Name", - "est_ct_ln": "Estimator Last Name", - "est_ea": "Estimator Email", - "est_ph1": "Estimator Phone #", - "federal_tax_payable": "Federal Tax Payable", - "federal_tax_rate": "Federal Tax Rate", - "ins_addr1": "Insurance Co. Address", - "ins_city": "Insurance City", - "ins_co_id": "Insurance Co. ID", - "ins_co_nm": "Insurance Company Name", - "ins_co_nm_short": "Ins. Co.", - "ins_ct_fn": "File Handler First Name", - "ins_ct_ln": "File Handler Last Name", - "ins_ea": "File Handler Email", - "ins_ph1": "File Handler Phone #", - "intake": { - "label": "Label", - "max": "Maximum", - "min": "Minimum", - "name": "Name", - "required": "Required?", - "type": "Type" - }, - "kmin": "Mileage In", - "kmout": "Mileage Out", - "la1": "LA1", - "la2": "LA2", - "la3": "LA3", - "la4": "LA4", - "laa": "Aluminum ", - "lab": "Body", - "labor_rate_desc": "Labor Rate Name", - "lad": "Diagnostic", - "lae": "Electrical", - "laf": "Frame", - "lag": "Glass", - "lam": "Mechanical", - "lar": "Refinish", - "las": "Structural", - "lau": "User Defined", - "local_tax_rate": "Local Tax Rate", - "loss_date": "Loss Date", - "loss_desc": "Loss Description", - "ma2s": "2 Stage Paint", - "ma3s": "3 Stage Pain", - "mabl": "MABL?", - "macs": "MACS?", - "mahw": "Hazardous Waste", - "mapa": "Paint Materials", - "mash": "Shop Materials", - "matd": "Tire Disposal", - "other_amount_payable": "Other Amount Payable", - "owner": "Owner", - "owner_owing": "Cust. Owes", - "ownr_ea": "Email", - "ownr_ph1": "Phone 1", - "paa": "Aftermarket", - "pac": "Rechromed", - "pae": "Existing", - "pag": "Glass", - "pal": "LKQ", - "pam": "Remanufactured", - "pan": "OEM/New", - "pao": "Other", - "pap": "OEM Partial", - "par": "Re-cored", - "parts_tax_rates": { - "prt_discp": "Discount %", - "prt_mktyp": "Markup Type", - "prt_mkupp": "Markup %", - "prt_tax_in": "Tax Indicator", - "prt_tax_rt": "Part Tax Rate", - "prt_type": "Part Type" - }, - "pas": "Sublet", - "pay_date": "Pay Date", - "phoneshort": "PH", - "policy_no": "Policy #", - "ponumber": "PO Number", - "production_vars": { - "note": "Production Note" - }, - "rate_la1": "LA1", - "rate_la2": "LA2", - "rate_la3": "LA3", - "rate_la4": "LA4", - "rate_laa": "Aluminum", - "rate_lab": "Body", - "rate_lad": "Diagnostic", - "rate_lae": "Electrical", - "rate_laf": "Frame", - "rate_lag": "Glass", - "rate_lam": "Mechanical", - "rate_lar": "Refinish", - "rate_las": "Structural", - "rate_lau": "User Defined", - "rate_ma2s": "2 Stage Paint", - "rate_ma3s": "3 Stage Paint", - "rate_mabl": "MABL??", - "rate_macs": "MACS??", - "rate_mahw": "Hazardous Waste", - "rate_mapa": "Paint Materials", - "rate_mash": "Shop Material", - "rate_matd": "Tire Disposal", - "referralsource": "Referral Source", - "regie_number": "Registration #", - "repairtotal": "Repair Total", - "ro_number": "RO #", - "scheduled_completion": "Scheduled Completion", - "scheduled_delivery": "Scheduled Delivery", - "scheduled_in": "Scheduled In", - "selling_dealer": "Selling Dealer", - "selling_dealer_contact": "Selling Dealer Contact", - "servicecar": "Service Car", - "servicing_dealer": "Servicing Dealer", - "servicing_dealer_contact": "Servicing Dealer Contact", - "special_coverage_policy": "Special Coverage Policy", - "specialcoveragepolicy": "Special Coverage Policy", - "state_tax_rate": "Provincial/State Tax Rate", - "status": "Job Status", - "storage_payable": "Storage", - "tax_lbr_rt": "Labor Tax Rate", - "tax_levies_rt": "Levies Tax Rate", - "tax_paint_mat_rt": "Paint Material Tax Rate", - "tax_registration_number": "Tax Registration Number", - "tax_shop_mat_rt": "Shop Material Tax Rate", - "tax_str_rt": "Storage Tax Rate", - "tax_sub_rt": "Sublet Tax Rate", - "tax_tow_rt": "Towing Tax Rate", - "towin": "Tow In", - "towing_payable": "Towing Payable", - "unitnumber": "Unit #", - "updated_at": "Updated At", - "uploaded_by": "Uploaded By", - "vehicle": "Vehicle" - }, - "forms": { - "admindates": "Administrative Dates", - "appraiserinfo": "Estimator Info", - "claiminfo": "Claim Information", - "estdates": "Estimate Dates", - "laborrates": "Labor Rates", - "lossinfo": "Loss Information", - "other": "Other", - "repairdates": "Repair Dates", - "scheddates": "Schedule Dates" - }, - "labels": { - "actual_completion_inferred": "$t(jobs.fields.actual_completion) inferred using $t(jobs.fields.scheduled_completion).", - "actual_delivery_inferred": "$t(jobs.fields.actual_delivery) inferred using $t(jobs.fields.scheduled_delivery).", - "actual_in_inferred": "$t(jobs.fields.actual_in) inferred using $t(jobs.fields.scheduled_in).", - "additionaltotal": "Additional Total", - "adjustmentrate": "Adjustment Rate", - "adjustments": "Adjustments", - "adminwarning": "Use the functionality on this page at your own risk. You are responsible for any and all changes to your data.", - "allocations": "Allocations", - "alreadyclosed": "This job has already been closed.", - "appointmentconfirmation": "Send confirmation to customer?", - "associationwarning": "Any changes to associations will require updating the data from the new parent record to the job.", - "audit": "Audit Trail", - "available": "Available", - "availablejobs": "Available Jobs", - "ca_bc_pvrt": { - "days": "Days", - "rate": "PVRT Rate" - }, - "ca_gst_all_if_null": "If the job is marked as a \"GST Registrant\" and this value is set to $0, the customer will be responsible for paying all of the GST by default. ", - "calc_repair_days": "Calculated Repair Days", - "calc_repair_days_tt": "This is the approximate number of days required to complete the repair according to the target touch time in your shop configuration (current set to {{target_touchtime}}).", - "cards": { - "customer": "Customer Information", - "damage": "Area of Damage", - "dates": "Dates", - "documents": "Recent Documents", - "estimator": "Estimator", - "filehandler": "File Handler", - "insurance": "Insurance Details", - "notes": "Notes", - "parts": "Parts", - "totals": "Totals", - "vehicle": "Vehicle" - }, - "changeclass": "Changing the job's class can have fundamental impacts to already exported accounting items. Are you sure you want to do this?", - "checklistcompletedby": "Checklist completed by {{by}} at {{at}}", - "checklistdocuments": "Checklist Documents", - "checklists": "Checklists", - "closeconfirm": "Are you sure you want to close this job? This cannot be easily undone.", - "closejob": "Close Job {{ro_number}}", - "contracts": "CC Contracts", - "cost": "Cost", - "cost_labor": "Cost - Labor", - "cost_parts": "Cost - Parts", - "costs": "Costs", - "create": { - "jobinfo": "Job Info", - "newowner": "Create a new Owner instead. ", - "newvehicle": "Create a new Vehicle Instead", - "novehicle": "No vehicle (only for ROs to track parts/labor only work).", - "ownerinfo": "Owner Info", - "vehicleinfo": "Vehicle Info" - }, - "creating_new_job": "Creating new job...", - "deductible": { - "stands": "Stands", - "waived": "Waived" - }, - "deleteconfirm": "Are you sure you want to delete this job? This cannot be undone. ", - "deletedelivery": "Delete Delivery Checklist", - "deleteintake": "Delete Intake Checklist", - "deliverchecklist": "Deliver Checklist", - "difference": "Difference", - "diskscan": "Scan Disk for Estimates", - "documents": "Documents", - "documents-images": "Images", - "documents-other": "Other Documents", - "duplicateconfirm": "Are you sure you want to duplicate this job? Some elements of this job will not be duplicated.", - "employeeassignments": "Employee Assignments", - "estimatelines": "Estimate Lines", - "existing_jobs": "Existing Jobs", - "federal_tax_amt": "Federal Taxes", - "gpdollars": "$ G.P.", - "gppercent": "% G.P.", - "hrs_claimed": "Hours Claimed", - "hrs_total": "Hours Total", - "importnote": "The job was initially imported.", - "inproduction": "In Production", - "intakechecklist": "Intake Checklist", - "job": "Job Details", - "jobcosting": "Job Costing", - "jobtotals": "Job Totals", - "labor_rates_subtotal": "Labor Rates Subtotal", - "laborallocations": "Labor Allocations", - "labortotals": "Labor Totals", - "lines": "Estimate Lines", - "local_tax_amt": "Local Taxes", - "mapa": "Paint Materials", - "markforreexport": "Mark for Re-export", - "mash": "Shop Materials", - "net_repairs": "Net Repairs", - "notes": "Notes", - "othertotal": "Other Totals", - "override_header": "Override estimate header on import?", - "ownerassociation": "Owner Association", - "parts": "Parts", - "parts_tax_rates": "Parts Tax rates", - "partsfilter": "Parts Only", - "partssubletstotal": "Parts & Sublets Total", - "partstotal": "Parts Total (ex. Taxes)", - "plitooltips": { - "billtotal": "The total amount of all bill lines that have been posted against this RO (not including credits, taxes, or labor adjustments).", - "creditmemos": "The total amount of all credit memos entered. This amount does not reflect any parts returns created.", - "creditsnotreceived": "The total amount of returns created for this job that do not have a corresponding credit memo posted. An amount greater than $0 indicates that vendors have not provided requested credit memos.", - "discrep1": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Too many bills/bill lines that have been posted against this RO. Check to make sure every bill posted on this RO is correctly posted and assigned.
  • \n
  • You do not have the latest supplement imported, or, a supplement must be submitted and then imported.
  • \n
  • You have posted a bill line to labor.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", - "discrep2": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Used an incorrect rate when deducting from labor.
  • \n
  • An outstanding imbalance higher in the reconciliation process.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", - "discrep3": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Credit memos that have not been received or posted.
  • \n
  • An outstanding imbalance higher in the reconciliation process.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", - "laboradj": "The sum of all bill lines that deducted from labor hours, rather than part prices.", - "partstotal": "This is the total of all parts and sublet amounts on the vehicle (some of these may require an in-house invoice).
\nItems such as shop and paint materials, labor online lines, etc. are not included in this total.", - "totalreturns": "The total amount of returns created for this job." - }, - "prt_dsmk_total": "Line Item Markup", - "rates": "Rates", - "rates_subtotal": "All Rates Subtotal", - "reconciliation": { - "billlinestotal": "Bill Lines Total", - "byassoc": "By Line Association", - "byprice": "By Price", - "clear": "Clear All", - "discrepancy": "Discrepancy", - "joblinestotal": "Job Lines Total", - "multipleactprices": "${{act_price}} is the price for multiple job lines.", - "multiplebilllines": "{{line_desc}} has 2 or more bill lines associated to it.", - "multiplebillsforactprice": "Found more than 1 bill matching ${{act_price}} retail price.", - "removedpartsstrikethrough": "Strike through lines represent parts that have been removed from the estimate. They are included for completeness of reconciliation." - }, - "reconciliationheader": "Parts & Sublet Reconciliation", - "returntotals": "Return Totals", - "rosaletotal": "RO Parts Total", - "sale_labor": "Sales - Labor", - "sale_parts": "Sales - Parts & Sublet", - "sales": "Sales", - "scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the job. ", - "specialcoveragepolicy": "Special Coverage Policy Applies", - "state_tax_amt": "Provincial/State Taxes", - "subletstotal": "Sublets Total", - "subtotal": "Subtotal", - "supplementnote": "The job had a supplement imported.", - "suspense": "Suspense", - "total_cost": "Total Cost", - "total_cust_payable": "Total Customer Amount Payable", - "total_repairs": "Total Repairs", - "total_sales": "Total Sales", - "totals": "Totals", - "unvoidnote": "This job was unvoided.", - "vehicle_info": "Vehicle", - "vehicleassociation": "Vehicle Association", - "viewallocations": "View Allocations", - "voidjob": "Are you sure you want to void this job? This cannot be easily undone. ", - "voidnote": "This job was voided." - }, - "successes": { - "addedtoproduction": "Job added to production board.", - "all_deleted": "{{count}} jobs deleted successfully.", - "closed": "Job closed successfully.", - "converted": "Job converted successfully.", - "created": "Job created successfully. Click to view.", - "creatednoclick": "Job created successfully. ", - "delete": "Job deleted successfully.", - "deleted": "Job deleted successfully.", - "duplicated": "Job duplicated successfully. ", - "exported": "Job(s) exported successfully. ", - "invoiced": "Job closed and invoiced successfully.", - "partsqueue": "Job added to parts queue.", - "save": "Job saved successfully.", - "savetitle": "Record saved successfully.", - "supplemented": "Job supplemented successfully. ", - "updated": "Job(s) updated successfully.", - "voided": "Job voided successfully." - } - }, - "landing": { - "bigfeature": { - "subtitle": "ImEX Online is built using world class technology by experts in the collision repair industry. This translates to software that is tailor made for the unique challenges faced by repair facilities with no compromises. ", - "title": "Bringing the latest technology to the automotive repair industry. " - }, - "footer": { - "company": { - "about": "About Us", - "contact": "Contact", - "disclaimers": "Disclaimers", - "name": "Company", - "privacypolicy": "Privacy Policy" - }, - "io": { - "help": "Help", - "name": "ImEX Online", - "status": "System Status" - }, - "slogan": "A whole new kind of shop management system." - }, - "hero": { - "button": "Coming Soon", - "title": "A whole new kind of shop management system." - }, - "labels": { - "features": "Features", - "managemyshop": "Manage my Shop", - "pricing": "Pricing" - }, - "pricing": { - "basic": { - "name": "Basic", - "sub": "Best suited for shops looking to increase their volume." - }, - "essentials": { - "name": "Essentials", - "sub": "Best suited for small and low volume shops." - }, - "pricingtitle": "Features", - "pro": { - "name": "Pro", - "sub": "Empower your shop with the tools to operate at peak capacity." - }, - "title": "Features", - "unlimited": { - "name": "Unlimited", - "sub": "Everything you need and more for the high volume shop." - } - } - }, - "menus": { - "currentuser": { - "languageselector": "Language", - "profile": "Profile" - }, - "header": { - "accounting": "Accounting", - "accounting-payables": "Payables", - "accounting-payments": "Payments", - "accounting-receivables": "Receivables", - "activejobs": "Active Jobs", - "alljobs": "All Jobs", - "allpayments": "All Payments", - "availablejobs": "Available Jobs", - "bills": "Bills", - "courtesycars": "Courtesy Cars", - "courtesycars-all": "All Courtesy Cars", - "courtesycars-contracts": "Contracts", - "courtesycars-newcontract": "New Contract", - "customers": "Customers", - "dashboard": "Dashboard", - "enterbills": "Enter Bills", - "enterpayment": "Enter Payments", - "entertimeticket": "Enter Time Tickets", - "export": "Export", - "export-logs": "Export Logs", - "help": "Help", - "home": "Home", - "jobs": "Jobs", - "newjob": "Create New Job", - "owners": "Owners", - "parts-queue": "Parts Queue", - "phonebook": "Phonebook", - "productionboard": "Production Board - Visual", - "productionlist": "Production Board - List", - "recent": "Recent Items", - "reportcenter": "Report Center", - "rescueme": "Rescue me!", - "schedule": "Schedule", - "scoreboard": "Scoreboard", - "search": { - "bills": "Bills", - "jobs": "Jobs", - "owners": "Owners", - "payments": "Payments", - "phonebook": "Phonebook", - "vehicles": "Vehicles" - }, - "shiftclock": "Shift Clock", - "shop": "My Shop", - "shop_config": "Configuration", - "shop_csi": "CSI", - "shop_templates": "Templates", - "shop_vendors": "Vendors", - "temporarydocs": "Temporary Documents", - "timetickets": "Time Tickets", - "vehicles": "Vehicles" - }, - "jobsactions": { - "admin": "Admin", - "closejob": "Close Job", - "deletejob": "Delete Job", - "duplicate": "Duplicate this Job", - "duplicatenolines": "Duplicate this Job without Repair Data", - "newcccontract": "Create Courtesy Car Contract", - "void": "Void Job" - }, - "jobsdetail": { - "claimdetail": "Claim Details", - "dates": "Dates", - "financials": "Financial Information", - "general": "General", - "insurance": "Insurance Information", - "labor": "Labor", - "partssublet": "Parts & Bills", - "rates": "Rates", - "repairdata": "Repair Data", - "totals": "Totals" - }, - "profilesidebar": { - "profile": "My Profile", - "shops": "My Shops" - }, - "tech": { - "home": "Home", - "jobclockin": "Job Clock In", - "jobclockout": "Job Clock Out", - "joblookup": "Job Lookup", - "login": "Login", - "logout": "Logout", - "productionboard": "Production Board - Visual", - "productionlist": "Production List", - "shiftclockin": "Shift Clock" - } - }, - "messaging": { - "actions": { - "link": "Link to Job", - "new": "New Conversation" - }, - "errors": { - "invalidphone": "The phone number is invalid. Unable to open conversation. " - }, - "labels": { - "archive": "Archive", - "maxtenimages": "You can only select up to a maximum of 10 images at a time.", - "messaging": "Messaging", - "noallowtxt": "This customer has not indicated their permission to be messaged.", - "nojobs": "Not associated to any job.", - "phonenumber": "Phone #", - "presets": "Presets", - "selectmedia": "Select Media", - "sentby": "Sent by {{by}} at {{time}}", - "typeamessage": "Send a message...", - "unarchive": "Unarchive" - } - }, - "notes": { - "actions": { - "actions": "Actions", - "deletenote": "Delete Note", - "edit": "Edit Note", - "new": "New Note" - }, - "fields": { - "createdby": "Created By", - "critical": "Critical", - "private": "Private", - "text": "Contents", - "updatedat": "Updated At" - }, - "labels": { - "newnoteplaceholder": "Add a note..." - }, - "successes": { - "create": "Note created successfully.", - "deleted": "Note deleted successfully.", - "updated": "Note updated successfully." - } - }, - "owners": { - "actions": { - "update": "Update Selected Records" - }, - "errors": { - "noaccess": "The record does not exist or you do not have access to it. ", - "selectexistingornew": "Select an existing owner record or create a new one. " - }, - "fields": { - "address": "Address", - "allow_text_message": "Permission to Text?", - "name": "Name", - "ownr_addr1": "Address", - "ownr_addr2": "Address 2", - "ownr_city": "City", - "ownr_co_nm": "Owner Co. Name", - "ownr_ctry": "Country", - "ownr_ea": "Email", - "ownr_fn": "First Name", - "ownr_ln": "Last Name", - "ownr_ph1": "Phone 1", - "ownr_st": "Province/State", - "ownr_title": "Title", - "ownr_zip": "Zip/Postal Code", - "preferred_contact": "Preferred Contact Method" - }, - "forms": { - "address": "Address", - "contact": "Contact Information", - "name": "Owner Details" - }, - "labels": { - "create_new": "Create a new owner record.", - "existing_owners": "Existing Owners", - "fromclaim": "Current Claim", - "fromowner": "Historical Owner Record", - "relatedjobs": "Related Jobs", - "updateowner": "Update Owner" - }, - "successes": { - "save": "Owner saved successfully." - } - }, - "parts": { - "actions": { - "order": "Order Parts" - } - }, - "parts_orders": { - "actions": { - "backordered": "Mark Backordered", - "receive": "Receive", - "receivebill": "Receive Bill" - }, - "errors": { - "backordering": "Error backordering part {{message}}.", - "creating": "Error encountered when creating parts order. " - }, - "fields": { - "act_price": "Price", - "backordered_eta": "B.O. ETA", - "backordered_on": "B.O. On", - "cost": "Cost", - "db_price": "List Price", - "deliver_by": "Date", - "job_line_id": "Job Line Id", - "line_desc": "Line Description", - "line_remarks": "Remarks", - "lineremarks": "Line Remarks", - "oem_partno": "Part #", - "order_date": "Order Date", - "order_number": "Order Number", - "orderedby": "Ordered By", - "quantity": "Qty.", - "return": "Return", - "status": "Status" - }, - "labels": { - "allpartsto": "All Parts Location", - "confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. ", - "email": "Send by Email", - "inthisorder": "Parts in this Order", - "newpartsorder": "New Parts Order", - "orderhistory": "Order History", - "parts_orders": "Parts Orders", - "print": "Show Printed Form", - "receive": "Receive Parts Order", - "returnpartsorder": "Return Parts Order" - }, - "successes": { - "created": "Parts order created successfully. ", - "received": "Parts order received.", - "return_created": "Parts return created successfully." - } - }, - "payments": { - "errors": { - "exporting": "Error exporting payment(s). {{error}}", - "exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors." - }, - "fields": { - "amount": "Amount", - "created_at": "Created At", - "date": "Payment Date", - "exportedat": "Exported At", - "memo": "Memo", - "payer": "Payer", - "paymentnum": "Payment Number", - "stripeid": "Stripe ID", - "transactionid": "Transaction ID", - "type": "Type" - }, - "labels": { - "balance": "Balance", - "ca_bc_etf_table": "ICBC ETF Table Converter", - "customer": "Customer", - "edit": "Edit Payment", - "electronicpayment": "Use Electronic Payment Processing?", - "findermodal": "ICBC Payment Finder", - "insurance": "Insurance", - "new": "New Payment", - "signup": "Please contact support to sign up for electronic payments.", - "title": "Payments", - "totalpayments": "Total Payments" - }, - "successes": { - "exported": "Payment(s) exported successfully.", - "payment": "Payment created successfully. ", - "stripe": "Credit card transaction charged successfully." - } - }, - "phonebook": { - "actions": { - "new": "New Phonebook Entry" - }, - "errors": { - "adding": "Error adding phonebook entry. {{error}}", - "saving": "Error saving phonebook entry. {{error}}" - }, - "fields": { - "address1": "Street 1", - "address2": "Street 2", - "category": "Category", - "city": "City", - "company": "Company", - "country": "Country", - "email": "Email", - "fax": "Fax", - "firstname": "First Name", - "lastname": "Last Name", - "phone1": "Phone 1", - "phone2": "Phone 2", - "state": "Province/State" - }, - "labels": { - "noneselected": "No phone book entry selected. ", - "onenamerequired": "At least one name related field is required.", - "vendorcategory": "Vendor" - }, - "successes": { - "added": "Phonebook entry added successfully. ", - "deleted": "Phonebook entry deleted successfully. ", - "saved": "Phonebook entry saved successfully. " - } - }, - "printcenter": { - "appointments": { - "appointment_confirmation": "Appointment Confirmation" - }, - "bills": { - "inhouse_invoice": "In House Invoice" - }, - "courtesycarcontract": { - "courtesy_car_contract": "Courtesy Car Contract", - "courtesy_car_impound": "Impound Charges", - "courtesy_car_terms": "Courtesy Car Terms" - }, - "errors": { - "nocontexttype": "No context type set." - }, - "jobs": { - "3rdpartyfields": { - "addr1": "Address 1", - "addr2": "Address 2", - "addr3": "Address 3", - "attn": "Attention", - "city": "City", - "custgst": "Customer Portion of GST", - "ded_amt": "Deductible", - "depreciation": "Depreciation", - "other": "Other", - "ponumber": "PO Number", - "refnumber": "Reference Number", - "sendtype": "Send by", - "state": "Province/State", - "zip": "Postal Code/Zip" - }, - "3rdpartypayer": "Invoice to Third Party Payer", - "appointment_confirmation": "Appointment Confirmation", - "appointment_reminder": "Appointment Reminder", - "casl_authorization": "CASL Authorization", - "coversheet_landscape": "Coversheet (Landscape)", - "coversheet_portrait": "Coversheet Portrait", - "csi_invitation": "CSI Invitation", - "diagnostic_authorization": "Diagnostic Authorization", - "estimate": "Estimate Only", - "estimate_detail": "Estimate Details", - "estimate_followup": "Estimate Followup", - "express_repair_checklist": "Express Repair Checklist", - "filing_coversheet_portrait": "Filing Coversheet (Portrait)", - "final_invoice": "Final Invoice", - "fippa_authorization": "FIPPA Authorization", - "glass_express_checklist": "Glass Express Checklist", - "guarantee": "Repair Guarantee", - "invoice_customer_payable": "Invoice (Customer Payable)", - "invoice_total_payable": "Invoice (Total Payable)", - "job_costing_ro": "Job Costing", - "job_notes": "Job Notes", - "key_tag": "Key Tag", - "paint_grid": "Paint Grid", - "parts_label_single": "Parts Label - Single", - "parts_list": "Parts List", - "parts_order": "Parts Order Confirmation", - "parts_order_confirmation": "", - "parts_order_history": "Parts Order History", - "parts_return_slip": "Parts Return Slip", - "payment_receipt": "Payment Receipt", - "payment_request": "Payment Request", - "payments_by_job": "Job Payments", - "purchases_by_ro_detail": "Purchases - Detail", - "purchases_by_ro_summary": "Purchases - Summary", - "qc_sheet": "Quality Control Sheet", - "ro_totals": "RO Totals", - "ro_with_description": "RO Summary with Descriptions", - "stolen_recovery_checklist": "Stolen Recovery Checklist", - "supplement_request": "Supplement Request", - "thank_you_ro": "Thank You Letter", - "thirdpartypayer": "Third Party Payer", - "vehicle_check_in": "Vehicle Intake", - "vehicle_delivery_check": "Vehicle Delivery Checklist", - "window_tag": "Window Tag", - "window_tag_sublet": "Window Tag - Sublet", - "work_authorization": "Work Authorization", - "worksheet_by_line_number": "Worksheet by Line Number", - "worksheet_sorted_by_operation": "Worksheet by Operation", - "worksheet_sorted_by_operation_no_hours": "Worksheet by Operation (No Hours)", - "worksheet_sorted_by_operation_part_type": "Worksheet by Operation & Part Type" - }, - "labels": { - "groups": { - "authorization": "Authorization", - "financial": "Financial", - "post": "Post-Production", - "pre": "Pre-Production", - "ro": "Repair Order", - "worksheet": "Worksheets" - }, - "misc": "Miscellaneous Documents", - "repairorder": "Repair Order Related", - "reportcentermodal": "Report Center", - "speedprint": "Speed Print", - "title": "Print Center" - }, - "payments": { - "ca_bc_etf_table": "ICBC ETF Table" - }, - "vendors": { - "purchases_by_vendor_detailed": "Purchases by Vendor - Detailed", - "purchases_by_vendor_summary": "Purchases by Vendor - Summary" - } - }, - "production": { - "actions": { - "addcolumns": "Add Columns", - "bodypriority-clear": "Clear Body Priority", - "bodypriority-set": "Set Body Priority", - "detailpriority-clear": "Clear Detail Priority", - "detailpriority-set": "Set Detail Priority", - "paintpriority-clear": "Clear Paint Priority", - "paintpriority-set": "Set Paint Priority", - "remove": "Remove from Production", - "removecolumn": "Remove Column", - "saveconfig": "Save Configuration" - }, - "errors": { - "boardupdate": "Error encountered updating job. {{message}}", - "removing": "Error removing from production board. {{error}}" - }, - "labels": { - "alert": "Alert", - "alertoff": "Remove alert from job", - "alerton": "Add alert to job", - "bodyhours": "B", - "bodypriority": "B/P", - "detailpriority": "D/P", - "employeesearch": "Employee Search", - "jobdetail": "Job Details", - "note": "Production Note", - "paintpriority": "P/P", - "refinishhours": "R", - "selectview": "Select a View", - "sublets": "Sublets", - "totalhours": "Total Hrs ", - "touchtime": "T/T", - "viewname": "View Name" - }, - "successes": { - "removed": "Job removed from production." - } - }, - "profile": { - "errors": { - "state": "Error reading page state. Please refresh." - }, - "labels": { - "activeshop": "Active Shop" - }, - "successes": { - "updated": "Profile updated successfully." - } - }, - "reportcenter": { - "actions": { - "generate": "Generate" - }, - "labels": { - "dates": "Dates", - "employee": "Employee", - "filterson": "Filters on {{object}}: {{field}}", - "generateasemail": "Generate as Email?", - "key": "Report", - "objects": { - "appointments": "Appointments", - "bills": "Bills", - "exportlogs": "Export Logs", - "jobs": "Jobs", - "parts_orders": "Parts Orders", - "payments": "Payments", - "scoreboard": "Scoreboard", - "timetickets": "Timetickets" - }, - "vendor": "Vendor" - }, - "templates": { - "anticipated_revenue": "Anticipated Revenue", - "attendance_detail": "Attendance (All Employees)", - "attendance_employee": "Employee Attendance", - "attendance_summary": "Attendance Summary (All Employees)", - "credits_not_received_date": "Credits not Received by Date", - "estimator_detail": "Jobs by Estimator (Detail)", - "estimator_summary": "Jobs by Estimator (Summary)", - "export_payables": "Export Log - Payables", - "export_payments": "Export Log - Payments", - "export_receivables": "Export Log - Receivables", - "gsr_by_csr": "Gross Sales by CSR", - "gsr_by_delivery_date": "Gross Sales by Delivery Date", - "gsr_by_estimator": "Gross Sales by Estimator", - "gsr_by_exported_date": "Gross Sales by Export Date", - "gsr_by_ins_co": "Gross Sales by Insurance Company", - "gsr_by_make": "Gross Sales by Vehicle Make", - "gsr_by_referral": "Gross Sales by Referral Source", - "gsr_by_ro": "Gross Sales by RO", - "gsr_labor_only": "Gross Sales - Labor Only", - "hours_sold_detail_closed": "Hours Sold Detail - Closed", - "hours_sold_detail_closed_csr": "Hours Sold Detail - Closed by CSR", - "hours_sold_detail_closed_ins_co": "Hours Sold Detail - Closed by Source", - "hours_sold_detail_open": "Hours Sold Detail - Open", - "hours_sold_detail_open_csr": "Hours Sold Detail - Open by CSR", - "hours_sold_detail_open_ins_co": "Hours Sold Detail - Open by Source", - "hours_sold_summary_closed": "Hours Sold Summary - Closed", - "hours_sold_summary_closed_csr": "Hours Sold Summary - Closed by CSR", - "hours_sold_summary_closed_ins_co": "Hours Sold Summary - Closed by Source", - "hours_sold_summary_open": "Hours Sold Summary - Open", - "hours_sold_summary_open_csr": "Hours Sold Summary - Open CSR", - "hours_sold_summary_open_ins_co": "Hours Sold Summary - Open by Source", - "job_costing_ro_csr": "Job Costing by CSR", - "job_costing_ro_date_detail": "Job Costing by RO - Detail", - "job_costing_ro_date_summary": "Job Costing by RO - Summary", - "job_costing_ro_estimator": "Job Costing by Estimator", - "job_costing_ro_ins_co": "Job Costing by RO Source", - "lag_time": "Lag Time", - "open_orders": "Open Orders by Date", - "open_orders_csr": "Open Orders by CSR", - "open_orders_estimator": "Open Orders by Estimator", - "open_orders_ins_co": "Open Orders by Insurance Company", - "parts_backorder": "Backordered Parts", - "parts_not_recieved": "Parts Not Received", - "payments_by_date": "Payments by Date", - "payments_by_date_type": "Payments by Date and Type", - "production_by_csr": "Production by CSR", - "production_by_last_name": "Production by Last Name", - "production_by_repair_status": "Production by Status", - "production_by_ro": "Production by RO", - "production_by_target_date": "Production by Target Date", - "purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)", - "purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)", - "purchases_by_date_range_detail": "Purchases by Date - Detail", - "purchases_by_date_range_summary": "Purchases by Date - Summary", - "purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed", - "purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary", - "purchases_grouped_by_vendor_detailed": "Purchases Grouped by Vendor - Detailed", - "purchases_grouped_by_vendor_summary": "Purchases Grouped by Vendor - Summary", - "schedule": "Appointment Schedule", - "scoreboard_detail": "Scoreboard Detail", - "scoreboard_summary": "Scoreboard Summary", - "supplement_ratio_ins_co": "Supplement Ratio by Source", - "thank_you_date": "Thank You Letters", - "timetickets": "Time Tickets", - "timetickets_employee": "Employee Time Tickets", - "timetickets_summary": "Time Tickets Summary", - "unclaimed_hrs": "Unclaimed Hours", - "void_ros": "Void ROs", - "work_in_progress_labour": "Work in Progress - Labor", - "work_in_progress_payables": "Work in Progress - Payables" - } - }, - "scoreboard": { - "actions": { - "edit": "Edit" - }, - "errors": { - "adding": "Error adding job to scoreboard. {{message}}", - "removing": "Error removing job from scoreboard. {{message}}", - "updating": "Error updating scoreboard. {{message}}" - }, - "fields": { - "bodyhrs": "Body Hours", - "date": "Date", - "painthrs": "Paint Hours" - }, - "labels": { - "asoftodaytarget": "As of Today", - "dailytarget": "Daily", - "monthlytarget": "Monthly", - "targets": "Targets", - "weeklytarget": "Weekly", - "workingdays": "Working Days / Month" - }, - "successes": { - "added": "Job added to scoreboard.", - "removed": "Job removed from scoreboard.", - "updated": "Scoreboard updated." - } - }, - "scoredboard": { - "successes": { - "updated": "Scoreboard entry updated." - } - }, - "tech": { - "fields": { - "employeeid": "Employee ID", - "pin": "PIN" - }, - "labels": { - "loggedin": "Logged in as {{name}}", - "notloggedin": "Not logged in." - } - }, - "templates": { - "errors": { - "updating": "Error updating template {{error}}." - }, - "successes": { - "updated": "Template updated successfully." - } - }, - "timetickets": { - "actions": { - "clockin": "Clock In", - "clockout": "Clock Out", - "enter": "Enter New Time Ticket", - "printemployee": "Print Time Tickets" - }, - "errors": { - "clockingin": "Error while clocking in. {{message}}", - "clockingout": "Error while clocking out. {{message}}", - "creating": "Error creating time ticket. {{message}}", - "deleting": "Error deleting time ticket. {{message}}", - "noemployeeforuser": "Unable to use Shift Clock", - "noemployeeforuser_sub": "An employee record has not been created for this user. Please create one before using the shift clock. " - }, - "fields": { - "actualhrs": "Actual Hours", - "ciecacode": "CIECA Code", - "clockhours": "Clock Hours", - "clockoff": "Clock Off", - "clockon": "Clocked In", - "cost_center": "Cost Center", - "date": "Ticket Date", - "efficiency": "Efficiency", - "employee": "Employee", - "flat_rate": "Flat Rate?", - "memo": "Memo", - "productivehrs": "Productive Hours", - "ro_number": "Job to Post Against" - }, - "labels": { - "alreadyclockedon": "You are already clocked in to the following job(s):", - "ambreak": "AM Break", - "amshift": "AM Shift", - "clockhours": "Shift Clock Hours Summary", - "clockintojob": "Clock In to Job", - "deleteconfirm": "Are you sure you want to delete this time ticket? This cannot be undone.", - "edit": "Edit Time Ticket", - "efficiency": "Efficiency", - "flat_rate": "Flat Rate", - "jobhours": "Job Related Time Tickets Summary", - "lunch": "Lunch", - "new": "New Time Ticket", - "pmbreak": "PM Break", - "pmshift": "PM Shift", - "shift": "Shift", - "shiftalreadyclockedon": "Active Shift Time Tickets", - "straight_time": "Straight Time", - "timetickets": "Time Tickets", - "zeroactualnegativeprod": "Actual hours must be 0 if entering negative productive hours." - }, - "successes": { - "clockedin": "Clocked in successfully.", - "clockedout": "Clocked out successfully.", - "created": "Time ticket entered successfully.", - "deleted": "Time ticket deleted successfully." - } - }, - "titles": { - "accounting-payables": "Payables | $t(titles.app)", - "accounting-payments": "Payments | $t(titles.app)", - "accounting-receivables": "Receivables | $t(titles.app)", - "app": "ImEX Online", - "bc": { - "accounting-payables": "Payables", - "accounting-payments": "Payments", - "accounting-receivables": "Receivables", - "availablejobs": "Available Jobs", - "bills-list": "Bills", - "contracts": "Contracts", - "contracts-create": "New Contract", - "contracts-detail": "Contract #{{number}}", - "courtesycars": "Courtesy Cars", - "courtesycars-detail": "Courtesy Car {{number}}", - "courtesycars-new": "New Courtesy Car", - "dashboard": "Dashboard", - "export-logs": "Export Logs", - "jobs": "Jobs", - "jobs-active": "Active Jobs", - "jobs-admin": "Admin", - "jobs-all": "All Jobs", - "jobs-checklist": "Checklist", - "jobs-close": "Close Job", - "jobs-deliver": "Deliver Job", - "jobs-detail": "Job {{number}}", - "jobs-intake": "Intake", - "jobs-new": "Create a New Job", - "owner-detail": "{{name}}", - "owners": "Owners", - "parts-queue": "Parts Queue", - "payments-all": "All Payments", - "phonebook": "Phonebook", - "productionboard": "Production Board - Visual", - "productionlist": "Production Board - List", - "profile": "My Profile", - "schedule": "Schedule", - "scoreboard": "Scoreboard", - "shop": "Manage my Shop ({{shopname}})", - "shop-csi": "CSI Responses", - "shop-templates": "Shop Templates", - "shop-vendors": "Vendors", - "temporarydocs": "Temporary Documents", - "timetickets": "Time Tickets", - "vehicle-details": "Vehicle: {{vehicle}}", - "vehicles": "Vehicles" - }, - "bills-list": "Bills | $t(titles.app)", - "contracts": "Courtesy Car Contracts | $t(titles.app)", - "contracts-create": "New Contract | $t(titles.app)", - "contracts-detail": "Contract {{id}} | $t(titles.app)", - "courtesycars": "Courtesy Cars | $t(titles.app)", - "courtesycars-create": "New Courtesy Car | $t(titles.app)", - "courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)", - "dashboard": "Dashboard | $t(titles.app)", - "export-logs": "Export Logs | $t(titles.app)", - "jobs": "Active Jobs | $t(titles.app)", - "jobs-admin": "Job {{ro_number}} - Admin | $t(titles.app)", - "jobs-all": "All Jobs | $t(titles.app)", - "jobs-checklist": "Job Checklist | $t(titles.app)", - "jobs-close": "Close Job {{number}} | $t(titles.app)", - "jobs-create": "Create a New Job | $t(titles.app)", - "jobs-deliver": "Deliver Job | $t(titles.app)", - "jobs-intake": "Intake | $t(titles.app)", - "jobsavailable": "Available Jobs | $t(titles.app)", - "jobsdetail": "Job {{ro_number}} | $t(titles.app)", - "jobsdocuments": "Job Documents {{ro_number}} | $t(titles.app)", - "manageroot": "Home | $t(titles.app)", - "owners": "All Owners | $t(titles.app)", - "owners-detail": "{{name}} | $t(titles.app)", - "parts-queue": "Parts Queue | $t(titles.app)", - "payments-all": "Payments | $t(titles.app)", - "phonebook": "Phonebook | $t(titles.app)", - "productionboard": "Production - Board", - "productionlist": "Production Board - List | $t(titles.app)", - "profile": "My Profile | $t(titles.app)", - "resetpassword": "Reset Password", - "resetpasswordvalidate": "Enter New Password", - "schedule": "Schedule | $t(titles.app)", - "scoreboard": "Scoreboard | $t(titles.app)", - "shop": "My Shop | $t(titles.app)", - "shop-csi": "CSI Responses | $t(titles.app)", - "shop-templates": "Shop Templates | $t(titles.app)", - "shop_vendors": "Vendors | $t(titles.app)", - "temporarydocs": "Temporary Documents | $t(titles.app)", - "timetickets": "Time Tickets | $t(titles.app)", - "vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)", - "vehicles": "All Vehicles | $t(titles.app)" - }, - "user": { - "actions": { - "changepassword": "Change Password", - "signout": "Sign Out", - "updateprofile": "Update Profile" - }, - "errors": { - "updating": "Error updating user or association {{message}}" - }, - "fields": { - "authlevel": "Authorization Level", - "displayname": "Display Name", - "email": "Email", - "photourl": "Avatar URL" - }, - "labels": { - "actions": "Actions" - }, - "successess": { - "passwordchanged": "Password changed successfully. " - } - }, - "vehicles": { - "errors": { - "noaccess": "The vehicle does not exist or you do not have access to it.", - "selectexistingornew": "Select an existing vehicle record or create a new one. ", - "validation": "Please ensure all fields are entered correctly.", - "validationtitle": "Validation Error" - }, - "fields": { - "description": "Vehicle Description", - "plate_no": "License Plate", - "plate_st": "Plate Jurisdiction", - "trim_color": "Trim Color", - "v_bstyle": "Body Style", - "v_color": "Color", - "v_cond": "Condition", - "v_engine": "Engine", - "v_make_desc": "Make", - "v_makecode": "Make Code", - "v_mldgcode": "Molding Code", - "v_model_desc": "Model", - "v_model_yr": "Year", - "v_options": "Options", - "v_paint_codes": "Paint Codes {{number}}", - "v_prod_dt": "Production Date", - "v_stage": "Stage", - "v_tone": "Tone", - "v_trimcode": "Trim Code", - "v_type": "Type", - "v_vin": "V.I.N." - }, - "forms": { - "detail": "Vehicle Details", - "misc": "Miscellaneous", - "registration": "Registration" - }, - "labels": { - "fromvehicle": "Historical Vehicle Record", - "relatedjobs": "Related Jobs", - "updatevehicle": "Update Vehicle Information" - }, - "successes": { - "save": "Vehicle saved successfully." - } - }, - "vendors": { - "actions": { - "addtophonebook": "Add to Phonebook", - "new": "New Vendor", - "newpreferredmake": "New Preferred Make" - }, - "errors": { - "deleting": "Error encountered while deleting vendor. ", - "saving": "Error encountered while saving vendor. " - }, - "fields": { - "active": "Active", - "am": "Aftermarket", - "city": "City", - "cost_center": "Cost Center", - "country": "Country", - "discount": "Discount % (as decimal)", - "display_name": "Display Name", - "due_date": "Payment Due Date", - "email": "Contact Email", - "favorite": "Favorite?", - "lkq": "LKQ", - "make": "Make", - "name": "Vendor Name", - "oem": "OEM", - "phone": "Phone", - "prompt_discount": "Prompt Discount %", - "state": "Province/State", - "street1": "Street", - "street2": "Address 2", - "taxid": "Tax ID", - "terms": "Payment Terms", - "zip": "Zip/Postal Code" - }, - "labels": { - "noneselected": "No vendor is selected.", - "preferredmakes": "Preferred Makes for Vendor", - "search": "Type a Vendor's Name" - }, - "successes": { - "deleted": "Vendor deleted successfully. ", - "saved": "Vendor saved successfully." - }, - "validation": { - "unique_vendor_name": "You must enter a unique vendor name." - } - } - } + "translation": { + "allocations": { + "actions": { + "assign": "Assign" + }, + "errors": { + "deleting": "Error encountered while deleting allocation. {{message}}", + "saving": "Error while allocating. {{message}}", + "validation": "Please ensure all fields are entered correctly. " + }, + "fields": { + "employee": "Allocated To" + }, + "successes": { + "deleted": "Allocation deleted successfully.", + "save": "Allocated successfully. " + } + }, + "appointments": { + "actions": { + "block": "Block Day", + "calculate": "Calculate SMART Dates", + "cancel": "Cancel", + "intake": "Intake", + "new": "New Appointment", + "preview": "Preview", + "reschedule": "Reschedule", + "sendreminder": "Send Reminder", + "viewjob": "View Job" + }, + "errors": { + "blocking": "Error creating block {{message}}.", + "canceling": "Error canceling appointment. {{message}}", + "saving": "Error scheduling appointment. {{message}}" + }, + "fields": { + "alt_transport": "Alt. Trans.", + "color": "Appointment Color", + "note": "Appt. Note", + "time": "Appointment Time", + "title": "Title" + }, + "labels": { + "arrivedon": "Arrived on: ", + "arrivingjobs": "Arriving Jobs", + "blocked": "Blocked", + "cancelledappointment": "Canceled appointment for: ", + "completingjobs": "Completing Jobs", + "history": "History", + "inproduction": "Jobs In Production", + "noarrivingjobs": "No jobs are arriving.", + "nocompletingjobs": "No jobs scheduled for completion.", + "nodateselected": "No date has been selected.", + "priorappointments": "Previous Appointments", + "reminder": "This is {{shopname}} reminding you about an appointment on {{date}} at {{time}}. Please let us know if you are not able to make the appointment. We look forward to seeing you soon. ", + "scheduledfor": "Scheduled appointment for: ", + "smartscheduling": "Smart Scheduling", + "suggesteddates": "Suggested Dates" + }, + "successes": { + "canceled": "Appointment canceled successfully.", + "created": "Appointment scheduled successfully.", + "saved": "Appointment saved successfully." + } + }, + "associations": { + "actions": { + "activate": "Activate" + }, + "fields": { + "active": "Active?", + "shopname": "Shop Name" + }, + "labels": { + "actions": "Actions" + } + }, + "audit": { + "fields": { + "created": "Time", + "operation": "Operation", + "useremail": "User", + "values": "Values" + } + }, + "audit_trail": { + "messages": { + "billposted": "Bill with invoice number {{invoice_number}} posted.", + "billupdated": "Bill with invoice number {{invoice_number}} updated.", + "jobassignmentchange": "Employee {{name}} assigned to {{operation}}", + "jobassignmentremoved": "Employee assignment removed for {{operation}}", + "jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.", + "jobconverted": "Job converted and assigned number {{ro_number}}.", + "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", + "jobimported": "Job imported.", + "jobinproductionchange": "Job production status set to {{inproduction}}", + "jobmodifylbradj": "Labor adjustments modified.", + "jobspartsorder": "Parts order {{order_number}} added to job.", + "jobspartsreturn": "Parts return {{order_number}} added to job.", + "jobstatuschange": "Job status changed to {{status}}.", + "jobsupplement": "Job supplement imported." + } + }, + "billlines": { + "actions": { + "newline": "New Line" + }, + "fields": { + "actual_cost": "Actual Cost", + "actual_price": "Retail", + "cost_center": "Cost Center", + "federal_tax_applicable": "Fed. Tax?", + "jobline": "Job Line", + "line_desc": "Line Description", + "local_tax_applicable": "Loc. Tax?", + "location": "Location", + "quantity": "Quantity", + "state_tax_applicable": "St. Tax?" + }, + "labels": { + "deductedfromlbr": "Deduct from Labor?", + "entered": "Entered", + "from": "From", + "other": "-- Not On Estimate --", + "reconciled": "Reconciled!", + "unreconciled": "Unreconciled" + } + }, + "bills": { + "actions": { + "edit": "Edit", + "receive": "Receive Part", + "return": "Return Items" + }, + "errors": { + "creating": "Error adding bill. {{error}}", + "deleting": "Error deleting bill. {{error}}", + "exporting": "Error exporting payable(s). {{error}}", + "exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.", + "invalidro": "Not a valid RO.", + "invalidvendor": "Not a valid vendor.", + "validation": "Please ensure all fields are entered correctly. " + }, + "fields": { + "allpartslocation": "Parts Bin", + "date": "Bill Date", + "exported": "Exported", + "federal_tax_rate": "Federal Tax Rate", + "invoice_number": "Invoice Number", + "is_credit_memo": "Credit Memo?", + "local_tax_rate": "Local Tax Rate", + "ro_number": "RO Number", + "state_tax_rate": "Provincial/State Tax Rate", + "total": "Bill Total", + "vendor": "Vendor", + "vendorname": "Vendor Name" + }, + "labels": { + "actions": "Actions", + "bill_lines": "Bill Lines", + "bill_total": "Bill Total Amount", + "billcmtotal": "Credit Memos", + "bills": "Bills", + "creditsnotreceived": "Credits Not Received", + "creditsreceived": "Credits Received", + "dedfromlbr": "Labor Adjustments", + "deleteconfirm": "Are you sure you want to delete this bill? It cannot be undone. If this bill has deductions from labors, manual changes may be required.", + "discrepancy": "Discrepancy", + "discrepwithcms": "Discrepancy including Credit Memos", + "discrepwithlbradj": "Discrepancy including Lbr. Adj.", + "editadjwarning": "This bill had lines which resulted in labor adjustments. Manual correction to adjustments may be required.", + "entered_total": "Total of Entered Lines", + "enteringcreditmemo": "You are entering a credit memo. Please ensure you are also entering positive values.", + "federal_tax": "Federal Tax", + "local_tax": "Local Tax", + "markforreexport": "Mark for Re-export", + "new": "New Bill", + "noneselected": "No bill selected.", + "onlycmforinvoiced": "Only credit memos can be entered for any job that has been invoiced, exported, or voided.", + "retailtotal": "Bills Retail Total", + "state_tax": "Provincial/State Tax", + "subtotal": "Subtotal", + "totalreturns": "Total Returns" + }, + "successes": { + "created": "Invoice added successfully.", + "deleted": "Bill deleted successfully.", + "exported": "Bill(s) exported successfully.", + "reexport": "Bill marked for re-export." + }, + "validation": { + "manualinhouse": "Manual posting to the in house vendor is restricted. ", + "unique_invoice_number": "This invoice number has already been entered for this vendor." + } + }, + "bodyshop": { + "actions": { + "addapptcolor": "Add Appointment Color", + "addbucket": "Add Definition", + "addpartslocation": "Add Parts Location", + "addspeedprint": "Add Speed Print", + "addtemplate": "Add Template", + "newlaborrate": "New Labor Rate", + "newsalestaxcode": "New Sales Tax Code", + "newstatus": "Add Status", + "testrender": "Test Render" + }, + "errors": { + "loading": "Unable to load shop details. Please call technical support.", + "saving": "Error encountered while saving. {{message}}" + }, + "fields": { + "address1": "Address 1", + "address2": "Address 2", + "appt_alt_transport": "Appointment Alternative Transportation Options", + "appt_colors": { + "color": "Color", + "label": "Label" + }, + "appt_length": "Default Appointment Length", + "attach_pdf_to_email": "Attach PDF copy to sent emails?", + "bill_federal_tax_rate": "Bills - Federal Tax Rate %", + "bill_local_tax_rate": "Bill - Provincial/State Tax Rate %", + "bill_state_tax_rate": "Bill - Provincial/State Tax Rate %", + "city": "City", + "country": "Country", + "dailybodytarget": "Scoreboard - Daily Body Target", + "dailypainttarget": "Scoreboard - Daily Paint Target", + "default_adjustment_rate": "Default Labor Deduction Adjustment Rate", + "deliver": { + "templates": "Delivery Templates" + }, + "dms": { + "default_journal": "Default Journal", + "dms_acctnumber": "DMS Account #", + "dms_wip_acctnumber": "DMS W.I.P. Account #", + "mappingname": "DMS Mapping Name" + }, + "email": "General Shop Email", + "enforce_class": "Enforce Class on Conversion?", + "enforce_referral": "Enforce Referrals", + "federal_tax_id": "Federal Tax ID (GST/HST)", + "inhousevendorid": "In House Vendor ID", + "insurance_vendor_id": "Insurance Vendor ID", + "intake": { + "templates": "Intake Templates" + }, + "invoice_federal_tax_rate": "Invoices - Federal Tax Rate", + "invoice_local_tax_rate": "Invoices - Local 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", + "logo_img_path": "Shop Logo", + "logo_img_path_height": "Logo Image Height", + "logo_img_path_width": "Logo Image Width", + "md_categories": "Categories", + "md_ccc_rates": "Courtesy Car Contract Rate Presets", + "md_classes": "Classes", + "md_hour_split": { + "paint": "Paint Hour Split", + "prep": "Prep Hour Split" + }, + "md_ins_co": { + "city": "City", + "name": "Insurance Company Name", + "state": "Province/State", + "street1": "Street 1", + "street2": "Street 2", + "zip": "Zip/Postal Code" + }, + "md_jobline_presets": "Jobline Presets", + "md_payment_types": "Payment Types", + "md_referral_sources": "Referral Sources", + "messaginglabel": "Messaging Preset Label", + "messagingtext": "Messaging Preset Text", + "noteslabel": "Note Label", + "notestext": "Note Text", + "partslocation": "Parts Location", + "phone": "Phone", + "prodtargethrs": "Production Target Hours", + "rbac": { + "accounting": { + "exportlog": "Accounting -> Export Log", + "payables": "Accounting -> Payables", + "payments": "Accounting -> Payments", + "receivables": "Accounting -> Receivables" + }, + "bills": { + "delete": "Bills -> Delete", + "enter": "Bills -> Enter", + "list": "Bills -> List", + "reexport": "Bills -> Re-export", + "view": "Bills -> View" + }, + "contracts": { + "create": "Contracts -> Create", + "detail": "Contracts -> Detail", + "list": "Contracts -> List" + }, + "courtesycar": { + "create": "Courtesy Car -> Create", + "detail": "Courtesy Car -> Detail", + "list": "Courtesy Car -> List" + }, + "csi": { + "export": "CSI -> Export", + "page": "CSI -> Page" + }, + "employees": { + "page": "Employees -> List" + }, + "jobs": { + "admin": "Jobs -> Admin", + "available-list": "Jobs -> Available List", + "checklist-view": "Jobs -> Checklist View", + "close": "Jobs -> Close", + "create": "Jobs -> Create", + "deliver": "Jobs -> Deliver", + "detail": "Jobs -> Detail", + "intake": "Jobs -> Intake", + "list-active": "Jobs -> List Active", + "list-all": "Jobs -> List All", + "partsqueue": "Jobs -> Parts Queue" + }, + "owners": { + "detail": "Owners -> Detail", + "list": "Owners -> List" + }, + "payments": { + "enter": "Payments -> Enter", + "list": "Payments -> List" + }, + "phonebook": { + "edit": "Phonebook -> Edit", + "view": "Phonebook -> View" + }, + "production": { + "board": "Production -> Board", + "list": "Production -> List" + }, + "schedule": { + "view": "Schedule -> View" + }, + "scoreboard": { + "view": "Scoreboard -> View" + }, + "shiftclock": { + "view": "Shift Clock -> View" + }, + "shop": { + "dashboard": "Shop -> Dashboard", + "rbac": "Shop -> RBAC", + "templates": "Shop -> Templates", + "vendors": "Shop -> Vendors" + }, + "temporarydocs": { + "view": "Temporary Docs -> View" + }, + "timetickets": { + "edit": "Time Tickets -> Edit", + "enter": "Time Tickets -> Enter", + "list": "Time Tickets -> List", + "shiftedit": "Time Tickets -> Shift Edit" + }, + "users": { + "editaccess": "Users -> Edit access" + } + }, + "responsibilitycenter": "Responsibility Center", + "responsibilitycenter_accountdesc": "Account Description", + "responsibilitycenter_accountitem": "Item", + "responsibilitycenter_accountname": "Account Name", + "responsibilitycenter_accountnumber": "Account Number", + "responsibilitycenter_rate": "Rate", + "responsibilitycenters": { + "ap": "Accounts Payable", + "ar": "Accounts Receivable", + "ats": "ATS", + "federal_tax": "Federal Tax", + "lab": "Body", + "lad": "Diagnostic", + "lae": "Electrical", + "laf": "Frame", + "lag": "Glass", + "lam": "Mechanical", + "lar": "Refinish", + "las": "Structural", + "lau": "Detail", + "local_tax": "Local Tax", + "mapa": "Paint Materials", + "mash": "Shop Materials", + "paa": "Aftermarket", + "pac": "Chrome", + "pal": "LKQ", + "pam": "Remanufactured", + "pan": "OEM", + "pao": "Other", + "pap": "OEM Partial", + "par": "Recored", + "pas": "Sublet", + "refund": "Refund", + "sales_tax_codes": { + "code": "Code", + "description": "Description", + "federal": "Federal Tax Applies", + "local": "Local Tax Applies", + "state": "Provincial/State Tax Applies" + }, + "state_tax": "Provincial/State Tax", + "tow": "Towing" + }, + "schedule_end_time": "Schedule Ending Time", + "schedule_start_time": "Schedule Starting Time", + "shopname": "Shop Name", + "speedprint": { + "id": "Id", + "label": "Label", + "templates": "Templates" + }, + "ssbuckets": { + "gte": "Greater Than/Equal to (hrs)", + "id": "ID", + "label": "Label", + "lt": "Less than (hrs)", + "target": "Target (count)" + }, + "state": "Province/State", + "state_tax_id": "Provincial/State Tax ID (PST, QST)", + "status": "Status Label", + "statuses": { + "active_statuses": "Active Statuses (Filtering for Active Jobs throughout system)", + "default_arrived": "Default Arrived Status (Transition to Production)", + "default_bo": "Default Backordered Status", + "default_canceled": "Default Canceled Status", + "default_completed": "Default Completed Status", + "default_delivered": "Default Delivered Status (Transition to Post-Production)", + "default_exported": "Default Exported Status", + "default_imported": "Default Imported Status", + "default_invoiced": "Default Invoiced Status", + "default_ordered": "Default Ordered Status", + "default_received": "Default Received Status", + "default_returned": "Default Returned", + "default_scheduled": "Default Scheduled Status", + "default_void": "Default Void", + "open_statuses": "Open Statuses", + "post_production_statuses": "Post-Production Statuses", + "pre_production_statuses": "Pre-Production Statuses", + "production_statuses": "Production Statuses" + }, + "target_touchtime": "Target Touch Time", + "tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs", + "use_fippa": "Use FIPPA for Names on Generated Documents?", + "website": "Website", + "zip_post": "Zip/Postal Code" + }, + "labels": { + "2tiername": "Name => RO", + "2tiersetup": "2 Tier Setup", + "2tiersource": "Source => RO", + "accountingsetup": "Accounting Setup", + "accountingtiers": "Number of Tiers to Use for Export", + "alljobstatuses": "All Job Statuses", + "allopenjobstatuses": "All Open Job Statuses", + "apptcolors": "Appointment Colors", + "businessinformation": "Business Information", + "checklists": "Checklists", + "csiq": "CSI Questions", + "customtemplates": "Custom Templates", + "defaultcostsmapping": "Default Costs Mapping", + "defaultprofitsmapping": "Default Profits Mapping", + "deliverchecklist": "Delivery Checklist", + "dms": { + "cdk": { + "payers": "CDK Payers" + }, + "cdk_dealerid": "CDK Dealer ID", + "title": "DMS" + }, + "emaillater": "Email Later", + "employees": "Employees", + "insurancecos": "Insurance Companies", + "intakechecklist": "Intake Checklist", + "jobstatuses": "Job Statuses", + "laborrates": "Labor Rates", + "licensing": "Licensing", + "messagingpresets": "Messaging Presets", + "notemplatesavailable": "No templates available to add.", + "notespresets": "Notes Presets", + "orderstatuses": "Order Statuses", + "partslocations": "Parts Locations", + "printlater": "Print Later", + "rbac": "Role Based Access Control", + "responsibilitycenters": { + "costs": "Cost Centers", + "profits": "Profit Centers", + "sales_tax_codes": "Sales Tax Codes", + "tax_accounts": "Tax Accounts", + "title": "Responsibility Centers" + }, + "scheduling": "SMART Scheduling", + "scoreboardsetup": "Scoreboard Setup", + "shopinfo": "Shop Information", + "speedprint": "Speed Print Configuration", + "ssbuckets": "Job Size Definitions", + "systemsettings": "System Settings", + "workingdays": "Working Days" + }, + "successes": { + "save": "Shop configuration saved successfully. " + }, + "validation": { + "larsplit": "Refinish hour split must add up to 1.", + "useremailmustexist": "This email is not a valid user." + } + }, + "checklist": { + "actions": { + "printall": "Print All Documents" + }, + "errors": { + "complete": "Error during job checklist completion. {{error}}", + "nochecklist": "No checklist has been configured for your shop. " + }, + "labels": { + "addtoproduction": "Add Job to Production?", + "allow_text_message": "Permission to Text?", + "checklist": "Checklist", + "printpack": "Job Intake Print Pack", + "removefromproduction": "Remove job from production?" + }, + "successes": { + "completed": "Job checklist completed." + } + }, + "contracts": { + "actions": { + "changerate": "Change Contract Rates", + "convertoro": "Convert to RO", + "decodelicense": "Decode License", + "find": "Find Contract", + "printcontract": "Print Contract", + "senddltoform": "Insert Driver's License Information" + }, + "errors": { + "fetchingjobinfo": "Error fetching job info. {{error}}.", + "returning": "Error returning courtesy car. {{error}}", + "saving": "Error saving contract. {{error}}", + "selectjobandcar": "Please ensure both a car and job are selected." + }, + "fields": { + "actax": "A/C Tax", + "actualreturn": "Actual Return Date", + "agreementnumber": "Agreement Number", + "cc_cardholder": "Cardholder Name", + "cc_expiry": "Credit Card Expiry Date", + "cc_num": "Credit Card Number", + "cleanupcharge": "Clean Up Charge", + "coverage": "Coverage", + "dailyfreekm": "Daily Free Mileage", + "dailyrate": "Daily Rate", + "damage": "Existing Damage", + "damagewaiver": "Damage Waiver", + "driver": "Driver", + "driver_addr1": "Driver Address 1", + "driver_addr2": "Driver Address 2", + "driver_city": "Driver City", + "driver_dlexpiry": "Driver's License Expiration Date", + "driver_dlnumber": "Driver's License Number", + "driver_dlst": "Driver's License Province/State", + "driver_dob": "Driver's DOB", + "driver_fn": "Driver's First Name", + "driver_ln": "Driver's Last Name", + "driver_ph1": "Driver's Phone", + "driver_state": "Driver's Province/State ", + "driver_zip": "Driver's Postal/ZIP Code", + "excesskmrate": "Excess Mileage", + "federaltax": "Federal Taxes", + "fuelin": "Fuel In", + "fuelout": "Fuel Out", + "kmend": "Mileage End", + "kmstart": "Mileage Start", + "localtax": "Local Taxes", + "refuelcharge": "Refuel Charge (per liter/gallon)", + "scheduledreturn": "Scheduled Return", + "start": "Contract Start", + "statetax": "Provincial/State Taxes", + "status": "Status" + }, + "labels": { + "agreement": "Agreement {{agreement_num}} - {{status}}", + "availablecars": "Available Cars", + "cardueforservice": "The courtesy car is due for servicing.", + "convertform": { + "applycleanupcharge": "Apply cleanup charge?", + "refuelqty": "Refuel qty.?" + }, + "correctdataonform": "Please review the information above. If any of it is not correct, you can fix it later.", + "dlexpirebeforereturn": "The driver's license expires before the car is expected to return. ", + "driverinformation": "Driver's Information", + "findcontract": "Find Contract", + "findermodal": "Contract Finder", + "noteconvertedfrom": "R.O. created from converted Courtesy Car Contract {{agreementnumber}}.", + "populatefromjob": "Populate from Job", + "rates": "Contract Rates", + "time": "Time", + "vehicle": "Vehicle", + "waitingforscan": "Please scan driver's license barcode..." + }, + "status": { + "new": "New Contract", + "out": "Out", + "returned": "Returned" + }, + "successes": { + "saved": "Contract saved successfully. " + } + }, + "courtesycars": { + "actions": { + "new": "New Courtesy Car", + "return": "Return Car" + }, + "errors": { + "saving": "Error saving courtesy card. {{error}}" + }, + "fields": { + "color": "Color", + "dailycost": "Daily Cost to Rent", + "damage": "Damage", + "fleetnumber": "Fleet Number", + "fuel": "Fuel Level", + "insuranceexpires": "Insurance Expires On", + "leaseenddate": "Lease Ends On", + "make": "Make", + "mileage": "Mileage", + "model": "Model", + "nextservicedate": "Next Service Date", + "nextservicekm": "Next Service KMs", + "notes": "Notes", + "plate": "Plate Number", + "purchasedate": "Purchase Date", + "registrationexpires": "Registration Expires On", + "serviceenddate": "Usage End Date", + "servicestartdate": "Usage Start Date", + "status": "Status", + "vin": "VIN", + "year": "Year" + }, + "labels": { + "courtesycar": "Courtesy Car", + "fuel": { + "12": "1/2", + "14": "1/4", + "18": "1/8", + "34": "3/4", + "38": "3/8", + "58": "5/8", + "78": "7/8", + "empty": "Empty", + "full": "Full" + }, + "outwith": "Out With", + "return": "Return Courtesy Car", + "status": "Status", + "uniquefleet": "Enter a unique fleet number.", + "usage": "Usage", + "vehicle": "Vehicle Description" + }, + "status": { + "in": "Available", + "inservice": "In Service", + "out": "Rented" + }, + "successes": { + "saved": "Courtesy Car saved successfully." + } + }, + "csi": { + "actions": { + "activate": "Activate" + }, + "errors": { + "creating": "Error creating survey {{message}}", + "notconfigured": "You do not have any current CSI Question Sets configured.", + "notfoundsubtitle": "We were unable to find a survey using the link you provided. Please ensure the URL is correct or reach out to your shop for more help.", + "notfoundtitle": "No survey found." + }, + "fields": { + "completedon": "Completed On" + }, + "labels": { + "nologgedinuser": "Please log out of ImEX Online", + "nologgedinuser_sub": "Users of ImEX Online cannot complete CSI surveys while logged in. Please log out and try again.", + "noneselected": "No response selected.", + "title": "Customer Satisfaction Survey" + }, + "successes": { + "created": "CSI created successfully. ", + "submitted": "Your responses have been submitted successfully.", + "submittedsub": "Your input is highly appreciated." + } + }, + "dashboard": { + "actions": { + "addcomponent": "Add Component" + }, + "errors": { + "refreshrequired": "You must refresh the dashboard data to see this component.", + "updatinglayout": "Error saving updated layout {{message}}" + }, + "labels": { + "bodyhrs": "Body Hrs", + "dollarsinproduction": "Dollars in Production", + "prodhrs": "Production Hrs", + "refhrs": "Refinish Hrs" + }, + "titles": { + "monthlyemployeeefficiency": "Monthly Employee Efficiency", + "monthlyjobcosting": "Monthly Job Costing ", + "monthlylaborsales": "Monthly Labor Sales", + "monthlypartssales": "Monthly Parts Sales", + "monthlyrevenuegraph": "Monthly Revenue Graph", + "prodhrssummary": "Production Hours Summary", + "productiondollars": "Total dollars in Production", + "productionhours": "Total hours in Production", + "projectedmonthlysales": "Projected Monthly Sales" + } + }, + "documents": { + "actions": { + "delete": "Delete Selected Documents", + "download": "Download Selected Images", + "reassign": "Reassign to another Job", + "selectallimages": "Select All Images", + "selectallotherdocuments": "Select All Other Documents" + }, + "errors": { + "deletes3": "Error deleting document from storage. ", + "deleting_cloudinary": "Error deleting document from storage. {{message}}", + "getpresignurl": "Error obtaining presigned URL for document. {{message}}", + "insert": "Unable to upload file. {{message}}", + "nodocuments": "There are no documents.", + "updating": "Error updating document. {{error}}" + }, + "labels": { + "confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.", + "doctype": "Document Type", + "newjobid": "Assign to Job", + "reassign_limitexceeded": "Reassigning all selected documents will exceed the job storage limit for your shop. ", + "reassign_limitexceeded_title": "Unable to reassign document(s)", + "storageexceeded": "You've exceeded your storage limit for this job. Please remove documents, or increase your storage plan.", + "storageexceeded_title": "Storage Limit Exceeded", + "upload": "Upload", + "upload_limitexceeded": "Uploading all selected documents will exceed the job storage limit for your shop. ", + "upload_limitexceeded_title": "Unable to upload document(s)", + "uploading": "Uploading...", + "usage": "of job storage used. ({{used}} / {{total}})" + }, + "successes": { + "delete": "Document(s) deleted successfully.", + "edituploaded": "Edited document uploaded successfully. Please close this window and refresh the documents list.", + "insert": "Uploaded document successfully. ", + "updated": "Document updated successfully. " + } + }, + "emails": { + "errors": { + "notsent": "Email not sent. Error encountered while sending {{message}}" + }, + "fields": { + "cc": "CC", + "subject": "Subject", + "to": "To" + }, + "labels": { + "attachments": "Attachments", + "documents": "Documents", + "generatingemail": "Generating email...", + "pdfcopywillbeattached": "A PDF copy of this email will be attached when it is sent.", + "preview": "Email Preview" + }, + "successes": { + "sent": "Email sent successfully." + } + }, + "employees": { + "actions": { + "new": "New Employee", + "newrate": "New Rate" + }, + "errors": { + "delete": "Error encountered while deleting employee. {{message}}", + "save": "Error encountered saving employee. {{message}}", + "validation": "Please check all fields.", + "validationtitle": "Unable to save employee." + }, + "fields": { + "active": "Active?", + "base_rate": "Base Rate", + "cost_center": "Cost Center", + "employee_number": "Employee Number", + "first_name": "First Name", + "flat_rate": "Flat Rate (Disabled is Straight Time)", + "hire_date": "Hire Date", + "last_name": "Last Name", + "pin": "Tech Console PIN", + "rate": "Rate", + "termination_date": "Termination Date", + "user_email": "User Email" + }, + "labels": { + "actions": "Actions", + "flat_rate": "Flat Rate", + "name": "Name", + "rate_type": "Rate Type", + "straight_time": "Straight Time" + }, + "successes": { + "delete": "Employee deleted successfully.", + "save": "Employee saved successfully." + }, + "validation": { + "unique_employee_number": "You must enter a unique employee number." + } + }, + "exportlogs": { + "fields": { + "createdat": "Created At" + }, + "labels": { + "attempts": "Export Attempts" + } + }, + "general": { + "actions": { + "add": "Add", + "calculate": "Calculate", + "cancel": "Cancel", + "clear": "Clear", + "close": "Close", + "copylink": "Copy Link", + "create": "Create", + "delete": "Delete", + "deleteall": "Delete All", + "deselectall": "Deselect All", + "edit": "Edit", + "login": "Login", + "refresh": "Refresh", + "remove": "Remove", + "reset": "Reset your changes.", + "resetpassword": "Reset Password", + "save": "Save", + "saveandnew": "Save and New", + "selectall": "Select All", + "senderrortosupport": "Send Error to Support", + "submit": "Submit", + "view": "View", + "viewreleasenotes": "See What's Changed" + }, + "errors": { + "notfound": "No record was found." + }, + "itemtypes": { + "contract": "CC Contract", + "courtesycar": "Courtesy Car", + "job": "Job", + "owner": "Owner", + "vehicle": "Vehicle" + }, + "labels": { + "actions": "Actions", + "areyousure": "Are you sure?", + "barcode": "Barcode", + "cancel": "Are you sure you want to cancel? Your changes will not be saved.", + "clear": "Clear", + "confirmpassword": "Confirm Password", + "created_at": "Created At", + "email": "Email", + "errors": "Errors", + "exceptiontitle": "An error has occurred.", + "friday": "Friday", + "globalsearch": "Global Search", + "hours": "hrs", + "in": "In", + "instanceconflictext": "Your $t(titles.app) account can only be used on one device at any given time. Refresh your session to take control.", + "instanceconflictitle": "Your account is being used elsewhere.", + "item": "Item", + "label": "Label", + "loading": "Loading...", + "loadingapp": "Loading $t(titles.app)", + "loadingshop": "Loading shop data...", + "loggingin": "Authorizing...", + "message": "Message", + "monday": "Monday", + "na": "N/A", + "newpassword": "New Password", + "no": "No", + "nointernet": "It looks like you're not connected to the internet.", + "nointernet_sub": "Please check your connection and try again. ", + "none": "None", + "out": "Out", + "password": "Password", + "passwordresetsuccess": "A password reset link has been sent to you.", + "passwordresetsuccess_sub": "You should receive this email in the next few minutes. Please check your email including any junk or spam folders. ", + "passwordresetvalidatesuccess": "Password successfully reset. ", + "passwordresetvalidatesuccess_sub": "You may now sign in again using your new password. ", + "passwordsdonotmatch": "The passwords you have entered do not match.", + "print": "Print", + "required": "Required", + "saturday": "Saturday", + "search": "Search...", + "searchresults": "Results for {{search}}", + "selectdate": "Select date...", + "sendagain": "Send Again", + "sendby": "Send By", + "signin": "Sign In", + "sms": "SMS", + "sub_status": { + "expired": "The subscription for this shop has expired. Please contact technical support to reactivate the subscription. " + }, + "successful": "Successful", + "sunday": "Sunday", + "text": "Text", + "thursday": "Thursday", + "totals": "Totals", + "tuesday": "Tuesday", + "unknown": "Unknown", + "username": "Username", + "view": "View", + "wednesday": "Wednesday", + "yes": "Yes" + }, + "languages": { + "english": "English", + "french": "French", + "spanish": "Spanish" + }, + "messages": { + "exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.", + "newversionmessage": "Click refresh below to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.", + "newversiontitle": "New version of ImEX Online Available", + "noacctfilepath": "There is no accounting file path set. You will not be able to export any items.", + "nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.", + "noshop": "You do not have access to any shops. Please reach out to your shop manager or technical support. ", + "notfoundsub": "Please make sure that you have access to the data or that the link is correct.", + "notfoundtitle": "We couldn't find what you're looking for...", + "partnernotrunning": "ImEX Online has detected that the partner is not running. Please ensure it is running to enable full functionality.", + "rbacunauth": "You are not authorized to view this content. Please reach out to your shop manager to change your access level.", + "unsavedchanges": "You have unsaved changes.", + "unsavedchangespopup": "You have unsaved changes. Are you sure you want to leave?" + }, + "validation": { + "invalidemail": "Please enter a valid email.", + "invalidphone": "Please enter a valid phone number.", + "required": "{{label}} is required. " + } + }, + "help": { + "actions": { + "connect": "Connect" + }, + "labels": { + "codeplacholder": "6 digit PIN code", + "rescuedesc": "Enter the 6 digit code provided by ImEX Online Support below and click connect.", + "rescuetitle": "Rescue Me!" + } + }, + "intake": { + "labels": { + "printpack": "Intake Print Pack" + } + }, + "joblines": { + "actions": { + "new": "New Line" + }, + "errors": { + "creating": "Error encountered while creating job line. {{message}}", + "updating": "Error encountered updating job line. {{message}}" + }, + "fields": { + "act_price": "Retail Price", + "db_price": "List Price", + "lbr_types": { + "LA1": "LA1", + "LA2": "LA2", + "LA3": "LA3", + "LA4": "LA4", + "LAA": "Aluminum", + "LAB": "Body", + "LAD": "Diagnostic", + "LAE": "Electrical", + "LAF": "Frame", + "LAG": "Glass", + "LAM": "Mechanical", + "LAR": "Refinish", + "LAS": "Structural", + "LAU": "User Defined" + }, + "line_desc": "Line Desc.", + "line_ind": "S#", + "line_no": "Line #", + "location": "Location", + "mod_lb_hrs": "Hrs", + "mod_lbr_ty": "Labor Type", + "notes": "Notes", + "oem_partno": "OEM Part #", + "op_code_desc": "Operation Code Description", + "part_qty": "Qty.", + "part_type": "Part Type", + "part_types": { + "CCC": "CC Cleaning", + "CCD": "CC Damage Waiver", + "CCDR": "CC Daily Rate", + "CCF": "CC Refuel", + "CCM": "CC Mileage", + "PAA": "Aftermarket", + "PAC": "Rechromed", + "PAE": "Existing", + "PAG": "Glass", + "PAL": "LKQ", + "PAM": "Remanufactured", + "PAN": "New/OEM", + "PAO": "Other", + "PAP": "OEM Partial", + "PAR": "Recored", + "PAS": "Sublet", + "PASL": "Sublet" + }, + "profitcenter_labor": "Profit Center: Labor", + "profitcenter_part": "Profit Center: Part", + "prt_dsmk_p": "Line Markup %", + "status": "Status", + "total": "Total", + "unq_seq": "Seq #" + }, + "labels": { + "billref": "Latest Bill", + "edit": "Edit Line", + "new": "New Line", + "nostatus": "No Status", + "presets": "Jobline Presets" + }, + "successes": { + "created": "Job line created successfully.", + "saved": "Job line saved.", + "updated": "Job line updated successfully." + }, + "validations": { + "hrsrequirediflbrtyp": "Labor hours are required if a labor type is selected. Clear the labor type if there are no labor hours.", + "requiredifparttype": "Required if a part type has been specified.", + "zeropriceexistingpart": "This line cannot have any price since it uses an existing part." + } + }, + "jobs": { + "actions": { + "addDocuments": "Add Job Documents", + "addNote": "Add Note", + "addtopartsqueue": "Add to Parts Queue", + "addtoproduction": "Add to Production", + "addtoscoreboard": "Add to Scoreboard", + "allocate": "Allocate", + "autoallocate": "Auto Allocate", + "changelaborrate": "Change Labor Rate", + "changestatus": "Change Status", + "convert": "Convert", + "deliver": "Deliver", + "dmsautoallocate": "DMS Auto Allocate", + "export": "Export", + "exportcustdata": "Export Customer Data", + "exportselected": "Export Selected", + "filterpartsonly": "Filter Parts Only", + "generatecsi": "Generate CSI & Copy Link", + "gotojob": "Go to Job", + "intake": "Intake", + "manualnew": "Create New Job Manually", + "mark": "Mark", + "markasexported": "Mark as Exported", + "markpstexempt": "Mark Job PST Exempt", + "markpstexemptconfirm": "Are you sure you want to do this? To undo this, you must manually update all PST rates.", + "postbills": "Post Bills", + "printCenter": "Print Center", + "recalculate": "Recalculate", + "reconcile": "Reconcile", + "removefromproduction": "Remove from Production", + "schedule": "Schedule", + "sendcsi": "Send CSI", + "sync": "Sync", + "uninvoice": "Uninvoice", + "unvoid": "Unvoid Job", + "viewchecklist": "View Checklists", + "viewdetail": "View Details" + }, + "errors": { + "addingtoproduction": "Error adding to production. {{error}}", + "cannotintake": "Intake cannot be completed for this job. It has either already been completed or the job is already here.", + "closing": "Error closing job. {{error}}", + "creating": "Error encountered while creating job. {{error}}", + "deleted": "Error deleting job. {{error}}", + "exporting": "Error exporting job. {{error}}", + "exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.", + "invoicing": "Error invoicing job. {{error}}", + "noaccess": "This job does not exist or you do not have access to it.", + "nodamage": "No damage points on estimate.", + "nodates": "No dates specified for this job.", + "nofinancial": "No financial data has been calculated yet for this job. Please save it again.", + "nojobselected": "No job is selected.", + "noowner": "No owner associated.", + "novehicle": "No vehicle associated.", + "saving": "Error encountered while saving record.", + "scanimport": "Error importing job. {{message}}", + "totalscalc": "Error while calculating new job totals.", + "updating": "Error while updating job(s). {{error}}", + "validation": "Please ensure all fields are entered correctly.", + "validationtitle": "Validation Error", + "voiding": "Error voiding job. {{error}}" + }, + "fields": { + "actual_completion": "Actual Completion", + "actual_delivery": "Actual Delivery", + "actual_in": "Actual In", + "adjustment_bottom_line": "Adjustments", + "adjustmenthours": "Adjustment Hours", + "alt_transport": "Alt. Trans.", + "ca_bc_pvrt": "PVRT", + "ca_customer_gst": "Customer Portion of GST", + "ca_gst_registrant": "GST Registrant", + "category": "Category", + "ccc": "CC Cleaning", + "ccd": "CC Damage Waiver", + "ccdr": "CC Daily Rate", + "ccf": "CC Refuel", + "ccm": "CC Mileage", + "cieca_id": "CIECA ID", + "claim_total": "Claim Total", + "class": "Class", + "clm_no": "Claim #", + "clm_total": "Claim Total", + "customerowing": "Customer Owing", + "date_estimated": "Date Estimated", + "date_exported": "Exported", + "date_invoiced": "Invoiced", + "date_open": "Open", + "date_scheduled": "Scheduled", + "ded_amt": "Deductible", + "ded_status": "Deductible Status", + "depreciation_taxes": "Depreciation/Taxes", + "dms": { + "center": "Center", + "cost": "Cost", + "cost_dms_acctnumber": "Cost DMS Acct #", + "dms_wip_acctnumber": "Cost WIP DMS Acct #", + "sale": "Sale", + "sale_dms_acctnumber": "Sale DMS Acct #" + }, + "driveable": "Driveable", + "employee_body": "Body", + "employee_csr": "Customer Service Rep.", + "employee_prep": "Prep", + "employee_refinish": "Refinish", + "est_addr1": "Estimator Address", + "est_co_nm": "Estimator Company", + "est_ct_fn": "Estimator First Name", + "est_ct_ln": "Estimator Last Name", + "est_ea": "Estimator Email", + "est_ph1": "Estimator Phone #", + "federal_tax_payable": "Federal Tax Payable", + "federal_tax_rate": "Federal Tax Rate", + "ins_addr1": "Insurance Co. Address", + "ins_city": "Insurance City", + "ins_co_id": "Insurance Co. ID", + "ins_co_nm": "Insurance Company Name", + "ins_co_nm_short": "Ins. Co.", + "ins_ct_fn": "File Handler First Name", + "ins_ct_ln": "File Handler Last Name", + "ins_ea": "File Handler Email", + "ins_ph1": "File Handler Phone #", + "intake": { + "label": "Label", + "max": "Maximum", + "min": "Minimum", + "name": "Name", + "required": "Required?", + "type": "Type" + }, + "kmin": "Mileage In", + "kmout": "Mileage Out", + "la1": "LA1", + "la2": "LA2", + "la3": "LA3", + "la4": "LA4", + "laa": "Aluminum ", + "lab": "Body", + "labor_rate_desc": "Labor Rate Name", + "lad": "Diagnostic", + "lae": "Electrical", + "laf": "Frame", + "lag": "Glass", + "lam": "Mechanical", + "lar": "Refinish", + "las": "Structural", + "lau": "User Defined", + "local_tax_rate": "Local Tax Rate", + "loss_date": "Loss Date", + "loss_desc": "Loss Description", + "ma2s": "2 Stage Paint", + "ma3s": "3 Stage Pain", + "mabl": "MABL?", + "macs": "MACS?", + "mahw": "Hazardous Waste", + "mapa": "Paint Materials", + "mash": "Shop Materials", + "matd": "Tire Disposal", + "other_amount_payable": "Other Amount Payable", + "owner": "Owner", + "owner_owing": "Cust. Owes", + "ownr_ea": "Email", + "ownr_ph1": "Phone 1", + "paa": "Aftermarket", + "pac": "Rechromed", + "pae": "Existing", + "pag": "Glass", + "pal": "LKQ", + "pam": "Remanufactured", + "pan": "OEM/New", + "pao": "Other", + "pap": "OEM Partial", + "par": "Re-cored", + "parts_tax_rates": { + "prt_discp": "Discount %", + "prt_mktyp": "Markup Type", + "prt_mkupp": "Markup %", + "prt_tax_in": "Tax Indicator", + "prt_tax_rt": "Part Tax Rate", + "prt_type": "Part Type" + }, + "pas": "Sublet", + "pay_date": "Pay Date", + "phoneshort": "PH", + "policy_no": "Policy #", + "ponumber": "PO Number", + "production_vars": { + "note": "Production Note" + }, + "rate_la1": "LA1", + "rate_la2": "LA2", + "rate_la3": "LA3", + "rate_la4": "LA4", + "rate_laa": "Aluminum", + "rate_lab": "Body", + "rate_lad": "Diagnostic", + "rate_lae": "Electrical", + "rate_laf": "Frame", + "rate_lag": "Glass", + "rate_lam": "Mechanical", + "rate_lar": "Refinish", + "rate_las": "Structural", + "rate_lau": "User Defined", + "rate_ma2s": "2 Stage Paint", + "rate_ma3s": "3 Stage Paint", + "rate_mabl": "MABL??", + "rate_macs": "MACS??", + "rate_mahw": "Hazardous Waste", + "rate_mapa": "Paint Materials", + "rate_mash": "Shop Material", + "rate_matd": "Tire Disposal", + "referralsource": "Referral Source", + "regie_number": "Registration #", + "repairtotal": "Repair Total", + "ro_number": "RO #", + "scheduled_completion": "Scheduled Completion", + "scheduled_delivery": "Scheduled Delivery", + "scheduled_in": "Scheduled In", + "selling_dealer": "Selling Dealer", + "selling_dealer_contact": "Selling Dealer Contact", + "servicecar": "Service Car", + "servicing_dealer": "Servicing Dealer", + "servicing_dealer_contact": "Servicing Dealer Contact", + "special_coverage_policy": "Special Coverage Policy", + "specialcoveragepolicy": "Special Coverage Policy", + "state_tax_rate": "Provincial/State Tax Rate", + "status": "Job Status", + "storage_payable": "Storage", + "tax_lbr_rt": "Labor Tax Rate", + "tax_levies_rt": "Levies Tax Rate", + "tax_paint_mat_rt": "Paint Material Tax Rate", + "tax_registration_number": "Tax Registration Number", + "tax_shop_mat_rt": "Shop Material Tax Rate", + "tax_str_rt": "Storage Tax Rate", + "tax_sub_rt": "Sublet Tax Rate", + "tax_tow_rt": "Towing Tax Rate", + "towin": "Tow In", + "towing_payable": "Towing Payable", + "unitnumber": "Unit #", + "updated_at": "Updated At", + "uploaded_by": "Uploaded By", + "vehicle": "Vehicle" + }, + "forms": { + "admindates": "Administrative Dates", + "appraiserinfo": "Estimator Info", + "claiminfo": "Claim Information", + "estdates": "Estimate Dates", + "laborrates": "Labor Rates", + "lossinfo": "Loss Information", + "other": "Other", + "repairdates": "Repair Dates", + "scheddates": "Schedule Dates" + }, + "labels": { + "actual_completion_inferred": "$t(jobs.fields.actual_completion) inferred using $t(jobs.fields.scheduled_completion).", + "actual_delivery_inferred": "$t(jobs.fields.actual_delivery) inferred using $t(jobs.fields.scheduled_delivery).", + "actual_in_inferred": "$t(jobs.fields.actual_in) inferred using $t(jobs.fields.scheduled_in).", + "additionaltotal": "Additional Total", + "adjustmentrate": "Adjustment Rate", + "adjustments": "Adjustments", + "adminwarning": "Use the functionality on this page at your own risk. You are responsible for any and all changes to your data.", + "allocations": "Allocations", + "alreadyclosed": "This job has already been closed.", + "appointmentconfirmation": "Send confirmation to customer?", + "associationwarning": "Any changes to associations will require updating the data from the new parent record to the job.", + "audit": "Audit Trail", + "available": "Available", + "availablejobs": "Available Jobs", + "ca_bc_pvrt": { + "days": "Days", + "rate": "PVRT Rate" + }, + "ca_gst_all_if_null": "If the job is marked as a \"GST Registrant\" and this value is set to $0, the customer will be responsible for paying all of the GST by default. ", + "calc_repair_days": "Calculated Repair Days", + "calc_repair_days_tt": "This is the approximate number of days required to complete the repair according to the target touch time in your shop configuration (current set to {{target_touchtime}}).", + "cards": { + "customer": "Customer Information", + "damage": "Area of Damage", + "dates": "Dates", + "documents": "Recent Documents", + "estimator": "Estimator", + "filehandler": "File Handler", + "insurance": "Insurance Details", + "notes": "Notes", + "parts": "Parts", + "totals": "Totals", + "vehicle": "Vehicle" + }, + "changeclass": "Changing the job's class can have fundamental impacts to already exported accounting items. Are you sure you want to do this?", + "checklistcompletedby": "Checklist completed by {{by}} at {{at}}", + "checklistdocuments": "Checklist Documents", + "checklists": "Checklists", + "closeconfirm": "Are you sure you want to close this job? This cannot be easily undone.", + "closejob": "Close Job {{ro_number}}", + "contracts": "CC Contracts", + "cost": "Cost", + "cost_labor": "Cost - Labor", + "cost_parts": "Cost - Parts", + "costs": "Costs", + "create": { + "jobinfo": "Job Info", + "newowner": "Create a new Owner instead. ", + "newvehicle": "Create a new Vehicle Instead", + "novehicle": "No vehicle (only for ROs to track parts/labor only work).", + "ownerinfo": "Owner Info", + "vehicleinfo": "Vehicle Info" + }, + "creating_new_job": "Creating new job...", + "deductible": { + "stands": "Stands", + "waived": "Waived" + }, + "deleteconfirm": "Are you sure you want to delete this job? This cannot be undone. ", + "deletedelivery": "Delete Delivery Checklist", + "deleteintake": "Delete Intake Checklist", + "deliverchecklist": "Deliver Checklist", + "difference": "Difference", + "diskscan": "Scan Disk for Estimates", + "dms": { + "kmoutnotgreaterthankmin": "Mileage out must be greater than mileage in." + }, + "documents": "Documents", + "documents-images": "Images", + "documents-other": "Other Documents", + "duplicateconfirm": "Are you sure you want to duplicate this job? Some elements of this job will not be duplicated.", + "employeeassignments": "Employee Assignments", + "estimatelines": "Estimate Lines", + "existing_jobs": "Existing Jobs", + "federal_tax_amt": "Federal Taxes", + "gpdollars": "$ G.P.", + "gppercent": "% G.P.", + "hrs_claimed": "Hours Claimed", + "hrs_total": "Hours Total", + "importnote": "The job was initially imported.", + "inproduction": "In Production", + "intakechecklist": "Intake Checklist", + "job": "Job Details", + "jobcosting": "Job Costing", + "jobtotals": "Job Totals", + "labor_rates_subtotal": "Labor Rates Subtotal", + "laborallocations": "Labor Allocations", + "labortotals": "Labor Totals", + "lines": "Estimate Lines", + "local_tax_amt": "Local Taxes", + "mapa": "Paint Materials", + "markforreexport": "Mark for Re-export", + "mash": "Shop Materials", + "net_repairs": "Net Repairs", + "notes": "Notes", + "othertotal": "Other Totals", + "override_header": "Override estimate header on import?", + "ownerassociation": "Owner Association", + "parts": "Parts", + "parts_tax_rates": "Parts Tax rates", + "partsfilter": "Parts Only", + "partssubletstotal": "Parts & Sublets Total", + "partstotal": "Parts Total (ex. Taxes)", + "plitooltips": { + "billtotal": "The total amount of all bill lines that have been posted against this RO (not including credits, taxes, or labor adjustments).", + "creditmemos": "The total amount of all credit memos entered. This amount does not reflect any parts returns created.", + "creditsnotreceived": "The total amount of returns created for this job that do not have a corresponding credit memo posted. An amount greater than $0 indicates that vendors have not provided requested credit memos.", + "discrep1": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Too many bills/bill lines that have been posted against this RO. Check to make sure every bill posted on this RO is correctly posted and assigned.
  • \n
  • You do not have the latest supplement imported, or, a supplement must be submitted and then imported.
  • \n
  • You have posted a bill line to labor.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", + "discrep2": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Used an incorrect rate when deducting from labor.
  • \n
  • An outstanding imbalance higher in the reconciliation process.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", + "discrep3": "If the discrepancy is not $0, you may have one of the following:

\n\n
    \n
  • Credit memos that have not been received or posted.
  • \n
  • An outstanding imbalance higher in the reconciliation process.
  • \n
\n
\nThere may be additional issues not listed above that prevent this job from reconciling.", + "laboradj": "The sum of all bill lines that deducted from labor hours, rather than part prices.", + "partstotal": "This is the total of all parts and sublet amounts on the vehicle (some of these may require an in-house invoice).
\nItems such as shop and paint materials, labor online lines, etc. are not included in this total.", + "totalreturns": "The total amount of returns created for this job." + }, + "prt_dsmk_total": "Line Item Markup", + "rates": "Rates", + "rates_subtotal": "All Rates Subtotal", + "reconciliation": { + "billlinestotal": "Bill Lines Total", + "byassoc": "By Line Association", + "byprice": "By Price", + "clear": "Clear All", + "discrepancy": "Discrepancy", + "joblinestotal": "Job Lines Total", + "multipleactprices": "${{act_price}} is the price for multiple job lines.", + "multiplebilllines": "{{line_desc}} has 2 or more bill lines associated to it.", + "multiplebillsforactprice": "Found more than 1 bill matching ${{act_price}} retail price.", + "removedpartsstrikethrough": "Strike through lines represent parts that have been removed from the estimate. They are included for completeness of reconciliation." + }, + "reconciliationheader": "Parts & Sublet Reconciliation", + "returntotals": "Return Totals", + "rosaletotal": "RO Parts Total", + "sale_labor": "Sales - Labor", + "sale_parts": "Sales - Parts & Sublet", + "sales": "Sales", + "scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the job. ", + "specialcoveragepolicy": "Special Coverage Policy Applies", + "state_tax_amt": "Provincial/State Taxes", + "subletstotal": "Sublets Total", + "subtotal": "Subtotal", + "supplementnote": "The job had a supplement imported.", + "suspense": "Suspense", + "total_cost": "Total Cost", + "total_cust_payable": "Total Customer Amount Payable", + "total_repairs": "Total Repairs", + "total_sales": "Total Sales", + "totals": "Totals", + "unvoidnote": "This job was unvoided.", + "vehicle_info": "Vehicle", + "vehicleassociation": "Vehicle Association", + "viewallocations": "View Allocations", + "voidjob": "Are you sure you want to void this job? This cannot be easily undone. ", + "voidnote": "This job was voided." + }, + "successes": { + "addedtoproduction": "Job added to production board.", + "all_deleted": "{{count}} jobs deleted successfully.", + "closed": "Job closed successfully.", + "converted": "Job converted successfully.", + "created": "Job created successfully. Click to view.", + "creatednoclick": "Job created successfully. ", + "delete": "Job deleted successfully.", + "deleted": "Job deleted successfully.", + "duplicated": "Job duplicated successfully. ", + "exported": "Job(s) exported successfully. ", + "invoiced": "Job closed and invoiced successfully.", + "partsqueue": "Job added to parts queue.", + "save": "Job saved successfully.", + "savetitle": "Record saved successfully.", + "supplemented": "Job supplemented successfully. ", + "updated": "Job(s) updated successfully.", + "voided": "Job voided successfully." + } + }, + "landing": { + "bigfeature": { + "subtitle": "ImEX Online is built using world class technology by experts in the collision repair industry. This translates to software that is tailor made for the unique challenges faced by repair facilities with no compromises. ", + "title": "Bringing the latest technology to the automotive repair industry. " + }, + "footer": { + "company": { + "about": "About Us", + "contact": "Contact", + "disclaimers": "Disclaimers", + "name": "Company", + "privacypolicy": "Privacy Policy" + }, + "io": { + "help": "Help", + "name": "ImEX Online", + "status": "System Status" + }, + "slogan": "A whole new kind of shop management system." + }, + "hero": { + "button": "Coming Soon", + "title": "A whole new kind of shop management system." + }, + "labels": { + "features": "Features", + "managemyshop": "Manage my Shop", + "pricing": "Pricing" + }, + "pricing": { + "basic": { + "name": "Basic", + "sub": "Best suited for shops looking to increase their volume." + }, + "essentials": { + "name": "Essentials", + "sub": "Best suited for small and low volume shops." + }, + "pricingtitle": "Features", + "pro": { + "name": "Pro", + "sub": "Empower your shop with the tools to operate at peak capacity." + }, + "title": "Features", + "unlimited": { + "name": "Unlimited", + "sub": "Everything you need and more for the high volume shop." + } + } + }, + "menus": { + "currentuser": { + "languageselector": "Language", + "profile": "Profile" + }, + "header": { + "accounting": "Accounting", + "accounting-payables": "Payables", + "accounting-payments": "Payments", + "accounting-receivables": "Receivables", + "activejobs": "Active Jobs", + "alljobs": "All Jobs", + "allpayments": "All Payments", + "availablejobs": "Available Jobs", + "bills": "Bills", + "courtesycars": "Courtesy Cars", + "courtesycars-all": "All Courtesy Cars", + "courtesycars-contracts": "Contracts", + "courtesycars-newcontract": "New Contract", + "customers": "Customers", + "dashboard": "Dashboard", + "enterbills": "Enter Bills", + "enterpayment": "Enter Payments", + "entertimeticket": "Enter Time Tickets", + "export": "Export", + "export-logs": "Export Logs", + "help": "Help", + "home": "Home", + "jobs": "Jobs", + "newjob": "Create New Job", + "owners": "Owners", + "parts-queue": "Parts Queue", + "phonebook": "Phonebook", + "productionboard": "Production Board - Visual", + "productionlist": "Production Board - List", + "recent": "Recent Items", + "reportcenter": "Report Center", + "rescueme": "Rescue me!", + "schedule": "Schedule", + "scoreboard": "Scoreboard", + "search": { + "bills": "Bills", + "jobs": "Jobs", + "owners": "Owners", + "payments": "Payments", + "phonebook": "Phonebook", + "vehicles": "Vehicles" + }, + "shiftclock": "Shift Clock", + "shop": "My Shop", + "shop_config": "Configuration", + "shop_csi": "CSI", + "shop_templates": "Templates", + "shop_vendors": "Vendors", + "temporarydocs": "Temporary Documents", + "timetickets": "Time Tickets", + "vehicles": "Vehicles" + }, + "jobsactions": { + "admin": "Admin", + "closejob": "Close Job", + "deletejob": "Delete Job", + "duplicate": "Duplicate this Job", + "duplicatenolines": "Duplicate this Job without Repair Data", + "newcccontract": "Create Courtesy Car Contract", + "void": "Void Job" + }, + "jobsdetail": { + "claimdetail": "Claim Details", + "dates": "Dates", + "financials": "Financial Information", + "general": "General", + "insurance": "Insurance Information", + "labor": "Labor", + "partssublet": "Parts & Bills", + "rates": "Rates", + "repairdata": "Repair Data", + "totals": "Totals" + }, + "profilesidebar": { + "profile": "My Profile", + "shops": "My Shops" + }, + "tech": { + "home": "Home", + "jobclockin": "Job Clock In", + "jobclockout": "Job Clock Out", + "joblookup": "Job Lookup", + "login": "Login", + "logout": "Logout", + "productionboard": "Production Board - Visual", + "productionlist": "Production List", + "shiftclockin": "Shift Clock" + } + }, + "messaging": { + "actions": { + "link": "Link to Job", + "new": "New Conversation" + }, + "errors": { + "invalidphone": "The phone number is invalid. Unable to open conversation. " + }, + "labels": { + "archive": "Archive", + "maxtenimages": "You can only select up to a maximum of 10 images at a time.", + "messaging": "Messaging", + "noallowtxt": "This customer has not indicated their permission to be messaged.", + "nojobs": "Not associated to any job.", + "phonenumber": "Phone #", + "presets": "Presets", + "selectmedia": "Select Media", + "sentby": "Sent by {{by}} at {{time}}", + "typeamessage": "Send a message...", + "unarchive": "Unarchive" + } + }, + "notes": { + "actions": { + "actions": "Actions", + "deletenote": "Delete Note", + "edit": "Edit Note", + "new": "New Note" + }, + "fields": { + "createdby": "Created By", + "critical": "Critical", + "private": "Private", + "text": "Contents", + "updatedat": "Updated At" + }, + "labels": { + "newnoteplaceholder": "Add a note..." + }, + "successes": { + "create": "Note created successfully.", + "deleted": "Note deleted successfully.", + "updated": "Note updated successfully." + } + }, + "owners": { + "actions": { + "update": "Update Selected Records" + }, + "errors": { + "noaccess": "The record does not exist or you do not have access to it. ", + "selectexistingornew": "Select an existing owner record or create a new one. " + }, + "fields": { + "address": "Address", + "allow_text_message": "Permission to Text?", + "name": "Name", + "ownr_addr1": "Address", + "ownr_addr2": "Address 2", + "ownr_city": "City", + "ownr_co_nm": "Owner Co. Name", + "ownr_ctry": "Country", + "ownr_ea": "Email", + "ownr_fn": "First Name", + "ownr_ln": "Last Name", + "ownr_ph1": "Phone 1", + "ownr_st": "Province/State", + "ownr_title": "Title", + "ownr_zip": "Zip/Postal Code", + "preferred_contact": "Preferred Contact Method" + }, + "forms": { + "address": "Address", + "contact": "Contact Information", + "name": "Owner Details" + }, + "labels": { + "create_new": "Create a new owner record.", + "existing_owners": "Existing Owners", + "fromclaim": "Current Claim", + "fromowner": "Historical Owner Record", + "relatedjobs": "Related Jobs", + "updateowner": "Update Owner" + }, + "successes": { + "save": "Owner saved successfully." + } + }, + "parts": { + "actions": { + "order": "Order Parts" + } + }, + "parts_orders": { + "actions": { + "backordered": "Mark Backordered", + "receive": "Receive", + "receivebill": "Receive Bill" + }, + "errors": { + "backordering": "Error backordering part {{message}}.", + "creating": "Error encountered when creating parts order. " + }, + "fields": { + "act_price": "Price", + "backordered_eta": "B.O. ETA", + "backordered_on": "B.O. On", + "cost": "Cost", + "db_price": "List Price", + "deliver_by": "Date", + "job_line_id": "Job Line Id", + "line_desc": "Line Description", + "line_remarks": "Remarks", + "lineremarks": "Line Remarks", + "oem_partno": "Part #", + "order_date": "Order Date", + "order_number": "Order Number", + "orderedby": "Ordered By", + "quantity": "Qty.", + "return": "Return", + "status": "Status" + }, + "labels": { + "allpartsto": "All Parts Location", + "confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. ", + "email": "Send by Email", + "inthisorder": "Parts in this Order", + "newpartsorder": "New Parts Order", + "orderhistory": "Order History", + "parts_orders": "Parts Orders", + "print": "Show Printed Form", + "receive": "Receive Parts Order", + "returnpartsorder": "Return Parts Order" + }, + "successes": { + "created": "Parts order created successfully. ", + "received": "Parts order received.", + "return_created": "Parts return created successfully." + } + }, + "payments": { + "errors": { + "exporting": "Error exporting payment(s). {{error}}", + "exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors." + }, + "fields": { + "amount": "Amount", + "created_at": "Created At", + "date": "Payment Date", + "exportedat": "Exported At", + "memo": "Memo", + "payer": "Payer", + "paymentnum": "Payment Number", + "stripeid": "Stripe ID", + "transactionid": "Transaction ID", + "type": "Type" + }, + "labels": { + "balance": "Balance", + "ca_bc_etf_table": "ICBC ETF Table Converter", + "customer": "Customer", + "edit": "Edit Payment", + "electronicpayment": "Use Electronic Payment Processing?", + "findermodal": "ICBC Payment Finder", + "insurance": "Insurance", + "new": "New Payment", + "signup": "Please contact support to sign up for electronic payments.", + "title": "Payments", + "totalpayments": "Total Payments" + }, + "successes": { + "exported": "Payment(s) exported successfully.", + "payment": "Payment created successfully. ", + "stripe": "Credit card transaction charged successfully." + } + }, + "phonebook": { + "actions": { + "new": "New Phonebook Entry" + }, + "errors": { + "adding": "Error adding phonebook entry. {{error}}", + "saving": "Error saving phonebook entry. {{error}}" + }, + "fields": { + "address1": "Street 1", + "address2": "Street 2", + "category": "Category", + "city": "City", + "company": "Company", + "country": "Country", + "email": "Email", + "fax": "Fax", + "firstname": "First Name", + "lastname": "Last Name", + "phone1": "Phone 1", + "phone2": "Phone 2", + "state": "Province/State" + }, + "labels": { + "noneselected": "No phone book entry selected. ", + "onenamerequired": "At least one name related field is required.", + "vendorcategory": "Vendor" + }, + "successes": { + "added": "Phonebook entry added successfully. ", + "deleted": "Phonebook entry deleted successfully. ", + "saved": "Phonebook entry saved successfully. " + } + }, + "printcenter": { + "appointments": { + "appointment_confirmation": "Appointment Confirmation" + }, + "bills": { + "inhouse_invoice": "In House Invoice" + }, + "courtesycarcontract": { + "courtesy_car_contract": "Courtesy Car Contract", + "courtesy_car_impound": "Impound Charges", + "courtesy_car_terms": "Courtesy Car Terms" + }, + "errors": { + "nocontexttype": "No context type set." + }, + "jobs": { + "3rdpartyfields": { + "addr1": "Address 1", + "addr2": "Address 2", + "addr3": "Address 3", + "attn": "Attention", + "city": "City", + "custgst": "Customer Portion of GST", + "ded_amt": "Deductible", + "depreciation": "Depreciation", + "other": "Other", + "ponumber": "PO Number", + "refnumber": "Reference Number", + "sendtype": "Send by", + "state": "Province/State", + "zip": "Postal Code/Zip" + }, + "3rdpartypayer": "Invoice to Third Party Payer", + "appointment_confirmation": "Appointment Confirmation", + "appointment_reminder": "Appointment Reminder", + "casl_authorization": "CASL Authorization", + "coversheet_landscape": "Coversheet (Landscape)", + "coversheet_portrait": "Coversheet Portrait", + "csi_invitation": "CSI Invitation", + "diagnostic_authorization": "Diagnostic Authorization", + "estimate": "Estimate Only", + "estimate_detail": "Estimate Details", + "estimate_followup": "Estimate Followup", + "express_repair_checklist": "Express Repair Checklist", + "filing_coversheet_portrait": "Filing Coversheet (Portrait)", + "final_invoice": "Final Invoice", + "fippa_authorization": "FIPPA Authorization", + "glass_express_checklist": "Glass Express Checklist", + "guarantee": "Repair Guarantee", + "invoice_customer_payable": "Invoice (Customer Payable)", + "invoice_total_payable": "Invoice (Total Payable)", + "job_costing_ro": "Job Costing", + "job_notes": "Job Notes", + "key_tag": "Key Tag", + "paint_grid": "Paint Grid", + "parts_label_single": "Parts Label - Single", + "parts_list": "Parts List", + "parts_order": "Parts Order Confirmation", + "parts_order_confirmation": "", + "parts_order_history": "Parts Order History", + "parts_return_slip": "Parts Return Slip", + "payment_receipt": "Payment Receipt", + "payment_request": "Payment Request", + "payments_by_job": "Job Payments", + "purchases_by_ro_detail": "Purchases - Detail", + "purchases_by_ro_summary": "Purchases - Summary", + "qc_sheet": "Quality Control Sheet", + "ro_totals": "RO Totals", + "ro_with_description": "RO Summary with Descriptions", + "stolen_recovery_checklist": "Stolen Recovery Checklist", + "supplement_request": "Supplement Request", + "thank_you_ro": "Thank You Letter", + "thirdpartypayer": "Third Party Payer", + "vehicle_check_in": "Vehicle Intake", + "vehicle_delivery_check": "Vehicle Delivery Checklist", + "window_tag": "Window Tag", + "window_tag_sublet": "Window Tag - Sublet", + "work_authorization": "Work Authorization", + "worksheet_by_line_number": "Worksheet by Line Number", + "worksheet_sorted_by_operation": "Worksheet by Operation", + "worksheet_sorted_by_operation_no_hours": "Worksheet by Operation (No Hours)", + "worksheet_sorted_by_operation_part_type": "Worksheet by Operation & Part Type" + }, + "labels": { + "groups": { + "authorization": "Authorization", + "financial": "Financial", + "post": "Post-Production", + "pre": "Pre-Production", + "ro": "Repair Order", + "worksheet": "Worksheets" + }, + "misc": "Miscellaneous Documents", + "repairorder": "Repair Order Related", + "reportcentermodal": "Report Center", + "speedprint": "Speed Print", + "title": "Print Center" + }, + "payments": { + "ca_bc_etf_table": "ICBC ETF Table" + }, + "vendors": { + "purchases_by_vendor_detailed": "Purchases by Vendor - Detailed", + "purchases_by_vendor_summary": "Purchases by Vendor - Summary" + } + }, + "production": { + "actions": { + "addcolumns": "Add Columns", + "bodypriority-clear": "Clear Body Priority", + "bodypriority-set": "Set Body Priority", + "detailpriority-clear": "Clear Detail Priority", + "detailpriority-set": "Set Detail Priority", + "paintpriority-clear": "Clear Paint Priority", + "paintpriority-set": "Set Paint Priority", + "remove": "Remove from Production", + "removecolumn": "Remove Column", + "saveconfig": "Save Configuration" + }, + "errors": { + "boardupdate": "Error encountered updating job. {{message}}", + "removing": "Error removing from production board. {{error}}" + }, + "labels": { + "alert": "Alert", + "alertoff": "Remove alert from job", + "alerton": "Add alert to job", + "bodyhours": "B", + "bodypriority": "B/P", + "detailpriority": "D/P", + "employeesearch": "Employee Search", + "jobdetail": "Job Details", + "note": "Production Note", + "paintpriority": "P/P", + "refinishhours": "R", + "selectview": "Select a View", + "sublets": "Sublets", + "totalhours": "Total Hrs ", + "touchtime": "T/T", + "viewname": "View Name" + }, + "successes": { + "removed": "Job removed from production." + } + }, + "profile": { + "errors": { + "state": "Error reading page state. Please refresh." + }, + "labels": { + "activeshop": "Active Shop" + }, + "successes": { + "updated": "Profile updated successfully." + } + }, + "reportcenter": { + "actions": { + "generate": "Generate" + }, + "labels": { + "dates": "Dates", + "employee": "Employee", + "filterson": "Filters on {{object}}: {{field}}", + "generateasemail": "Generate as Email?", + "key": "Report", + "objects": { + "appointments": "Appointments", + "bills": "Bills", + "exportlogs": "Export Logs", + "jobs": "Jobs", + "parts_orders": "Parts Orders", + "payments": "Payments", + "scoreboard": "Scoreboard", + "timetickets": "Timetickets" + }, + "vendor": "Vendor" + }, + "templates": { + "anticipated_revenue": "Anticipated Revenue", + "attendance_detail": "Attendance (All Employees)", + "attendance_employee": "Employee Attendance", + "attendance_summary": "Attendance Summary (All Employees)", + "credits_not_received_date": "Credits not Received by Date", + "estimator_detail": "Jobs by Estimator (Detail)", + "estimator_summary": "Jobs by Estimator (Summary)", + "export_payables": "Export Log - Payables", + "export_payments": "Export Log - Payments", + "export_receivables": "Export Log - Receivables", + "gsr_by_csr": "Gross Sales by CSR", + "gsr_by_delivery_date": "Gross Sales by Delivery Date", + "gsr_by_estimator": "Gross Sales by Estimator", + "gsr_by_exported_date": "Gross Sales by Export Date", + "gsr_by_ins_co": "Gross Sales by Insurance Company", + "gsr_by_make": "Gross Sales by Vehicle Make", + "gsr_by_referral": "Gross Sales by Referral Source", + "gsr_by_ro": "Gross Sales by RO", + "gsr_labor_only": "Gross Sales - Labor Only", + "hours_sold_detail_closed": "Hours Sold Detail - Closed", + "hours_sold_detail_closed_csr": "Hours Sold Detail - Closed by CSR", + "hours_sold_detail_closed_ins_co": "Hours Sold Detail - Closed by Source", + "hours_sold_detail_open": "Hours Sold Detail - Open", + "hours_sold_detail_open_csr": "Hours Sold Detail - Open by CSR", + "hours_sold_detail_open_ins_co": "Hours Sold Detail - Open by Source", + "hours_sold_summary_closed": "Hours Sold Summary - Closed", + "hours_sold_summary_closed_csr": "Hours Sold Summary - Closed by CSR", + "hours_sold_summary_closed_ins_co": "Hours Sold Summary - Closed by Source", + "hours_sold_summary_open": "Hours Sold Summary - Open", + "hours_sold_summary_open_csr": "Hours Sold Summary - Open CSR", + "hours_sold_summary_open_ins_co": "Hours Sold Summary - Open by Source", + "job_costing_ro_csr": "Job Costing by CSR", + "job_costing_ro_date_detail": "Job Costing by RO - Detail", + "job_costing_ro_date_summary": "Job Costing by RO - Summary", + "job_costing_ro_estimator": "Job Costing by Estimator", + "job_costing_ro_ins_co": "Job Costing by RO Source", + "lag_time": "Lag Time", + "open_orders": "Open Orders by Date", + "open_orders_csr": "Open Orders by CSR", + "open_orders_estimator": "Open Orders by Estimator", + "open_orders_ins_co": "Open Orders by Insurance Company", + "parts_backorder": "Backordered Parts", + "parts_not_recieved": "Parts Not Received", + "payments_by_date": "Payments by Date", + "payments_by_date_type": "Payments by Date and Type", + "production_by_csr": "Production by CSR", + "production_by_last_name": "Production by Last Name", + "production_by_repair_status": "Production by Status", + "production_by_ro": "Production by RO", + "production_by_target_date": "Production by Target Date", + "purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)", + "purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)", + "purchases_by_date_range_detail": "Purchases by Date - Detail", + "purchases_by_date_range_summary": "Purchases by Date - Summary", + "purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed", + "purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary", + "purchases_grouped_by_vendor_detailed": "Purchases Grouped by Vendor - Detailed", + "purchases_grouped_by_vendor_summary": "Purchases Grouped by Vendor - Summary", + "schedule": "Appointment Schedule", + "scoreboard_detail": "Scoreboard Detail", + "scoreboard_summary": "Scoreboard Summary", + "supplement_ratio_ins_co": "Supplement Ratio by Source", + "thank_you_date": "Thank You Letters", + "timetickets": "Time Tickets", + "timetickets_employee": "Employee Time Tickets", + "timetickets_summary": "Time Tickets Summary", + "unclaimed_hrs": "Unclaimed Hours", + "void_ros": "Void ROs", + "work_in_progress_labour": "Work in Progress - Labor", + "work_in_progress_payables": "Work in Progress - Payables" + } + }, + "scoreboard": { + "actions": { + "edit": "Edit" + }, + "errors": { + "adding": "Error adding job to scoreboard. {{message}}", + "removing": "Error removing job from scoreboard. {{message}}", + "updating": "Error updating scoreboard. {{message}}" + }, + "fields": { + "bodyhrs": "Body Hours", + "date": "Date", + "painthrs": "Paint Hours" + }, + "labels": { + "asoftodaytarget": "As of Today", + "dailytarget": "Daily", + "monthlytarget": "Monthly", + "targets": "Targets", + "weeklytarget": "Weekly", + "workingdays": "Working Days / Month" + }, + "successes": { + "added": "Job added to scoreboard.", + "removed": "Job removed from scoreboard.", + "updated": "Scoreboard updated." + } + }, + "scoredboard": { + "successes": { + "updated": "Scoreboard entry updated." + } + }, + "tech": { + "fields": { + "employeeid": "Employee ID", + "pin": "PIN" + }, + "labels": { + "loggedin": "Logged in as {{name}}", + "notloggedin": "Not logged in." + } + }, + "templates": { + "errors": { + "updating": "Error updating template {{error}}." + }, + "successes": { + "updated": "Template updated successfully." + } + }, + "timetickets": { + "actions": { + "clockin": "Clock In", + "clockout": "Clock Out", + "enter": "Enter New Time Ticket", + "printemployee": "Print Time Tickets" + }, + "errors": { + "clockingin": "Error while clocking in. {{message}}", + "clockingout": "Error while clocking out. {{message}}", + "creating": "Error creating time ticket. {{message}}", + "deleting": "Error deleting time ticket. {{message}}", + "noemployeeforuser": "Unable to use Shift Clock", + "noemployeeforuser_sub": "An employee record has not been created for this user. Please create one before using the shift clock. " + }, + "fields": { + "actualhrs": "Actual Hours", + "ciecacode": "CIECA Code", + "clockhours": "Clock Hours", + "clockoff": "Clock Off", + "clockon": "Clocked In", + "cost_center": "Cost Center", + "date": "Ticket Date", + "efficiency": "Efficiency", + "employee": "Employee", + "flat_rate": "Flat Rate?", + "memo": "Memo", + "productivehrs": "Productive Hours", + "ro_number": "Job to Post Against" + }, + "labels": { + "alreadyclockedon": "You are already clocked in to the following job(s):", + "ambreak": "AM Break", + "amshift": "AM Shift", + "clockhours": "Shift Clock Hours Summary", + "clockintojob": "Clock In to Job", + "deleteconfirm": "Are you sure you want to delete this time ticket? This cannot be undone.", + "edit": "Edit Time Ticket", + "efficiency": "Efficiency", + "flat_rate": "Flat Rate", + "jobhours": "Job Related Time Tickets Summary", + "lunch": "Lunch", + "new": "New Time Ticket", + "pmbreak": "PM Break", + "pmshift": "PM Shift", + "shift": "Shift", + "shiftalreadyclockedon": "Active Shift Time Tickets", + "straight_time": "Straight Time", + "timetickets": "Time Tickets", + "zeroactualnegativeprod": "Actual hours must be 0 if entering negative productive hours." + }, + "successes": { + "clockedin": "Clocked in successfully.", + "clockedout": "Clocked out successfully.", + "created": "Time ticket entered successfully.", + "deleted": "Time ticket deleted successfully." + } + }, + "titles": { + "accounting-payables": "Payables | $t(titles.app)", + "accounting-payments": "Payments | $t(titles.app)", + "accounting-receivables": "Receivables | $t(titles.app)", + "app": "ImEX Online", + "bc": { + "accounting-payables": "Payables", + "accounting-payments": "Payments", + "accounting-receivables": "Receivables", + "availablejobs": "Available Jobs", + "bills-list": "Bills", + "contracts": "Contracts", + "contracts-create": "New Contract", + "contracts-detail": "Contract #{{number}}", + "courtesycars": "Courtesy Cars", + "courtesycars-detail": "Courtesy Car {{number}}", + "courtesycars-new": "New Courtesy Car", + "dashboard": "Dashboard", + "export-logs": "Export Logs", + "jobs": "Jobs", + "jobs-active": "Active Jobs", + "jobs-admin": "Admin", + "jobs-all": "All Jobs", + "jobs-checklist": "Checklist", + "jobs-close": "Close Job", + "jobs-deliver": "Deliver Job", + "jobs-detail": "Job {{number}}", + "jobs-intake": "Intake", + "jobs-new": "Create a New Job", + "owner-detail": "{{name}}", + "owners": "Owners", + "parts-queue": "Parts Queue", + "payments-all": "All Payments", + "phonebook": "Phonebook", + "productionboard": "Production Board - Visual", + "productionlist": "Production Board - List", + "profile": "My Profile", + "schedule": "Schedule", + "scoreboard": "Scoreboard", + "shop": "Manage my Shop ({{shopname}})", + "shop-csi": "CSI Responses", + "shop-templates": "Shop Templates", + "shop-vendors": "Vendors", + "temporarydocs": "Temporary Documents", + "timetickets": "Time Tickets", + "vehicle-details": "Vehicle: {{vehicle}}", + "vehicles": "Vehicles" + }, + "bills-list": "Bills | $t(titles.app)", + "contracts": "Courtesy Car Contracts | $t(titles.app)", + "contracts-create": "New Contract | $t(titles.app)", + "contracts-detail": "Contract {{id}} | $t(titles.app)", + "courtesycars": "Courtesy Cars | $t(titles.app)", + "courtesycars-create": "New Courtesy Car | $t(titles.app)", + "courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)", + "dashboard": "Dashboard | $t(titles.app)", + "export-logs": "Export Logs | $t(titles.app)", + "jobs": "Active Jobs | $t(titles.app)", + "jobs-admin": "Job {{ro_number}} - Admin | $t(titles.app)", + "jobs-all": "All Jobs | $t(titles.app)", + "jobs-checklist": "Job Checklist | $t(titles.app)", + "jobs-close": "Close Job {{number}} | $t(titles.app)", + "jobs-create": "Create a New Job | $t(titles.app)", + "jobs-deliver": "Deliver Job | $t(titles.app)", + "jobs-intake": "Intake | $t(titles.app)", + "jobsavailable": "Available Jobs | $t(titles.app)", + "jobsdetail": "Job {{ro_number}} | $t(titles.app)", + "jobsdocuments": "Job Documents {{ro_number}} | $t(titles.app)", + "manageroot": "Home | $t(titles.app)", + "owners": "All Owners | $t(titles.app)", + "owners-detail": "{{name}} | $t(titles.app)", + "parts-queue": "Parts Queue | $t(titles.app)", + "payments-all": "Payments | $t(titles.app)", + "phonebook": "Phonebook | $t(titles.app)", + "productionboard": "Production - Board", + "productionlist": "Production Board - List | $t(titles.app)", + "profile": "My Profile | $t(titles.app)", + "resetpassword": "Reset Password", + "resetpasswordvalidate": "Enter New Password", + "schedule": "Schedule | $t(titles.app)", + "scoreboard": "Scoreboard | $t(titles.app)", + "shop": "My Shop | $t(titles.app)", + "shop-csi": "CSI Responses | $t(titles.app)", + "shop-templates": "Shop Templates | $t(titles.app)", + "shop_vendors": "Vendors | $t(titles.app)", + "temporarydocs": "Temporary Documents | $t(titles.app)", + "timetickets": "Time Tickets | $t(titles.app)", + "vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)", + "vehicles": "All Vehicles | $t(titles.app)" + }, + "user": { + "actions": { + "changepassword": "Change Password", + "signout": "Sign Out", + "updateprofile": "Update Profile" + }, + "errors": { + "updating": "Error updating user or association {{message}}" + }, + "fields": { + "authlevel": "Authorization Level", + "displayname": "Display Name", + "email": "Email", + "photourl": "Avatar URL" + }, + "labels": { + "actions": "Actions" + }, + "successess": { + "passwordchanged": "Password changed successfully. " + } + }, + "vehicles": { + "errors": { + "noaccess": "The vehicle does not exist or you do not have access to it.", + "selectexistingornew": "Select an existing vehicle record or create a new one. ", + "validation": "Please ensure all fields are entered correctly.", + "validationtitle": "Validation Error" + }, + "fields": { + "description": "Vehicle Description", + "plate_no": "License Plate", + "plate_st": "Plate Jurisdiction", + "trim_color": "Trim Color", + "v_bstyle": "Body Style", + "v_color": "Color", + "v_cond": "Condition", + "v_engine": "Engine", + "v_make_desc": "Make", + "v_makecode": "Make Code", + "v_mldgcode": "Molding Code", + "v_model_desc": "Model", + "v_model_yr": "Year", + "v_options": "Options", + "v_paint_codes": "Paint Codes {{number}}", + "v_prod_dt": "Production Date", + "v_stage": "Stage", + "v_tone": "Tone", + "v_trimcode": "Trim Code", + "v_type": "Type", + "v_vin": "V.I.N." + }, + "forms": { + "detail": "Vehicle Details", + "misc": "Miscellaneous", + "registration": "Registration" + }, + "labels": { + "fromvehicle": "Historical Vehicle Record", + "relatedjobs": "Related Jobs", + "updatevehicle": "Update Vehicle Information" + }, + "successes": { + "save": "Vehicle saved successfully." + } + }, + "vendors": { + "actions": { + "addtophonebook": "Add to Phonebook", + "new": "New Vendor", + "newpreferredmake": "New Preferred Make" + }, + "errors": { + "deleting": "Error encountered while deleting vendor. ", + "saving": "Error encountered while saving vendor. " + }, + "fields": { + "active": "Active", + "am": "Aftermarket", + "city": "City", + "cost_center": "Cost Center", + "country": "Country", + "discount": "Discount % (as decimal)", + "display_name": "Display Name", + "due_date": "Payment Due Date", + "email": "Contact Email", + "favorite": "Favorite?", + "lkq": "LKQ", + "make": "Make", + "name": "Vendor Name", + "oem": "OEM", + "phone": "Phone", + "prompt_discount": "Prompt Discount %", + "state": "Province/State", + "street1": "Street", + "street2": "Address 2", + "taxid": "Tax ID", + "terms": "Payment Terms", + "zip": "Zip/Postal Code" + }, + "labels": { + "noneselected": "No vendor is selected.", + "preferredmakes": "Preferred Makes for Vendor", + "search": "Type a Vendor's Name" + }, + "successes": { + "deleted": "Vendor deleted successfully. ", + "saved": "Vendor saved successfully." + }, + "validation": { + "unique_vendor_name": "You must enter a unique vendor name." + } + } + } } diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index e519774c2..59729161f 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -474,6 +474,9 @@ "defaultprofitsmapping": "", "deliverchecklist": "", "dms": { + "cdk": { + "payers": "" + }, "cdk_dealerid": "", "title": "" }, @@ -1373,6 +1376,9 @@ "deliverchecklist": "", "difference": "", "diskscan": "", + "dms": { + "kmoutnotgreaterthankmin": "" + }, "documents": "documentos", "documents-images": "", "documents-other": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 170f304e5..9259be63c 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -474,6 +474,9 @@ "defaultprofitsmapping": "", "deliverchecklist": "", "dms": { + "cdk": { + "payers": "" + }, "cdk_dealerid": "", "title": "" }, @@ -1373,6 +1376,9 @@ "deliverchecklist": "", "difference": "", "diskscan": "", + "dms": { + "kmoutnotgreaterthankmin": "" + }, "documents": "Les documents", "documents-images": "", "documents-other": "", diff --git a/hasura/migrations/1629520416914_create_table_public_dms_vehicles/down.yaml b/hasura/migrations/1629520416914_create_table_public_dms_vehicles/down.yaml new file mode 100644 index 000000000..e8a69a7f3 --- /dev/null +++ b/hasura/migrations/1629520416914_create_table_public_dms_vehicles/down.yaml @@ -0,0 +1,5 @@ +- args: + cascade: false + read_only: false + sql: DROP TABLE "public"."dms_vehicles"; + type: run_sql diff --git a/hasura/migrations/1629520416914_create_table_public_dms_vehicles/up.yaml b/hasura/migrations/1629520416914_create_table_public_dms_vehicles/up.yaml new file mode 100644 index 000000000..eadd2690a --- /dev/null +++ b/hasura/migrations/1629520416914_create_table_public_dms_vehicles/up.yaml @@ -0,0 +1,18 @@ +- args: + cascade: false + read_only: false + sql: CREATE EXTENSION IF NOT EXISTS pgcrypto; + type: run_sql +- args: + cascade: false + read_only: false + sql: CREATE TABLE "public"."dms_vehicles"("id" uuid NOT NULL DEFAULT gen_random_uuid(), + "created_at" timestamptz NOT NULL DEFAULT now(), "makecode" text NOT NULL, "modelcode" + text NOT NULL, "make" text NOT NULL, "model" text NOT NULL, "bodyshopid" uuid + NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") + ON UPDATE cascade ON DELETE cascade); + type: run_sql +- args: + name: dms_vehicles + schema: public + type: add_existing_table_or_view diff --git a/hasura/migrations/1629520454038_track_all_relationships/down.yaml b/hasura/migrations/1629520454038_track_all_relationships/down.yaml new file mode 100644 index 000000000..d745605a5 --- /dev/null +++ b/hasura/migrations/1629520454038_track_all_relationships/down.yaml @@ -0,0 +1,12 @@ +- args: + relationship: dms_vehicles + table: + name: bodyshops + schema: public + type: drop_relationship +- args: + relationship: bodyshop + table: + name: dms_vehicles + schema: public + type: drop_relationship diff --git a/hasura/migrations/1629520454038_track_all_relationships/up.yaml b/hasura/migrations/1629520454038_track_all_relationships/up.yaml new file mode 100644 index 000000000..a6ec79cc2 --- /dev/null +++ b/hasura/migrations/1629520454038_track_all_relationships/up.yaml @@ -0,0 +1,20 @@ +- args: + name: dms_vehicles + table: + name: bodyshops + schema: public + using: + foreign_key_constraint_on: + column: bodyshopid + table: + name: dms_vehicles + schema: public + type: create_array_relationship +- args: + name: bodyshop + table: + name: dms_vehicles + schema: public + using: + foreign_key_constraint_on: bodyshopid + type: create_object_relationship diff --git a/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/down.yaml b/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/down.yaml new file mode 100644 index 000000000..972d7b719 --- /dev/null +++ b/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: dms_vehicles + schema: public + type: drop_select_permission diff --git a/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/up.yaml b/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/up.yaml new file mode 100644 index 000000000..892fb145f --- /dev/null +++ b/hasura/migrations/1629520509486_update_permission_user_public_table_dms_vehicles/up.yaml @@ -0,0 +1,28 @@ +- args: + permission: + allow_aggregations: false + backend_only: false + columns: + - id + - created_at + - makecode + - modelcode + - make + - model + - bodyshopid + computed_fields: [] + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + limit: null + role: user + table: + name: dms_vehicles + schema: public + type: create_select_permission diff --git a/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/down.yaml b/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/down.yaml new file mode 100644 index 000000000..1d905252b --- /dev/null +++ b/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: dms_vehicles + schema: public + type: drop_insert_permission diff --git a/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/up.yaml b/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/up.yaml new file mode 100644 index 000000000..13cb03c98 --- /dev/null +++ b/hasura/migrations/1629520623978_update_permission_user_public_table_dms_vehicles/up.yaml @@ -0,0 +1,27 @@ +- args: + permission: + allow_upsert: true + backend_only: false + check: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - id + - created_at + - makecode + - modelcode + - make + - model + - bodyshopid + set: {} + role: user + table: + name: dms_vehicles + schema: public + type: create_insert_permission diff --git a/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/down.yaml b/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/down.yaml new file mode 100644 index 000000000..45e52f5d8 --- /dev/null +++ b/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: dms_vehicles + schema: public + type: drop_update_permission diff --git a/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/up.yaml b/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/up.yaml new file mode 100644 index 000000000..71a547c0e --- /dev/null +++ b/hasura/migrations/1629520632595_update_permission_user_public_table_dms_vehicles/up.yaml @@ -0,0 +1,26 @@ +- args: + permission: + backend_only: false + columns: + - make + - makecode + - model + - modelcode + - created_at + - bodyshopid + - id + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + set: {} + role: user + table: + name: dms_vehicles + schema: public + type: create_update_permission diff --git a/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/down.yaml b/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/down.yaml new file mode 100644 index 000000000..a4ff6bf77 --- /dev/null +++ b/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/down.yaml @@ -0,0 +1,6 @@ +- args: + role: user + table: + name: dms_vehicles + schema: public + type: drop_delete_permission diff --git a/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/up.yaml b/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/up.yaml new file mode 100644 index 000000000..f1ee13adf --- /dev/null +++ b/hasura/migrations/1629521860924_update_permission_user_public_table_dms_vehicles/up.yaml @@ -0,0 +1,17 @@ +- args: + permission: + backend_only: false + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + role: user + table: + name: dms_vehicles + schema: public + type: create_delete_permission diff --git a/hasura/migrations/1629738990845_run_sql_migration/down.yaml b/hasura/migrations/1629738990845_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1629738990845_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1629738990845_run_sql_migration/up.yaml b/hasura/migrations/1629738990845_run_sql_migration/up.yaml new file mode 100644 index 000000000..75c3b0f55 --- /dev/null +++ b/hasura/migrations/1629738990845_run_sql_migration/up.yaml @@ -0,0 +1,13 @@ +- args: + cascade: true + read_only: false + sql: CREATE OR REPLACE FUNCTION public.search_dms_vehicles(search text)RETURNS + SETOF dms_vehicles LANGUAGE plpgsql STABLE AS $FUNCTION$ BEGIN IF search='' + THEN RETURN query SELECT*FROM dms_vehicles;ELSE RETURN query SELECT*FROM dms_vehicles + WHERE make ILIKE'%'||search||'%' OR model ILIKE'%'||search||'%' ORDER BY make + ILIKE'%'||search||'%' OR NULL,model ILIKE'%'||search||'%' OR NULL;END IF;END$FUNCTION$; + type: run_sql +- args: + name: search_dms_vehicles + schema: public + type: track_function diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml index 6b280e543..943808d52 100644 --- a/hasura/migrations/metadata.yaml +++ b/hasura/migrations/metadata.yaml @@ -721,6 +721,13 @@ tables: table: schema: public name: csiquestions + - name: dms_vehicles + using: + foreign_key_constraint_on: + column: bodyshopid + table: + schema: public + name: dms_vehicles - name: documents using: foreign_key_constraint_on: @@ -1527,6 +1534,87 @@ tables: - active: _eq: true check: null +- table: + schema: public + name: dms_vehicles + object_relationships: + - name: bodyshop + using: + foreign_key_constraint_on: bodyshopid + insert_permissions: + - role: user + permission: + check: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - id + - created_at + - makecode + - modelcode + - make + - model + - bodyshopid + backend_only: false + select_permissions: + - role: user + permission: + columns: + - id + - created_at + - makecode + - modelcode + - make + - model + - bodyshopid + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + update_permissions: + - role: user + permission: + columns: + - make + - makecode + - model + - modelcode + - created_at + - bodyshopid + - id + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + check: null + delete_permissions: + - role: user + permission: + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true - table: schema: public name: documents @@ -4554,6 +4642,9 @@ functions: - function: schema: public name: search_cccontracts +- function: + schema: public + name: search_dms_vehicles - function: schema: public name: search_exportlog diff --git a/server.js b/server.js index 4b81464eb..e3beaa86f 100644 --- a/server.js +++ b/server.js @@ -21,6 +21,23 @@ const app = express(); const port = process.env.PORT || 5000; //const port = 5000; +const http = require("http"); +const server = http.createServer(app); +const { Server } = require("socket.io"); +const io = new Server(server, { + path: "/ws", + cors: { + origin: [ + "https://test.imex.online", + "http://localhost:3000", + "https://imex.online", + ], + methods: ["GET", "POST"], + }, +}); +exports.io = io; +require("./server/web-sockets/web-socket"); + //app.use(fb.validateFirebaseIdToken); app.use(compression()); app.use(bodyParser.json({ limit: "50mb" })); @@ -136,25 +153,13 @@ app.post("/data/ah", data.autohouse); var ioevent = require("./server/ioevent/ioevent"); app.post("/ioevent", ioevent.default); +var cdkGetMake = require("./server/cdk/cdk-get-makes"); +app.post("/cdk/getvehicles", fb.validateFirebaseIdToken, cdkGetMake.default); + app.get("/", async function (req, res) { res.status(200).send("Access Forbidden."); }); -const http = require("http"); -const server = http.createServer(app); -const { Server } = require("socket.io"); -const io = new Server(server, { - path: "/ws", - cors: { - origin: [ - "https://test.imex.online", - "http://localhost:3000", - "https://imex.online", - ], - methods: ["GET", "POST"], - }, -}); - server.listen(port, (error) => { if (error) throw error; logger.log( @@ -163,5 +168,3 @@ server.listen(port, (error) => { "api" ); }); -exports.io = io; -require("./server/web-sockets/web-socket"); diff --git a/server/cdk/cdk-get-makes.js b/server/cdk/cdk-get-makes.js index cdcb21eb8..da3343541 100644 --- a/server/cdk/cdk-get-makes.js +++ b/server/cdk/cdk-get-makes.js @@ -15,32 +15,101 @@ const Dinero = require("dinero.js"); const _ = require("lodash"); const { CDK_CREDENTIALS, CheckCdkResponseForError } = require("./cdk-wsdl"); const { performance } = require("perf_hooks"); +const apiGqlClient = require("../graphql-client/graphql-client").client; -exports.default = async function (socket, cdk_dealerid) { +// exports.default = async function (socket, cdk_dealerid) { +// try { +// CdkBase.createLogEvent( +// socket, +// "DEBUG", +// `Getting makes and models list from CDK.` +// ); +// return await GetCdkMakes(socket, cdk_dealerid); +// } catch (error) { +// CdkBase.createLogEvent( +// socket, +// "ERROR", +// `Error encountered in CdkGetMakes. ${error}` +// ); +// } +// }; + +exports.default = async function ReloadCdkMakes(req, res) { + const { bodyshopid, cdk_dealerid } = req.body; try { - CdkBase.createLogEvent( - socket, - "DEBUG", - `Getting makes and models list from CDK.` + const BearerToken = req.headers.authorization; + //Query all CDK Models + const newList = await GetCdkMakes(req, cdk_dealerid); + console.log("🚀 ~ file: cdk-get-makes.js ~ line 40 ~ newList", newList); + + //Clear out the existing records + const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, { + headers: { + Authorization: BearerToken, + }, + }); + + const deleteResult = await client + .setHeaders({ Authorization: BearerToken }) + .request(queries.DELETE_ALL_DMS_VEHICLES, {}); + console.log( + "🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", + deleteResult + ); + + //Insert the new ones. + + const insertResult = await client + .setHeaders({ Authorization: BearerToken }) + .request(queries.INSERT_DMS_VEHICLES, { + vehicles: newList.map((i) => { + return { + bodyshopid, + makecode: i.makeCode, + modelcode: i.modelCode, + make: i.makeFullName, + model: i.modelFullName, + }; + }), + }); + console.log( + "🚀 ~ file: cdk-get-makes.js ~ line 66 ~ insertResult", + insertResult + ); + + logger.log( + "cdk-replace-makes-models-success", + "DEBUG", + req.user.email, + null, + { + cdk_dealerid, + count: newList.length, + } ); - return await GetCdkMakes(socket, cdk_dealerid); } catch (error) { - CdkBase.createLogEvent( - socket, + logger.log( + "cdk-replace-makes-models-error", "ERROR", - `Error encountered in CdkGetMakes. ${error}` + req.user.email, + null, + { + cdk_dealerid, + error, + } ); } }; -async function GetCdkMakes(socket, cdk_dealerid) { - CdkBase.createLogEvent(socket, "TRACE", `{1} Begin GetCDkMakes WSDL Call`); +async function GetCdkMakes(req, cdk_dealerid) { + logger.log("cdk-replace-makes-models", "DEBUG", req.user.email, null, { + cdk_dealerid, + }); try { const soapClientVehicleInsert = await soap.createClientAsync( CdkWsdl.VehicleInsert ); - const start = performance.now(); const soapResponseVehicleSearch = await soapClientVehicleInsert.getMakeModelAsync( @@ -51,28 +120,25 @@ async function GetCdkMakes(socket, cdk_dealerid) { {} ); - CheckCdkResponseForError(socket, soapResponseVehicleSearch); + + CheckCdkResponseForError(null, soapResponseVehicleSearch); const [ result, //rawResponse, soapheader, rawRequest ] = soapResponseVehicleSearch; - const end = performance.now(); - CdkBase.createLogEvent( - socket, - "TRACE", - `soapClientVehicleInsert.getMakeModelAsync Result Length ${ - result.return.length - } and took ${end - start}ms` + + return result.return; + } catch (error) { + logger.log( + "cdk-replace-makes-models-error", + "ERROR", + req.user.email, + null, + { + cdk_dealerid, + error, + } ); - return result.return.map((element, index) => { - return { id: index, ...element }; - }); - } catch (error) { - CdkBase.createLogEvent( - socket, - "ERROR", - `Error in GetCdkMakes - ${JSON.stringify(error, null, 2)}` - ); throw new Error(error); } } diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index e5aa5cdbf..4e87d89b8 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -10,153 +10,72 @@ const soap = require("soap"); const queries = require("../graphql-client/queries"); const CdkBase = require("../web-sockets/web-socket"); const CdkWsdl = require("./cdk-wsdl").default; -const logger = require("../utils/logger"); const { CDK_CREDENTIALS, CheckCdkResponseForError } = require("./cdk-wsdl"); +const moment = require("moment"); -exports.default = async function (socket, jobid) { +exports.default = async function (socket, { txEnvelope, jobid }) { socket.logEvents = []; socket.recordid = jobid; + socket.txEnvelope = txEnvelope; try { CdkBase.createLogEvent( socket, "DEBUG", `Received Job export request for id ${jobid}` ); - //The following values will be stored on the socket to allow callbacks. - //let clVFV, clADPV, clADPC; + const JobData = await QueryJobData(socket, jobid); + socket.JobData = JobData; const DealerId = JobData.bodyshop.cdk_dealerid; CdkBase.createLogEvent( socket, - "TRACE", + "DEBUG", `Dealer ID detected: ${JSON.stringify(DealerId)}` ); - //{1} Begin Calculate DMS Vehicle Id - socket.clVFV = await CalculateDmsVid(socket, JobData); - if (socket.clVFV.newId === "Y") { - //{1.2} This is a new Vehicle ID + CdkBase.createLogEvent( + socket, + "DEBUG", + `{1} Begin Calculate DMS Vehicle ID using VIN: ${JobData.v_vin}` + ); + socket.DMSVid = await CalculateDmsVid(socket, JobData); + + if (socket.DMSVid.newId === "N") { CdkBase.createLogEvent( socket, "DEBUG", - `{1.2} clVFV DMSVid does *not* exist.` + `{2.1} Querying the Vehicle using the DMSVid: ${socket.DMSVid}` ); - CdkBase.createLogEvent( - socket, - "TRACE", - `{1.2} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}` - ); - //Check if DMSCustId is Empty - which it should always be? - //{6.6} Should check to see if a customer exists so that we can marry it to the new vehicle. + socket.DMSVeh = await QueryDmsVehicleById(socket, JobData, socket.DMSVid); + + const DMSVehCustomer = + socket.DMSVeh && + socket.DMSVeh.owners.find((o) => o.id.assigningPartyId === "CURRENT"); + CdkBase.createLogEvent( socket, "DEBUG", - `{6.6} Trying to find customer ID in DMS.` + `{2.2} Querying the Customer using the ID from DMSVeh: ${DMSVehCustomer.id.value}` ); - - //Array - const strIDS = await FindCustomerIdFromDms(socket, JobData); - if (strIDS && strIDS.length > 0) { - CdkBase.createLogEvent( - socket, - "DEBUG", - `{8.2} ${strIDS.length} Customer ID(s) found.` - ); - CdkBase.createLogEvent( - socket, - "TRACE", - `{8.2} strIDS: ${JSON.stringify(strIDS, null, 2)}` - ); - if (strIDS.length > 1) { - //We have multiple IDs - //TODO: Do we need to let the person select it? - CdkBase.createLogEvent( - socket, - "WARNING", - `{F} Mutliple customer ids have been found (${strIDS.length})` - ); - CdkBase.createLogEvent( - socket, - "DEBUG", - `Asking for user intervention to select customer.` - ); - socket.emit("cdk-select-customer", strIDS); - - return; - } - } else { - CdkBase.createLogEvent( - socket, - "DEBUG", - `{8.5} Customer ID(s) *not* found.` - ); - - //Create a customer number, then use that to insert the customer record. - const newCustomerNumber = await GenerateCustomerNumberFromDms( - socket, - JobData - ); - CdkBase.createLogEvent( - socket, - "DEBUG", - `{10.1} New Customer number generated. newCustomerNumber: ${newCustomerNumber}` - ); - - //Use the new customer number to insert the customer record. - socket.clADPC = await CreateCustomerInDms( - socket, - JobData, - newCustomerNumber - ); - CdkBase.createLogEvent( - socket, - "DEBUG", - `{11.1} New Customer inserted.` - ); - CdkBase.createLogEvent( - socket, - "TRACE", - `{11.1} clADPC: ${JSON.stringify(socket.clADPC, null, 2)}` - ); - } - } else { - CdkBase.createLogEvent(socket, "DEBUG", `{1.1} clVFV DMSVid does exist.`); - CdkBase.createLogEvent( + socket.DMSVehCustomer = await QueryDmsCustomerById( socket, - "TRACE", - `{1.1} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}` + JobData, + DMSVehCustomer.id.value ); - - //{2} Begin Find Vehicle in DMS - socket.clADPV = await FindVehicleInDms(socket, JobData, socket.clVFV); //TODO: Verify that this should always return a result. If an ID was found previously, it should be correct? - - //{2.2} Check if the vehicle was found in the DMS. - if (socket.clADPV.AppErrorNo === "0") { - //Vehicle was found. - CdkBase.createLogEvent( - socket, - "DEBUG", - `{1.4} Vehicle was found in the DMS.` - ); - CdkBase.createLogEvent( - socket, - "TRACE", - `{1.4} clADPV: ${JSON.stringify(socket.clADPV, null, 2)}` - ); - } else { - //Vehicle was not found. - CdkBase.createLogEvent( - socket, - "DEBUG", - `{6.4} Vehicle does not exist in DMS. Will have to create one.` - ); - CdkBase.createLogEvent( - socket, - "TRACE", - `{6.4} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}` - ); - } } + + CdkBase.createLogEvent( + socket, + "DEBUG", + `{2.3} Querying the Customer using the name.` + ); + + socket.DMSCustList = await QueryDmsCustomerByName(socket, JobData); + + socket.emit("cdk-select-customer", [ + ...(socket.DMSVehCustomer ? [socket.DMSVehCustomer] : []), + ...socket.DMSCustList, + ]); } catch (error) { CdkBase.createLogEvent( socket, @@ -174,6 +93,84 @@ exports.default = async function (socket, jobid) { } }; +async function CdkSelectedCustomer(socket, selectedCustomerId) { + try { + if (selectedCustomerId) { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{3.1} Querying the Customer using Customer ID: ${selectedCustomerId}` + ); + socket.DMSCust = await QueryDmsCustomerById( + socket, + socket.JobData, + selectedCustomerId + ); + } else { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{3.2} Generating a new customer ID.` + ); + const newCustomerId = await GenerateDmsCustomerNumber(socket); + CdkBase.createLogEvent( + socket, + "DEBUG", + `{3.3} Inserting new customer with ID: ${newCustomerId}` + ); + socket.DMSCust = await InsertDmsCustomer(socket, newCustomerId); + } + + if (socket.DMSVid.newId === "Y") { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{4.1} Inserting new vehicle with ID: ID ${socket.DMSVid.vehiclesVehId}` + ); + socket.DMSVeh = await InsertDmsVehicle(socket); + } else { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{4.2} Querying Existing Vehicle using ID ${socket.DMSVid.vehiclesVehId}` + ); + socket.DMSVeh = await QueryDmsVehicleById( + socket, + socket.JobData, + socket.DMSVid + ); + CdkBase.createLogEvent( + socket, + "DEBUG", + `{4.3} Updating Existing Vehicle to associate to owner.` + ); + socket.DMSVeh = await UpdateDmsVehicle(socket); + } + CdkBase.createLogEvent( + socket, + "DEBUG", + `{5}Updating Service Vehicle History.` + ); + await InsertServiceVehicleHistory(socket); + } catch (error) { + CdkBase.createLogEvent( + socket, + "ERROR", + `Error encountered in CdkSelectedCustomer. ${error}` + ); + } finally { + //Ensure we always insert logEvents + //GQL to insert logevents. + CdkBase.createLogEvent( + socket, + "DEBUG", + `Capturing log events to database.` + ); + } +} + +exports.CdkSelectedCustomer = CdkSelectedCustomer; + async function QueryJobData(socket, jobid) { CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`); const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {}); @@ -188,81 +185,255 @@ async function QueryJobData(socket, jobid) { return result.jobs_by_pk; } -async function CreateCustomerInDms(socket, JobData, newCustomerNumber) { - CdkBase.createLogEvent(socket, "DEBUG", `{11} Begin Create Customer in DMS`); - +async function CalculateDmsVid(socket, JobData) { try { - const soapClientCustomerInsertUpdate = await soap.createClientAsync( - CdkWsdl.CustomerInsertUpdate + const soapClientVehicleInsertUpdate = await soap.createClientAsync( + CdkWsdl.VehicleInsertUpdate ); - const soapResponseCustomerInsertUpdate = - await soapClientCustomerInsertUpdate.insertAsync( - { - arg0: CDK_CREDENTIALS, - arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. - arg2: { userId: null }, - arg3: { - //Copied the required fields from the other integration. - //TODO: Verify whether we need to bring more information in. - id: { value: newCustomerNumber }, - address: { - city: JobData.ownr_city, - country: null, - postalcode: JobData.ownr_zip, - stateOrProvince: JobData.ownr_st, - }, - contactInfo: { - mainTelephoneNumber: { main: true, value: JobData.ownr_ph1 }, - }, - demographics: null, - name1: { - companyname: null, - firstName: JobData.ownr_fn, - fullname: null, - lastName: JobData.ownr_ln, - middleName: null, - nameType: "Person", - suffix: null, - title: null, - }, - }, - }, + const soapResponseVehicleInsertUpdate = + await soapClientVehicleInsertUpdate.getVehIdsAsync({ + arg0: CDK_CREDENTIALS, + arg1: { id: JobData.bodyshop.cdk_dealerid }, + arg2: { VIN: JobData.v_vin }, + }); - {} - ); - CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); - const [ - result, //rawResponse, soapheader, rawRequest - ] = soapResponseCustomerInsertUpdate; + const [result, rawResponse, , rawRequest] = soapResponseVehicleInsertUpdate; + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientVehicleInsertUpdate.getVehIdsAsync request.` + ); + + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientVehicleInsertUpdate.getVehIdsAsync response.` + ); CdkBase.createLogEvent( socket, "TRACE", - `soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify( + `soapClientVehicleInsertUpdate.getVehIdsAsync Result ${JSON.stringify( result, null, 2 )}` ); - const customer = result && result.return; - return customer; + CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); + return result && result.return && result.return[0]; } catch (error) { + CdkBase.createXmlEvent( + socket, + error.request, + `soapClientVehicleInsertUpdate.getVehIdsAsync request.`, + true + ); + + CdkBase.createXmlEvent( + socket, + error.response && error.response.data, + `soapClientVehicleInsertUpdate.getVehIdsAsync response.`, + true + ); CdkBase.createLogEvent( socket, "ERROR", - `Error in CreateCustomerInDms - ${JSON.stringify(error, null, 2)}` + `{1} Error in CalculateDmsVid - ${error}` ); throw new Error(error); } } -async function GenerateCustomerNumberFromDms(socket, JobData) { +async function QueryDmsVehicleById(socket, JobData, DMSVid) { + try { + const soapClientVehicleInsertUpdate = await soap.createClientAsync( + CdkWsdl.VehicleInsertUpdate + ); + + const soapResponseVehicleInsertUpdate = + await soapClientVehicleInsertUpdate.readAsync({ + arg0: CDK_CREDENTIALS, + arg1: { id: JobData.bodyshop.cdk_dealerid }, + arg2: { + fileType: "VEHICLES", + vehiclesVehicleId: DMSVid.vehiclesVehId, + }, + }); + + const [result, rawResponse, , rawRequest] = soapResponseVehicleInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientVehicleInsertUpdate.readAsync request.` + ); + + CdkBase.createLogEvent( + socket, + "TRACE", + `soapClientVehicleInsertUpdate.readAsync Result ${JSON.stringify( + result, + null, + 2 + )}` + ); + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientVehicleInsertUpdate.readAsync response.` + ); + CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); + const VehicleFromDMS = result && result.return && result.return.vehicle; + return VehicleFromDMS; + } catch (error) { + CdkBase.createLogEvent( + socket, + "ERROR", + `Error in QueryDmsVehicleById - ${error}` + ); + throw new Error(error); + } +} + +async function QueryDmsCustomerById(socket, JobData, CustomerId) { + try { + const soapClientCustomerInsertUpdate = await soap.createClientAsync( + CdkWsdl.CustomerInsertUpdate + ); + const soapResponseCustomerInsertUpdate = + await soapClientCustomerInsertUpdate.readAsync({ + arg0: CDK_CREDENTIALS, + arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. + arg2: { + // userId: CustomerId, + }, + arg3: CustomerId, + }); + + const [result, rawResponse, , rawRequest] = + soapResponseCustomerInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientCustomerInsertUpdate.readAsync request.` + ); + + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientCustomerInsertUpdate.readAsync response.` + ); + CdkBase.createLogEvent( + socket, + "TRACE", + `soapClientCustomerInsertUpdate.readAsync Result ${JSON.stringify( + result, + null, + 2 + )}` + ); + CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); + const CustomersFromDms = + result && result.return && result.return.customerParty; + return CustomersFromDms; + } catch (error) { + CdkBase.createXmlEvent( + socket, + error.request, + `soapClientCustomerInsertUpdate.readAsync request.`, + true + ); + + CdkBase.createXmlEvent( + socket, + error.response && error.response.data, + `soapClientCustomerInsertUpdate.readAsync response.`, + true + ); + + CdkBase.createLogEvent( + socket, + "ERROR", + `Error in QueryDmsCustomerById - ${error}` + ); + throw new Error(error); + } +} + +async function QueryDmsCustomerByName(socket, JobData) { + const ownerName = `${JobData.ownr_ln},${JobData.ownr_fn}`; CdkBase.createLogEvent( socket, "DEBUG", - `{10} Begin Generate Customer Number from DMS` + `Begin Query DMS Customer by Name using: ${ownerName}` ); + try { + const soapClientCustomerSearch = await soap.createClientAsync( + CdkWsdl.CustomerSearch + ); + const soapResponseCustomerSearch = + await soapClientCustomerSearch.executeSearchAsync({ + arg0: CDK_CREDENTIALS, + arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. + arg2: { + verb: "EXACT", + key: ownerName, + }, + }); + + const [result, rawResponse, , rawRequest] = soapResponseCustomerSearch; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientCustomerSearch.executeSearchBulkAsync request.` + ); + + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientCustomerSearch.executeSearchBulkAsync response.` + ); + + CdkBase.createLogEvent( + socket, + "TRACE", + `soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify( + result, + null, + 2 + )}` + ); + CheckCdkResponseForError(socket, soapResponseCustomerSearch); + const CustomersFromDms = (result && result.return) || []; + return CustomersFromDms; + } catch (error) { + CdkBase.createXmlEvent( + socket, + error.request, + `soapClientCustomerSearch.executeSearchBulkAsync request.`, + true + ); + + CdkBase.createXmlEvent( + socket, + error.response && error.response.data, + `soapClientCustomerSearch.executeSearchBulkAsync response.`, + true + ); + + CdkBase.createLogEvent( + socket, + "ERROR", + `Error in QueryDmsCustomerByName - ${error}` + ); + throw new Error(error); + } +} + +async function GenerateDmsCustomerNumber(socket) { try { const soapClientCustomerInsertUpdate = await soap.createClientAsync( CdkWsdl.CustomerInsertUpdate @@ -271,16 +442,27 @@ async function GenerateCustomerNumberFromDms(socket, JobData) { await soapClientCustomerInsertUpdate.getCustomerNumberAsync( { arg0: CDK_CREDENTIALS, - arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. + arg1: { dealerId: socket.JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. arg2: { userId: null }, }, {} ); - CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); - const [ - result, //rawResponse, soapheader, rawRequest - ] = soapResponseCustomerInsertUpdate; + + const [result, rawResponse, , rawRequest] = + soapResponseCustomerInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientCustomerInsertUpdate.getCustomerNumberAsync request.` + ); + + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientCustomerInsertUpdate.getCustomerNumberAsync response.` + ); CdkBase.createLogEvent( socket, @@ -291,163 +473,378 @@ async function GenerateCustomerNumberFromDms(socket, JobData) { 2 )}` ); + CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); const customerNumber = result && result.return && result.return.customerNumber; return customerNumber; } catch (error) { + CdkBase.createXmlEvent( + socket, + error.request, + `soapClientCustomerInsertUpdate.getCustomerNumberAsync request.`, + true + ); + + CdkBase.createXmlEvent( + socket, + error.response && error.response.data, + `soapClientCustomerInsertUpdate.getCustomerNumberAsync response.`, + true + ); CdkBase.createLogEvent( socket, "ERROR", - `Error in GenerateCustomerNumberFromDms - ${JSON.stringify( - error, - null, - 2 - )}` + `Error in GenerateDmsCustomerNumber - ${error}` ); throw new Error(error); } } -async function FindCustomerIdFromDms(socket, JobData) { - const ownerName = `${JobData.ownr_ln},${JobData.ownr_fn}`; - CdkBase.createLogEvent( - socket, - "DEBUG", - `{8} Begin Read Customer from DMS using OWNER NAME: ${ownerName}` - ); - +async function InsertDmsCustomer(socket, newCustomerNumber) { try { - const soapClientCustomerSearch = await soap.createClientAsync( - CdkWsdl.CustomerSearch + const soapClientCustomerInsertUpdate = await soap.createClientAsync( + CdkWsdl.CustomerInsertUpdate ); - const soapResponseCustomerSearch = - await soapClientCustomerSearch.executeSearchAsync( + const soapResponseCustomerInsertUpdate = + await soapClientCustomerInsertUpdate.insertAsync( { arg0: CDK_CREDENTIALS, - arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. - arg2: { - verb: "EXACT", - key: ownerName, + arg1: { dealerId: socket.JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. + arg2: { userId: null }, + arg3: { + //Copied the required fields from the other integration. + //TODO: Verify whether we need to bring more information in. + id: { value: newCustomerNumber }, + address: { + addressLine: socket.JobData.ownr_addr1, + city: socket.JobData.ownr_city, + country: null, + postalCode: socket.JobData.ownr_zip, + stateOrProvince: socket.JobData.ownr_st, + }, + contactInfo: { + mainTelephoneNumber: { + main: true, + value: socket.JobData.ownr_ph1, + }, + }, + demographics: null, + name1: { + companyname: socket.JobData.ownr_co_nm, + firstName: socket.JobData.ownr_fn, + fullname: null, + lastName: socket.JobData.ownr_ln, + middleName: null, + nameType: "Person", + suffix: null, + title: null, + }, }, }, {} ); - CheckCdkResponseForError(socket, soapResponseCustomerSearch); - const [ - result, // rawResponse, soapheader, rawRequest - ] = soapResponseCustomerSearch; + + const [result, rawResponse, , rawRequest] = + soapResponseCustomerInsertUpdate; + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientCustomerInsertUpdate.insertAsync request.` + ); + + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientCustomerInsertUpdate.insertAsync response.` + ); CdkBase.createLogEvent( socket, "TRACE", - `soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify( + `soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify( result, null, 2 )}` ); - const CustomersFromDms = result && result.return; - return CustomersFromDms; + CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); + const customer = result && result.return && result.return.customerParty; + return customer; } catch (error) { + CdkBase.createXmlEvent( + socket, + error.request, + `soapClientCustomerInsertUpdate.insertAsync request.`, + true + ); + + CdkBase.createXmlEvent( + socket, + error.response && error.response.data, + `soapClientCustomerInsertUpdate.insertAsync response.`, + true + ); CdkBase.createLogEvent( socket, "ERROR", - `Error in FindCustomerIdFromDms - ${JSON.stringify(error, null, 2)}` + `Error in InsertDmsCustomer - ${error}` ); throw new Error(error); } } -async function FindVehicleInDms(socket, JobData, clVFV) { - CdkBase.createLogEvent( - socket, - "DEBUG", - `{2}/{6} Begin Find Vehicle In DMS using clVFV: ${clVFV}` - ); - +async function InsertDmsVehicle(socket) { try { const soapClientVehicleInsertUpdate = await soap.createClientAsync( CdkWsdl.VehicleInsertUpdate ); + const soapResponseVehicleInsertUpdate = - await soapClientVehicleInsertUpdate.readBulkAsync( - { - arg0: CDK_CREDENTIALS, - arg1: { id: JobData.bodyshop.cdk_dealerid }, - arg2: { - fileType: "VEHICLES", - vehiclesVehicleId: clVFV.vehiclesVehId, + await soapClientVehicleInsertUpdate.insertAsync({ + arg0: CDK_CREDENTIALS, + arg1: { id: socket.JobData.bodyshop.cdk_dealerid }, + arg2: { + dealer: { + dealerNumber: socket.JobData.bodyshop.cdk_dealerid, + inServiceDate: moment().startOf("day").toISOString(), + vehicleId: socket.DMSVid.vehiclesVehId, + }, + manufacturer: {}, + vehicle: { + deliveryDate: moment().format("YYYYMMDD"), + make: socket.txEnvelope.dms_make, + modelAbrev: socket.txEnvelope.dms_model, + modelYear: socket.JobData.v_model_yr, + odometerStatus: socket.txEnvelope.kmout, + saleClassValue: "MISC", + VIN: socket.JobData.v_vin, + }, + owners: { + id: { + assigningPartyId: "CURRENT", + value: socket.DMSCust.id.value, + }, }, }, + arg3: "VEHICLES", + }); + + const [result, rawResponse, , rawRequest] = soapResponseVehicleInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientVehicleInsertUpdate.insertAsync request.` + ); - {} - ); - CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); - const [ - result, //rawResponse, soapheader, rawRequest - ] = soapResponseVehicleInsertUpdate; CdkBase.createLogEvent( socket, "TRACE", - `soapClientVehicleInsertUpdate.readBulkAsync Result ${JSON.stringify( + `soapClientVehicleInsertUpdate.insertAsync Result ${JSON.stringify( result, null, 2 )}` ); - const VehicleFromDMS = result && result.return && result.return[0]; + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientVehicleInsertUpdate.insertAsync response.` + ); + CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); + const VehicleFromDMS = result && result.return && result.return.vehicle; return VehicleFromDMS; } catch (error) { CdkBase.createLogEvent( socket, "ERROR", - `Error in FindVehicleInDms - ${JSON.stringify(error, null, 2)}` + `Error in InsertDmsVehicle - ${error}` ); throw new Error(error); } } -async function CalculateDmsVid(socket, JobData) { - CdkBase.createLogEvent( - socket, - "TRACE", - `{1} Begin Calculate DMS Vehicle ID using VIN: ${JobData.v_vin}` - ); - +async function UpdateDmsVehicle(socket) { try { const soapClientVehicleInsertUpdate = await soap.createClientAsync( CdkWsdl.VehicleInsertUpdate ); - const soapResponseVehicleInsertUpdate = - await soapClientVehicleInsertUpdate.getVehIdsAsync( - { - arg0: CDK_CREDENTIALS, - arg1: { id: JobData.bodyshop.cdk_dealerid }, - arg2: { VIN: JobData.v_vin }, - }, - {} - ); - CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); - const [ - result, //rawResponse, soapheader, rawRequest - ] = soapResponseVehicleInsertUpdate; + const soapResponseVehicleInsertUpdate = + await soapClientVehicleInsertUpdate.updateAsync({ + arg0: CDK_CREDENTIALS, + arg1: { id: socket.JobData.bodyshop.cdk_dealerid }, + arg2: { + ...socket.DMSVeh, + dealer: { + ...socket.DMSVeh.dealer, + inServiceDate: moment( + socket.DMSVeh.dealer.inServiceDate + ).toISOString(), + }, + vehicle: { + ...socket.DMSVeh.vehicle, + deliveryDate: moment( + socket.DMSVeh.vehicle.deliveryDate + ).toISOString(), + }, + owners: { + id: { + assigningPartyId: "CURRENT", + value: socket.DMSCust.id.value, + }, + }, + }, + arg3: "VEHICLES", + }); + const [result, rawResponse, , rawRequest] = soapResponseVehicleInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientVehicleInsertUpdate.updateAsync request.` + ); + CdkBase.createLogEvent( socket, "TRACE", - `soapClientVehicleInsertUpdate.searchIDsByVINAsync Result ${JSON.stringify( + `soapClientVehicleInsertUpdate.updateAsync Result ${JSON.stringify( result, null, 2 )}` ); - const DmsVehicle = result && result.return && result.return[0]; - return DmsVehicle; + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientVehicleInsertUpdate.updateAsync response.` + ); + CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); + const VehicleFromDMS = result && result.return && result.return.vehicle; + return VehicleFromDMS; } catch (error) { CdkBase.createLogEvent( socket, "ERROR", - `Error in CalculateDmsVid - ${JSON.stringify(error, null, 2)}` + `Error in UpdateDmsVehicle - ${error}` + ); + throw new Error(error); + } +} + +async function InsertServiceVehicleHistory(socket) { + try { + const soapClientServiceHistoryInsert = await soap.createClientAsync( + CdkWsdl.ServiceHistoryInsert + ); + + const soapResponseServiceHistoryInsert = + await soapClientServiceHistoryInsert.serviceHistoryHeaderInsertAsync({ + authToken: CDK_CREDENTIALS, + dealerId: { dealerId: socket.JobData.bodyshop.cdk_dealerid }, + serviceHistoryHeader: { + vehID: socket.DMSVid.vehiclesVehId, + roNumber: socket.JobData.ro_number.match(/\d+/g), + mileage: socket.txEnvelope.kmout, + openDate: moment(socket.JobData.actual_in).format("YYYY-MM-DD"), + openTime: moment(socket.JobData.actual_in).format("HH:MM:SS"), + closeDate: moment(socket.JobData.invoice_date).format("YYYY-MM-DD"), + closeTime: moment(socket.JobData.invoice_date).format("HH:MM:SS"), + comments: socket.txEnvelope.story, + cashierID: socket.JobData.bodyshop.cdk_configuration.cashierid, //NEEDS TO BE PROVIDED BY DEALER. + }, + }); + + const [result, rawResponse, , rawRequest] = + soapResponseServiceHistoryInsert; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert request.` + ); + + CdkBase.createLogEvent( + socket, + "TRACE", + `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert Result ${JSON.stringify( + result, + null, + 2 + )}` + ); + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert response.` + ); + CheckCdkResponseForError(socket, soapResponseServiceHistoryInsert); + const VehicleFromDMS = result && result.return && result.return.vehicle; + return VehicleFromDMS; + } catch (error) { + CdkBase.createLogEvent( + socket, + "ERROR", + `Error in InsertServiceVehicleHistory - ${error}` + ); + throw new Error(error); + } +} +async function InsertDmsStartWip(socket) { + try { + const soapClientAccountingGLInsertUpdate = await soap.createClientAsync( + CdkWsdl.AccountingGLInsertUpdate + ); + + const soapResponseAccountingGLInsertUpdate = + await soapClientAccountingGLInsertUpdate.startWIPAsync({ + arg0: CDK_CREDENTIALS, + arg1: { id: socket.JobData.bodyshop.cdk_dealerid }, + arg2: { + acctgDate: moment().toISOString(), + desc: socket.txEnvelope.story, + docType: 7 || 10, //Need to check what this usually would be? + //1 Cash Receipt , 2 Check, 3 Journal Voucher, 4 Parts invoice, 5 Payable Invoice, 6 Recurring Entry, 7 Repair Order Invoice, 8 Vehicle Purchase Invoice, 9 Vehicle Sale Invoice, 10 Other, 11 Payroll, 12 Finance Charge, 13 FMLR Invoice, 14 Parts Credit Memo, 15 Manufacturer Document, 16 FMLR Credit Memo + m13Flag: 0, + refer: socket.JobData.ro_number, + srcCo: socket.txEnvelope.journal, + srcJrnl: socket.txEnvelope.journal, + userID: "?", //Where is this coming from? + //userName: "IMEX", + }, + }); + + const [result, rawResponse, , rawRequest] = + soapResponseAccountingGLInsertUpdate; + + CdkBase.createXmlEvent( + socket, + rawRequest, + `soapClientAccountingGLInsertUpdate.startWIPAsync request.` + ); + + CdkBase.createLogEvent( + socket, + "TRACE", + `soapClientAccountingGLInsertUpdate.startWIPAsync Result ${JSON.stringify( + result, + null, + 2 + )}` + ); + CdkBase.createXmlEvent( + socket, + rawResponse, + `soapClientAccountingGLInsertUpdate.startWIPAsync response.` + ); + CheckCdkResponseForError(socket, soapResponseAccountingGLInsertUpdate); + const VehicleFromDMS = result && result.return && result.return.vehicle; + return VehicleFromDMS; + } catch (error) { + CdkBase.createLogEvent( + socket, + "ERROR", + `Error in QueryDmsVehicleById - ${error}` ); throw new Error(error); } diff --git a/server/cdk/cdk-wsdl.js b/server/cdk/cdk-wsdl.js index e020e3d89..b020cc477 100644 --- a/server/cdk/cdk-wsdl.js +++ b/server/cdk/cdk-wsdl.js @@ -78,11 +78,12 @@ exports.checkIndividualResult = checkIndividualResult; const cdkDomain = "https://uat-3pa.dmotorworks.com"; exports.default = { // VehicleSearch: `${cdkDomain}/pip-vehicle/services/VehicleSearch?wsdl`, + AccountingGLInsertUpdate: `${cdkDomain}/pip-accounting-gl/services/AccountingGLInsertUpdate?wsdl`, VehicleInsertUpdate: `${cdkDomain}/pip-vehicle/services/VehicleInsertUpdate?wsdl`, CustomerInsertUpdate: `${cdkDomain}/pip-customer/services/CustomerInsertUpdate?wsdl`, CustomerSearch: `${cdkDomain}/pip-customer/services/CustomerSearch?wsdl`, VehicleSearch: `${cdkDomain}/pip-vehicle/services/VehicleSearch?wsdl`, - VehicleInsert: `${cdkDomain}/pip-vehicle/services/VehicleInsertUpdate?wsdl`, + ServiceHistoryInsert: `${cdkDomain}/pip-service-history-insert/services/ServiceHistoryInsert?wsdl`, }; // The following login credentials will be used for all PIPs and all environments (User Acceptance Testing and Production). diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 557f00dfa..10f5f545b 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -133,6 +133,7 @@ query QUERY_JOBS_FOR_CDK_EXPORT($id: uuid!) { ownr_fn ownr_addr1 ownr_addr2 + ownr_ph1 ownr_zip ownr_city ownr_st @@ -932,6 +933,19 @@ exports.GET_AUTOHOUSE_SHOPS = `query GET_AUTOHOUSE_SHOPS { imexshopid } } +`; +exports.DELETE_ALL_DMS_VEHICLES = `mutation DELETE_ALL_DMS_VEHICLES{ + delete_dms_vehicles(where: {}) { + affected_rows + } +} +`; +exports.INSERT_DMS_VEHICLES = `mutation INSERT_DMS_VEHICLES($vehicles: [dms_vehicles_insert_input!]!) { + insert_dms_vehicles(objects: $vehicles) { +affected_rows + } +} + `; exports.GET_CDK_ALLOCATIONS = ` diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index 0b96ed27d..c822f42e7 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -8,7 +8,10 @@ require("dotenv").config({ const { io } = require("../../server"); const { admin } = require("../firebase/firebase-handler"); -const CdkJobExport = require("../cdk/cdk-job-export").default; +const { + default: CdkJobExport, + CdkSelectedCustomer, +} = require("../cdk/cdk-job-export"); const CdkGetMakes = require("../cdk/cdk-get-makes").default; const CdkCalculateAllocations = require("../cdk/cdk-calculate-allocations").default; @@ -60,7 +63,7 @@ io.on("connection", (socket) => { `User selected customer ID ${selectedCustomerId}` ); socket.selectedCustomerId = selectedCustomerId; - //CdkJobExport(socket, jobid); + CdkSelectedCustomer(socket, selectedCustomerId); }); socket.on("cdk-get-makes", async (cdk_dealerid, callback) => { @@ -123,8 +126,40 @@ function createLogEvent(socket, level, message) { } } +function createXmlEvent(socket, xml, message, isError = false) { + if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("TRACE")) { + socket.emit("log-event", { + timestamp: new Date(), + level: isError ? "ERROR" : "TRACE", + message: `${message}: ${xml}`, + }); + } + + logger.log( + isError ? "ws-log-event-xml-error" : "ws-log-event-xml", + isError ? "ERROR" : "TRACE", + socket.user.email, + socket.recordid, + { + wsmessage: message, + xml, + } + ); + + if (socket.logEvents && isArray(socket.logEvents)) { + socket.logEvents.push({ + timestamp: new Date(), + level: isError ? "ERROR" : "TRACE", + message, + xml, + }); + } +} + function LogLevelHierarchy(level) { switch (level) { + case "XML": + return 5; case "TRACE": return 5; case "DEBUG": @@ -141,3 +176,4 @@ function LogLevelHierarchy(level) { } exports.createLogEvent = createLogEvent; +exports.createXmlEvent = createXmlEvent;