Added invoice totals + high level reconciliation on PLI jobs tab. BOD-26

This commit is contained in:
Patrick Fic
2020-05-13 16:34:03 -07:00
parent 23a6900906
commit 0473421c6c
15 changed files with 253 additions and 124 deletions

View File

@@ -5902,6 +5902,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>retailtotal</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>state_tax</name> <name>state_tax</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -9374,6 +9395,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>difference</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>documents</name> <name>documents</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -44,21 +44,23 @@ export default function InvoiceFormComponent({
setDiscount(matchingVendors[0].discount); setDiscount(matchingVendors[0].discount);
} }
} }
}, [form, setDiscount, vendorAutoCompleteOptions]); if (form.getFieldValue("jobid")) {
loadLines({ variables: { id: form.getFieldValue("jobid") } });
}
}, [form, setDiscount, vendorAutoCompleteOptions, loadLines]);
return ( return (
<div className="invoice-form-wrapper"> <div className='invoice-form-wrapper'>
<div className="invoice-form-invoice-details"> <div className='invoice-form-invoice-details'>
<Form.Item <Form.Item
name="jobid" name='jobid'
label={t("invoices.fields.ro_number")} label={t("invoices.fields.ro_number")}
rules={[ rules={[
{ {
required: true, required: true,
message: t("general.validation.required"), message: t("general.validation.required"),
}, },
]} ]}>
>
<JobSearchSelect <JobSearchSelect
options={roAutoCompleteOptions} options={roAutoCompleteOptions}
disabled={invoiceEdit} disabled={invoiceEdit}
@@ -71,81 +73,73 @@ export default function InvoiceFormComponent({
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.vendor")} label={t("invoices.fields.vendor")}
name="vendorid" name='vendorid'
style={{ display: invoiceEdit ? "none" : null }} style={{ display: invoiceEdit ? "none" : null }}
rules={[ rules={[
{ {
required: true, required: true,
message: t("general.validation.required"), message: t("general.validation.required"),
}, },
]} ]}>
>
<VendorSearchSelect <VendorSearchSelect
options={vendorAutoCompleteOptions} options={vendorAutoCompleteOptions}
onSelect={handleVendorSelect} onSelect={handleVendorSelect}
/> />
</Form.Item> </Form.Item>
</div> </div>
<div className="invoice-form-invoice-details"> <div className='invoice-form-invoice-details'>
<Form.Item <Form.Item
label={t("invoices.fields.invoice_number")} label={t("invoices.fields.invoice_number")}
name="invoice_number" name='invoice_number'
rules={[ rules={[
{ {
required: true, required: true,
message: t("general.validation.required"), message: t("general.validation.required"),
}, },
]} ]}>
>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.date")} label={t("invoices.fields.date")}
name="date" name='date'
rules={[ rules={[
{ {
required: true, required: true,
message: t("general.validation.required"), message: t("general.validation.required"),
}, },
]} ]}>
>
<DatePicker /> <DatePicker />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.is_credit_memo")} label={t("invoices.fields.is_credit_memo")}
name="is_credit_memo" name='is_credit_memo'
valuePropName="checked" valuePropName='checked'>
>
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.total")} label={t("invoices.fields.total")}
name="total" name='total'
rules={[ rules={[
{ {
required: true, required: true,
message: t("general.validation.required"), message: t("general.validation.required"),
}, },
]} ]}>
>
<CurrencyInput /> <CurrencyInput />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.federal_tax_rate")} label={t("invoices.fields.federal_tax_rate")}
name="federal_tax_rate" name='federal_tax_rate'>
>
<CurrencyInput /> <CurrencyInput />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.state_tax_rate")} label={t("invoices.fields.state_tax_rate")}
name="state_tax_rate" name='state_tax_rate'>
>
<CurrencyInput /> <CurrencyInput />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("invoices.fields.local_tax_rate")} label={t("invoices.fields.local_tax_rate")}
name="local_tax_rate" name='local_tax_rate'>
>
<CurrencyInput /> <CurrencyInput />
</Form.Item> </Form.Item>
</div> </div>
@@ -161,19 +155,18 @@ export default function InvoiceFormComponent({
// </Form.Item> // </Form.Item>
} }
<Form.Item <Form.Item
name="upload" name='upload'
label="Upload" label='Upload'
style={{ display: invoiceEdit ? "none" : null }} style={{ display: invoiceEdit ? "none" : null }}
valuePropName="fileList" valuePropName='fileList'
getValueFromEvent={(e) => { getValueFromEvent={(e) => {
console.log("Upload event:", e); console.log("Upload event:", e);
if (Array.isArray(e)) { if (Array.isArray(e)) {
return e; return e;
} }
return e && e.fileList; return e && e.fileList;
}} }}>
> <Upload name='logo' beforeUpload={() => false} listType='picture'>
<Upload name="logo" beforeUpload={() => false} listType="picture">
<Button>Click to upload</Button> <Button>Click to upload</Button>
</Upload> </Upload>
</Form.Item> </Form.Item>
@@ -196,7 +189,7 @@ export default function InvoiceFormComponent({
totals = CalculateInvoiceTotal(values); totals = CalculateInvoiceTotal(values);
if (!!totals) if (!!totals)
return ( return (
<div className="invoice-form-totals"> <div className='invoice-form-totals'>
<Statistic <Statistic
title={t("invoices.labels.subtotal")} title={t("invoices.labels.subtotal")}
value={totals.subtotal.toFormat()} value={totals.subtotal.toFormat()}

View File

@@ -1,16 +1,18 @@
import { Button, Descriptions, Table } from "antd"; import { Button, Descriptions, Table, Checkbox } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import { SyncOutlined } from "@ant-design/icons";
export default function InvoicesListTableComponent({ export default function InvoicesListTableComponent({
loading, loading,
invoices, invoices,
selectedInvoice, selectedInvoice,
handleOnRowClick, handleOnRowClick,
refetch,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -65,8 +67,7 @@ export default function InvoicesListTableComponent({
key: "actions", key: "actions",
render: (text, record) => ( render: (text, record) => (
<Link <Link
to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`} to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}>
>
<Button>{t("invoices.actions.edit")}</Button> <Button>{t("invoices.actions.edit")}</Button>
</Link> </Link>
), ),
@@ -120,24 +121,74 @@ export default function InvoicesListTableComponent({
state.sortedInfo.columnKey === "cost_center" && state.sortedInfo.columnKey === "cost_center" &&
state.sortedInfo.order, state.sortedInfo.order,
}, },
{
title: t("invoicelines.fields.federal_tax_applicable"),
dataIndex: "applicable_taxes.federal",
key: "applicable_taxes.federal",
render: (text, record) => (
<Checkbox
disabled
checked={
(record.applicable_taxes && record.applicable_taxes.federal) ||
false
}
/>
),
},
{
title: t("invoicelines.fields.state_tax_applicable"),
dataIndex: "applicable_taxes.state",
key: "applicable_taxes.state",
render: (text, record) => (
<Checkbox
disabled
checked={
(record.applicable_taxes && record.applicable_taxes.state) ||
false
}
/>
),
},
{
title: t("invoicelines.fields.local_tax_applicable"),
dataIndex: "applicable_taxes.local",
key: "applicable_taxes.local",
render: (text, record) => (
<Checkbox
disabled
checked={
(record.applicable_taxes && record.applicable_taxes.local) ||
false
}
/>
),
},
]; ];
return ( return (
<div> <div>
<Descriptions title="User Info"> <Descriptions
<Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item> title={`${t("invoices.fields.invoice_number")} ${
<Descriptions.Item label="Telephone">1810000000</Descriptions.Item> record.invoice_number
<Descriptions.Item label="Live">Hangzhou, Zhejiang</Descriptions.Item> }`}>
<Descriptions.Item label="Remark">empty</Descriptions.Item> <Descriptions.Item label={t("invoices.fields.federal_tax_rate")}>
<Descriptions.Item label="Address"> {record.federal_tax_rate || ""}
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China </Descriptions.Item>
<Descriptions.Item label={t("invoices.fields.state_tax_rate")}>
{record.state_tax_rate || ""}
</Descriptions.Item>
<Descriptions.Item label={t("invoices.fields.local_tax_rate")}>
{record.local_tax_rate || ""}
</Descriptions.Item>
<Descriptions.Item label={t("invoices.fields.is_credit_memo")}>
<Checkbox disabled checked={record.is_credit_memo || false} />
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Table <Table
size="small" size='small'
pagination={{ position: "top", defaultPageSize: 25 }} pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns.map((item) => ({ ...item }))} columns={columns.map((item) => ({ ...item }))}
rowKey="id" rowKey='id'
dataSource={record.invoicelines} dataSource={record.invoicelines}
/> />
</div> </div>
@@ -147,11 +198,18 @@ export default function InvoicesListTableComponent({
return ( return (
<Table <Table
loading={loading} loading={loading}
size="small" size='small'
title={() => (
<div>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
</div>
)}
expandedRowRender={rowExpander} expandedRowRender={rowExpander}
pagination={{ position: "top", defaultPageSize: 25 }} pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns.map((item) => ({ ...item }))} columns={columns.map((item) => ({ ...item }))}
rowKey="id" rowKey='id'
dataSource={invoices} dataSource={invoices}
onChange={handleTableChange} onChange={handleTableChange}
expandable={{ expandable={{

View File

@@ -0,0 +1,67 @@
import React from "react";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import { Statistic, Descriptions } from "antd";
import { useTranslation } from "react-i18next";
import Dinero from "dinero.js";
export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
const { t } = useTranslation();
if (loading) return <LoadingSkeleton />;
const totals = JSON.parse(jobTotals);
let invoiceTotals = Dinero({ amount: 0 });
invoices.forEach((i) =>
i.invoicelines.forEach((il) => {
invoiceTotals = invoiceTotals.add(
Dinero({
amount:
((il.actual_price || 0) * i.is_credit_memo ? -1 : 1 || 0) * 100,
})
);
})
);
const discrepancy = Dinero(totals.parts.parts.total).subtract(invoiceTotals);
return (
<div>
<Descriptions
bordered
size='small'
column={1}
title={t("jobs.labels.partssubletstotal")}>
<Descriptions.Item label={t("jobs.labels.partstotal")}>
<Statistic
value={Dinero(totals.parts.parts.total).toFormat()}
suffix={`(${Dinero(
totals.parts.parts.subtotal
).toFormat()} ± ${Dinero(
totals.parts.parts.adjustments
).toFormat()})`}
/>
</Descriptions.Item>
<Descriptions.Item label={t("jobs.labels.subletstotal")}>
<Statistic
value={Dinero(totals.parts.sublets.total).toFormat()}
suffix={`(${Dinero(
totals.parts.sublets.subtotal
).toFormat()} ± ${Dinero(
totals.parts.sublets.adjustments
).toFormat()})`}
/>
</Descriptions.Item>
<Descriptions.Item label={t("invoices.labels.retailtotal")}>
<Statistic value={invoiceTotals.toFormat()} />
</Descriptions.Item>
<Descriptions.Item label={t("invoices.labels.discrepancy")}>
<Statistic
valueStyle={{
color: discrepancy.getAmount === 0 ? "green" : "red",
}}
value={discrepancy.toFormat()}
/>
</Descriptions.Item>
</Descriptions>
</div>
);
}

View File

@@ -4,6 +4,7 @@ import { connect } from "react-redux";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import InvoicesListTableComponent from "../invoices-list-table/invoices-list-table.component"; import InvoicesListTableComponent from "../invoices-list-table/invoices-list-table.component";
import JobInvoicesTotalsComponent from "../job-invoices-total/job-invoices-total.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setInvoiceEnterContext: (context) => setInvoiceEnterContext: (context) =>
@@ -27,13 +28,19 @@ export function JobsDetailPliComponent({
job, job,
}, },
}); });
}} }}>
>
Enter Invoice Enter Invoice
</Button> </Button>
{invoicesQuery.error ? ( {invoicesQuery.error ? (
<AlertComponent message={invoicesQuery.error.message} type="error" /> <AlertComponent message={invoicesQuery.error.message} type='error' />
) : null} ) : null}
<JobInvoicesTotalsComponent
invoices={invoicesQuery.data ? invoicesQuery.data.invoices : null}
loading={invoicesQuery.loading}
jobTotals={job.job_totals}
/>
<InvoicesListTableComponent <InvoicesListTableComponent
loading={invoicesQuery.loading} loading={invoicesQuery.loading}
handleOnRowClick={handleOnRowClick} handleOnRowClick={handleOnRowClick}

View File

@@ -12,7 +12,7 @@ function JobsDocumentsComponent({
invoicesCallback, invoicesCallback,
}) { }) {
const [galleryImages, setgalleryImages] = useState([]); const [galleryImages, setgalleryImages] = useState([]);
console.log("Gallery Data", data);
useEffect(() => { useEffect(() => {
setgalleryImages( setgalleryImages(
data.reduce((acc, value) => { data.reduce((acc, value) => {
@@ -34,7 +34,7 @@ function JobsDocumentsComponent({
}, [data, setgalleryImages]); }, [data, setgalleryImages]);
return ( return (
<div className="clearfix"> <div className='clearfix'>
<DocumentsUploadContainer <DocumentsUploadContainer
jobId={jobId} jobId={jobId}
invoiceId={invoiceId} invoiceId={invoiceId}

View File

@@ -31,7 +31,7 @@ export function LaborAllocationsTable({ joblines, timetickets, bodyshop }) {
</Typography.Title> </Typography.Title>
<Row> <Row>
<Col span={12}> <Col span={6}>
<strong>{t("timetickets.fields.cost_center")}</strong> <strong>{t("timetickets.fields.cost_center")}</strong>
</Col> </Col>
<Col span={6}> <Col span={6}>
@@ -40,12 +40,23 @@ export function LaborAllocationsTable({ joblines, timetickets, bodyshop }) {
<Col span={6}> <Col span={6}>
<strong>{t("jobs.labels.hrs_claimed")}</strong> <strong>{t("jobs.labels.hrs_claimed")}</strong>
</Col> </Col>
<Col span={6}>
<strong>{t("jobs.labels.difference")}</strong>
</Col>
</Row> </Row>
{totals.map((t, idx) => ( {totals.map((t, idx) => (
<Row key={idx}> <Row key={idx}>
<Col span={12}>{t.cost_center}</Col> <Col span={6}>{t.cost_center}</Col>
<Col span={6}>{t.total}</Col> <Col span={6}>{t.total.toFixed(2)}</Col>
<Col span={6}>{t.claimed}</Col> <Col span={6}>{t.claimed.toFixed(2)}</Col>
<Col span={6}>
<strong
style={{
color: Math.round(t.total - t.claimed) > 0 ? "green" : "red",
}}>
{(t.total - t.claimed).toFixed(2)}
</strong>
</Col>
</Row> </Row>
))} ))}
</div> </div>

View File

@@ -49,6 +49,9 @@ export const QUERY_INVOICES_BY_JOBID = gql`
total total
invoice_number invoice_number
date date
federal_tax_rate
state_tax_rate
local_tax_rate
invoicelines { invoicelines {
actual_price actual_price
quantity quantity
@@ -56,6 +59,7 @@ export const QUERY_INVOICES_BY_JOBID = gql`
cost_center cost_center
id id
line_desc line_desc
applicable_taxes
} }
} }
} }

View File

@@ -1,5 +0,0 @@
import React from "react";
export default function InvoiceDetailPageComponent() {
return <div>Invoice Detail Page Component</div>;
}

View File

@@ -1,27 +0,0 @@
import React from "react";
import { useParams } from "react-router-dom";
import InvoiceDetailPageComponent from "./invoice-detail.page.component";
import { useQuery } from "@apollo/react-hooks";
import { QUERY_INVOICE_BY_PK } from "../../graphql/invoices.queries";
import AlertComponent from "../../components/alert/alert.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { Form } from "antd";
export default function InvoiceDetailPageContainer() {
const { invoiceId } = useParams();
const [form] = Form.useForm();
const { loading, error, data } = useQuery(QUERY_INVOICE_BY_PK, {
variables: { invoiceid: invoiceId },
skip: !!!invoiceId,
});
if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<Form form={form} initialValues={data ? data.invoices_by_pk : {}}>
<InvoiceDetailPageComponent />
</Form>
);
}

View File

@@ -1,28 +1,16 @@
import Icon, { import Icon, { BarsOutlined, CalendarFilled, DollarCircleOutlined, FileImageFilled, ToolFilled } from "@ant-design/icons";
BarsOutlined,
CalendarFilled,
DollarCircleOutlined,
FileImageFilled,
ToolFilled,
} from "@ant-design/icons";
import { Form, notification, Tabs } from "antd"; import { Form, notification, Tabs } from "antd";
import moment from "moment"; import moment from "moment";
import queryString from "query-string";
import React, { lazy, Suspense } from "react"; import React, { lazy, Suspense } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import { FaHardHat, FaHistory, FaInfo, FaRegStickyNote, FaShieldAlt } from "react-icons/fa";
FaHardHat,
FaHistory,
FaInfo,
FaRegStickyNote,
FaShieldAlt,
} from "react-icons/fa";
import { useHistory, useLocation } from "react-router-dom";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import queryString from "query-string";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { CalculateJob } from "../../components/job-totals-table/job-totals.utility"; import { CalculateJob } from "../../components/job-totals-table/job-totals.utility";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { selectBodyshop } from "../../redux/user/user.selectors";
const JobsLinesContainer = lazy(() => const JobsLinesContainer = lazy(() =>
import("../../components/job-detail-lines/job-lines.container") import("../../components/job-detail-lines/job-lines.container")
@@ -127,14 +115,6 @@ export function JobsDetailPage({
fallback={<LoadingSpinner message={t("general.labels.loadingapp")} />}> fallback={<LoadingSpinner message={t("general.labels.loadingapp")} />}>
<ScheduleJobModalContainer /> <ScheduleJobModalContainer />
<JobLineUpsertModalContainer /> <JobLineUpsertModalContainer />
<button
onClick={() => {
let r = CalculateJob(job, bodyshop.shoprates);
console.log("r", r);
}}>
Calculate
</button>
<Form <Form
form={form} form={form}
//onFieldsChange={(a, b) => console.log("a,b", a, b)} //onFieldsChange={(a, b) => console.log("a,b", a, b)}

View File

@@ -67,9 +67,7 @@ const ContractsList = lazy(() =>
const InvoicesListPage = lazy(() => const InvoicesListPage = lazy(() =>
import("../invoices/invoices.page.container") import("../invoices/invoices.page.container")
); );
const InvoiceDetailPage = lazy(() =>
import("../invoice-detail/invoice-detail.page.container")
);
const EnterInvoiceModalContainer = lazy(() => const EnterInvoiceModalContainer = lazy(() =>
import("../../components/invoice-enter-modal/invoice-enter-modal.container") import("../../components/invoice-enter-modal/invoice-enter-modal.container")
); );
@@ -201,11 +199,6 @@ export default function Manage({ match }) {
path={`${match.path}/invoices`} path={`${match.path}/invoices`}
component={InvoicesListPage} component={InvoicesListPage}
/> />
<Route
exact
path={`${match.path}/invoices/:invoiceId`}
component={InvoiceDetailPage}
/>
<Route <Route
exact exact
path={`${match.path}/owners`} path={`${match.path}/owners`}

View File

@@ -407,6 +407,7 @@
"local_tax": "Local Tax", "local_tax": "Local Tax",
"new": "New Invoice", "new": "New Invoice",
"noneselected": "No invoice selected.", "noneselected": "No invoice selected.",
"retailtotal": "Retail Total of Invoices (Ex. Taxes)",
"state_tax": "State Tax", "state_tax": "State Tax",
"subtotal": "Subtotal" "subtotal": "Subtotal"
}, },
@@ -597,6 +598,7 @@
"vehicleinfo": "Vehicle Info" "vehicleinfo": "Vehicle Info"
}, },
"creating_new_job": "Creating new job...", "creating_new_job": "Creating new job...",
"difference": "Difference",
"documents": "Documents", "documents": "Documents",
"duplicateconfirm": "Are you sure you want to duplicate this job? Some elements of this job will not be duplicated.", "duplicateconfirm": "Are you sure you want to duplicate this job? Some elements of this job will not be duplicated.",
"existing_jobs": "Existing Jobs", "existing_jobs": "Existing Jobs",

View File

@@ -407,6 +407,7 @@
"local_tax": "", "local_tax": "",
"new": "", "new": "",
"noneselected": "", "noneselected": "",
"retailtotal": "",
"state_tax": "", "state_tax": "",
"subtotal": "" "subtotal": ""
}, },
@@ -597,6 +598,7 @@
"vehicleinfo": "" "vehicleinfo": ""
}, },
"creating_new_job": "Creando nuevo trabajo ...", "creating_new_job": "Creando nuevo trabajo ...",
"difference": "",
"documents": "documentos", "documents": "documentos",
"duplicateconfirm": "", "duplicateconfirm": "",
"existing_jobs": "Empleos existentes", "existing_jobs": "Empleos existentes",

View File

@@ -407,6 +407,7 @@
"local_tax": "", "local_tax": "",
"new": "", "new": "",
"noneselected": "", "noneselected": "",
"retailtotal": "",
"state_tax": "", "state_tax": "",
"subtotal": "" "subtotal": ""
}, },
@@ -597,6 +598,7 @@
"vehicleinfo": "" "vehicleinfo": ""
}, },
"creating_new_job": "Création d'un nouvel emploi ...", "creating_new_job": "Création d'un nouvel emploi ...",
"difference": "",
"documents": "Les documents", "documents": "Les documents",
"duplicateconfirm": "", "duplicateconfirm": "",
"existing_jobs": "Emplois existants", "existing_jobs": "Emplois existants",