Added invoice and invoice detail pages. Begin work on paginated invoices page.
This commit is contained in:
@@ -8949,6 +8949,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>header</name>
|
<name>header</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>accounting</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>activejobs</name>
|
<name>activejobs</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -9117,6 +9138,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>invoices</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>jobs</name>
|
<name>jobs</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import Icon, { CarFilled, FileAddFilled, FileFilled, GlobalOutlined, HomeFilled, TeamOutlined } from "@ant-design/icons";
|
import Icon, {
|
||||||
|
CarFilled,
|
||||||
|
FileAddFilled,
|
||||||
|
FileFilled,
|
||||||
|
GlobalOutlined,
|
||||||
|
HomeFilled,
|
||||||
|
TeamOutlined,
|
||||||
|
DollarCircleFilled,
|
||||||
|
} from "@ant-design/icons";
|
||||||
import { Avatar, Col, Menu, Row } from "antd";
|
import { Avatar, Col, Menu, Row } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -13,7 +21,7 @@ export default ({
|
|||||||
logo,
|
logo,
|
||||||
handleMenuClick,
|
handleMenuClick,
|
||||||
currentUser,
|
currentUser,
|
||||||
signOutStart
|
signOutStart,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
//TODO Add
|
//TODO Add
|
||||||
@@ -159,6 +167,19 @@ export default ({
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
|
|
||||||
|
<Menu.SubMenu
|
||||||
|
title={
|
||||||
|
<span>
|
||||||
|
<DollarCircleFilled />
|
||||||
|
<span>{t("menus.header.accounting")}</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Menu.Item key="invoices">
|
||||||
|
<Link to="/manage/invoices">{t("menus.header.invoices")}</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
|
||||||
<Menu.SubMenu title={t("menus.header.shop")}>
|
<Menu.SubMenu title={t("menus.header.shop")}>
|
||||||
<Menu.Item key="shop">
|
<Menu.Item key="shop">
|
||||||
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link>
|
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link>
|
||||||
|
|||||||
@@ -33,18 +33,18 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
console.log("otherTotals", otherTotals);
|
// console.log("otherTotals", otherTotals);
|
||||||
console.log("job", job);
|
// console.log("job", job);
|
||||||
console.log("parts pst", statePartsTax);
|
// console.log("parts pst", statePartsTax);
|
||||||
console.log(
|
// console.log(
|
||||||
"pst on labor",
|
// "pst on labor",
|
||||||
otherTotals.rates.rates_subtotal * (job.tax_lbr_rt || 0)
|
// otherTotals.rates.rates_subtotal * (job.tax_lbr_rt || 0)
|
||||||
);
|
// );
|
||||||
console.log(
|
// console.log(
|
||||||
"pst on mat",
|
// "pst on mat",
|
||||||
(otherTotals.rates.paint_mat.total + otherTotals.rates.shop_mat.total) *
|
// (otherTotals.rates.paint_mat.total + otherTotals.rates.shop_mat.total) *
|
||||||
(job.tax_paint_mat_rt || 0)
|
// (job.tax_paint_mat_rt || 0)
|
||||||
);
|
// );
|
||||||
|
|
||||||
let ret = {
|
let ret = {
|
||||||
subtotal: subtotal,
|
subtotal: subtotal,
|
||||||
|
|||||||
@@ -10,6 +10,32 @@ export const INSERT_NEW_INVOICE = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
||||||
|
query QUERY_ALL_INVOICES_PAGINATED($offset: Int, $limit: Int) {
|
||||||
|
invoices(offset: $offset, limit: $limit, order_by: { date: desc }) {
|
||||||
|
id
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
total
|
||||||
|
invoice_number
|
||||||
|
date
|
||||||
|
job {
|
||||||
|
id
|
||||||
|
ro_number
|
||||||
|
}
|
||||||
|
invoicelines {
|
||||||
|
actual_price
|
||||||
|
actual_cost
|
||||||
|
cost_center
|
||||||
|
id
|
||||||
|
line_desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const QUERY_INVOICES_BY_JOBID = gql`
|
export const QUERY_INVOICES_BY_JOBID = gql`
|
||||||
query QUERY_INVOICES_BY_JOBID($jobid: uuid!) {
|
query QUERY_INVOICES_BY_JOBID($jobid: uuid!) {
|
||||||
invoices(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
invoices(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function InvoiceDetailPageComponent() {
|
||||||
|
return <div>Invoice Detail Page Component</div>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import InvoiceDetailPageComponent from "./invoice-detail.page.component";
|
||||||
|
|
||||||
|
export default function InvoiceDetailPageContainer() {
|
||||||
|
const { invoiceId } = useParams();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<InvoiceDetailPageComponent />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
188
client/src/pages/invoices/invoices.page.component.jsx
Normal file
188
client/src/pages/invoices/invoices.page.component.jsx
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
import { Button, Descriptions, Table } from "antd";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
|
||||||
|
export default function InvoicesPageComponent({
|
||||||
|
loading,
|
||||||
|
invoices,
|
||||||
|
selectedInvoice,
|
||||||
|
handleFetchMore,
|
||||||
|
handleOnRowClick,
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("invoices.fields.vendorname"),
|
||||||
|
dataIndex: "vendorname",
|
||||||
|
key: "vendorname",
|
||||||
|
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoices.fields.invoice_number"),
|
||||||
|
dataIndex: "invoice_number",
|
||||||
|
key: "invoice_number",
|
||||||
|
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "invoice_number" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoices.fields.date"),
|
||||||
|
dataIndex: "date",
|
||||||
|
key: "date",
|
||||||
|
|
||||||
|
sorter: (a, b) => a.date - b.date,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoices.fields.total"),
|
||||||
|
dataIndex: "total",
|
||||||
|
key: "total",
|
||||||
|
|
||||||
|
sorter: (a, b) => a.total - b.total,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<CurrencyFormatter>{record.total}</CurrencyFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("general.labels.actions"),
|
||||||
|
dataIndex: "actions",
|
||||||
|
key: "actions",
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link to={`/manage/invoices/${record.id}`}>
|
||||||
|
<Button>{t("invoices.actions.edit")}</Button>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
|
const rowExpander = (record) => {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("invoicelines.fields.line_desc"),
|
||||||
|
dataIndex: "line_desc",
|
||||||
|
key: "line_desc",
|
||||||
|
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoicelines.fields.retail"),
|
||||||
|
dataIndex: "actual_price",
|
||||||
|
key: "actual_price",
|
||||||
|
sorter: (a, b) => a.actual_price - b.actual_price,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "actual_price" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<CurrencyFormatter>{record.actual_price}</CurrencyFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoicelines.fields.actual_cost"),
|
||||||
|
dataIndex: "actual_cost",
|
||||||
|
key: "actual_cost",
|
||||||
|
sorter: (a, b) => a.actual_cost - b.actual_cost,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "actual_cost" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<CurrencyFormatter>{record.actual_cost}</CurrencyFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("invoicelines.fields.cost_center"),
|
||||||
|
dataIndex: "cost_center",
|
||||||
|
key: "cost_center",
|
||||||
|
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "cost_center" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Descriptions title="User Info">
|
||||||
|
<Descriptions.Item label="UserName">Zhou Maomao</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="Telephone">1810000000</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="Live">Hangzhou, Zhejiang</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="Remark">empty</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="Address">
|
||||||
|
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
|
columns={columns.map((item) => ({ ...item }))}
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={record.invoicelines}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
loading={loading}
|
||||||
|
size="small"
|
||||||
|
expandedRowRender={rowExpander}
|
||||||
|
pagination={{
|
||||||
|
position: "top",
|
||||||
|
defaultPageSize: 1,
|
||||||
|
onChange: (page, pageSize) => {
|
||||||
|
handleOnRowClick(page * pageSize);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
columns={columns.map((item) => ({ ...item }))}
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={invoices}
|
||||||
|
onChange={handleTableChange}
|
||||||
|
expandable={{
|
||||||
|
expandedRowKeys: [selectedInvoice],
|
||||||
|
onExpand: (expanded, record) => {
|
||||||
|
handleOnRowClick(expanded ? record : null);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
rowSelection={{
|
||||||
|
onSelect: (record) => {
|
||||||
|
handleOnRowClick(record);
|
||||||
|
},
|
||||||
|
selectedRowKeys: [selectedInvoice],
|
||||||
|
type: "radio",
|
||||||
|
}}
|
||||||
|
onRow={(record, rowIndex) => {
|
||||||
|
return {
|
||||||
|
onClick: (event) => {
|
||||||
|
handleOnRowClick(record);
|
||||||
|
}, // click row
|
||||||
|
onDoubleClick: (event) => {}, // double click row
|
||||||
|
onContextMenu: (event) => {}, // right button click row
|
||||||
|
onMouseEnter: (event) => {}, // mouse enter row
|
||||||
|
onMouseLeave: (event) => {}, // mouse leave row
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
57
client/src/pages/invoices/invoices.page.container.jsx
Normal file
57
client/src/pages/invoices/invoices.page.container.jsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
|
import React from "react";
|
||||||
|
import { QUERY_ALL_INVOICES_PAGINATED } from "../../graphql/invoices.queries";
|
||||||
|
import InvoicesPageComponent from "./invoices.page.component";
|
||||||
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
|
import queryString from "query-string";
|
||||||
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
|
export default function InvoicesPageContainer() {
|
||||||
|
const { loading, error, data, fetchMore } = useQuery(
|
||||||
|
QUERY_ALL_INVOICES_PAGINATED,
|
||||||
|
{
|
||||||
|
variables: { offset: 0, limit: 1 },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const search = queryString.parse(useLocation().search);
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const handleOnRowClick = (record) => {
|
||||||
|
if (record) {
|
||||||
|
if (record.id) {
|
||||||
|
search.invoiceid = record.id;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete search.invoiceid;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFetchMore = (offset) => {
|
||||||
|
fetchMore({
|
||||||
|
variables: {
|
||||||
|
offset: offset,
|
||||||
|
},
|
||||||
|
updateQuery: (prev, { fetchMoreResult }) => {
|
||||||
|
if (!fetchMoreResult) return prev;
|
||||||
|
return Object.assign({}, prev, {
|
||||||
|
invoices: [...prev.invoices, ...fetchMoreResult.invoices],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<InvoicesPageComponent
|
||||||
|
loading={loading}
|
||||||
|
invoices={data ? data.invoices : null}
|
||||||
|
selectedInvoice={search.invoiceid}
|
||||||
|
handleFetchMore={handleFetchMore}
|
||||||
|
handleOnRowClick={handleOnRowClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -64,6 +64,13 @@ const ContractDetailPage = lazy(() =>
|
|||||||
const ContractsList = lazy(() =>
|
const ContractsList = lazy(() =>
|
||||||
import("../contracts/contracts.page.container")
|
import("../contracts/contracts.page.container")
|
||||||
);
|
);
|
||||||
|
const InvoicesListPage = lazy(() =>
|
||||||
|
import("../invoices/invoices.page.container")
|
||||||
|
);
|
||||||
|
const InvoiceDetailPage = lazy(() =>
|
||||||
|
import("../invoice-detail/invoice-detail.page.container")
|
||||||
|
);
|
||||||
|
|
||||||
const { Header, Content, Footer } = Layout;
|
const { Header, Content, Footer } = Layout;
|
||||||
|
|
||||||
export default function Manage({ match }) {
|
export default function Manage({ match }) {
|
||||||
@@ -154,6 +161,18 @@ export default function Manage({ match }) {
|
|||||||
path={`${match.path}/vehicles/:vehId`}
|
path={`${match.path}/vehicles/:vehId`}
|
||||||
component={VehiclesDetailContainer}
|
component={VehiclesDetailContainer}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`${match.path}/invoices`}
|
||||||
|
component={InvoicesListPage}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path={`${match.path}/invoices/:invoiceId`}
|
||||||
|
component={InvoiceDetailPage}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path={`${match.path}/owners`}
|
path={`${match.path}/owners`}
|
||||||
|
|||||||
@@ -575,6 +575,7 @@
|
|||||||
"profile": "Profile"
|
"profile": "Profile"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
"accounting": "Accounting",
|
||||||
"activejobs": "Active Jobs",
|
"activejobs": "Active Jobs",
|
||||||
"availablejobs": "Available Jobs",
|
"availablejobs": "Available Jobs",
|
||||||
"courtesycars": "Courtesy Cars",
|
"courtesycars": "Courtesy Cars",
|
||||||
@@ -583,6 +584,7 @@
|
|||||||
"courtesycars-newcontract": "New Contract",
|
"courtesycars-newcontract": "New Contract",
|
||||||
"customers": "Customers",
|
"customers": "Customers",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
|
"invoices": "Invoices",
|
||||||
"jobs": "Jobs",
|
"jobs": "Jobs",
|
||||||
"owners": "Owners",
|
"owners": "Owners",
|
||||||
"schedule": "Schedule",
|
"schedule": "Schedule",
|
||||||
|
|||||||
@@ -575,6 +575,7 @@
|
|||||||
"profile": "Perfil"
|
"profile": "Perfil"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
"accounting": "",
|
||||||
"activejobs": "Empleos activos",
|
"activejobs": "Empleos activos",
|
||||||
"availablejobs": "Trabajos disponibles",
|
"availablejobs": "Trabajos disponibles",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
@@ -583,6 +584,7 @@
|
|||||||
"courtesycars-newcontract": "",
|
"courtesycars-newcontract": "",
|
||||||
"customers": "Clientes",
|
"customers": "Clientes",
|
||||||
"home": "Casa",
|
"home": "Casa",
|
||||||
|
"invoices": "",
|
||||||
"jobs": "Trabajos",
|
"jobs": "Trabajos",
|
||||||
"owners": "propietarios",
|
"owners": "propietarios",
|
||||||
"schedule": "Programar",
|
"schedule": "Programar",
|
||||||
|
|||||||
@@ -575,6 +575,7 @@
|
|||||||
"profile": "Profil"
|
"profile": "Profil"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
"accounting": "",
|
||||||
"activejobs": "Emplois actifs",
|
"activejobs": "Emplois actifs",
|
||||||
"availablejobs": "Emplois disponibles",
|
"availablejobs": "Emplois disponibles",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
@@ -583,6 +584,7 @@
|
|||||||
"courtesycars-newcontract": "",
|
"courtesycars-newcontract": "",
|
||||||
"customers": "Les clients",
|
"customers": "Les clients",
|
||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
|
"invoices": "",
|
||||||
"jobs": "Emplois",
|
"jobs": "Emplois",
|
||||||
"owners": "Propriétaires",
|
"owners": "Propriétaires",
|
||||||
"schedule": "Programme",
|
"schedule": "Programme",
|
||||||
|
|||||||
Reference in New Issue
Block a user