MAJOR CHANGE: Renamed invoices to bills BOD-410
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,18 +4,15 @@ 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 { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import InvoiceExportButton from "../invoice-export-button/invoice-export-button.component";
|
import PayableExportButton from "../payable-export-button/payable-export-button.component";
|
||||||
import InvoiceExportAllButton from "../invoice-export-all-button/invoice-export-all-button.component";
|
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
export default function AccountingPayablesTableComponent({
|
export default function AccountingPayablesTableComponent({ loading, bills }) {
|
||||||
loading,
|
|
||||||
invoices,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedInvoices, setSelectedInvoices] = useState([]);
|
const [selectedBills, setSelectedBills] = useState([]);
|
||||||
const [transInProgress, setTransInProgress] = useState(false);
|
const [transInProgress, setTransInProgress] = useState(false);
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
@@ -28,7 +25,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.vendorname"),
|
title: t("bills.fields.vendorname"),
|
||||||
dataIndex: "vendorname",
|
dataIndex: "vendorname",
|
||||||
key: "vendorname",
|
key: "vendorname",
|
||||||
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||||
@@ -46,7 +43,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.invoice_number"),
|
title: t("bills.fields.invoice_number"),
|
||||||
dataIndex: "invoice_number",
|
dataIndex: "invoice_number",
|
||||||
key: "invoice_number",
|
key: "invoice_number",
|
||||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||||
@@ -56,9 +53,9 @@ export default function AccountingPayablesTableComponent({
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
pathname: `/manage/invoices`,
|
pathname: `/manage/bills`,
|
||||||
search: queryString.stringify({
|
search: queryString.stringify({
|
||||||
invoiceid: record.id,
|
billid: record.id,
|
||||||
vendorid: record.vendor.id,
|
vendorid: record.vendor.id,
|
||||||
}),
|
}),
|
||||||
}}
|
}}
|
||||||
@@ -79,7 +76,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.date"),
|
title: t("bills.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
key: "date",
|
key: "date",
|
||||||
|
|
||||||
@@ -89,7 +86,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.total"),
|
title: t("bills.fields.total"),
|
||||||
dataIndex: "total",
|
dataIndex: "total",
|
||||||
key: "total",
|
key: "total",
|
||||||
|
|
||||||
@@ -101,7 +98,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.is_credit_memo"),
|
title: t("bills.fields.is_credit_memo"),
|
||||||
dataIndex: "is_credit_memo",
|
dataIndex: "is_credit_memo",
|
||||||
key: "is_credit_memo",
|
key: "is_credit_memo",
|
||||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||||
@@ -120,8 +117,8 @@ export default function AccountingPayablesTableComponent({
|
|||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<div>
|
||||||
<InvoiceExportButton
|
<PayableExportButton
|
||||||
invoiceId={record.id}
|
billId={record.id}
|
||||||
disabled={transInProgress || !!record.exported}
|
disabled={transInProgress || !!record.exported}
|
||||||
loadingCallback={setTransInProgress}
|
loadingCallback={setTransInProgress}
|
||||||
/>
|
/>
|
||||||
@@ -136,7 +133,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const dataSource = state.search
|
const dataSource = state.search
|
||||||
? invoices.filter(
|
? bills.filter(
|
||||||
(v) =>
|
(v) =>
|
||||||
(v.vendor.name || "")
|
(v.vendor.name || "")
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
@@ -145,7 +142,7 @@ export default function AccountingPayablesTableComponent({
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(state.search.toLowerCase())
|
.includes(state.search.toLowerCase())
|
||||||
)
|
)
|
||||||
: invoices;
|
: bills;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -160,11 +157,11 @@ export default function AccountingPayablesTableComponent({
|
|||||||
placeholder={t("general.labels.search")}
|
placeholder={t("general.labels.search")}
|
||||||
allowClear
|
allowClear
|
||||||
/>
|
/>
|
||||||
<InvoiceExportAllButton
|
<PayableExportAll
|
||||||
invoiceIds={selectedInvoices}
|
billIds={selectedBills}
|
||||||
disabled={transInProgress || selectedInvoices.length === 0}
|
disabled={transInProgress || selectedBills.length === 0}
|
||||||
loadingCallback={setTransInProgress}
|
loadingCallback={setTransInProgress}
|
||||||
completedCallback={setSelectedInvoices}
|
completedCallback={setSelectedBills}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -177,14 +174,14 @@ export default function AccountingPayablesTableComponent({
|
|||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
onSelectAll: (selected, selectedRows) =>
|
onSelectAll: (selected, selectedRows) =>
|
||||||
setSelectedInvoices(selectedRows.map((i) => i.id)),
|
setSelectedBills(selectedRows.map((i) => i.id)),
|
||||||
onSelect: (record, selected, selectedRows, nativeEvent) => {
|
onSelect: (record, selected, selectedRows, nativeEvent) => {
|
||||||
setSelectedInvoices(selectedRows.map((i) => i.id));
|
setSelectedBills(selectedRows.map((i) => i.id));
|
||||||
},
|
},
|
||||||
getCheckboxProps: (record) => ({
|
getCheckboxProps: (record) => ({
|
||||||
disabled: record.exported,
|
disabled: record.exported,
|
||||||
}),
|
}),
|
||||||
selectedRowKeys: selectedInvoices,
|
selectedRowKeys: selectedBills,
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,57 +1,47 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/react-hooks";
|
import { useMutation, useQuery } from "@apollo/react-hooks";
|
||||||
import { Form, Button } from "antd";
|
import { Button, Form } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { UPDATE_BILL_LINE } from "../../graphql/bill-lines.queries";
|
||||||
import {
|
import { QUERY_BILL_BY_PK, UPDATE_BILL } from "../../graphql/bills.queries";
|
||||||
QUERY_INVOICE_BY_PK,
|
|
||||||
UPDATE_INVOICE,
|
|
||||||
} from "../../graphql/invoices.queries";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import InvoiceFormContainer from "../invoice-form/invoice-form.container";
|
import BillFormContainer from "../bill-form/bill-form.container";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
|
||||||
import { UPDATE_INVOICE_LINE } from "../../graphql/invoice-lines.queries";
|
|
||||||
import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-gallery.container";
|
import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-gallery.container";
|
||||||
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
export default function BillDetailEditcontainer() {
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function InvoiceDetailEditContainer({ bodyshop }) {
|
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [updateLoading, setUpdateLoading] = useState(false);
|
const [updateLoading, setUpdateLoading] = useState(false);
|
||||||
const [updateInvoice] = useMutation(UPDATE_INVOICE);
|
const [update_bill] = useMutation(UPDATE_BILL);
|
||||||
const [updateInvoiceLine] = useMutation(UPDATE_INVOICE_LINE);
|
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
|
||||||
|
|
||||||
const { loading, error, data, refetch } = useQuery(QUERY_INVOICE_BY_PK, {
|
const { loading, error, data, refetch } = useQuery(QUERY_BILL_BY_PK, {
|
||||||
variables: { invoiceid: search.invoiceid },
|
variables: { billid: search.billid },
|
||||||
skip: !!!search.invoiceid,
|
skip: !!!search.billid,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
setUpdateLoading(true);
|
setUpdateLoading(true);
|
||||||
const { invoicelines, upload, ...invoice } = values;
|
const { billlines, upload, ...bill } = values;
|
||||||
const updates = [];
|
const updates = [];
|
||||||
updates.push(
|
updates.push(
|
||||||
updateInvoice({
|
update_bill({
|
||||||
variables: { invoiceId: search.invoiceid, invoice: invoice },
|
variables: { billId: search.billid, bill: bill },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
invoicelines.forEach((il) => {
|
billlines.forEach((il) => {
|
||||||
delete il.__typename;
|
delete il.__typename;
|
||||||
updates.push(
|
updates.push(
|
||||||
updateInvoiceLine({
|
updateBillLine({
|
||||||
variables: {
|
variables: {
|
||||||
invoicelineId: il.id,
|
billLineId: il.id,
|
||||||
invoiceLine: {
|
billLine: {
|
||||||
...il,
|
...il,
|
||||||
joblineid: il.joblineid === "noline" ? null : il.joblineid,
|
joblineid: il.joblineid === "noline" ? null : il.joblineid,
|
||||||
},
|
},
|
||||||
@@ -65,14 +55,13 @@ export function InvoiceDetailEditContainer({ bodyshop }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (search.invoiceid) {
|
if (search.billid) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
}, [form, search.invoiceid]);
|
}, [form, search.billid]);
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
if (!!!search.invoiceid)
|
if (!!!search.billid) return <div>{t("bills.labels.noneselected")}</div>;
|
||||||
return <div>{t("invoices.labels.noneselected")}</div>;
|
|
||||||
return (
|
return (
|
||||||
<LoadingSkeleton loading={loading}>
|
<LoadingSkeleton loading={loading}>
|
||||||
<Form
|
<Form
|
||||||
@@ -81,9 +70,9 @@ export function InvoiceDetailEditContainer({ bodyshop }) {
|
|||||||
initialValues={
|
initialValues={
|
||||||
data
|
data
|
||||||
? {
|
? {
|
||||||
...data.invoices_by_pk,
|
...data.bills_by_pk,
|
||||||
|
|
||||||
invoicelines: data.invoices_by_pk.invoicelines.map((i) => {
|
billlines: data.bills_by_pk.billlines.map((i) => {
|
||||||
return {
|
return {
|
||||||
...i,
|
...i,
|
||||||
joblineid: !!i.joblineid ? i.joblineid : "noline",
|
joblineid: !!i.joblineid ? i.joblineid : "noline",
|
||||||
@@ -100,9 +89,7 @@ export function InvoiceDetailEditContainer({ bodyshop }) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
date: data.invoices_by_pk
|
date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null,
|
||||||
? moment(data.invoices_by_pk.date)
|
|
||||||
: null,
|
|
||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
}
|
}
|
||||||
@@ -110,15 +97,14 @@ export function InvoiceDetailEditContainer({ bodyshop }) {
|
|||||||
<Button htmlType="submit" loading={updateLoading} type="primary">
|
<Button htmlType="submit" loading={updateLoading} type="primary">
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
<InvoiceFormContainer form={form} invoiceEdit />
|
<BillFormContainer form={form} billEdit />
|
||||||
<JobDocumentsGallery
|
<JobDocumentsGallery
|
||||||
jobId={data ? data.invoices_by_pk.jobid : null}
|
jobId={data ? data.bills_by_pk.jobid : null}
|
||||||
invoiceId={search.invoiceid}
|
billId={search.billid}
|
||||||
documentsList={data ? data.invoices_by_pk.documents : []}
|
documentsList={data ? data.bills_by_pk.documents : []}
|
||||||
invoicesCallback={refetch}
|
billsCallback={refetch}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
</LoadingSkeleton>
|
</LoadingSkeleton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(mapStateToProps, null)(InvoiceDetailEditContainer);
|
|
||||||
@@ -4,28 +4,28 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { INSERT_NEW_INVOICE } from "../../graphql/invoices.queries";
|
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectInvoiceEnterModal } from "../../redux/modals/modals.selectors";
|
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
||||||
import InvoiceFormContainer from "../invoice-form/invoice-form.container";
|
import BillFormContainer from "../bill-form/bill-form.container";
|
||||||
import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
invoiceEnterModal: selectInvoiceEnterModal,
|
billEnterModal: selectBillEnterModal,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
toggleModalVisible: () => dispatch(toggleModalVisible("invoiceEnter")),
|
toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")),
|
||||||
});
|
});
|
||||||
|
|
||||||
function InvoiceEnterModalContainer({
|
function BillEnterModalContainer({
|
||||||
invoiceEnterModal,
|
billEnterModal,
|
||||||
toggleModalVisible,
|
toggleModalVisible,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -33,21 +33,21 @@ function InvoiceEnterModalContainer({
|
|||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [enterAgain, setEnterAgain] = useState(false);
|
const [enterAgain, setEnterAgain] = useState(false);
|
||||||
const [insertInvoice] = useMutation(INSERT_NEW_INVOICE);
|
const [insertBill] = useMutation(INSERT_NEW_BILL);
|
||||||
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleFinish = (values) => {
|
const handleFinish = (values) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { upload, location, ...remainingValues } = values;
|
const { upload, location, ...remainingValues } = values;
|
||||||
insertInvoice({
|
insertBill({
|
||||||
variables: {
|
variables: {
|
||||||
invoice: [
|
bill: [
|
||||||
Object.assign({}, remainingValues, {
|
Object.assign({}, remainingValues, {
|
||||||
invoicelines: {
|
billlines: {
|
||||||
data:
|
data:
|
||||||
remainingValues.invoicelines &&
|
remainingValues.billlines &&
|
||||||
remainingValues.invoicelines.map((i) => {
|
remainingValues.billlines.map((i) => {
|
||||||
return {
|
return {
|
||||||
...i,
|
...i,
|
||||||
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
||||||
@@ -59,11 +59,11 @@ function InvoiceEnterModalContainer({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
const invoiceId = r.data.insert_invoices.returning[0].id;
|
const billId = r.data.insert_bills.returning[0].id;
|
||||||
|
|
||||||
updateJobLines({
|
updateJobLines({
|
||||||
variables: {
|
variables: {
|
||||||
ids: remainingValues.invoicelines
|
ids: remainingValues.billlines
|
||||||
.filter((il) => il.joblineid !== "noline")
|
.filter((il) => il.joblineid !== "noline")
|
||||||
.map((li) => li.joblineid),
|
.map((li) => li.joblineid),
|
||||||
status: bodyshop.md_order_statuses.default_received || "Received*",
|
status: bodyshop.md_order_statuses.default_received || "Received*",
|
||||||
@@ -80,7 +80,7 @@ function InvoiceEnterModalContainer({
|
|||||||
bodyshop: bodyshop,
|
bodyshop: bodyshop,
|
||||||
uploaded_by: currentUser.email,
|
uploaded_by: currentUser.email,
|
||||||
jobId: values.jobid,
|
jobId: values.jobid,
|
||||||
invoiceId: invoiceId,
|
billId: billId,
|
||||||
tagsArray: null,
|
tagsArray: null,
|
||||||
callback: null,
|
callback: null,
|
||||||
}
|
}
|
||||||
@@ -90,14 +90,13 @@ function InvoiceEnterModalContainer({
|
|||||||
///////////////////////////
|
///////////////////////////
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("invoices.successes.created"),
|
message: t("bills.successes.created"),
|
||||||
});
|
});
|
||||||
if (invoiceEnterModal.actions.refetch)
|
if (billEnterModal.actions.refetch) billEnterModal.actions.refetch();
|
||||||
invoiceEnterModal.actions.refetch();
|
|
||||||
|
|
||||||
if (enterAgain) {
|
if (enterAgain) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue({ invoicelines: [] });
|
form.setFieldsValue({ billlines: [] });
|
||||||
} else {
|
} else {
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
}
|
}
|
||||||
@@ -108,7 +107,7 @@ function InvoiceEnterModalContainer({
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
setEnterAgain(false);
|
setEnterAgain(false);
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.creating", {
|
message: t("bills.errors.creating", {
|
||||||
message: JSON.stringify(error),
|
message: JSON.stringify(error),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -124,14 +123,14 @@ function InvoiceEnterModalContainer({
|
|||||||
}, [enterAgain, form]);
|
}, [enterAgain, form]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (invoiceEnterModal.visible) form.resetFields();
|
if (billEnterModal.visible) form.resetFields();
|
||||||
}, [invoiceEnterModal.visible, form]);
|
}, [billEnterModal.visible, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t("invoices.labels.new")}
|
title={t("bills.labels.new")}
|
||||||
width={"90%"}
|
width={"90%"}
|
||||||
visible={invoiceEnterModal.visible}
|
visible={billEnterModal.visible}
|
||||||
okText={t("general.actions.save")}
|
okText={t("general.actions.save")}
|
||||||
onOk={() => form.submit()}
|
onOk={() => form.submit()}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
@@ -142,7 +141,7 @@ function InvoiceEnterModalContainer({
|
|||||||
<Button loading={loading} onClick={() => form.submit()}>
|
<Button loading={loading} onClick={() => form.submit()}>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
{invoiceEnterModal.context && invoiceEnterModal.context.id ? null : (
|
{billEnterModal.context && billEnterModal.context.id ? null : (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
@@ -166,26 +165,25 @@ function InvoiceEnterModalContainer({
|
|||||||
setEnterAgain(false);
|
setEnterAgain(false);
|
||||||
}}
|
}}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
...invoiceEnterModal.context.invoice,
|
...billEnterModal.context.bill,
|
||||||
jobid:
|
jobid:
|
||||||
(invoiceEnterModal.context.job &&
|
(billEnterModal.context.job && billEnterModal.context.job.id) ||
|
||||||
invoiceEnterModal.context.job.id) ||
|
|
||||||
null,
|
null,
|
||||||
federal_tax_rate:
|
federal_tax_rate:
|
||||||
(bodyshop.invoice_tax_rates &&
|
(bodyshop.bill_tax_rates &&
|
||||||
bodyshop.invoice_tax_rates.federal_tax_rate) ||
|
bodyshop.bill_tax_rates.federal_tax_rate) ||
|
||||||
0,
|
0,
|
||||||
state_tax_rate:
|
state_tax_rate:
|
||||||
(bodyshop.invoice_tax_rates &&
|
(bodyshop.bill_tax_rates &&
|
||||||
bodyshop.invoice_tax_rates.state_tax_rate) ||
|
bodyshop.bill_tax_rates.state_tax_rate) ||
|
||||||
0,
|
0,
|
||||||
local_tax_rate:
|
local_tax_rate:
|
||||||
(bodyshop.invoice_tax_rates &&
|
(bodyshop.bill_tax_rates &&
|
||||||
bodyshop.invoice_tax_rates.local_tax_rate) ||
|
bodyshop.bill_tax_rates.local_tax_rate) ||
|
||||||
0,
|
0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<InvoiceFormContainer form={form} />
|
<BillFormContainer form={form} />
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
@@ -194,4 +192,4 @@ function InvoiceEnterModalContainer({
|
|||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(InvoiceEnterModalContainer);
|
)(BillEnterModalContainer);
|
||||||
@@ -20,25 +20,21 @@ import CurrencyInput from "../form-items-formatted/currency-form-item.component"
|
|||||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
import InvoiceFormLines from "./invoice-form.lines.component";
|
import BillFormLines from "./bill-form.lines.component";
|
||||||
import "./invoice-form.styles.scss";
|
import { CalculateBillTotal } from "./bill-form.totals.utility";
|
||||||
import { CalculateInvoiceTotal } from "./invoice-form.totals.utility";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({});
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
||||||
});
|
|
||||||
|
|
||||||
export function InvoiceFormComponent({
|
export function BillFormComponent({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
form,
|
form,
|
||||||
vendorAutoCompleteOptions,
|
vendorAutoCompleteOptions,
|
||||||
lineData,
|
lineData,
|
||||||
responsibilityCenters,
|
responsibilityCenters,
|
||||||
loadLines,
|
loadLines,
|
||||||
invoiceEdit,
|
billEdit,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -69,7 +65,7 @@ export function InvoiceFormComponent({
|
|||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="jobid"
|
name="jobid"
|
||||||
label={t("invoices.fields.ro_number")}
|
label={t("bills.fields.ro_number")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -78,7 +74,7 @@ export function InvoiceFormComponent({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<JobSearchSelect
|
<JobSearchSelect
|
||||||
disabled={invoiceEdit}
|
disabled={billEdit}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (form.getFieldValue("jobid") !== null) {
|
if (form.getFieldValue("jobid") !== null) {
|
||||||
loadLines({ variables: { id: form.getFieldValue("jobid") } });
|
loadLines({ variables: { id: form.getFieldValue("jobid") } });
|
||||||
@@ -87,9 +83,9 @@ export function InvoiceFormComponent({
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.vendor")}
|
label={t("bills.fields.vendor")}
|
||||||
name="vendorid"
|
name="vendorid"
|
||||||
style={{ display: invoiceEdit ? "none" : null }}
|
style={{ display: billEdit ? "none" : null }}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -106,7 +102,7 @@ export function InvoiceFormComponent({
|
|||||||
|
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.invoice_number")}
|
label={t("bills.fields.invoice_number")}
|
||||||
name="invoice_number"
|
name="invoice_number"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
@@ -118,7 +114,7 @@ export function InvoiceFormComponent({
|
|||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.date")}
|
label={t("bills.fields.date")}
|
||||||
name="date"
|
name="date"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
@@ -130,14 +126,14 @@ export function InvoiceFormComponent({
|
|||||||
<FormDatePicker />
|
<FormDatePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.is_credit_memo")}
|
label={t("bills.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("bills.fields.total")}
|
||||||
name="total"
|
name="total"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
@@ -149,28 +145,25 @@ export function InvoiceFormComponent({
|
|||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.federal_tax_rate")}
|
label={t("bills.fields.federal_tax_rate")}
|
||||||
name="federal_tax_rate"
|
name="federal_tax_rate"
|
||||||
>
|
>
|
||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.state_tax_rate")}
|
label={t("bills.fields.state_tax_rate")}
|
||||||
name="state_tax_rate"
|
name="state_tax_rate"
|
||||||
>
|
>
|
||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoices.fields.local_tax_rate")}
|
label={t("bills.fields.local_tax_rate")}
|
||||||
name="local_tax_rate"
|
name="local_tax_rate"
|
||||||
>
|
>
|
||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item label={t("bills.fields.allpartslocation")} name="location">
|
||||||
label={t("invoices.fields.allpartslocation")}
|
|
||||||
name="location"
|
|
||||||
>
|
|
||||||
<Select style={{ width: "10rem" }}>
|
<Select style={{ width: "10rem" }}>
|
||||||
{bodyshop.md_parts_locations.map((loc, idx) => (
|
{bodyshop.md_parts_locations.map((loc, idx) => (
|
||||||
<Select.Option key={idx} value={loc}>
|
<Select.Option key={idx} value={loc}>
|
||||||
@@ -181,9 +174,9 @@ export function InvoiceFormComponent({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>
|
||||||
{t("invoices.labels.invoice_lines")}
|
{t("bills.labels.bill_lines")}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<InvoiceFormLines
|
<BillFormLines
|
||||||
lineData={lineData}
|
lineData={lineData}
|
||||||
discount={discount}
|
discount={discount}
|
||||||
form={form}
|
form={form}
|
||||||
@@ -193,7 +186,7 @@ export function InvoiceFormComponent({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="upload"
|
name="upload"
|
||||||
label="Upload"
|
label="Upload"
|
||||||
style={{ display: invoiceEdit ? "none" : null }}
|
style={{ display: billEdit ? "none" : null }}
|
||||||
valuePropName="fileList"
|
valuePropName="fileList"
|
||||||
getValueFromEvent={(e) => {
|
getValueFromEvent={(e) => {
|
||||||
if (Array.isArray(e)) {
|
if (Array.isArray(e)) {
|
||||||
@@ -210,7 +203,7 @@ export function InvoiceFormComponent({
|
|||||||
<Form.Item shouldUpdate>
|
<Form.Item shouldUpdate>
|
||||||
{() => {
|
{() => {
|
||||||
const values = form.getFieldsValue([
|
const values = form.getFieldsValue([
|
||||||
"invoicelines",
|
"billlines",
|
||||||
"total",
|
"total",
|
||||||
"federal_tax_rate",
|
"federal_tax_rate",
|
||||||
"state_tax_rate",
|
"state_tax_rate",
|
||||||
@@ -219,46 +212,46 @@ export function InvoiceFormComponent({
|
|||||||
let totals;
|
let totals;
|
||||||
if (
|
if (
|
||||||
!!values.total &&
|
!!values.total &&
|
||||||
!!values.invoicelines &&
|
!!values.billlines &&
|
||||||
values.invoicelines.length > 0
|
values.billlines.length > 0
|
||||||
)
|
)
|
||||||
totals = CalculateInvoiceTotal(values);
|
totals = CalculateBillTotal(values);
|
||||||
if (!!totals)
|
if (!!totals)
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.subtotal")}
|
title={t("bills.labels.subtotal")}
|
||||||
value={totals.subtotal.toFormat()}
|
value={totals.subtotal.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.federal_tax")}
|
title={t("bills.labels.federal_tax")}
|
||||||
value={totals.federalTax.toFormat()}
|
value={totals.federalTax.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.state_tax")}
|
title={t("bills.labels.state_tax")}
|
||||||
value={totals.stateTax.toFormat()}
|
value={totals.stateTax.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.local_tax")}
|
title={t("bills.labels.local_tax")}
|
||||||
value={totals.localTax.toFormat()}
|
value={totals.localTax.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.entered_total")}
|
title={t("bills.labels.entered_total")}
|
||||||
value={totals.enteredTotal.toFormat()}
|
value={totals.enteredTotal.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.invoice_total")}
|
title={t("bills.labels.bill_total")}
|
||||||
value={totals.invoiceTotal.toFormat()}
|
value={totals.invoiceTotal.toFormat()}
|
||||||
precision={2}
|
precision={2}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.discrepancy")}
|
title={t("bills.labels.discrepancy")}
|
||||||
valueStyle={{
|
valueStyle={{
|
||||||
color:
|
color:
|
||||||
totals.discrepancy.getAmount() === 0 ? "green" : "red",
|
totals.discrepancy.getAmount() === 0 ? "green" : "red",
|
||||||
@@ -270,7 +263,7 @@ export function InvoiceFormComponent({
|
|||||||
{form.getFieldValue("is_credit_memo") ? (
|
{form.getFieldValue("is_credit_memo") ? (
|
||||||
<AlertComponent
|
<AlertComponent
|
||||||
type="warning"
|
type="warning"
|
||||||
message={t("invoices.labels.enteringcreditmemo")}
|
message={t("bills.labels.enteringcreditmemo")}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -282,7 +275,4 @@ export function InvoiceFormComponent({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(mapStateToProps, mapDispatchToProps)(BillFormComponent);
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(InvoiceFormComponent);
|
|
||||||
@@ -2,27 +2,27 @@ import { useLazyQuery, useQuery } from "@apollo/react-hooks";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { GET_JOB_LINES_TO_ENTER_INVOICE } from "../../graphql/jobs-lines.queries";
|
import { GET_JOB_LINES_TO_ENTER_BILL } from "../../graphql/jobs-lines.queries";
|
||||||
import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
|
import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import InvoiceFormComponent from "./invoice-form.component";
|
import BillFormComponent from "./bill-form.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoiceFormContainer({ bodyshop, form, invoiceEdit }) {
|
export function BillFormContainer({ bodyshop, form, billEdit }) {
|
||||||
const { data: VendorAutoCompleteData } = useQuery(SEARCH_VENDOR_AUTOCOMPLETE);
|
const { data: VendorAutoCompleteData } = useQuery(SEARCH_VENDOR_AUTOCOMPLETE);
|
||||||
|
|
||||||
const [loadLines, { data: lineData }] = useLazyQuery(
|
const [loadLines, { data: lineData }] = useLazyQuery(
|
||||||
GET_JOB_LINES_TO_ENTER_INVOICE
|
GET_JOB_LINES_TO_ENTER_BILL
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<InvoiceFormComponent
|
<BillFormComponent
|
||||||
form={form}
|
form={form}
|
||||||
invoiceEdit={invoiceEdit}
|
billEdit={billEdit}
|
||||||
vendorAutoCompleteOptions={
|
vendorAutoCompleteOptions={
|
||||||
VendorAutoCompleteData && VendorAutoCompleteData.vendors
|
VendorAutoCompleteData && VendorAutoCompleteData.vendors
|
||||||
}
|
}
|
||||||
@@ -33,4 +33,4 @@ export function InvoiceFormContainer({ bodyshop, form, invoiceEdit }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(mapStateToProps, null)(InvoiceFormContainer);
|
export default connect(mapStateToProps, null)(BillFormContainer);
|
||||||
@@ -11,10 +11,10 @@ import {
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import InvoiceLineSearchSelect from "../invoice-line-search-select/invoice-line-search-select.component";
|
import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
export default function InvoiceEnterModalLinesComponent({
|
export default function BillEnterModalLinesComponent({
|
||||||
lineData,
|
lineData,
|
||||||
discount,
|
discount,
|
||||||
form,
|
form,
|
||||||
@@ -24,7 +24,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
const { setFieldsValue, getFieldsValue } = form;
|
const { setFieldsValue, getFieldsValue } = form;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.List name="invoicelines">
|
<Form.List name="billlines">
|
||||||
{(fields, { add, remove, move }) => {
|
{(fields, { add, remove, move }) => {
|
||||||
return (
|
return (
|
||||||
<div className="invoice-form-lines-wrapper">
|
<div className="invoice-form-lines-wrapper">
|
||||||
@@ -34,7 +34,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
<LayoutFormRow style={{ flex: 1 }} grow>
|
<LayoutFormRow style={{ flex: 1 }} grow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.jobline")}
|
label={t("billlines.fields.jobline")}
|
||||||
key={`${index}joblinename`}
|
key={`${index}joblinename`}
|
||||||
name={[field.name, "joblineid"]}
|
name={[field.name, "joblineid"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -44,13 +44,13 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InvoiceLineSearchSelect
|
<BillLineSearchSelect
|
||||||
options={lineData}
|
options={lineData}
|
||||||
onSelect={(value, opt) => {
|
onSelect={(value, opt) => {
|
||||||
setFieldsValue({
|
setFieldsValue({
|
||||||
invoicelines: getFieldsValue([
|
billlines: getFieldsValue([
|
||||||
"invoicelines",
|
"billlines",
|
||||||
]).invoicelines.map((item, idx) => {
|
]).billlines.map((item, idx) => {
|
||||||
if (idx === index) {
|
if (idx === index) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -72,7 +72,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.line_desc")}
|
label={t("billlines.fields.line_desc")}
|
||||||
key={`${index}line_desc`}
|
key={`${index}line_desc`}
|
||||||
name={[field.name, "line_desc"]}
|
name={[field.name, "line_desc"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -85,7 +85,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.quantity")}
|
label={t("billlines.fields.quantity")}
|
||||||
key={`${index}quantity`}
|
key={`${index}quantity`}
|
||||||
name={[field.name, "quantity"]}
|
name={[field.name, "quantity"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -98,7 +98,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<InputNumber precision={0} min={0} />
|
<InputNumber precision={0} min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.actual")}
|
label={t("billlines.fields.actual")}
|
||||||
key={`${index}actual_price`}
|
key={`${index}actual_price`}
|
||||||
name={[field.name, "actual_price"]}
|
name={[field.name, "actual_price"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -112,9 +112,9 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
min={0}
|
min={0}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
setFieldsValue({
|
setFieldsValue({
|
||||||
invoicelines: getFieldsValue(
|
billlines: getFieldsValue(
|
||||||
"invoicelines"
|
"billlines"
|
||||||
).invoicelines.map((item, idx) => {
|
).billlines.map((item, idx) => {
|
||||||
if (idx === index) {
|
if (idx === index) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -131,7 +131,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.actual_cost")}
|
label={t("billlines.fields.actual_cost")}
|
||||||
key={`${index}actual_cost`}
|
key={`${index}actual_cost`}
|
||||||
name={[field.name, "actual_cost"]}
|
name={[field.name, "actual_cost"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -145,8 +145,9 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item shouldUpdate>
|
<Form.Item shouldUpdate>
|
||||||
{() => {
|
{() => {
|
||||||
const line = getFieldsValue(["invoicelines"])
|
const line = getFieldsValue(["billlines"]).billlines[
|
||||||
.invoicelines[index];
|
index
|
||||||
|
];
|
||||||
if (!!!line) return null;
|
if (!!!line) return null;
|
||||||
const lineDiscount = (
|
const lineDiscount = (
|
||||||
1 -
|
1 -
|
||||||
@@ -161,7 +162,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.cost_center")}
|
label={t("billlines.fields.cost_center")}
|
||||||
key={`${index}cost_center`}
|
key={`${index}cost_center`}
|
||||||
name={[field.name, "cost_center"]}
|
name={[field.name, "cost_center"]}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -180,7 +181,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.federal_tax_applicable")}
|
label={t("billlines.fields.federal_tax_applicable")}
|
||||||
key={`${index}fedtax`}
|
key={`${index}fedtax`}
|
||||||
initialValue={true}
|
initialValue={true}
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
@@ -189,7 +190,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.state_tax_applicable")}
|
label={t("billlines.fields.state_tax_applicable")}
|
||||||
key={`${index}statetax`}
|
key={`${index}statetax`}
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
name={[field.name, "applicable_taxes", "state"]}
|
name={[field.name, "applicable_taxes", "state"]}
|
||||||
@@ -197,7 +198,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("invoicelines.fields.local_tax_applicable")}
|
label={t("billlines.fields.local_tax_applicable")}
|
||||||
key={`${index}localtax`}
|
key={`${index}localtax`}
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
name={[field.name, "applicable_taxes", "local"]}
|
name={[field.name, "applicable_taxes", "local"]}
|
||||||
@@ -227,7 +228,7 @@ export default function InvoiceEnterModalLinesComponent({
|
|||||||
}}
|
}}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
{t("invoicelines.actions.newline")}
|
{t("billlines.actions.newline")}
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
export const CalculateInvoiceTotal = (invoice) => {
|
export const CalculateBillTotal = (invoice) => {
|
||||||
logImEXEvent("invoice_calculate_total");
|
logImEXEvent("invoice_calculate_total");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
total,
|
total,
|
||||||
|
billlines,
|
||||||
invoicelines,
|
|
||||||
federal_tax_rate,
|
federal_tax_rate,
|
||||||
local_tax_rate,
|
local_tax_rate,
|
||||||
state_tax_rate,
|
state_tax_rate,
|
||||||
@@ -17,8 +16,10 @@ export const CalculateInvoiceTotal = (invoice) => {
|
|||||||
let federalTax = Dinero({ amount: 0 });
|
let federalTax = Dinero({ amount: 0 });
|
||||||
let stateTax = Dinero({ amount: 0 });
|
let stateTax = Dinero({ amount: 0 });
|
||||||
let localTax = Dinero({ amount: 0 });
|
let localTax = Dinero({ amount: 0 });
|
||||||
if (!!!invoicelines) return null;
|
|
||||||
invoicelines.forEach((i) => {
|
if (!!!billlines) return null;
|
||||||
|
|
||||||
|
billlines.forEach((i) => {
|
||||||
if (!!i) {
|
if (!!i) {
|
||||||
const itemTotal = Dinero({
|
const itemTotal = Dinero({
|
||||||
amount: Math.round((i.actual_cost || 0) * 100) || 0,
|
amount: Math.round((i.actual_cost || 0) * 100) || 0,
|
||||||
@@ -5,7 +5,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|||||||
|
|
||||||
//To be used as a form element only.
|
//To be used as a form element only.
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const InvoiceLineSearchSelect = (
|
const BillLineSearchSelect = (
|
||||||
{ value, onChange, options, onBlur, onSelect },
|
{ value, onChange, options, onBlur, onSelect },
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
@@ -33,7 +33,7 @@ const InvoiceLineSearchSelect = (
|
|||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
>
|
>
|
||||||
<Select.Option key={null} value={"noline"} cost={0} line_desc={""}>
|
<Select.Option key={null} value={"noline"} cost={0} line_desc={""}>
|
||||||
{t("invoicelines.labels.other")}
|
{t("billlines.labels.other")}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
{options
|
{options
|
||||||
? options.map((item) => (
|
? options.map((item) => (
|
||||||
@@ -68,4 +68,4 @@ const InvoiceLineSearchSelect = (
|
|||||||
</Select>
|
</Select>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default forwardRef(InvoiceLineSearchSelect);
|
export default forwardRef(BillLineSearchSelect);
|
||||||
@@ -14,38 +14,34 @@ import { useLocation } from "react-router-dom";
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setPartsOrderContext: (context) =>
|
setPartsOrderContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
||||||
setInvoiceEnterContext: (context) =>
|
setBillEnterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
setReconciliationContext: (context) =>
|
setReconciliationContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "reconciliation" })),
|
dispatch(setModalContext({ context: context, modal: "reconciliation" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoicesListTableComponent({
|
export function BillsListTableComponent({
|
||||||
job,
|
job,
|
||||||
loading,
|
billsQuery,
|
||||||
invoicesQuery,
|
|
||||||
handleOnRowClick,
|
handleOnRowClick,
|
||||||
setPartsOrderContext,
|
setPartsOrderContext,
|
||||||
setInvoiceEnterContext,
|
setBillEnterContext,
|
||||||
setReconciliationContext,
|
setReconciliationContext,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [
|
const [selectedBillLinesByBill, setSelectedBillLinesByBill] = useState({});
|
||||||
selectedInvoiceLinesByInvoice,
|
|
||||||
setSelectedInvoiceLinesByInvoice,
|
|
||||||
] = useState({});
|
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
});
|
});
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const selectedInvoice = search.invoiceid;
|
const selectedBill = search.billid;
|
||||||
|
|
||||||
const invoices = invoicesQuery.data ? invoicesQuery.data.invoices : [];
|
const bills = billsQuery.data ? billsQuery.data.bills : [];
|
||||||
const { refetch } = invoicesQuery;
|
const { refetch } = billsQuery;
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.vendorname"),
|
title: t("bills.fields.vendorname"),
|
||||||
dataIndex: "vendorname",
|
dataIndex: "vendorname",
|
||||||
key: "vendorname",
|
key: "vendorname",
|
||||||
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||||
@@ -54,7 +50,7 @@ export function InvoicesListTableComponent({
|
|||||||
render: (text, record) => <span>{record.vendor.name}</span>,
|
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.invoice_number"),
|
title: t("bills.fields.invoice_number"),
|
||||||
dataIndex: "invoice_number",
|
dataIndex: "invoice_number",
|
||||||
key: "invoice_number",
|
key: "invoice_number",
|
||||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||||
@@ -63,7 +59,7 @@ export function InvoicesListTableComponent({
|
|||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.date"),
|
title: t("bills.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
key: "date",
|
key: "date",
|
||||||
sorter: (a, b) => a.date - b.date,
|
sorter: (a, b) => a.date - b.date,
|
||||||
@@ -72,7 +68,7 @@ export function InvoicesListTableComponent({
|
|||||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.total"),
|
title: t("bills.fields.total"),
|
||||||
dataIndex: "total",
|
dataIndex: "total",
|
||||||
key: "total",
|
key: "total",
|
||||||
sorter: (a, b) => a.total - b.total,
|
sorter: (a, b) => a.total - b.total,
|
||||||
@@ -83,7 +79,7 @@ export function InvoicesListTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.is_credit_memo"),
|
title: t("bills.fields.is_credit_memo"),
|
||||||
dataIndex: "is_credit_memo",
|
dataIndex: "is_credit_memo",
|
||||||
key: "is_credit_memo",
|
key: "is_credit_memo",
|
||||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||||
@@ -99,9 +95,9 @@ export function InvoicesListTableComponent({
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<div>
|
||||||
<Link
|
<Link
|
||||||
to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}
|
to={`/manage/bills?billid=${record.id}&vendorid=${record.vendorid}`}
|
||||||
>
|
>
|
||||||
<Button>{t("invoices.actions.edit")}</Button>
|
<Button>{t("bills.actions.edit")}</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -115,7 +111,7 @@ export function InvoicesListTableComponent({
|
|||||||
const rowExpander = (record) => {
|
const rowExpander = (record) => {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.line_desc"),
|
title: t("billlines.fields.line_desc"),
|
||||||
dataIndex: "line_desc",
|
dataIndex: "line_desc",
|
||||||
key: "line_desc",
|
key: "line_desc",
|
||||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||||
@@ -123,7 +119,7 @@ export function InvoicesListTableComponent({
|
|||||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.retail"),
|
title: t("billlines.fields.retail"),
|
||||||
dataIndex: "actual_price",
|
dataIndex: "actual_price",
|
||||||
key: "actual_price",
|
key: "actual_price",
|
||||||
sorter: (a, b) => a.actual_price - b.actual_price,
|
sorter: (a, b) => a.actual_price - b.actual_price,
|
||||||
@@ -135,7 +131,7 @@ export function InvoicesListTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.actual_cost"),
|
title: t("billlines.fields.actual_cost"),
|
||||||
dataIndex: "actual_cost",
|
dataIndex: "actual_cost",
|
||||||
key: "actual_cost",
|
key: "actual_cost",
|
||||||
sorter: (a, b) => a.actual_cost - b.actual_cost,
|
sorter: (a, b) => a.actual_cost - b.actual_cost,
|
||||||
@@ -147,7 +143,7 @@ export function InvoicesListTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.quantity"),
|
title: t("billlines.fields.quantity"),
|
||||||
dataIndex: "quantity",
|
dataIndex: "quantity",
|
||||||
key: "quantity",
|
key: "quantity",
|
||||||
sorter: (a, b) => a.quantity - b.quantity,
|
sorter: (a, b) => a.quantity - b.quantity,
|
||||||
@@ -155,7 +151,7 @@ export function InvoicesListTableComponent({
|
|||||||
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.cost_center"),
|
title: t("billlines.fields.cost_center"),
|
||||||
dataIndex: "cost_center",
|
dataIndex: "cost_center",
|
||||||
key: "cost_center",
|
key: "cost_center",
|
||||||
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
|
sorter: (a, b) => alphaSort(a.cost_center, b.cost_center),
|
||||||
@@ -164,7 +160,7 @@ export function InvoicesListTableComponent({
|
|||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.federal_tax_applicable"),
|
title: t("billlines.fields.federal_tax_applicable"),
|
||||||
dataIndex: "applicable_taxes.federal",
|
dataIndex: "applicable_taxes.federal",
|
||||||
key: "applicable_taxes.federal",
|
key: "applicable_taxes.federal",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
@@ -178,7 +174,7 @@ export function InvoicesListTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.state_tax_applicable"),
|
title: t("billlines.fields.state_tax_applicable"),
|
||||||
dataIndex: "applicable_taxes.state",
|
dataIndex: "applicable_taxes.state",
|
||||||
key: "applicable_taxes.state",
|
key: "applicable_taxes.state",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
@@ -192,7 +188,7 @@ export function InvoicesListTableComponent({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.local_tax_applicable"),
|
title: t("billlines.fields.local_tax_applicable"),
|
||||||
dataIndex: "applicable_taxes.local",
|
dataIndex: "applicable_taxes.local",
|
||||||
key: "applicable_taxes.local",
|
key: "applicable_taxes.local",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
@@ -207,26 +203,26 @@ export function InvoicesListTableComponent({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleOnInvoiceRowclick = (selectedRows) => {
|
const handleOnBillrowclick = (selectedRows) => {
|
||||||
setSelectedInvoiceLinesByInvoice({
|
setSelectedBillLinesByBill({
|
||||||
...selectedInvoiceLinesByInvoice,
|
...selectedBillLinesByBill,
|
||||||
[record.id]: selectedRows.map((r) => r.id),
|
[record.id]: selectedRows.map((r) => r.id),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title level={3}>{`${t("invoices.fields.invoice_number")} ${
|
<Typography.Title level={3}>{`${t("bills.fields.invoice_number")} ${
|
||||||
record.invoice_number
|
record.invoice_number
|
||||||
}`}</Typography.Title>
|
}`}</Typography.Title>
|
||||||
<Descriptions>
|
<Descriptions>
|
||||||
<Descriptions.Item label={t("invoices.fields.federal_tax_rate")}>
|
<Descriptions.Item label={t("bills.fields.federal_tax_rate")}>
|
||||||
{`${record.federal_tax_rate}%` || ""}
|
{`${record.federal_tax_rate}%` || ""}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label={t("invoices.fields.state_tax_rate")}>
|
<Descriptions.Item label={t("bills.fields.state_tax_rate")}>
|
||||||
{`${record.state_tax_rate}%` || ""}
|
{`${record.state_tax_rate}%` || ""}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label={t("invoices.fields.local_tax_rate")}>
|
<Descriptions.Item label={t("bills.fields.local_tax_rate")}>
|
||||||
{`${record.local_tax_rate}%` || ""}
|
{`${record.local_tax_rate}%` || ""}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
@@ -238,11 +234,11 @@ export function InvoicesListTableComponent({
|
|||||||
context: {
|
context: {
|
||||||
jobId: job.id,
|
jobId: job.id,
|
||||||
vendorId: record.vendorid,
|
vendorId: record.vendorid,
|
||||||
returnFromInvoice: record.id,
|
returnFromBill: record.id,
|
||||||
invoiceNumber: record.invoice_number,
|
invoiceNumber: record.invoice_number,
|
||||||
linesToOrder: record.invoicelines
|
linesToOrder: record.billlines
|
||||||
.filter((il) =>
|
.filter((il) =>
|
||||||
selectedInvoiceLinesByInvoice[record.id].includes(il.id)
|
selectedBillLinesByBill[record.id].includes(il.id)
|
||||||
)
|
)
|
||||||
.map((i) => {
|
.map((i) => {
|
||||||
return {
|
return {
|
||||||
@@ -258,7 +254,7 @@ export function InvoicesListTableComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("invoices.actions.return")}
|
{t("bills.actions.return")}
|
||||||
</Button>
|
</Button>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
@@ -266,15 +262,15 @@ export function InvoicesListTableComponent({
|
|||||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={record.invoicelines}
|
dataSource={record.billlines}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
onSelect: (record, selected, selectedRows) => {
|
onSelect: (record, selected, selectedRows) => {
|
||||||
handleOnInvoiceRowclick(selectedRows);
|
handleOnBillrowclick(selectedRows);
|
||||||
},
|
},
|
||||||
onSelectAll: (selected, selectedRows, changeRows) => {
|
onSelectAll: (selected, selectedRows, changeRows) => {
|
||||||
handleOnInvoiceRowclick(selectedRows);
|
handleOnBillrowclick(selectedRows);
|
||||||
},
|
},
|
||||||
selectedRowKeys: selectedInvoiceLinesByInvoice[record.id],
|
selectedRowKeys: selectedBillLinesByBill[record.id],
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -284,11 +280,9 @@ export function InvoicesListTableComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
||||||
{t("invoices.labels.invoices")}
|
|
||||||
</Typography.Title>
|
|
||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={billsQuery.loading}
|
||||||
size="small"
|
size="small"
|
||||||
title={() => (
|
title={() => (
|
||||||
<div className="imex-table-header">
|
<div className="imex-table-header">
|
||||||
@@ -299,25 +293,23 @@ export function InvoicesListTableComponent({
|
|||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInvoiceEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: invoicesQuery.refetch },
|
actions: { refetch: billsQuery.refetch },
|
||||||
context: {
|
context: {
|
||||||
job,
|
job,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("jobs.actions.postInvoices")}
|
{t("jobs.actions.postbills")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setReconciliationContext({
|
setReconciliationContext({
|
||||||
actions: { refetch: invoicesQuery.refetch },
|
actions: { refetch: billsQuery.refetch },
|
||||||
context: {
|
context: {
|
||||||
job,
|
job,
|
||||||
invoices:
|
bills: (billsQuery.data && billsQuery.data.bills) || [],
|
||||||
(invoicesQuery.data && invoicesQuery.data.invoices) ||
|
|
||||||
[],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@@ -342,10 +334,10 @@ export function InvoicesListTableComponent({
|
|||||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={invoices}
|
dataSource={bills}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
expandable={{
|
expandable={{
|
||||||
expandedRowKeys: [selectedInvoice],
|
expandedRowKeys: [selectedBill],
|
||||||
onExpand: (expanded, record) => {
|
onExpand: (expanded, record) => {
|
||||||
handleOnRowClick(expanded ? record : null);
|
handleOnRowClick(expanded ? record : null);
|
||||||
},
|
},
|
||||||
@@ -354,7 +346,7 @@ export function InvoicesListTableComponent({
|
|||||||
onSelect: (record) => {
|
onSelect: (record) => {
|
||||||
handleOnRowClick(record);
|
handleOnRowClick(record);
|
||||||
},
|
},
|
||||||
selectedRowKeys: [selectedInvoice],
|
selectedRowKeys: [selectedBill],
|
||||||
type: "radio",
|
type: "radio",
|
||||||
}}
|
}}
|
||||||
onRow={(record, rowIndex) => {
|
onRow={(record, rowIndex) => {
|
||||||
@@ -372,4 +364,4 @@ export function InvoicesListTableComponent({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(null, mapDispatchToProps)(InvoicesListTableComponent);
|
export default connect(null, mapDispatchToProps)(BillsListTableComponent);
|
||||||
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
|
||||||
export default function InvoicesVendorsList() {
|
export default function BillsVendorsList() {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export default function InvoicesVendorsList() {
|
|||||||
|
|
||||||
const handleOnRowClick = (record) => {
|
const handleOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
delete search.invoiceid;
|
delete search.billid;
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
search.vendorid = record.id;
|
search.vendorid = record.id;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history.push({ search: queryString.stringify(search) });
|
||||||
@@ -116,9 +116,9 @@ export function ContractConvertToRo({ bodyshop, currentUser, contract }) {
|
|||||||
shopid: bodyshop.id,
|
shopid: bodyshop.id,
|
||||||
ownerid: contract.job.ownerid,
|
ownerid: contract.job.ownerid,
|
||||||
vehicleid: contract.job.vehicleid,
|
vehicleid: contract.job.vehicleid,
|
||||||
federal_tax_rate: bodyshop.invoice_tax_rates.federal_tax_rate / 100,
|
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
|
||||||
state_tax_rate: bodyshop.invoice_tax_rates.state_tax_rate / 100,
|
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||||
local_tax_rate: bodyshop.invoice_tax_rates.local_tax_rate / 100,
|
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
|
||||||
clm_no: `${contract.job.clm_no}-CC`,
|
clm_no: `${contract.job.clm_no}-CC`,
|
||||||
clm_total: 1234, //TODO
|
clm_total: 1234, //TODO
|
||||||
ownr_fn: contract.job.owner.ownr_fn,
|
ownr_fn: contract.job.owner.ownr_fn,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
toggleModalVisible: () => dispatch(toggleModalVisible("courtesyCarReturn")),
|
toggleModalVisible: () => dispatch(toggleModalVisible("courtesyCarReturn")),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoiceEnterModalContainer({
|
export function BillEnterModalContainer({
|
||||||
courtesyCarReturnModal,
|
courtesyCarReturnModal,
|
||||||
toggleModalVisible,
|
toggleModalVisible,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
@@ -84,4 +84,4 @@ export function InvoiceEnterModalContainer({
|
|||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(InvoiceEnterModalContainer);
|
)(BillEnterModalContainer);
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import {
|
||||||
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
import DocumentsUploadComponent from "./documents-upload.component";
|
import DocumentsUploadComponent from "./documents-upload.component";
|
||||||
import { handleUpload } from "./documents-upload.utility";
|
import { handleUpload } from "./documents-upload.utility";
|
||||||
|
|
||||||
@@ -13,7 +16,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
export function DocumentsUploadContainer({
|
export function DocumentsUploadContainer({
|
||||||
jobId,
|
jobId,
|
||||||
tagsArray,
|
tagsArray,
|
||||||
invoiceId,
|
billId,
|
||||||
currentUser,
|
currentUser,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
callbackAfterUpload,
|
callbackAfterUpload,
|
||||||
@@ -26,7 +29,7 @@ export function DocumentsUploadContainer({
|
|||||||
bodyshop: bodyshop,
|
bodyshop: bodyshop,
|
||||||
uploaded_by: currentUser.email,
|
uploaded_by: currentUser.email,
|
||||||
jobId: jobId,
|
jobId: jobId,
|
||||||
invoiceId: invoiceId,
|
billId: billId,
|
||||||
tagsArray: tagsArray,
|
tagsArray: tagsArray,
|
||||||
callback: callbackAfterUpload,
|
callback: callbackAfterUpload,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -67,14 +67,7 @@ export const uploadToS3 = (
|
|||||||
onProgress,
|
onProgress,
|
||||||
context
|
context
|
||||||
) => {
|
) => {
|
||||||
const {
|
const { bodyshop, jobId, billId, uploaded_by, callback, tagsArray } = context;
|
||||||
bodyshop,
|
|
||||||
jobId,
|
|
||||||
invoiceId,
|
|
||||||
uploaded_by,
|
|
||||||
callback,
|
|
||||||
tagsArray,
|
|
||||||
} = context;
|
|
||||||
|
|
||||||
let timestamp = Math.floor(Date.now() / 1000);
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
let public_id = fileName;
|
let public_id = fileName;
|
||||||
@@ -121,7 +114,7 @@ export const uploadToS3 = (
|
|||||||
jobid: jobId,
|
jobid: jobId,
|
||||||
uploaded_by: uploaded_by,
|
uploaded_by: uploaded_by,
|
||||||
key: fileName,
|
key: fileName,
|
||||||
invoiceid: invoiceId,
|
billid: billId,
|
||||||
type: fileType,
|
type: fileType,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -132,16 +132,16 @@ export default function GlobalSearch() {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: renderTitle(t("menus.header.search.invoices")),
|
label: renderTitle(t("menus.header.search.bills")),
|
||||||
options: data.search_invoices.map((invoice) => {
|
options: data.search_bills.map((bill) => {
|
||||||
return {
|
return {
|
||||||
value: `${invoice.invoice_number}`,
|
value: `${bill.invoice_number}`,
|
||||||
label: (
|
label: (
|
||||||
<Link to={`/manage/invoices?invoiceid=${invoice.id}`}>
|
<Link to={`/manage/bills?billid=${bill.id}`}>
|
||||||
<div className="imex-flex-row">
|
<div className="imex-flex-row">
|
||||||
<span className="imex-flex-row__margin-large">{`${invoice.invoice_number}`}</span>
|
<span className="imex-flex-row__margin-large">{`${bill.invoice_number}`}</span>
|
||||||
<span className="imex-flex-row__margin-large">{`${invoice.vendor.name}`}</span>
|
<span className="imex-flex-row__margin-large">{`${bill.vendor.name}`}</span>
|
||||||
<span className="imex-flex-row__margin-large">{`${invoice.date}`}</span>
|
<span className="imex-flex-row__margin-large">{`${bill.date}`}</span>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setInvoiceEnterContext: (context) =>
|
setBillEnterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
setTimeTicketContext: (context) =>
|
setTimeTicketContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
||||||
setPaymentContext: (context) =>
|
setPaymentContext: (context) =>
|
||||||
@@ -57,7 +57,7 @@ function Header({
|
|||||||
currentUser,
|
currentUser,
|
||||||
selectedHeader,
|
selectedHeader,
|
||||||
signOutStart,
|
signOutStart,
|
||||||
setInvoiceEnterContext,
|
setBillEnterContext,
|
||||||
setTimeTicketContext,
|
setTimeTicketContext,
|
||||||
setPaymentContext,
|
setPaymentContext,
|
||||||
recentItems,
|
recentItems,
|
||||||
@@ -183,20 +183,20 @@ function Header({
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Menu.Item key="invoices">
|
<Menu.Item key="bills">
|
||||||
<Link to="/manage/invoices">{t("menus.header.invoices")}</Link>
|
<Link to="/manage/bills">{t("menus.header.bills")}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="enterinvoices"
|
key="enterbills"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInvoiceEnterContext({
|
setBillEnterContext({
|
||||||
actions: {},
|
actions: {},
|
||||||
context: {},
|
context: {},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon component={FaFileInvoiceDollar} />
|
<Icon component={FaFileInvoiceDollar} />
|
||||||
{t("menus.header.enterinvoices")}
|
{t("menus.header.enterbills")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item key="allpayments">
|
<Menu.Item key="allpayments">
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
// .invoice-form-wrapper {
|
|
||||||
// display: flex;
|
|
||||||
// flex-direction: column;
|
|
||||||
// justify-content: left;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .invoice-form-totals {
|
|
||||||
// display: flex;
|
|
||||||
// justify-content: space-around;
|
|
||||||
// align-items: flex-start;
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
// & > * {
|
|
||||||
// padding: 5px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .invoice-form-invoice-details {
|
|
||||||
// display: flex;
|
|
||||||
// align-items: flex-start;
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
// & > * {
|
|
||||||
// padding: 5px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .invoice-form-lines-wrapper {
|
|
||||||
// border: 3px ridge rgba(28, 110, 164, 0.24);
|
|
||||||
// border-radius: 4px;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .invoice-form-line {
|
|
||||||
// display: flex;
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
// align-items: flex-start;
|
|
||||||
// justify-content: space-around;
|
|
||||||
// border-bottom: 2px dashed rgba(7, 7, 7, 0.4);
|
|
||||||
// F & > * {
|
|
||||||
// margin: 5px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
//DEPRECATED.
|
|
||||||
|
|
||||||
// import React, { useState } from "react";
|
|
||||||
// import { QUERY_INVOICES_BY_VENDOR_PAGINATED } from "../../graphql/invoices.queries";
|
|
||||||
// import { useQuery } from "@apollo/react-hooks";
|
|
||||||
// import queryString from "query-string";
|
|
||||||
// import { useHistory, useLocation } from "react-router-dom";
|
|
||||||
// import { Table, Input } from "antd";
|
|
||||||
// import { useTranslation } from "react-i18next";
|
|
||||||
// import { alphaSort } from "../../utils/sorters";
|
|
||||||
// import AlertComponent from "../alert/alert.component";
|
|
||||||
// import { DateFormatter } from "../../utils/DateFormatter";
|
|
||||||
// import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|
||||||
|
|
||||||
// export default function InvoicesByVendorList() {
|
|
||||||
// const search = queryString.parse(useLocation().search);
|
|
||||||
// const history = useHistory();
|
|
||||||
// const { page, sortcolumn, sortorder } = search;
|
|
||||||
|
|
||||||
// const { loading, error, data } = useQuery(
|
|
||||||
// QUERY_INVOICES_BY_VENDOR_PAGINATED,
|
|
||||||
// {
|
|
||||||
// variables: {
|
|
||||||
// vendorId: search.vendorid,
|
|
||||||
// offset: page ? (page - 1) * 25 : 0,
|
|
||||||
// limit: 25,
|
|
||||||
// order: [
|
|
||||||
// {
|
|
||||||
// [sortcolumn || "date"]: sortorder
|
|
||||||
// ? sortorder === "descend"
|
|
||||||
// ? "desc"
|
|
||||||
// : "asc"
|
|
||||||
// : "desc",
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// skip: !!!search.vendorid,
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const { t } = useTranslation();
|
|
||||||
|
|
||||||
// const [state, setState] = useState({
|
|
||||||
// sortedInfo: {},
|
|
||||||
// search: "",
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const handleTableChange = (pagination, filters, sorter) => {
|
|
||||||
// setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
|
||||||
// search.page = pagination.current;
|
|
||||||
// search.sortcolumn = sorter.columnKey;
|
|
||||||
// search.sortorder = sorter.order;
|
|
||||||
// history.push({ search: queryString.stringify(search) });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// 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 columns = [
|
|
||||||
// {
|
|
||||||
// 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>
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// const handleSearch = (e) => {
|
|
||||||
// setState({ ...state, search: e.target.value });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const dataSource = state.search
|
|
||||||
// ? data.invoices.filter(
|
|
||||||
// (i) =>
|
|
||||||
// (i.invoice_number || "")
|
|
||||||
// .toLowerCase()
|
|
||||||
// .includes(state.search.toLowerCase()) ||
|
|
||||||
// (i.amount || "").toString().includes(state.search)
|
|
||||||
// )
|
|
||||||
// : (data && data.invoices) || [];
|
|
||||||
|
|
||||||
// if (error) return <AlertComponent message={error.message} type='error' />;
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Table
|
|
||||||
// loading={loading}
|
|
||||||
// title={() => {
|
|
||||||
// return (
|
|
||||||
// <div>
|
|
||||||
// <Input
|
|
||||||
// value={state.search}
|
|
||||||
// onChange={handleSearch}
|
|
||||||
// placeholder={t("general.labels.search")}
|
|
||||||
// allowClear
|
|
||||||
// />
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
// }}
|
|
||||||
// dataSource={dataSource}
|
|
||||||
// size='small'
|
|
||||||
// scroll={{ x: true }}
|
|
||||||
// pagination={{
|
|
||||||
// position: "top",
|
|
||||||
// pageSize: 25,
|
|
||||||
// current: parseInt(page || 1),
|
|
||||||
// total: data ? data.invoices_aggregate.aggregate.count : 0,
|
|
||||||
// }}
|
|
||||||
// columns={columns}
|
|
||||||
// rowKey='id'
|
|
||||||
// onChange={handleTableChange}
|
|
||||||
// rowSelection={{
|
|
||||||
// onSelect: (record) => {
|
|
||||||
// handleOnRowClick(record);
|
|
||||||
// },
|
|
||||||
// selectedRowKeys: [search.invoiceid],
|
|
||||||
// type: "radio",
|
|
||||||
// }}
|
|
||||||
// onRow={(record, rowIndex) => {
|
|
||||||
// return {
|
|
||||||
// onClick: (event) => {
|
|
||||||
// handleOnRowClick(record);
|
|
||||||
// }, // click row
|
|
||||||
// };
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
@@ -4,9 +4,9 @@ import React from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import "./job-invoices-total.styles.scss";
|
import "./job-bills-total.styles.scss";
|
||||||
|
|
||||||
export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
|
export default function JobBillsTotalComponent({ loading, bills, jobTotals }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (loading) return <LoadingSkeleton />;
|
if (loading) return <LoadingSkeleton />;
|
||||||
@@ -17,10 +17,10 @@ export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
|
|||||||
|
|
||||||
const totals = jobTotals;
|
const totals = jobTotals;
|
||||||
|
|
||||||
let invoiceTotals = Dinero({ amount: 0 });
|
let billTotals = Dinero({ amount: 0 });
|
||||||
invoices.forEach((i) =>
|
bills.forEach((i) =>
|
||||||
i.invoicelines.forEach((il) => {
|
i.billlines.forEach((il) => {
|
||||||
invoiceTotals = invoiceTotals.add(
|
billTotals = billTotals.add(
|
||||||
Dinero({
|
Dinero({
|
||||||
amount: Math.round(
|
amount: Math.round(
|
||||||
(il.actual_cost || 0) * (i.is_credit_memo ? -1 : 1) * 100
|
(il.actual_cost || 0) * (i.is_credit_memo ? -1 : 1) * 100
|
||||||
@@ -30,10 +30,10 @@ export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const discrepancy = Dinero(totals.parts.parts.total).subtract(invoiceTotals);
|
const discrepancy = Dinero(totals.parts.parts.total).subtract(billTotals);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="job-invoices-totals-container">
|
<div className="job-bills-totals-container">
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("jobs.labels.partstotal")}
|
title={t("jobs.labels.partstotal")}
|
||||||
value={Dinero(totals.parts.parts.total).toFormat()}
|
value={Dinero(totals.parts.parts.total).toFormat()}
|
||||||
@@ -43,11 +43,11 @@ export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
|
|||||||
value={Dinero(totals.parts.sublets.total).toFormat()}
|
value={Dinero(totals.parts.sublets.total).toFormat()}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.retailtotal")}
|
title={t("bills.labels.retailtotal")}
|
||||||
value={invoiceTotals.toFormat()}
|
value={billTotals.toFormat()}
|
||||||
/>
|
/>
|
||||||
<Statistic
|
<Statistic
|
||||||
title={t("invoices.labels.discrepancy")}
|
title={t("bills.labels.discrepancy")}
|
||||||
valueStyle={{
|
valueStyle={{
|
||||||
color: discrepancy.getAmount === 0 ? "green" : "red",
|
color: discrepancy.getAmount === 0 ? "green" : "red",
|
||||||
}}
|
}}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.job-invoices-totals-container {
|
.job-bills-totals-container {
|
||||||
margin: 0rem 2rem;
|
margin: 0rem 2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -51,28 +51,25 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
|||||||
{ parts: {}, labor: {} }
|
{ parts: {}, labor: {} }
|
||||||
);
|
);
|
||||||
|
|
||||||
const invoiceTotalsByProfitCenter = job.invoices.reduce(
|
const billTotalsByProfitCenter = job.bills.reduce((bill_acc, bill_val) => {
|
||||||
(inv_acc, inv_val) => {
|
//At the invoice level.
|
||||||
//At the invoice level.
|
bill_val.billlines.map((line_val) => {
|
||||||
inv_val.invoicelines.map((line_val) => {
|
//At the invoice line level.
|
||||||
//At the invoice line level.
|
//console.log("JobCostingPartsTable -> line_val", line_val);
|
||||||
//console.log("JobCostingPartsTable -> line_val", line_val);
|
if (!!!bill_acc[line_val.cost_center])
|
||||||
if (!!!inv_acc[line_val.cost_center])
|
bill_acc[line_val.cost_center] = Dinero();
|
||||||
inv_acc[line_val.cost_center] = Dinero();
|
|
||||||
|
|
||||||
inv_acc[line_val.cost_center] = inv_acc[line_val.cost_center].add(
|
bill_acc[line_val.cost_center] = bill_acc[line_val.cost_center].add(
|
||||||
Dinero({
|
Dinero({
|
||||||
amount: Math.round((line_val.actual_cost || 0) * 100),
|
amount: Math.round((line_val.actual_cost || 0) * 100),
|
||||||
})
|
})
|
||||||
.multiply(line_val.quantity)
|
.multiply(line_val.quantity)
|
||||||
.multiply(inv_val.is_credit_memo ? -1 : 1)
|
.multiply(bill_val.is_credit_memo ? -1 : 1)
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
return inv_acc;
|
return bill_acc;
|
||||||
},
|
}, {});
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ticketTotalsByProfitCenter = job.timetickets.reduce(
|
const ticketTotalsByProfitCenter = job.timetickets.reduce(
|
||||||
(ticket_acc, ticket_val) => {
|
(ticket_acc, ticket_val) => {
|
||||||
@@ -114,12 +111,11 @@ export function JobCostingModalComponent({ bodyshop, job }) {
|
|||||||
|
|
||||||
const cost_labor =
|
const cost_labor =
|
||||||
ticketTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 });
|
ticketTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 });
|
||||||
const cost_parts =
|
const cost_parts = billTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 });
|
||||||
invoiceTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 });
|
|
||||||
|
|
||||||
const cost = (
|
const cost = (billTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 })).add(
|
||||||
invoiceTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 })
|
ticketTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 })
|
||||||
).add(ticketTotalsByProfitCenter[ccVal] || Dinero({ amount: 0 }));
|
);
|
||||||
const totalSales = sale_labor.add(sale_parts);
|
const totalSales = sale_labor.add(sale_parts);
|
||||||
const gpdollars = totalSales.subtract(cost);
|
const gpdollars = totalSales.subtract(cost);
|
||||||
const gppercent = (
|
const gppercent = (
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
|
||||||
export default function JobReconciliationInvoiceTable({
|
export default function JobReconciliationBillsTable({
|
||||||
invoiceLineState,
|
billLineState,
|
||||||
invoiceLineData,
|
invoiceLineData,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -15,12 +15,12 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [selectedLines, setSelectedLines] = invoiceLineState;
|
const [selectedLines, setSelectedLines] = billLineState;
|
||||||
const [total, setTotal] = useState(Dinero({ amount: 0 }).toFormat());
|
const [total, setTotal] = useState(Dinero({ amount: 0 }).toFormat());
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.line_desc"),
|
title: t("billlines.fields.line_desc"),
|
||||||
dataIndex: "line_desc",
|
dataIndex: "line_desc",
|
||||||
key: "line_desc",
|
key: "line_desc",
|
||||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||||
@@ -28,7 +28,7 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.retail"),
|
title: t("billlines.fields.retail"),
|
||||||
dataIndex: "actual_price",
|
dataIndex: "actual_price",
|
||||||
key: "actual_price",
|
key: "actual_price",
|
||||||
sorter: (a, b) => a.actual_price - b.actual_price,
|
sorter: (a, b) => a.actual_price - b.actual_price,
|
||||||
@@ -39,7 +39,7 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.actual_cost"),
|
title: t("billlines.fields.actual_cost"),
|
||||||
dataIndex: "actual_cost",
|
dataIndex: "actual_cost",
|
||||||
key: "actual_cost",
|
key: "actual_cost",
|
||||||
sorter: (a, b) => a.actual_cost - b.actual_cost,
|
sorter: (a, b) => a.actual_cost - b.actual_cost,
|
||||||
@@ -50,7 +50,7 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoicelines.fields.quantity"),
|
title: t("billlines.fields.quantity"),
|
||||||
dataIndex: "quantity",
|
dataIndex: "quantity",
|
||||||
key: "quantity",
|
key: "quantity",
|
||||||
sorter: (a, b) => a.quantity - b.quantity,
|
sorter: (a, b) => a.quantity - b.quantity,
|
||||||
@@ -58,7 +58,7 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.is_credit_memo"),
|
title: t("bills.fields.is_credit_memo"),
|
||||||
dataIndex: "is_credit_memo",
|
dataIndex: "is_credit_memo",
|
||||||
key: "is_credit_memo",
|
key: "is_credit_memo",
|
||||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||||
@@ -95,11 +95,11 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table
|
<Table
|
||||||
size='small'
|
size="small"
|
||||||
title={() => <div></div>}
|
title={() => <div></div>}
|
||||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey='id'
|
rowKey="id"
|
||||||
dataSource={invoiceLineData}
|
dataSource={invoiceLineData}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
@@ -107,7 +107,7 @@ export default function JobReconciliationInvoiceTable({
|
|||||||
selectedRowKeys: selectedLines,
|
selectedRowKeys: selectedLines,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Statistic value={total} title='total' />
|
<Statistic value={total} title="total" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import { Col, Row } from "antd";
|
import { Col, Row } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import JobReconciliationInvoicesTable from "../job-reconciliation-invoices-table/job-reconciliation-invoices-table.component";
|
import JobReconciliationBillsTable from "../job-reconciliation-bills-table/job-reconciliation-bills-table.component";
|
||||||
import JobReconciliationPartsTable from "../job-reconciliation-parts-table/job-reconciliation-parts-table.component";
|
import JobReconciliationPartsTable from "../job-reconciliation-parts-table/job-reconciliation-parts-table.component";
|
||||||
|
|
||||||
export default function JobReconciliationModalComponent({ job, invoices }) {
|
export default function JobReconciliationModalComponent({ job, bills }) {
|
||||||
const jobLineState = useState([]);
|
const jobLineState = useState([]);
|
||||||
const invoiceLineState = useState([]);
|
const billLineState = useState([]);
|
||||||
|
|
||||||
const invoiceLineData =
|
const invoiceLineData =
|
||||||
invoices
|
bills
|
||||||
.map((i) =>
|
.map((i) =>
|
||||||
i.invoicelines.map((il) => {
|
i.billlines.map((il) => {
|
||||||
return { ...il, is_credit_memo: i.is_credit_memo };
|
return { ...il, is_credit_memo: i.is_credit_memo };
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -28,9 +28,9 @@ export default function JobReconciliationModalComponent({ job, invoices }) {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<JobReconciliationInvoicesTable
|
<JobReconciliationBillsTable
|
||||||
invoiceLineData={invoiceLineData}
|
invoiceLineData={invoiceLineData}
|
||||||
invoiceLineState={invoiceLineState}
|
billLineState={billLineState}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -5,27 +5,22 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectReconciliation } from "../../redux/modals/modals.selectors";
|
import { selectReconciliation } from "../../redux/modals/modals.selectors";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
|
||||||
import JobReconciliationModalComponent from "./job-reconciliation-modal.component";
|
import JobReconciliationModalComponent from "./job-reconciliation-modal.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
reconciliationModal: selectReconciliation,
|
reconciliationModal: selectReconciliation,
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
currentUser: selectCurrentUser,
|
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
toggleModalVisible: () => dispatch(toggleModalVisible("reconciliation")),
|
toggleModalVisible: () => dispatch(toggleModalVisible("reconciliation")),
|
||||||
});
|
});
|
||||||
|
|
||||||
function InvoiceEnterModalContainer({
|
function JobReconciliationModalContainer({
|
||||||
reconciliationModal,
|
reconciliationModal,
|
||||||
toggleModalVisible,
|
toggleModalVisible,
|
||||||
bodyshop,
|
|
||||||
currentUser,
|
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { context, visible } = reconciliationModal;
|
const { context, visible } = reconciliationModal;
|
||||||
const { job, invoices } = context;
|
const { job, bills } = context;
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
@@ -39,8 +34,9 @@ function InvoiceEnterModalContainer({
|
|||||||
okText={t("general.actions.save")}
|
okText={t("general.actions.save")}
|
||||||
onOk={handleCancel}
|
onOk={handleCancel}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
destroyOnClose>
|
destroyOnClose
|
||||||
<JobReconciliationModalComponent job={job} invoices={invoices} />
|
>
|
||||||
|
<JobReconciliationModalComponent job={job} bills={bills} />
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -48,4 +44,4 @@ function InvoiceEnterModalContainer({
|
|||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(InvoiceEnterModalContainer);
|
)(JobReconciliationModalContainer);
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setScheduleContext: (context) =>
|
setScheduleContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "schedule" })),
|
dispatch(setModalContext({ context: context, modal: "schedule" })),
|
||||||
setInvoiceEnterContext: (context) =>
|
setBillEnterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
setPaymentContext: (context) =>
|
setPaymentContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||||
setJobCostingContext: (context) =>
|
setJobCostingContext: (context) =>
|
||||||
@@ -33,7 +33,7 @@ export function JobsDetailHeaderActions({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
refetch,
|
refetch,
|
||||||
setScheduleContext,
|
setScheduleContext,
|
||||||
setInvoiceEnterContext,
|
setBillEnterContext,
|
||||||
setPaymentContext,
|
setPaymentContext,
|
||||||
setJobCostingContext,
|
setJobCostingContext,
|
||||||
}) {
|
}) {
|
||||||
@@ -147,11 +147,11 @@ export function JobsDetailHeaderActions({
|
|||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
key="postinvoices"
|
key="postbills"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
logImEXEvent("job_header_enter_invoice");
|
logImEXEvent("job_header_enter_bills");
|
||||||
|
|
||||||
setInvoiceEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
job: job,
|
job: job,
|
||||||
@@ -159,7 +159,7 @@ export function JobsDetailHeaderActions({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("jobs.actions.postInvoices")}
|
{t("jobs.actions.postbills")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
disabled={!!job.date_invoiced || !jobInPostProduction}
|
disabled={!!job.date_invoiced || !jobInPostProduction}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Col, Row } from "antd";
|
import { Col, Row } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import InvoicesListTableComponent from "../invoices-list-table/invoices-list-table.component";
|
import BillsListTable from "../bills-list-table/bills-list-table.component";
|
||||||
import JobInvoicesTotalsComponent from "../job-invoices-total/job-invoices-total.component";
|
import JobBillsTotal from "../job-bills-total/job-bills-total.component";
|
||||||
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
||||||
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
|
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
|
||||||
const tableCol = {
|
const tableCol = {
|
||||||
@@ -25,37 +25,33 @@ const totalsCol = {
|
|||||||
|
|
||||||
export default function JobsDetailPliComponent({
|
export default function JobsDetailPliComponent({
|
||||||
job,
|
job,
|
||||||
invoicesQuery,
|
billsQuery,
|
||||||
handleInvoiceOnRowClick,
|
handleBillOnRowClick,
|
||||||
handlePartsOrderOnRowClick,
|
handlePartsOrderOnRowClick,
|
||||||
selectedInvoice,
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PartsOrderModal />
|
<PartsOrderModal />
|
||||||
{invoicesQuery.error ? (
|
{billsQuery.error ? (
|
||||||
<AlertComponent message={invoicesQuery.error.message} type="error" />
|
<AlertComponent message={billsQuery.error.message} type="error" />
|
||||||
) : null}
|
) : null}
|
||||||
<Row>
|
<Row>
|
||||||
<Col {...tableCol}>
|
<Col {...tableCol}>
|
||||||
<PartsOrderListTableComponent
|
<PartsOrderListTableComponent
|
||||||
job={job}
|
job={job}
|
||||||
loading={invoicesQuery.loading}
|
|
||||||
handleOnRowClick={handlePartsOrderOnRowClick}
|
handleOnRowClick={handlePartsOrderOnRowClick}
|
||||||
selectedInvoice={selectedInvoice}
|
billsQuery={billsQuery}
|
||||||
invoicesQuery={invoicesQuery}
|
|
||||||
/>
|
/>
|
||||||
<InvoicesListTableComponent
|
<BillsListTable
|
||||||
job={job}
|
job={job}
|
||||||
loading={invoicesQuery.loading}
|
handleOnRowClick={handleBillOnRowClick}
|
||||||
handleOnRowClick={handleInvoiceOnRowClick}
|
billsQuery={billsQuery}
|
||||||
invoicesQuery={invoicesQuery}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col {...totalsCol}>
|
<Col {...totalsCol}>
|
||||||
<JobInvoicesTotalsComponent
|
<JobBillsTotal
|
||||||
invoices={invoicesQuery.data ? invoicesQuery.data.invoices : []}
|
bills={billsQuery.data ? billsQuery.data.bills : []}
|
||||||
loading={invoicesQuery.loading}
|
loading={billsQuery.loading}
|
||||||
jobTotals={job.job_totals}
|
jobTotals={job.job_totals}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -2,25 +2,25 @@ import { useQuery } from "@apollo/react-hooks";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import { QUERY_INVOICES_BY_JOBID } from "../../graphql/invoices.queries";
|
import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
|
||||||
import JobsDetailPliComponent from "./jobs-detail-pli.component";
|
import JobsDetailPliComponent from "./jobs-detail-pli.component";
|
||||||
|
|
||||||
export default function JobsDetailPliContainer({ job }) {
|
export default function JobsDetailPliContainer({ job }) {
|
||||||
const invoicesQuery = useQuery(QUERY_INVOICES_BY_JOBID, {
|
const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, {
|
||||||
variables: { jobid: job.id },
|
variables: { jobid: job.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const handleInvoiceOnRowClick = (record) => {
|
const handleBillOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
search.invoiceid = record.id;
|
search.billid = record.id;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history.push({ search: queryString.stringify(search) });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delete search.invoiceid;
|
delete search.billid;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history.push({ search: queryString.stringify(search) });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -40,8 +40,8 @@ export default function JobsDetailPliContainer({ job }) {
|
|||||||
return (
|
return (
|
||||||
<JobsDetailPliComponent
|
<JobsDetailPliComponent
|
||||||
job={job}
|
job={job}
|
||||||
invoicesQuery={invoicesQuery}
|
billsQuery={billsQuery}
|
||||||
handleInvoiceOnRowClick={handleInvoiceOnRowClick}
|
handleBillOnRowClick={handleBillOnRowClick}
|
||||||
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ function JobsDocumentsComponent({
|
|||||||
data,
|
data,
|
||||||
jobId,
|
jobId,
|
||||||
refetch,
|
refetch,
|
||||||
invoiceId,
|
billId,
|
||||||
invoicesCallback,
|
billsCallback,
|
||||||
}) {
|
}) {
|
||||||
const [galleryImages, setgalleryImages] = useState([]);
|
const [galleryImages, setgalleryImages] = useState([]);
|
||||||
|
|
||||||
@@ -34,18 +34,18 @@ function JobsDocumentsComponent({
|
|||||||
}, [data, setgalleryImages]);
|
}, [data, setgalleryImages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='clearfix'>
|
<div className="clearfix">
|
||||||
<DocumentsUploadContainer
|
<DocumentsUploadContainer
|
||||||
jobId={jobId}
|
jobId={jobId}
|
||||||
invoiceId={invoiceId}
|
billId={billId}
|
||||||
callbackAfterUpload={invoicesCallback || refetch}
|
callbackAfterUpload={billsCallback || refetch}
|
||||||
tagsArray={["test"]}
|
tagsArray={["test"]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<JobsDocumentsDownloadButton galleryImages={galleryImages} />
|
<JobsDocumentsDownloadButton galleryImages={galleryImages} />
|
||||||
<JobsDocumentsDeleteButton
|
<JobsDocumentsDeleteButton
|
||||||
galleryImages={galleryImages}
|
galleryImages={galleryImages}
|
||||||
deletionCallback={invoicesCallback || refetch}
|
deletionCallback={billsCallback || refetch}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Gallery
|
<Gallery
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import JobDocuments from "./jobs-documents-gallery.component";
|
|||||||
|
|
||||||
export default function JobsDocumentsContainer({
|
export default function JobsDocumentsContainer({
|
||||||
jobId,
|
jobId,
|
||||||
invoiceId,
|
billId,
|
||||||
documentsList,
|
documentsList,
|
||||||
invoicesCallback,
|
billsCallback,
|
||||||
}) {
|
}) {
|
||||||
const { loading, error, data, refetch } = useQuery(GET_DOCUMENTS_BY_JOB, {
|
const { loading, error, data, refetch } = useQuery(GET_DOCUMENTS_BY_JOB, {
|
||||||
variables: { jobId: jobId },
|
variables: { jobId: jobId },
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
skip: !!invoiceId,
|
skip: !!billId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loading) return <LoadingSpinner />;
|
if (loading) return <LoadingSpinner />;
|
||||||
@@ -23,10 +23,10 @@ export default function JobsDocumentsContainer({
|
|||||||
return (
|
return (
|
||||||
<JobDocuments
|
<JobDocuments
|
||||||
data={(data && data.documents) || documentsList || []}
|
data={(data && data.documents) || documentsList || []}
|
||||||
invoiceId={invoiceId}
|
billId={billId}
|
||||||
jobId={jobId}
|
jobId={jobId}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
invoicesCallback={invoicesCallback}
|
billsCallback={billsCallback}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ export function JobsExportAllButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Set the list of selected invoices to be nothing.
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -20,16 +20,16 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setInvoiceEnterContext: (context) =>
|
setBillEnterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function PartsOrderListTableComponent({
|
export function PartsOrderListTableComponent({
|
||||||
setInvoiceEnterContext,
|
setBillEnterContext,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
job,
|
job,
|
||||||
loading,
|
|
||||||
invoicesQuery,
|
billsQuery,
|
||||||
handleOnRowClick,
|
handleOnRowClick,
|
||||||
}) {
|
}) {
|
||||||
const responsibilityCenters = bodyshop.md_responsibility_centers;
|
const responsibilityCenters = bodyshop.md_responsibility_centers;
|
||||||
@@ -41,10 +41,8 @@ export function PartsOrderListTableComponent({
|
|||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const selectedpartsorder = search.partsorderid;
|
const selectedpartsorder = search.partsorderid;
|
||||||
|
|
||||||
const parts_orders = invoicesQuery.data
|
const parts_orders = billsQuery.data ? billsQuery.data.parts_orders : [];
|
||||||
? invoicesQuery.data.parts_orders
|
const { refetch } = billsQuery;
|
||||||
: [];
|
|
||||||
const { refetch } = invoicesQuery;
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("vendors.fields.name"),
|
title: t("vendors.fields.name"),
|
||||||
@@ -93,15 +91,15 @@ export function PartsOrderListTableComponent({
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
logImEXEvent("parts_order_receive_invoice");
|
logImEXEvent("parts_order_receive_bill");
|
||||||
|
|
||||||
setInvoiceEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {
|
context: {
|
||||||
job: job,
|
job: job,
|
||||||
invoice: {
|
bill: {
|
||||||
vendorid: record.vendor.id,
|
vendorid: record.vendor.id,
|
||||||
invoicelines: record.parts_order_lines.map((pol) => {
|
billlines: record.parts_order_lines.map((pol) => {
|
||||||
return {
|
return {
|
||||||
joblineid: pol.job_line_id,
|
joblineid: pol.job_line_id,
|
||||||
line_desc: pol.line_desc,
|
line_desc: pol.line_desc,
|
||||||
@@ -119,7 +117,7 @@ export function PartsOrderListTableComponent({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("parts_orders.actions.receiveinvoice")}
|
{t("parts_orders.actions.receivebill")}
|
||||||
</Button>
|
</Button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -227,7 +225,7 @@ export function PartsOrderListTableComponent({
|
|||||||
{t("parts_orders.labels.parts_orders")}
|
{t("parts_orders.labels.parts_orders")}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={billsQuery.loading}
|
||||||
size="small"
|
size="small"
|
||||||
title={() => (
|
title={() => (
|
||||||
<div className="imex-table-header">
|
<div className="imex-table-header">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { INSERT_NEW_INVOICE } from "../../graphql/invoices.queries";
|
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
||||||
import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries";
|
||||||
import { INSERT_NEW_PARTS_ORDERS } from "../../graphql/parts-orders.queries";
|
import { INSERT_NEW_PARTS_ORDERS } from "../../graphql/parts-orders.queries";
|
||||||
import { QUERY_ALL_VENDORS_FOR_ORDER } from "../../graphql/vendors.queries";
|
import { QUERY_ALL_VENDORS_FOR_ORDER } from "../../graphql/vendors.queries";
|
||||||
@@ -68,7 +68,7 @@ export function PartsOrderModalContainer({
|
|||||||
|
|
||||||
const [insertPartOrder] = useMutation(INSERT_NEW_PARTS_ORDERS);
|
const [insertPartOrder] = useMutation(INSERT_NEW_PARTS_ORDERS);
|
||||||
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS);
|
||||||
const [insertInvoice] = useMutation(INSERT_NEW_INVOICE);
|
const [insertBill] = useMutation(INSERT_NEW_BILL);
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
logImEXEvent("parts_order_insert");
|
logImEXEvent("parts_order_insert");
|
||||||
@@ -120,9 +120,9 @@ export function PartsOrderModalContainer({
|
|||||||
jobid: jobId,
|
jobid: jobId,
|
||||||
total: 0,
|
total: 0,
|
||||||
invoice_number: `${jobId}`,
|
invoice_number: `${jobId}`,
|
||||||
federal_tax_rate: bodyshop.invoice_tax_rates.federal_tax_rate || 0,
|
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate || 0,
|
||||||
state_tax_rate: bodyshop.invoice_tax_rates.state_tax_rate || 0,
|
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate || 0,
|
||||||
local_tax_rate: bodyshop.invoice_tax_rates.local_tax_rate || 0,
|
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate || 0,
|
||||||
invoicelines: {
|
invoicelines: {
|
||||||
data: values.parts_order_lines.data.map((p) => {
|
data: values.parts_order_lines.data.map((p) => {
|
||||||
return {
|
return {
|
||||||
@@ -138,8 +138,8 @@ export function PartsOrderModalContainer({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await insertInvoice({
|
await insertBill({
|
||||||
variables: { invoice: invoiceToPost },
|
variables: { bill: invoiceToPost },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth } from "../../firebase/firebase.utils";
|
||||||
import { UPDATE_INVOICES } from "../../graphql/invoices.queries";
|
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
@@ -14,15 +14,15 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoiceExportAllButton({
|
export function PayableExportAll({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
invoiceIds,
|
billids,
|
||||||
disabled,
|
disabled,
|
||||||
loadingCallback,
|
loadingCallback,
|
||||||
completedCallback,
|
completedCallback,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [updateInvoice] = useMutation(UPDATE_INVOICES);
|
const [updateBill] = useMutation(UPDATE_BILLS);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleQbxml = async () => {
|
const handleQbxml = async () => {
|
||||||
@@ -35,7 +35,7 @@ export function InvoiceExportAllButton({
|
|||||||
try {
|
try {
|
||||||
QbXmlResponse = await axios.post(
|
QbXmlResponse = await axios.post(
|
||||||
"/accounting/qbxml/payables",
|
"/accounting/qbxml/payables",
|
||||||
{ invoices: invoiceIds },
|
{ bills: billids },
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
||||||
@@ -45,7 +45,7 @@ export function InvoiceExportAllButton({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error getting QBXML from Server.", error);
|
console.log("Error getting QBXML from Server.", error);
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -64,7 +64,7 @@ export function InvoiceExportAllButton({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error connecting to quickbooks or partner.", error);
|
console.log("Error connecting to quickbooks or partner.", error);
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting-partner"),
|
message: t("bills.errors.exporting-partner"),
|
||||||
});
|
});
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -80,36 +80,35 @@ export function InvoiceExportAllButton({
|
|||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.map((ft) =>
|
failedTransactions.map((ft) =>
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
error: ft.errorMessage || "",
|
error: ft.errorMessage || "",
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (successfulTransactions.length > 0) {
|
if (successfulTransactions.length > 0) {
|
||||||
const invoiceUpdateResponse = await updateInvoice({
|
const billUpdateResponse = await updateBill({
|
||||||
variables: {
|
variables: {
|
||||||
invoiceIdList: successfulTransactions.map((st) => st.id),
|
billIdList: successfulTransactions.map((st) => st.id),
|
||||||
invoice: {
|
bill: {
|
||||||
exported: true,
|
exported: true,
|
||||||
exported_at: new Date(),
|
exported_at: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!!!invoiceUpdateResponse.errors) {
|
if (!!!billUpdateResponse.errors) {
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.exporting", {
|
message: t("jobs.errors.exporting", {
|
||||||
error: JSON.stringify(invoiceUpdateResponse.error),
|
error: JSON.stringify(billUpdateResponse.error),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the list of selected invoices to be nothing.
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -127,4 +126,4 @@ export function InvoiceExportAllButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(InvoiceExportAllButton);
|
export default connect(mapStateToProps, null)(PayableExportAll);
|
||||||
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth } from "../../firebase/firebase.utils";
|
||||||
import { UPDATE_INVOICES } from "../../graphql/invoices.queries";
|
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
@@ -14,14 +14,14 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoiceExportButton({
|
export function PayableExportButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
invoiceId,
|
billId,
|
||||||
disabled,
|
disabled,
|
||||||
loadingCallback,
|
loadingCallback,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [updateInvoice] = useMutation(UPDATE_INVOICES);
|
const [updateBill] = useMutation(UPDATE_BILLS);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleQbxml = async () => {
|
const handleQbxml = async () => {
|
||||||
@@ -34,7 +34,7 @@ export function InvoiceExportButton({
|
|||||||
try {
|
try {
|
||||||
QbXmlResponse = await axios.post(
|
QbXmlResponse = await axios.post(
|
||||||
"/accounting/qbxml/payables",
|
"/accounting/qbxml/payables",
|
||||||
{ invoices: [invoiceId] },
|
{ bills: [billId] },
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
||||||
@@ -44,7 +44,7 @@ export function InvoiceExportButton({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error getting QBXML from Server.", error);
|
console.log("Error getting QBXML from Server.", error);
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -63,7 +63,7 @@ export function InvoiceExportButton({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error connecting to quickbooks or partner.", error);
|
console.log("Error connecting to quickbooks or partner.", error);
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting-partner"),
|
message: t("bills.errors.exporting-partner"),
|
||||||
});
|
});
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -79,30 +79,30 @@ export function InvoiceExportButton({
|
|||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.map((ft) =>
|
failedTransactions.map((ft) =>
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("invoices.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
error: ft.errorMessage || "",
|
error: ft.errorMessage || "",
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (successfulTransactions.length > 0) {
|
if (successfulTransactions.length > 0) {
|
||||||
const invoiceUpdateResponse = await updateInvoice({
|
const billUpdateResponse = await updateBill({
|
||||||
variables: {
|
variables: {
|
||||||
invoiceIdList: successfulTransactions.map((st) => st.id),
|
billIdList: successfulTransactions.map((st) => st.id),
|
||||||
invoice: {
|
bill: {
|
||||||
exported: true,
|
exported: true,
|
||||||
exported_at: new Date(),
|
exported_at: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!!!invoiceUpdateResponse.errors) {
|
if (!!!billUpdateResponse.errors) {
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.exporting", {
|
message: t("jobs.errors.exporting", {
|
||||||
error: JSON.stringify(invoiceUpdateResponse.error),
|
error: JSON.stringify(billUpdateResponse.error),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -124,4 +124,4 @@ export function InvoiceExportButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(InvoiceExportButton);
|
export default connect(mapStateToProps, null)(PayableExportButton);
|
||||||
@@ -25,7 +25,7 @@ export function PaymentFormComponent({ form, stripeStateArr, bodyshop }) {
|
|||||||
<div>
|
<div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="jobid"
|
name="jobid"
|
||||||
label={t("invoices.fields.ro_number")}
|
label={t("bills.fields.ro_number")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
toggleModalVisible: () => dispatch(toggleModalVisible("payment")),
|
toggleModalVisible: () => dispatch(toggleModalVisible("payment")),
|
||||||
});
|
});
|
||||||
|
|
||||||
function InvoiceEnterModalContainer({
|
function BillEnterModalContainer({
|
||||||
paymentModal,
|
paymentModal,
|
||||||
toggleModalVisible,
|
toggleModalVisible,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
@@ -189,7 +189,7 @@ function InvoiceEnterModalContainer({
|
|||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(InvoiceEnterModalContainer);
|
)(BillEnterModalContainer);
|
||||||
|
|
||||||
// const pr = stripe.paymentRequest({
|
// const pr = stripe.paymentRequest({
|
||||||
// country: "CA",
|
// country: "CA",
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ export default {
|
|||||||
"jobs:close": 5,
|
"jobs:close": 5,
|
||||||
"jobs:detail": 1,
|
"jobs:detail": 1,
|
||||||
|
|
||||||
"invoices:enter": 2,
|
"bills:enter": 2,
|
||||||
"invoices:view": 2,
|
"bills:view": 2,
|
||||||
"invoices:list": 2,
|
"bills:list": 2,
|
||||||
|
|
||||||
"employees:page": 5,
|
"employees:page": 5,
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export default function ShopInfoComponent({ form, saveLoading }) {
|
|||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.invoice_federal_tax_rate")}
|
label={t("bodyshop.fields.invoice_federal_tax_rate")}
|
||||||
name={["invoice_tax_rates", "federal_tax_rate"]}
|
name={["bill_tax_rates", "federal_tax_rate"]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -149,7 +149,7 @@ export default function ShopInfoComponent({ form, saveLoading }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.invoice_state_tax_rate")}
|
label={t("bodyshop.fields.invoice_state_tax_rate")}
|
||||||
name={["invoice_tax_rates", "state_tax_rate"]}
|
name={["bill_tax_rates", "state_tax_rate"]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -161,7 +161,7 @@ export default function ShopInfoComponent({ form, saveLoading }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.invoice_local_tax_rate")}
|
label={t("bodyshop.fields.invoice_local_tax_rate")}
|
||||||
name={["invoice_tax_rates", "local_tax_rate"]}
|
name={["bill_tax_rates", "local_tax_rate"]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
|
|||||||
@@ -238,38 +238,38 @@ export default function ShopInfoRbacComponent({ form }) {
|
|||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.invoices.enter")}
|
label={t("bodyshop.fields.rbac.bills.enter")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: t("general.validation.required"),
|
message: t("general.validation.required"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
name={["md_rbac", "invoices:enter"]}
|
name={["md_rbac", "bills:enter"]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.invoices.view")}
|
label={t("bodyshop.fields.rbac.bills.view")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: t("general.validation.required"),
|
message: t("general.validation.required"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
name={["md_rbac", "invoices:view"]}
|
name={["md_rbac", "bills:view"]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.invoices.list")}
|
label={t("bodyshop.fields.rbac.bills.list")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: t("general.validation.required"),
|
message: t("general.validation.required"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
name={["md_rbac", "invoices:list"]}
|
name={["md_rbac", "bills:list"]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default function VendorsFormComponent({
|
|||||||
}}
|
}}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
{t("invoicelines.actions.newline")}
|
{t("billlines.actions.newline")}
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ export const QUERY_JOBS_FOR_EXPORT = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QUERY_INVOICES_FOR_EXPORT = gql`
|
export const QUERY_BILLS_FOR_EXPORT = gql`
|
||||||
query QUERY_INVOICES_FOR_EXPORT {
|
query QUERY_BILLS_FOR_EXPORT {
|
||||||
invoices(where: { exported: { _eq: false } }) {
|
bills(where: { exported: { _eq: false } }) {
|
||||||
id
|
id
|
||||||
exported
|
exported
|
||||||
date
|
date
|
||||||
|
|||||||
14
client/src/graphql/bill-lines.queries.js
Normal file
14
client/src/graphql/bill-lines.queries.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
|
export const UPDATE_BILL_LINE = gql`
|
||||||
|
mutation UPDATE_BILL_LINE(
|
||||||
|
$billLineId: uuid!
|
||||||
|
$billLine: billlines_set_input!
|
||||||
|
) {
|
||||||
|
update_billlines(where: { id: { _eq: $billLineId } }, _set: $billLine) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
export const INSERT_NEW_INVOICE = gql`
|
export const INSERT_NEW_BILL = gql`
|
||||||
mutation INSERT_NEW_INVOICE($invoice: [invoices_insert_input!]!) {
|
mutation INSERT_NEW_BILL($bill: [bills_insert_input!]!) {
|
||||||
insert_invoices(objects: $invoice) {
|
insert_bills(objects: $bill) {
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
@@ -10,14 +10,14 @@ export const INSERT_NEW_INVOICE = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
export const QUERY_ALL_BILLS_PAGINATED = gql`
|
||||||
query QUERY_ALL_INVOICES_PAGINATED(
|
query QUERY_ALL_BILLS_PAGINATED(
|
||||||
$search: String
|
$search: String
|
||||||
$offset: Int
|
$offset: Int
|
||||||
$limit: Int
|
$limit: Int
|
||||||
$order: [invoices_order_by!]!
|
$order: [bills_order_by!]!
|
||||||
) {
|
) {
|
||||||
search_invoices(
|
search_bills(
|
||||||
args: { search: $search }
|
args: { search: $search }
|
||||||
offset: $offset
|
offset: $offset
|
||||||
limit: $limit
|
limit: $limit
|
||||||
@@ -39,7 +39,7 @@ export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
|||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
}
|
}
|
||||||
invoicelines {
|
billlines {
|
||||||
actual_price
|
actual_price
|
||||||
quantity
|
quantity
|
||||||
actual_cost
|
actual_cost
|
||||||
@@ -48,7 +48,7 @@ export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
|||||||
line_desc
|
line_desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
search_invoices_aggregate(args: { search: $search }) {
|
search_bills_aggregate(args: { search: $search }) {
|
||||||
aggregate {
|
aggregate {
|
||||||
count(distinct: true)
|
count(distinct: true)
|
||||||
}
|
}
|
||||||
@@ -56,8 +56,8 @@ export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QUERY_INVOICES_BY_JOBID = gql`
|
export const QUERY_BILLS_BY_JOBID = gql`
|
||||||
query QUERY_PARTS_INVOICES_BY_JOBID($jobid: uuid!) {
|
query QUERY_PARTS_BILLS_BY_JOBID($jobid: uuid!) {
|
||||||
parts_orders(
|
parts_orders(
|
||||||
where: { jobid: { _eq: $jobid } }
|
where: { jobid: { _eq: $jobid } }
|
||||||
order_by: { order_date: desc }
|
order_by: { order_date: desc }
|
||||||
@@ -89,7 +89,7 @@ export const QUERY_INVOICES_BY_JOBID = gql`
|
|||||||
order_number
|
order_number
|
||||||
user_email
|
user_email
|
||||||
}
|
}
|
||||||
invoices(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
bills(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||||
id
|
id
|
||||||
vendorid
|
vendorid
|
||||||
vendor {
|
vendor {
|
||||||
@@ -103,7 +103,7 @@ export const QUERY_INVOICES_BY_JOBID = gql`
|
|||||||
state_tax_rate
|
state_tax_rate
|
||||||
local_tax_rate
|
local_tax_rate
|
||||||
is_credit_memo
|
is_credit_memo
|
||||||
invoicelines {
|
billlines {
|
||||||
actual_price
|
actual_price
|
||||||
quantity
|
quantity
|
||||||
actual_cost
|
actual_cost
|
||||||
@@ -117,57 +117,39 @@ export const QUERY_INVOICES_BY_JOBID = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const QUERY_INVOICES_BY_VENDOR = gql`
|
// export const QUERY_INVOICES_BY_VENDOR_PAGINATED = gql`
|
||||||
query QUERY_INVOICES_BY_VENDOR($vendorId: uuid!) {
|
// query QUERY_INVOICES_BY_VENDOR_PAGINATED(
|
||||||
invoices(
|
// $vendorId: uuid!
|
||||||
where: { vendorid: { _eq: $vendorId } }
|
// $offset: Int
|
||||||
order_by: { date: desc }
|
// $limit: Int
|
||||||
) {
|
// $order: [invoices_order_by!]!
|
||||||
id
|
// ) {
|
||||||
job {
|
// invoices(
|
||||||
id
|
// where: { vendorid: { _eq: $vendorId } }
|
||||||
ro_number
|
// offset: $offset
|
||||||
}
|
// limit: $limit
|
||||||
total
|
// order_by: $order
|
||||||
invoice_number
|
// ) {
|
||||||
date
|
// id
|
||||||
}
|
// job {
|
||||||
}
|
// id
|
||||||
`;
|
// ro_number
|
||||||
|
// }
|
||||||
|
// total
|
||||||
|
// invoice_number
|
||||||
|
// date
|
||||||
|
// }
|
||||||
|
// invoices_aggregate(where: { vendorid: { _eq: $vendorId } }) {
|
||||||
|
// aggregate {
|
||||||
|
// count(distinct: true)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// `;
|
||||||
|
|
||||||
export const QUERY_INVOICES_BY_VENDOR_PAGINATED = gql`
|
export const QUERY_BILL_BY_PK = gql`
|
||||||
query QUERY_INVOICES_BY_VENDOR_PAGINATED(
|
query QUERY_BILL_BY_PK($billid: uuid!) {
|
||||||
$vendorId: uuid!
|
bills_by_pk(id: $billid) {
|
||||||
$offset: Int
|
|
||||||
$limit: Int
|
|
||||||
$order: [invoices_order_by!]!
|
|
||||||
) {
|
|
||||||
invoices(
|
|
||||||
where: { vendorid: { _eq: $vendorId } }
|
|
||||||
offset: $offset
|
|
||||||
limit: $limit
|
|
||||||
order_by: $order
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
job {
|
|
||||||
id
|
|
||||||
ro_number
|
|
||||||
}
|
|
||||||
total
|
|
||||||
invoice_number
|
|
||||||
date
|
|
||||||
}
|
|
||||||
invoices_aggregate(where: { vendorid: { _eq: $vendorId } }) {
|
|
||||||
aggregate {
|
|
||||||
count(distinct: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const QUERY_INVOICE_BY_PK = gql`
|
|
||||||
query QUERY_INVOICE_BY_PK($invoiceid: uuid!) {
|
|
||||||
invoices_by_pk(id: $invoiceid) {
|
|
||||||
due_date
|
due_date
|
||||||
exported
|
exported
|
||||||
exported_at
|
exported_at
|
||||||
@@ -187,7 +169,7 @@ export const QUERY_INVOICE_BY_PK = gql`
|
|||||||
name
|
name
|
||||||
discount
|
discount
|
||||||
}
|
}
|
||||||
invoicelines {
|
billlines {
|
||||||
id
|
id
|
||||||
line_desc
|
line_desc
|
||||||
actual_price
|
actual_price
|
||||||
@@ -207,9 +189,9 @@ export const QUERY_INVOICE_BY_PK = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE_INVOICE = gql`
|
export const UPDATE_BILL = gql`
|
||||||
mutation UPDATE_INVOICE($invoiceId: uuid!, $invoice: invoices_set_input!) {
|
mutation UPDATE_BILL($billId: uuid!, $bill: bills_set_input!) {
|
||||||
update_invoices(where: { id: { _eq: $invoiceId } }, _set: $invoice) {
|
update_bills(where: { id: { _eq: $billId } }, _set: $bill) {
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
exported
|
exported
|
||||||
@@ -219,12 +201,9 @@ export const UPDATE_INVOICE = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE_INVOICES = gql`
|
export const UPDATE_BILLS = gql`
|
||||||
mutation UPDATE_INVOICES(
|
mutation UPDATE_BILLS($billIdList: [uuid!]!, $bill: bills_set_input!) {
|
||||||
$invoiceIdList: [uuid!]!
|
update_bills(where: { id: { _in: $billIdList } }, _set: $bill) {
|
||||||
$invoice: invoices_set_input!
|
|
||||||
) {
|
|
||||||
update_invoices(where: { id: { _in: $invoiceIdList } }, _set: $invoice) {
|
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
exported
|
exported
|
||||||
@@ -48,7 +48,7 @@ export const QUERY_BODYSHOP = gql`
|
|||||||
template_header
|
template_header
|
||||||
textid
|
textid
|
||||||
production_config
|
production_config
|
||||||
invoice_tax_rates
|
bill_tax_rates
|
||||||
inhousevendorid
|
inhousevendorid
|
||||||
accountingconfig
|
accountingconfig
|
||||||
appt_length
|
appt_length
|
||||||
@@ -118,7 +118,7 @@ export const UPDATE_SHOP = gql`
|
|||||||
template_header
|
template_header
|
||||||
textid
|
textid
|
||||||
production_config
|
production_config
|
||||||
invoice_tax_rates
|
bill_tax_rates
|
||||||
appt_length
|
appt_length
|
||||||
stripe_acct_id
|
stripe_acct_id
|
||||||
ssbuckets
|
ssbuckets
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import gql from "graphql-tag";
|
|
||||||
|
|
||||||
export const UPDATE_INVOICE_LINE = gql`
|
|
||||||
mutation UPDATE_INVOICE_LINE(
|
|
||||||
$invoicelineId: uuid!
|
|
||||||
$invoiceLine: invoicelines_set_input!
|
|
||||||
) {
|
|
||||||
update_invoicelines(
|
|
||||||
where: { id: { _eq: $invoicelineId } }
|
|
||||||
_set: $invoiceLine
|
|
||||||
) {
|
|
||||||
returning {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -124,8 +124,8 @@ export const UPDATE_JOB_LINE = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GET_JOB_LINES_TO_ENTER_INVOICE = gql`
|
export const GET_JOB_LINES_TO_ENTER_BILL = gql`
|
||||||
query GET_JOB_LINES_TO_ENTER_INVOICE($id: uuid!) {
|
query GET_JOB_LINES_TO_ENTER_BILL($id: uuid!) {
|
||||||
joblines(where: { jobid: { _eq: $id } }) {
|
joblines(where: { jobid: { _eq: $id } }) {
|
||||||
id
|
id
|
||||||
line_desc
|
line_desc
|
||||||
|
|||||||
@@ -215,13 +215,13 @@ export const QUERY_JOB_COSTING_DETAILS = gql`
|
|||||||
lbr_amt
|
lbr_amt
|
||||||
op_code_desc
|
op_code_desc
|
||||||
}
|
}
|
||||||
invoices {
|
bills {
|
||||||
id
|
id
|
||||||
federal_tax_rate
|
federal_tax_rate
|
||||||
local_tax_rate
|
local_tax_rate
|
||||||
state_tax_rate
|
state_tax_rate
|
||||||
is_credit_memo
|
is_credit_memo
|
||||||
invoicelines {
|
billlines {
|
||||||
actual_cost
|
actual_cost
|
||||||
cost_center
|
cost_center
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
|||||||
memo
|
memo
|
||||||
transactionid
|
transactionid
|
||||||
}
|
}
|
||||||
search_invoices(args: { search: $search }) {
|
search_bills(args: { search: $search }) {
|
||||||
id
|
id
|
||||||
date
|
date
|
||||||
invoice_number
|
invoice_number
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
|
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
import { QUERY_INVOICES_FOR_EXPORT } from "../../graphql/accounting.queries";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import { QUERY_BILLS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
||||||
import {
|
import {
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -20,6 +21,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function AccountingPayablesContainer({
|
export function AccountingPayablesContainer({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
@@ -38,7 +40,7 @@ export function AccountingPayablesContainer({
|
|||||||
]);
|
]);
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||||
|
|
||||||
const { loading, error, data } = useQuery(QUERY_INVOICES_FOR_EXPORT);
|
const { loading, error, data } = useQuery(QUERY_BILLS_FOR_EXPORT);
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ export function AccountingPayablesContainer({
|
|||||||
<RbacWrapper action="accounting:payables">
|
<RbacWrapper action="accounting:payables">
|
||||||
<AccountingPayablesTable
|
<AccountingPayablesTable
|
||||||
loadaing={loading}
|
loadaing={loading}
|
||||||
invoices={data ? data.invoices : []}
|
bills={data ? data.bills : []}
|
||||||
/>
|
/>
|
||||||
</RbacWrapper>
|
</RbacWrapper>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ import { alphaSort } from "../../utils/sorters";
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setPartsOrderContext: (context) =>
|
setPartsOrderContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
||||||
setInvoiceEnterContext: (context) =>
|
setBillEnterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoicesListPage({
|
export function BillsListPage({
|
||||||
loading,
|
loading,
|
||||||
data,
|
data,
|
||||||
refetch,
|
refetch,
|
||||||
total,
|
total,
|
||||||
setPartsOrderContext,
|
setPartsOrderContext,
|
||||||
setInvoiceEnterContext,
|
setBillEnterContext,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
@@ -35,7 +35,7 @@ export function InvoicesListPage({
|
|||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.vendorname"),
|
title: t("bills.fields.vendorname"),
|
||||||
dataIndex: "vendorname",
|
dataIndex: "vendorname",
|
||||||
key: "vendorname",
|
key: "vendorname",
|
||||||
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||||
@@ -44,7 +44,7 @@ export function InvoicesListPage({
|
|||||||
render: (text, record) => <span>{record.vendor.name}</span>,
|
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.invoice_number"),
|
title: t("bills.fields.invoice_number"),
|
||||||
dataIndex: "invoice_number",
|
dataIndex: "invoice_number",
|
||||||
key: "invoice_number",
|
key: "invoice_number",
|
||||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||||
@@ -53,7 +53,7 @@ export function InvoicesListPage({
|
|||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.date"),
|
title: t("bills.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
key: "date",
|
key: "date",
|
||||||
sorter: (a, b) => a.date - b.date,
|
sorter: (a, b) => a.date - b.date,
|
||||||
@@ -62,7 +62,7 @@ export function InvoicesListPage({
|
|||||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.total"),
|
title: t("bills.fields.total"),
|
||||||
dataIndex: "total",
|
dataIndex: "total",
|
||||||
key: "total",
|
key: "total",
|
||||||
sorter: (a, b) => a.total - b.total,
|
sorter: (a, b) => a.total - b.total,
|
||||||
@@ -73,7 +73,7 @@ export function InvoicesListPage({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("invoices.fields.is_credit_memo"),
|
title: t("bills.fields.is_credit_memo"),
|
||||||
dataIndex: "is_credit_memo",
|
dataIndex: "is_credit_memo",
|
||||||
key: "is_credit_memo",
|
key: "is_credit_memo",
|
||||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||||
@@ -88,8 +88,8 @@ export function InvoicesListPage({
|
|||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<div>
|
||||||
<Link to={`/manage/invoices?invoiceid=${record.id}`}>
|
<Link to={`/manage/bills?billid=${record.id}`}>
|
||||||
<Button>{t("invoices.actions.edit")}</Button>
|
<Button>{t("bills.actions.edit")}</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Button
|
<Button
|
||||||
disabled={record.is_credit_memo}
|
disabled={record.is_credit_memo}
|
||||||
@@ -99,9 +99,9 @@ export function InvoicesListPage({
|
|||||||
context: {
|
context: {
|
||||||
jobId: record.jobid,
|
jobId: record.jobid,
|
||||||
vendorId: record.vendorid,
|
vendorId: record.vendorid,
|
||||||
returnFromInvoice: record.id,
|
returnFromBill: record.id,
|
||||||
invoiceNumber: record.invoice_number,
|
invoiceNumber: record.invoice_number,
|
||||||
linesToOrder: record.invoicelines.map((i) => {
|
linesToOrder: record.billlines.map((i) => {
|
||||||
return {
|
return {
|
||||||
line_desc: i.line_desc,
|
line_desc: i.line_desc,
|
||||||
db_price: i.actual_price,
|
db_price: i.actual_price,
|
||||||
@@ -115,7 +115,7 @@ export function InvoicesListPage({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("invoices.actions.return")}
|
{t("bills.actions.return")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -132,9 +132,7 @@ export function InvoicesListPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
||||||
{t("invoices.labels.invoices")}
|
|
||||||
</Typography.Title>
|
|
||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={loading}
|
||||||
size="small"
|
size="small"
|
||||||
@@ -145,13 +143,13 @@ export function InvoicesListPage({
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInvoiceEnterContext({
|
setBillEnterContext({
|
||||||
actions: { refetch: refetch },
|
actions: { refetch: refetch },
|
||||||
context: {},
|
context: {},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("jobs.actions.postInvoices")}
|
{t("jobs.actions.postbills")}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="imex-table-header__search">
|
<div className="imex-table-header__search">
|
||||||
<Input.Search
|
<Input.Search
|
||||||
@@ -179,4 +177,4 @@ export function InvoicesListPage({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(null, mapDispatchToProps)(InvoicesListPage);
|
export default connect(null, mapDispatchToProps)(BillsListPage);
|
||||||
@@ -4,13 +4,13 @@ import { useQuery } from "react-apollo";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import InvoiceDetailEditContainer from "../../components/invoice-detail-edit/invoice-detail-edit.container";
|
import BillDetailEditContainer from "../../components/bill-detail-edit/bill-detail-edit.container";
|
||||||
import { QUERY_ALL_INVOICES_PAGINATED } from "../../graphql/invoices.queries";
|
import { QUERY_ALL_BILLS_PAGINATED } from "../../graphql/bills.queries";
|
||||||
import {
|
import {
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import InvoicesPageComponent from "./invoices.page.component";
|
import BillsPageComponent from "./bills.page.component";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
|
|
||||||
@@ -19,21 +19,21 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function InvoicesPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const searchParams = queryString.parse(useLocation().search);
|
const searchParams = queryString.parse(useLocation().search);
|
||||||
const { page, sortcolumn, sortorder, search } = searchParams;
|
const { page, sortcolumn, sortorder, search } = searchParams;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = t("titles.invoices-list");
|
document.title = t("titles.bills-list");
|
||||||
setSelectedHeader("invoices");
|
setSelectedHeader("bills");
|
||||||
setBreadcrumbs([
|
setBreadcrumbs([
|
||||||
{ link: "/manage/invoices", label: t("titles.bc.invoices-list") },
|
{ link: "/manage/bills", label: t("titles.bc.bills-list") },
|
||||||
]);
|
]);
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||||
|
|
||||||
const { loading, error, data, refetch } = useQuery(
|
const { loading, error, data, refetch } = useQuery(
|
||||||
QUERY_ALL_INVOICES_PAGINATED,
|
QUERY_ALL_BILLS_PAGINATED,
|
||||||
{
|
{
|
||||||
variables: {
|
variables: {
|
||||||
search: search || "",
|
search: search || "",
|
||||||
@@ -54,18 +54,18 @@ export function InvoicesPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
|||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
return (
|
return (
|
||||||
<RbacWrapper action="invoices:list">
|
<RbacWrapper action="bills:list">
|
||||||
<div>
|
<div>
|
||||||
<InvoicesPageComponent
|
<BillsPageComponent
|
||||||
data={data ? data.search_invoices : []}
|
data={data ? data.search_bills : []}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
total={data ? data.search_invoices_aggregate.aggregate.count : 0}
|
total={data ? data.search_bills_aggregate.aggregate.count : 0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InvoiceDetailEditContainer />
|
<BillDetailEditContainer />
|
||||||
</div>
|
</div>
|
||||||
</RbacWrapper>
|
</RbacWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(null, mapDispatchToProps)(InvoicesPageContainer);
|
export default connect(null, mapDispatchToProps)(BillsPageContainer);
|
||||||
@@ -74,15 +74,13 @@ const ContractDetailPage = lazy(() =>
|
|||||||
const ContractsList = lazy(() =>
|
const ContractsList = lazy(() =>
|
||||||
import("../contracts/contracts.page.container")
|
import("../contracts/contracts.page.container")
|
||||||
);
|
);
|
||||||
const InvoicesListPage = lazy(() =>
|
const BillsListPage = lazy(() => import("../bills/bills.page.container"));
|
||||||
import("../invoices/invoices.page.container")
|
|
||||||
);
|
|
||||||
|
|
||||||
const JobCostingModal = lazy(() =>
|
const JobCostingModal = lazy(() =>
|
||||||
import("../../components/job-costing-modal/job-costing-modal.container")
|
import("../../components/job-costing-modal/job-costing-modal.container")
|
||||||
);
|
);
|
||||||
const EnterInvoiceModalContainer = lazy(() =>
|
const BillEnterModalContainer = lazy(() =>
|
||||||
import("../../components/invoice-enter-modal/invoice-enter-modal.container")
|
import("../../components/bill-enter-modal/bill-enter-modal.container")
|
||||||
);
|
);
|
||||||
const TimeTicketModalContainer = lazy(() =>
|
const TimeTicketModalContainer = lazy(() =>
|
||||||
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
||||||
@@ -174,7 +172,7 @@ export function Manage({ match, conflict }) {
|
|||||||
<PaymentModalContainer />
|
<PaymentModalContainer />
|
||||||
</Elements>
|
</Elements>
|
||||||
<BreadCrumbs />
|
<BreadCrumbs />
|
||||||
<EnterInvoiceModalContainer />
|
<BillEnterModalContainer />
|
||||||
<JobCostingModal />
|
<JobCostingModal />
|
||||||
<EmailOverlayContainer />
|
<EmailOverlayContainer />
|
||||||
<TimeTicketModalContainer />
|
<TimeTicketModalContainer />
|
||||||
@@ -280,8 +278,8 @@ export function Manage({ match, conflict }) {
|
|||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path={`${match.path}/invoices`}
|
path={`${match.path}/bills`}
|
||||||
component={InvoicesListPage}
|
component={BillsListPage}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const baseModal = {
|
|||||||
|
|
||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
jobLineEdit: { ...baseModal },
|
jobLineEdit: { ...baseModal },
|
||||||
invoiceEnter: { ...baseModal },
|
billEnter: { ...baseModal },
|
||||||
courtesyCarReturn: { ...baseModal },
|
courtesyCarReturn: { ...baseModal },
|
||||||
noteUpsert: { ...baseModal },
|
noteUpsert: { ...baseModal },
|
||||||
schedule: { ...baseModal },
|
schedule: { ...baseModal },
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export const selectJobLineEditModal = createSelector(
|
|||||||
(modals) => modals.jobLineEdit
|
(modals) => modals.jobLineEdit
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectInvoiceEnterModal = createSelector(
|
export const selectBillEnterModal = createSelector(
|
||||||
[selectModals],
|
[selectModals],
|
||||||
(modals) => modals.invoiceEnter
|
(modals) => modals.billEnter
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectCourtesyCarReturn = createSelector(
|
export const selectCourtesyCarReturn = createSelector(
|
||||||
|
|||||||
@@ -73,6 +73,76 @@
|
|||||||
"values": "Values"
|
"values": "Values"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"billlines": {
|
||||||
|
"actions": {
|
||||||
|
"newline": "New Line"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"actual": "Actual",
|
||||||
|
"actual_cost": "Actual Cost",
|
||||||
|
"cost_center": "Cost Center",
|
||||||
|
"federal_tax_applicable": "Fed. Tax?",
|
||||||
|
"jobline": "Job Line",
|
||||||
|
"line_desc": "Line Description",
|
||||||
|
"local_tax_applicable": "Loc. Tax?",
|
||||||
|
"quantity": "Quantity",
|
||||||
|
"retail": "Retail",
|
||||||
|
"state_tax_applicable": "St. Tax?"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"entered": "Entered",
|
||||||
|
"other": "--Not On Estimate--",
|
||||||
|
"reconciled": "Reconciled!",
|
||||||
|
"unreconciled": "Unreconciled"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bills": {
|
||||||
|
"actions": {
|
||||||
|
"edit": "Edit",
|
||||||
|
"receive": "Receive Part",
|
||||||
|
"return": "Return Items"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"creating": "Error adding bill.",
|
||||||
|
"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",
|
||||||
|
"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": "State Tax Rate",
|
||||||
|
"total": "Bill Total",
|
||||||
|
"vendor": "Vendor",
|
||||||
|
"vendorname": "Vendor Name"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"bill_lines": "Bill Lines",
|
||||||
|
"bill_total": "Bill Total Amount",
|
||||||
|
"bills": "Bills",
|
||||||
|
"discrepancy": "Discrepancy",
|
||||||
|
"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",
|
||||||
|
"new": "New Bill",
|
||||||
|
"noneselected": "No bill selected.",
|
||||||
|
"retailtotal": "Retail Total of Bill (Ex. Taxes)",
|
||||||
|
"state_tax": "State Tax",
|
||||||
|
"subtotal": "Subtotal"
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"created": "Invoice added successfully."
|
||||||
|
}
|
||||||
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addbucket": "Add Bucket",
|
"addbucket": "Add Bucket",
|
||||||
@@ -91,6 +161,9 @@
|
|||||||
"address1": "Address 1",
|
"address1": "Address 1",
|
||||||
"address2": "Address 2",
|
"address2": "Address 2",
|
||||||
"appt_length": "Default Appointment Length",
|
"appt_length": "Default Appointment Length",
|
||||||
|
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
||||||
|
"bill_local_tax_rate": "Bill - State Tax Rate %",
|
||||||
|
"bill_state_tax_rate": "Bill - State Tax Rate %",
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"country": "Country",
|
"country": "Country",
|
||||||
"dailybodytarget": "Scoreboard - Daily Body Target",
|
"dailybodytarget": "Scoreboard - Daily Body Target",
|
||||||
@@ -99,9 +172,6 @@
|
|||||||
"enforce_class": "Enforce Class on Conversion?",
|
"enforce_class": "Enforce Class on Conversion?",
|
||||||
"federal_tax_id": "Federal Tax ID (GST/HST)",
|
"federal_tax_id": "Federal Tax ID (GST/HST)",
|
||||||
"insurance_vendor_id": "Insurance Vendor ID",
|
"insurance_vendor_id": "Insurance Vendor ID",
|
||||||
"invoice_federal_tax_rate": "Invoices - Federal Tax Rate %",
|
|
||||||
"invoice_local_tax_rate": "Invoices - State Tax Rate %",
|
|
||||||
"invoice_state_tax_rate": "Invoices - State Tax Rate %",
|
|
||||||
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
||||||
"logo_img_path": "Shop Logo",
|
"logo_img_path": "Shop Logo",
|
||||||
"md_categories": "Categories",
|
"md_categories": "Categories",
|
||||||
@@ -121,6 +191,11 @@
|
|||||||
"payments": "Accounting -> Payments",
|
"payments": "Accounting -> Payments",
|
||||||
"receivables": "Accounting -> Receivables"
|
"receivables": "Accounting -> Receivables"
|
||||||
},
|
},
|
||||||
|
"bills": {
|
||||||
|
"enter": "Bills -> Enter",
|
||||||
|
"list": "Bills -> List",
|
||||||
|
"view": "Bills -> View"
|
||||||
|
},
|
||||||
"contracts": {
|
"contracts": {
|
||||||
"create": "Contracts -> Create",
|
"create": "Contracts -> Create",
|
||||||
"detail": "Contracts -> Detail",
|
"detail": "Contracts -> Detail",
|
||||||
@@ -138,11 +213,6 @@
|
|||||||
"employees": {
|
"employees": {
|
||||||
"page": "Employees -> List"
|
"page": "Employees -> List"
|
||||||
},
|
},
|
||||||
"invoices": {
|
|
||||||
"enter": "Invoices -> Enter",
|
|
||||||
"list": "Invoices -> List",
|
|
||||||
"view": "Invoices -> View"
|
|
||||||
},
|
|
||||||
"jobs": {
|
"jobs": {
|
||||||
"available-list": "Jobs -> Available List",
|
"available-list": "Jobs -> Available List",
|
||||||
"close": "Jobs -> Close",
|
"close": "Jobs -> Close",
|
||||||
@@ -614,76 +684,6 @@
|
|||||||
"rescuetitle": "Rescue Me!"
|
"rescuetitle": "Rescue Me!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invoicelines": {
|
|
||||||
"actions": {
|
|
||||||
"newline": "New Line"
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"actual": "Actual",
|
|
||||||
"actual_cost": "Actual Cost",
|
|
||||||
"cost_center": "Cost Center",
|
|
||||||
"federal_tax_applicable": "Fed. Tax?",
|
|
||||||
"jobline": "Job Line",
|
|
||||||
"line_desc": "Invoice Line Description",
|
|
||||||
"local_tax_applicable": "Loc. Tax?",
|
|
||||||
"quantity": "Quantity",
|
|
||||||
"retail": "Retail",
|
|
||||||
"state_tax_applicable": "St. Tax?"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"entered": "Entered",
|
|
||||||
"other": "--Not On Estimate--",
|
|
||||||
"reconciled": "Reconciled!",
|
|
||||||
"unreconciled": "Unreconciled"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"invoices": {
|
|
||||||
"actions": {
|
|
||||||
"edit": "Edit",
|
|
||||||
"receive": "Receive Part",
|
|
||||||
"return": "Return Items"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"creating": "Error adding invoice.",
|
|
||||||
"exporting": "Error exporting invoice(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": "Invoice Date",
|
|
||||||
"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": "State Tax Rate",
|
|
||||||
"total": "Invoice Total",
|
|
||||||
"vendor": "Vendor",
|
|
||||||
"vendorname": "Vendor Name"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"actions": "Actions",
|
|
||||||
"discrepancy": "Discrepancy",
|
|
||||||
"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",
|
|
||||||
"invoice_lines": "Invoice Lines",
|
|
||||||
"invoice_total": "Invoice Total Amount",
|
|
||||||
"invoices": "Invoices",
|
|
||||||
"local_tax": "Local Tax",
|
|
||||||
"new": "New Invoice",
|
|
||||||
"noneselected": "No invoice selected.",
|
|
||||||
"retailtotal": "Retail Total of Invoices (Ex. Taxes)",
|
|
||||||
"state_tax": "State Tax",
|
|
||||||
"subtotal": "Subtotal"
|
|
||||||
},
|
|
||||||
"successes": {
|
|
||||||
"created": "Invoice added successfully."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": "New Line"
|
"new": "New Line"
|
||||||
@@ -778,7 +778,7 @@
|
|||||||
"intake": "Intake",
|
"intake": "Intake",
|
||||||
"manualnew": "Create New Job Manually",
|
"manualnew": "Create New Job Manually",
|
||||||
"mark": "Mark",
|
"mark": "Mark",
|
||||||
"postInvoices": "Post Invoices",
|
"postbills": "Post Bills",
|
||||||
"printCenter": "Print Center",
|
"printCenter": "Print Center",
|
||||||
"recalculate": "Recalculate",
|
"recalculate": "Recalculate",
|
||||||
"reconcile": "Reconcile",
|
"reconcile": "Reconcile",
|
||||||
@@ -1071,17 +1071,17 @@
|
|||||||
"alljobs": "All Jobs",
|
"alljobs": "All Jobs",
|
||||||
"allpayments": "All Payments",
|
"allpayments": "All Payments",
|
||||||
"availablejobs": "Available Jobs",
|
"availablejobs": "Available Jobs",
|
||||||
|
"bills": "Bills",
|
||||||
"courtesycars": "Courtesy Cars",
|
"courtesycars": "Courtesy Cars",
|
||||||
"courtesycars-all": "All Courtesy Cars",
|
"courtesycars-all": "All Courtesy Cars",
|
||||||
"courtesycars-contracts": "Contracts",
|
"courtesycars-contracts": "Contracts",
|
||||||
"courtesycars-newcontract": "New Contract",
|
"courtesycars-newcontract": "New Contract",
|
||||||
"customers": "Customers",
|
"customers": "Customers",
|
||||||
"enterinvoices": "Enter Invoices",
|
"enterbills": "Enter Bills",
|
||||||
"enterpayment": "Enter Payments",
|
"enterpayment": "Enter Payments",
|
||||||
"entertimeticket": "Enter Time Tickets",
|
"entertimeticket": "Enter Time Tickets",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"invoices": "Invoices",
|
|
||||||
"jobs": "Jobs",
|
"jobs": "Jobs",
|
||||||
"owners": "Owners",
|
"owners": "Owners",
|
||||||
"productionboard": "Production Board - Visual",
|
"productionboard": "Production Board - Visual",
|
||||||
@@ -1221,7 +1221,7 @@
|
|||||||
"actions": {
|
"actions": {
|
||||||
"backordered": "Backordered",
|
"backordered": "Backordered",
|
||||||
"receive": "Receive",
|
"receive": "Receive",
|
||||||
"receiveinvoice": "Receive Invoice"
|
"receivebill": "Receive Bill"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"backordering": "Error backordering part {{message}}.",
|
"backordering": "Error backordering part {{message}}.",
|
||||||
@@ -1451,13 +1451,13 @@
|
|||||||
"accounting-payments": "Payments",
|
"accounting-payments": "Payments",
|
||||||
"accounting-receivables": "Receivables",
|
"accounting-receivables": "Receivables",
|
||||||
"availablejobs": "Available Jobs",
|
"availablejobs": "Available Jobs",
|
||||||
|
"bills-list": "Bills",
|
||||||
"contracts": "Contracts",
|
"contracts": "Contracts",
|
||||||
"contracts-create": "New Contract",
|
"contracts-create": "New Contract",
|
||||||
"contracts-detail": "Contract #{{number}}",
|
"contracts-detail": "Contract #{{number}}",
|
||||||
"courtesycars": "Courtesy Cars",
|
"courtesycars": "Courtesy Cars",
|
||||||
"courtesycars-detail": "Courtesy Car {{number}}",
|
"courtesycars-detail": "Courtesy Car {{number}}",
|
||||||
"courtesycars-new": "New Courtesy Car",
|
"courtesycars-new": "New Courtesy Car",
|
||||||
"invoices-list": "Invoices",
|
|
||||||
"jobs": "Jobs",
|
"jobs": "Jobs",
|
||||||
"jobs-active": "Active Jobs",
|
"jobs-active": "Active Jobs",
|
||||||
"jobs-all": "All Jobs",
|
"jobs-all": "All Jobs",
|
||||||
@@ -1481,13 +1481,13 @@
|
|||||||
"vehicle-details": "Vehicle: {{vehicle}}",
|
"vehicle-details": "Vehicle: {{vehicle}}",
|
||||||
"vehicles": "Vehicles"
|
"vehicles": "Vehicles"
|
||||||
},
|
},
|
||||||
|
"bills-list": "Bills | $t(titles.app)",
|
||||||
"contracts": "Courtesy Car Contracts | $t(titles.app)",
|
"contracts": "Courtesy Car Contracts | $t(titles.app)",
|
||||||
"contracts-create": "New Contract | $t(titles.app)",
|
"contracts-create": "New Contract | $t(titles.app)",
|
||||||
"contracts-detail": "Contract {{id}} | $t(titles.app)",
|
"contracts-detail": "Contract {{id}} | $t(titles.app)",
|
||||||
"courtesycars": "Courtesy Cars | $t(titles.app)",
|
"courtesycars": "Courtesy Cars | $t(titles.app)",
|
||||||
"courtesycars-create": "New Courtesy Car | $t(titles.app)",
|
"courtesycars-create": "New Courtesy Car | $t(titles.app)",
|
||||||
"courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)",
|
"courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)",
|
||||||
"invoices-list": "Invoices | $t(titles.app)",
|
|
||||||
"jobs": "Active Jobs | $t(titles.app)",
|
"jobs": "Active Jobs | $t(titles.app)",
|
||||||
"jobs-all": "All Jobs | $t(titles.app)",
|
"jobs-all": "All Jobs | $t(titles.app)",
|
||||||
"jobs-close": "Close Job {{number}} | $t(titles.app)",
|
"jobs-close": "Close Job {{number}} | $t(titles.app)",
|
||||||
|
|||||||
@@ -73,6 +73,76 @@
|
|||||||
"values": ""
|
"values": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"billlines": {
|
||||||
|
"actions": {
|
||||||
|
"newline": ""
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"actual": "",
|
||||||
|
"actual_cost": "",
|
||||||
|
"cost_center": "",
|
||||||
|
"federal_tax_applicable": "",
|
||||||
|
"jobline": "",
|
||||||
|
"line_desc": "",
|
||||||
|
"local_tax_applicable": "",
|
||||||
|
"quantity": "",
|
||||||
|
"retail": "",
|
||||||
|
"state_tax_applicable": ""
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"entered": "",
|
||||||
|
"other": "",
|
||||||
|
"reconciled": "",
|
||||||
|
"unreconciled": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bills": {
|
||||||
|
"actions": {
|
||||||
|
"edit": "",
|
||||||
|
"receive": "",
|
||||||
|
"return": ""
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"creating": "",
|
||||||
|
"exporting": "",
|
||||||
|
"exporting-partner": "",
|
||||||
|
"invalidro": "",
|
||||||
|
"invalidvendor": "",
|
||||||
|
"validation": ""
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"allpartslocation": "",
|
||||||
|
"date": "",
|
||||||
|
"federal_tax_rate": "",
|
||||||
|
"invoice_number": "",
|
||||||
|
"is_credit_memo": "",
|
||||||
|
"local_tax_rate": "",
|
||||||
|
"ro_number": "",
|
||||||
|
"state_tax_rate": "",
|
||||||
|
"total": "",
|
||||||
|
"vendor": "",
|
||||||
|
"vendorname": ""
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"actions": "",
|
||||||
|
"bill_lines": "",
|
||||||
|
"bill_total": "",
|
||||||
|
"bills": "",
|
||||||
|
"discrepancy": "",
|
||||||
|
"entered_total": "",
|
||||||
|
"enteringcreditmemo": "",
|
||||||
|
"federal_tax": "",
|
||||||
|
"local_tax": "",
|
||||||
|
"new": "",
|
||||||
|
"noneselected": "",
|
||||||
|
"retailtotal": "",
|
||||||
|
"state_tax": "",
|
||||||
|
"subtotal": ""
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"created": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addbucket": "",
|
"addbucket": "",
|
||||||
@@ -91,6 +161,9 @@
|
|||||||
"address1": "",
|
"address1": "",
|
||||||
"address2": "",
|
"address2": "",
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
|
"bill_federal_tax_rate": "",
|
||||||
|
"bill_local_tax_rate": "",
|
||||||
|
"bill_state_tax_rate": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
"country": "",
|
"country": "",
|
||||||
"dailybodytarget": "",
|
"dailybodytarget": "",
|
||||||
@@ -99,9 +172,6 @@
|
|||||||
"enforce_class": "",
|
"enforce_class": "",
|
||||||
"federal_tax_id": "",
|
"federal_tax_id": "",
|
||||||
"insurance_vendor_id": "",
|
"insurance_vendor_id": "",
|
||||||
"invoice_federal_tax_rate": "",
|
|
||||||
"invoice_local_tax_rate": "",
|
|
||||||
"invoice_state_tax_rate": "",
|
|
||||||
"lastnumberworkingdays": "",
|
"lastnumberworkingdays": "",
|
||||||
"logo_img_path": "",
|
"logo_img_path": "",
|
||||||
"md_categories": "",
|
"md_categories": "",
|
||||||
@@ -121,6 +191,11 @@
|
|||||||
"payments": "",
|
"payments": "",
|
||||||
"receivables": ""
|
"receivables": ""
|
||||||
},
|
},
|
||||||
|
"bills": {
|
||||||
|
"enter": "",
|
||||||
|
"list": "",
|
||||||
|
"view": ""
|
||||||
|
},
|
||||||
"contracts": {
|
"contracts": {
|
||||||
"create": "",
|
"create": "",
|
||||||
"detail": "",
|
"detail": "",
|
||||||
@@ -138,11 +213,6 @@
|
|||||||
"employees": {
|
"employees": {
|
||||||
"page": ""
|
"page": ""
|
||||||
},
|
},
|
||||||
"invoices": {
|
|
||||||
"enter": "",
|
|
||||||
"list": "",
|
|
||||||
"view": ""
|
|
||||||
},
|
|
||||||
"jobs": {
|
"jobs": {
|
||||||
"available-list": "",
|
"available-list": "",
|
||||||
"close": "",
|
"close": "",
|
||||||
@@ -614,76 +684,6 @@
|
|||||||
"rescuetitle": ""
|
"rescuetitle": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invoicelines": {
|
|
||||||
"actions": {
|
|
||||||
"newline": ""
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"actual": "",
|
|
||||||
"actual_cost": "",
|
|
||||||
"cost_center": "",
|
|
||||||
"federal_tax_applicable": "",
|
|
||||||
"jobline": "",
|
|
||||||
"line_desc": "",
|
|
||||||
"local_tax_applicable": "",
|
|
||||||
"quantity": "",
|
|
||||||
"retail": "",
|
|
||||||
"state_tax_applicable": ""
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"entered": "",
|
|
||||||
"other": "",
|
|
||||||
"reconciled": "",
|
|
||||||
"unreconciled": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"invoices": {
|
|
||||||
"actions": {
|
|
||||||
"edit": "",
|
|
||||||
"receive": "",
|
|
||||||
"return": ""
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"creating": "",
|
|
||||||
"exporting": "",
|
|
||||||
"exporting-partner": "",
|
|
||||||
"invalidro": "",
|
|
||||||
"invalidvendor": "",
|
|
||||||
"validation": ""
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"allpartslocation": "",
|
|
||||||
"date": "",
|
|
||||||
"federal_tax_rate": "",
|
|
||||||
"invoice_number": "",
|
|
||||||
"is_credit_memo": "",
|
|
||||||
"local_tax_rate": "",
|
|
||||||
"ro_number": "",
|
|
||||||
"state_tax_rate": "",
|
|
||||||
"total": "",
|
|
||||||
"vendor": "",
|
|
||||||
"vendorname": ""
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"actions": "",
|
|
||||||
"discrepancy": "",
|
|
||||||
"entered_total": "",
|
|
||||||
"enteringcreditmemo": "",
|
|
||||||
"federal_tax": "",
|
|
||||||
"invoice_lines": "",
|
|
||||||
"invoice_total": "",
|
|
||||||
"invoices": "",
|
|
||||||
"local_tax": "",
|
|
||||||
"new": "",
|
|
||||||
"noneselected": "",
|
|
||||||
"retailtotal": "",
|
|
||||||
"state_tax": "",
|
|
||||||
"subtotal": ""
|
|
||||||
},
|
|
||||||
"successes": {
|
|
||||||
"created": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": ""
|
"new": ""
|
||||||
@@ -778,7 +778,7 @@
|
|||||||
"intake": "",
|
"intake": "",
|
||||||
"manualnew": "",
|
"manualnew": "",
|
||||||
"mark": "",
|
"mark": "",
|
||||||
"postInvoices": "Contabilizar facturas",
|
"postbills": "Contabilizar facturas",
|
||||||
"printCenter": "Centro de impresión",
|
"printCenter": "Centro de impresión",
|
||||||
"recalculate": "",
|
"recalculate": "",
|
||||||
"reconcile": "",
|
"reconcile": "",
|
||||||
@@ -1071,17 +1071,17 @@
|
|||||||
"alljobs": "",
|
"alljobs": "",
|
||||||
"allpayments": "",
|
"allpayments": "",
|
||||||
"availablejobs": "Trabajos disponibles",
|
"availablejobs": "Trabajos disponibles",
|
||||||
|
"bills": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-all": "",
|
"courtesycars-all": "",
|
||||||
"courtesycars-contracts": "",
|
"courtesycars-contracts": "",
|
||||||
"courtesycars-newcontract": "",
|
"courtesycars-newcontract": "",
|
||||||
"customers": "Clientes",
|
"customers": "Clientes",
|
||||||
"enterinvoices": "",
|
"enterbills": "",
|
||||||
"enterpayment": "",
|
"enterpayment": "",
|
||||||
"entertimeticket": "",
|
"entertimeticket": "",
|
||||||
"export": "",
|
"export": "",
|
||||||
"home": "Casa",
|
"home": "Casa",
|
||||||
"invoices": "",
|
|
||||||
"jobs": "Trabajos",
|
"jobs": "Trabajos",
|
||||||
"owners": "propietarios",
|
"owners": "propietarios",
|
||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
@@ -1221,7 +1221,7 @@
|
|||||||
"actions": {
|
"actions": {
|
||||||
"backordered": "",
|
"backordered": "",
|
||||||
"receive": "",
|
"receive": "",
|
||||||
"receiveinvoice": ""
|
"receivebill": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"backordering": "",
|
"backordering": "",
|
||||||
@@ -1451,13 +1451,13 @@
|
|||||||
"accounting-payments": "",
|
"accounting-payments": "",
|
||||||
"accounting-receivables": "",
|
"accounting-receivables": "",
|
||||||
"availablejobs": "",
|
"availablejobs": "",
|
||||||
|
"bills-list": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"contracts-create": "",
|
"contracts-create": "",
|
||||||
"contracts-detail": "",
|
"contracts-detail": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-detail": "",
|
"courtesycars-detail": "",
|
||||||
"courtesycars-new": "",
|
"courtesycars-new": "",
|
||||||
"invoices-list": "",
|
|
||||||
"jobs": "",
|
"jobs": "",
|
||||||
"jobs-active": "",
|
"jobs-active": "",
|
||||||
"jobs-all": "",
|
"jobs-all": "",
|
||||||
@@ -1481,13 +1481,13 @@
|
|||||||
"vehicle-details": "",
|
"vehicle-details": "",
|
||||||
"vehicles": ""
|
"vehicles": ""
|
||||||
},
|
},
|
||||||
|
"bills-list": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"contracts-create": "",
|
"contracts-create": "",
|
||||||
"contracts-detail": "",
|
"contracts-detail": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-create": "",
|
"courtesycars-create": "",
|
||||||
"courtesycars-detail": "",
|
"courtesycars-detail": "",
|
||||||
"invoices-list": "",
|
|
||||||
"jobs": "Todos los trabajos | $t(titles.app)",
|
"jobs": "Todos los trabajos | $t(titles.app)",
|
||||||
"jobs-all": "",
|
"jobs-all": "",
|
||||||
"jobs-close": "",
|
"jobs-close": "",
|
||||||
|
|||||||
@@ -73,6 +73,76 @@
|
|||||||
"values": ""
|
"values": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"billlines": {
|
||||||
|
"actions": {
|
||||||
|
"newline": ""
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"actual": "",
|
||||||
|
"actual_cost": "",
|
||||||
|
"cost_center": "",
|
||||||
|
"federal_tax_applicable": "",
|
||||||
|
"jobline": "",
|
||||||
|
"line_desc": "",
|
||||||
|
"local_tax_applicable": "",
|
||||||
|
"quantity": "",
|
||||||
|
"retail": "",
|
||||||
|
"state_tax_applicable": ""
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"entered": "",
|
||||||
|
"other": "",
|
||||||
|
"reconciled": "",
|
||||||
|
"unreconciled": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bills": {
|
||||||
|
"actions": {
|
||||||
|
"edit": "",
|
||||||
|
"receive": "",
|
||||||
|
"return": ""
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"creating": "",
|
||||||
|
"exporting": "",
|
||||||
|
"exporting-partner": "",
|
||||||
|
"invalidro": "",
|
||||||
|
"invalidvendor": "",
|
||||||
|
"validation": ""
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"allpartslocation": "",
|
||||||
|
"date": "",
|
||||||
|
"federal_tax_rate": "",
|
||||||
|
"invoice_number": "",
|
||||||
|
"is_credit_memo": "",
|
||||||
|
"local_tax_rate": "",
|
||||||
|
"ro_number": "",
|
||||||
|
"state_tax_rate": "",
|
||||||
|
"total": "",
|
||||||
|
"vendor": "",
|
||||||
|
"vendorname": ""
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"actions": "",
|
||||||
|
"bill_lines": "",
|
||||||
|
"bill_total": "",
|
||||||
|
"bills": "",
|
||||||
|
"discrepancy": "",
|
||||||
|
"entered_total": "",
|
||||||
|
"enteringcreditmemo": "",
|
||||||
|
"federal_tax": "",
|
||||||
|
"local_tax": "",
|
||||||
|
"new": "",
|
||||||
|
"noneselected": "",
|
||||||
|
"retailtotal": "",
|
||||||
|
"state_tax": "",
|
||||||
|
"subtotal": ""
|
||||||
|
},
|
||||||
|
"successes": {
|
||||||
|
"created": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addbucket": "",
|
"addbucket": "",
|
||||||
@@ -91,6 +161,9 @@
|
|||||||
"address1": "",
|
"address1": "",
|
||||||
"address2": "",
|
"address2": "",
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
|
"bill_federal_tax_rate": "",
|
||||||
|
"bill_local_tax_rate": "",
|
||||||
|
"bill_state_tax_rate": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
"country": "",
|
"country": "",
|
||||||
"dailybodytarget": "",
|
"dailybodytarget": "",
|
||||||
@@ -99,9 +172,6 @@
|
|||||||
"enforce_class": "",
|
"enforce_class": "",
|
||||||
"federal_tax_id": "",
|
"federal_tax_id": "",
|
||||||
"insurance_vendor_id": "",
|
"insurance_vendor_id": "",
|
||||||
"invoice_federal_tax_rate": "",
|
|
||||||
"invoice_local_tax_rate": "",
|
|
||||||
"invoice_state_tax_rate": "",
|
|
||||||
"lastnumberworkingdays": "",
|
"lastnumberworkingdays": "",
|
||||||
"logo_img_path": "",
|
"logo_img_path": "",
|
||||||
"md_categories": "",
|
"md_categories": "",
|
||||||
@@ -121,6 +191,11 @@
|
|||||||
"payments": "",
|
"payments": "",
|
||||||
"receivables": ""
|
"receivables": ""
|
||||||
},
|
},
|
||||||
|
"bills": {
|
||||||
|
"enter": "",
|
||||||
|
"list": "",
|
||||||
|
"view": ""
|
||||||
|
},
|
||||||
"contracts": {
|
"contracts": {
|
||||||
"create": "",
|
"create": "",
|
||||||
"detail": "",
|
"detail": "",
|
||||||
@@ -138,11 +213,6 @@
|
|||||||
"employees": {
|
"employees": {
|
||||||
"page": ""
|
"page": ""
|
||||||
},
|
},
|
||||||
"invoices": {
|
|
||||||
"enter": "",
|
|
||||||
"list": "",
|
|
||||||
"view": ""
|
|
||||||
},
|
|
||||||
"jobs": {
|
"jobs": {
|
||||||
"available-list": "",
|
"available-list": "",
|
||||||
"close": "",
|
"close": "",
|
||||||
@@ -614,76 +684,6 @@
|
|||||||
"rescuetitle": ""
|
"rescuetitle": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invoicelines": {
|
|
||||||
"actions": {
|
|
||||||
"newline": ""
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"actual": "",
|
|
||||||
"actual_cost": "",
|
|
||||||
"cost_center": "",
|
|
||||||
"federal_tax_applicable": "",
|
|
||||||
"jobline": "",
|
|
||||||
"line_desc": "",
|
|
||||||
"local_tax_applicable": "",
|
|
||||||
"quantity": "",
|
|
||||||
"retail": "",
|
|
||||||
"state_tax_applicable": ""
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"entered": "",
|
|
||||||
"other": "",
|
|
||||||
"reconciled": "",
|
|
||||||
"unreconciled": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"invoices": {
|
|
||||||
"actions": {
|
|
||||||
"edit": "",
|
|
||||||
"receive": "",
|
|
||||||
"return": ""
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"creating": "",
|
|
||||||
"exporting": "",
|
|
||||||
"exporting-partner": "",
|
|
||||||
"invalidro": "",
|
|
||||||
"invalidvendor": "",
|
|
||||||
"validation": ""
|
|
||||||
},
|
|
||||||
"fields": {
|
|
||||||
"allpartslocation": "",
|
|
||||||
"date": "",
|
|
||||||
"federal_tax_rate": "",
|
|
||||||
"invoice_number": "",
|
|
||||||
"is_credit_memo": "",
|
|
||||||
"local_tax_rate": "",
|
|
||||||
"ro_number": "",
|
|
||||||
"state_tax_rate": "",
|
|
||||||
"total": "",
|
|
||||||
"vendor": "",
|
|
||||||
"vendorname": ""
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"actions": "",
|
|
||||||
"discrepancy": "",
|
|
||||||
"entered_total": "",
|
|
||||||
"enteringcreditmemo": "",
|
|
||||||
"federal_tax": "",
|
|
||||||
"invoice_lines": "",
|
|
||||||
"invoice_total": "",
|
|
||||||
"invoices": "",
|
|
||||||
"local_tax": "",
|
|
||||||
"new": "",
|
|
||||||
"noneselected": "",
|
|
||||||
"retailtotal": "",
|
|
||||||
"state_tax": "",
|
|
||||||
"subtotal": ""
|
|
||||||
},
|
|
||||||
"successes": {
|
|
||||||
"created": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"joblines": {
|
"joblines": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": ""
|
"new": ""
|
||||||
@@ -778,7 +778,7 @@
|
|||||||
"intake": "",
|
"intake": "",
|
||||||
"manualnew": "",
|
"manualnew": "",
|
||||||
"mark": "",
|
"mark": "",
|
||||||
"postInvoices": "Poster des factures",
|
"postbills": "Poster des factures",
|
||||||
"printCenter": "Centre d'impression",
|
"printCenter": "Centre d'impression",
|
||||||
"recalculate": "",
|
"recalculate": "",
|
||||||
"reconcile": "",
|
"reconcile": "",
|
||||||
@@ -1071,17 +1071,17 @@
|
|||||||
"alljobs": "",
|
"alljobs": "",
|
||||||
"allpayments": "",
|
"allpayments": "",
|
||||||
"availablejobs": "Emplois disponibles",
|
"availablejobs": "Emplois disponibles",
|
||||||
|
"bills": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-all": "",
|
"courtesycars-all": "",
|
||||||
"courtesycars-contracts": "",
|
"courtesycars-contracts": "",
|
||||||
"courtesycars-newcontract": "",
|
"courtesycars-newcontract": "",
|
||||||
"customers": "Les clients",
|
"customers": "Les clients",
|
||||||
"enterinvoices": "",
|
"enterbills": "",
|
||||||
"enterpayment": "",
|
"enterpayment": "",
|
||||||
"entertimeticket": "",
|
"entertimeticket": "",
|
||||||
"export": "",
|
"export": "",
|
||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
"invoices": "",
|
|
||||||
"jobs": "Emplois",
|
"jobs": "Emplois",
|
||||||
"owners": "Propriétaires",
|
"owners": "Propriétaires",
|
||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
@@ -1221,7 +1221,7 @@
|
|||||||
"actions": {
|
"actions": {
|
||||||
"backordered": "",
|
"backordered": "",
|
||||||
"receive": "",
|
"receive": "",
|
||||||
"receiveinvoice": ""
|
"receivebill": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"backordering": "",
|
"backordering": "",
|
||||||
@@ -1451,13 +1451,13 @@
|
|||||||
"accounting-payments": "",
|
"accounting-payments": "",
|
||||||
"accounting-receivables": "",
|
"accounting-receivables": "",
|
||||||
"availablejobs": "",
|
"availablejobs": "",
|
||||||
|
"bills-list": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"contracts-create": "",
|
"contracts-create": "",
|
||||||
"contracts-detail": "",
|
"contracts-detail": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-detail": "",
|
"courtesycars-detail": "",
|
||||||
"courtesycars-new": "",
|
"courtesycars-new": "",
|
||||||
"invoices-list": "",
|
|
||||||
"jobs": "",
|
"jobs": "",
|
||||||
"jobs-active": "",
|
"jobs-active": "",
|
||||||
"jobs-all": "",
|
"jobs-all": "",
|
||||||
@@ -1481,13 +1481,13 @@
|
|||||||
"vehicle-details": "",
|
"vehicle-details": "",
|
||||||
"vehicles": ""
|
"vehicles": ""
|
||||||
},
|
},
|
||||||
|
"bills-list": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"contracts-create": "",
|
"contracts-create": "",
|
||||||
"contracts-detail": "",
|
"contracts-detail": "",
|
||||||
"courtesycars": "",
|
"courtesycars": "",
|
||||||
"courtesycars-create": "",
|
"courtesycars-create": "",
|
||||||
"courtesycars-detail": "",
|
"courtesycars-detail": "",
|
||||||
"invoices-list": "",
|
|
||||||
"jobs": "Tous les emplois | $t(titles.app)",
|
"jobs": "Tous les emplois | $t(titles.app)",
|
||||||
"jobs-all": "",
|
"jobs-all": "",
|
||||||
"jobs-close": "",
|
"jobs-close": "",
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: true
|
||||||
|
read_only: false
|
||||||
|
sql: DROP FUNCTION IF EXISTS search_invoices;
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."bills" rename to "invoices";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."invoices" rename to "bills";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."billlines" rename to "invoicelines";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."invoicelines" rename to "billlines";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."billlines" rename column "billid" to "invoiceid";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."billlines" rename column "invoiceid" to "billid";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: bill
|
||||||
|
new_name: invoice
|
||||||
|
table:
|
||||||
|
name: billlines
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoice
|
||||||
|
new_name: bill
|
||||||
|
table:
|
||||||
|
name: billlines
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: bill
|
||||||
|
new_name: invoice
|
||||||
|
table:
|
||||||
|
name: jobs
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoice
|
||||||
|
new_name: bill
|
||||||
|
table:
|
||||||
|
name: jobs
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: bills
|
||||||
|
new_name: invoices
|
||||||
|
table:
|
||||||
|
name: jobs
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoices
|
||||||
|
new_name: bills
|
||||||
|
table:
|
||||||
|
name: jobs
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: bill
|
||||||
|
new_name: invoice
|
||||||
|
table:
|
||||||
|
name: documents
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoice
|
||||||
|
new_name: bill
|
||||||
|
table:
|
||||||
|
name: documents
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: bill
|
||||||
|
new_name: invoice
|
||||||
|
table:
|
||||||
|
name: parts_orders
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoice
|
||||||
|
new_name: bill
|
||||||
|
table:
|
||||||
|
name: parts_orders
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
- args:
|
||||||
|
cascade: true
|
||||||
|
read_only: false
|
||||||
|
sql: "CREATE OR REPLACE FUNCTION public.search_bills(search text)\n RETURNS SETOF
|
||||||
|
bills\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = ''
|
||||||
|
then\n return query select * from bills ;\n else \n return query SELECT\n
|
||||||
|
\ *\nFROM\n bills\nWHERE\n search <% (invoice_number);\n end if;\n\n\tEND\n$function$;"
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: billlines
|
||||||
|
new_name: invoicelines
|
||||||
|
table:
|
||||||
|
name: bills
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
- args:
|
||||||
|
name: invoicelines
|
||||||
|
new_name: billlines
|
||||||
|
table:
|
||||||
|
name: bills
|
||||||
|
schema: public
|
||||||
|
type: rename_relationship
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
- args:
|
||||||
|
cascade: true
|
||||||
|
read_only: false
|
||||||
|
sql: "CREATE OR REPLACE FUNCTION public.search_bills(search text)\n RETURNS SETOF
|
||||||
|
bills\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = ''
|
||||||
|
then\n return query select * from bills ;\n else \n return query SELECT\n
|
||||||
|
\ *\nFROM\n bills\nWHERE\n search <% (invoice_number);\n end if;\n\n\tEND\n$function$;"
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
12
hasura/migrations/1600814334466_run_sql_migration/up.yaml
Normal file
12
hasura/migrations/1600814334466_run_sql_migration/up.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
- args:
|
||||||
|
cascade: true
|
||||||
|
read_only: false
|
||||||
|
sql: "CREATE OR REPLACE FUNCTION public.search_bills(search text)\n RETURNS SETOF
|
||||||
|
bills\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = ''
|
||||||
|
then\n return query select * from bills ;\n else \n return query SELECT\n
|
||||||
|
\ *\nFROM\n bills\nWHERE\n search <% (invoice_number);\n end if;\n\n\tEND\n$function$;"
|
||||||
|
type: run_sql
|
||||||
|
- args:
|
||||||
|
name: search_bills
|
||||||
|
schema: public
|
||||||
|
type: track_function
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."documents" rename column "billid" to "invoiceid";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."documents" rename column "invoiceid" to "billid";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."bodyshops" rename column "bill_tax_rates" to "invoice_tax_rates";
|
||||||
|
type: run_sql
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
- args:
|
||||||
|
cascade: false
|
||||||
|
read_only: false
|
||||||
|
sql: alter table "public"."bodyshops" rename column "invoice_tax_rates" to "bill_tax_rates";
|
||||||
|
type: run_sql
|
||||||
@@ -348,6 +348,227 @@ tables:
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: billlines
|
||||||
|
object_relationships:
|
||||||
|
- name: bill
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: billid
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
bill:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
columns:
|
||||||
|
- actual_cost
|
||||||
|
- actual_price
|
||||||
|
- applicable_taxes
|
||||||
|
- cost_center
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- billid
|
||||||
|
- joblineid
|
||||||
|
- line_desc
|
||||||
|
- quantity
|
||||||
|
- updated_at
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- actual_cost
|
||||||
|
- actual_price
|
||||||
|
- applicable_taxes
|
||||||
|
- cost_center
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- billid
|
||||||
|
- joblineid
|
||||||
|
- line_desc
|
||||||
|
- quantity
|
||||||
|
- updated_at
|
||||||
|
filter:
|
||||||
|
bill:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- actual_cost
|
||||||
|
- actual_price
|
||||||
|
- applicable_taxes
|
||||||
|
- cost_center
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- billid
|
||||||
|
- joblineid
|
||||||
|
- line_desc
|
||||||
|
- quantity
|
||||||
|
- updated_at
|
||||||
|
filter:
|
||||||
|
bill:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
check: null
|
||||||
|
delete_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
filter:
|
||||||
|
bill:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
- table:
|
||||||
|
schema: public
|
||||||
|
name: bills
|
||||||
|
object_relationships:
|
||||||
|
- name: job
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: jobid
|
||||||
|
- name: vendor
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: vendorid
|
||||||
|
array_relationships:
|
||||||
|
- name: billlines
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: billid
|
||||||
|
table:
|
||||||
|
schema: public
|
||||||
|
name: billlines
|
||||||
|
- name: documents
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: billid
|
||||||
|
table:
|
||||||
|
schema: public
|
||||||
|
name: documents
|
||||||
|
- name: parts_orders
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: returnfrominvoice
|
||||||
|
table:
|
||||||
|
schema: public
|
||||||
|
name: parts_orders
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
columns:
|
||||||
|
- created_at
|
||||||
|
- date
|
||||||
|
- due_date
|
||||||
|
- exported
|
||||||
|
- exported_at
|
||||||
|
- federal_tax_rate
|
||||||
|
- id
|
||||||
|
- invoice_number
|
||||||
|
- is_credit_memo
|
||||||
|
- jobid
|
||||||
|
- local_tax_rate
|
||||||
|
- state_tax_rate
|
||||||
|
- total
|
||||||
|
- updated_at
|
||||||
|
- vendorid
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- created_at
|
||||||
|
- date
|
||||||
|
- due_date
|
||||||
|
- exported
|
||||||
|
- exported_at
|
||||||
|
- federal_tax_rate
|
||||||
|
- id
|
||||||
|
- invoice_number
|
||||||
|
- is_credit_memo
|
||||||
|
- jobid
|
||||||
|
- local_tax_rate
|
||||||
|
- state_tax_rate
|
||||||
|
- total
|
||||||
|
- updated_at
|
||||||
|
- vendorid
|
||||||
|
filter:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
allow_aggregations: true
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- created_at
|
||||||
|
- date
|
||||||
|
- due_date
|
||||||
|
- exported
|
||||||
|
- exported_at
|
||||||
|
- federal_tax_rate
|
||||||
|
- id
|
||||||
|
- invoice_number
|
||||||
|
- is_credit_memo
|
||||||
|
- jobid
|
||||||
|
- local_tax_rate
|
||||||
|
- state_tax_rate
|
||||||
|
- total
|
||||||
|
- updated_at
|
||||||
|
- vendorid
|
||||||
|
filter:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
check: null
|
||||||
- table:
|
- table:
|
||||||
schema: public
|
schema: public
|
||||||
name: bodyshops
|
name: bodyshops
|
||||||
@@ -483,7 +704,7 @@ tables:
|
|||||||
- inhousevendorid
|
- inhousevendorid
|
||||||
- insurance_vendor_id
|
- insurance_vendor_id
|
||||||
- intakechecklist
|
- intakechecklist
|
||||||
- invoice_tax_rates
|
- bill_tax_rates
|
||||||
- logo_img_path
|
- logo_img_path
|
||||||
- md_categories
|
- md_categories
|
||||||
- md_classes
|
- md_classes
|
||||||
@@ -541,7 +762,7 @@ tables:
|
|||||||
- inhousevendorid
|
- inhousevendorid
|
||||||
- insurance_vendor_id
|
- insurance_vendor_id
|
||||||
- intakechecklist
|
- intakechecklist
|
||||||
- invoice_tax_rates
|
- bill_tax_rates
|
||||||
- logo_img_path
|
- logo_img_path
|
||||||
- md_categories
|
- md_categories
|
||||||
- md_classes
|
- md_classes
|
||||||
@@ -1170,9 +1391,9 @@ tables:
|
|||||||
schema: public
|
schema: public
|
||||||
name: documents
|
name: documents
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: invoice
|
- name: bill
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: invoiceid
|
foreign_key_constraint_on: billid
|
||||||
- name: job
|
- name: job
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: jobid
|
foreign_key_constraint_on: jobid
|
||||||
@@ -1197,7 +1418,7 @@ tables:
|
|||||||
- jobid
|
- jobid
|
||||||
- name
|
- name
|
||||||
- key
|
- key
|
||||||
- invoiceid
|
- billid
|
||||||
- type
|
- type
|
||||||
select_permissions:
|
select_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
@@ -1210,7 +1431,7 @@ tables:
|
|||||||
- created_at
|
- created_at
|
||||||
- updated_at
|
- updated_at
|
||||||
- id
|
- id
|
||||||
- invoiceid
|
- billid
|
||||||
- jobid
|
- jobid
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
@@ -1393,227 +1614,6 @@ tables:
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
- table:
|
|
||||||
schema: public
|
|
||||||
name: invoicelines
|
|
||||||
object_relationships:
|
|
||||||
- name: invoice
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: invoiceid
|
|
||||||
insert_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
check:
|
|
||||||
invoice:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
columns:
|
|
||||||
- actual_cost
|
|
||||||
- actual_price
|
|
||||||
- applicable_taxes
|
|
||||||
- cost_center
|
|
||||||
- created_at
|
|
||||||
- id
|
|
||||||
- invoiceid
|
|
||||||
- joblineid
|
|
||||||
- line_desc
|
|
||||||
- quantity
|
|
||||||
- updated_at
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- actual_cost
|
|
||||||
- actual_price
|
|
||||||
- applicable_taxes
|
|
||||||
- cost_center
|
|
||||||
- created_at
|
|
||||||
- id
|
|
||||||
- invoiceid
|
|
||||||
- joblineid
|
|
||||||
- line_desc
|
|
||||||
- quantity
|
|
||||||
- updated_at
|
|
||||||
filter:
|
|
||||||
invoice:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
update_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- actual_cost
|
|
||||||
- actual_price
|
|
||||||
- applicable_taxes
|
|
||||||
- cost_center
|
|
||||||
- created_at
|
|
||||||
- id
|
|
||||||
- invoiceid
|
|
||||||
- joblineid
|
|
||||||
- line_desc
|
|
||||||
- quantity
|
|
||||||
- updated_at
|
|
||||||
filter:
|
|
||||||
invoice:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
check: null
|
|
||||||
delete_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
filter:
|
|
||||||
invoice:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
- table:
|
|
||||||
schema: public
|
|
||||||
name: invoices
|
|
||||||
object_relationships:
|
|
||||||
- name: job
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: jobid
|
|
||||||
- name: vendor
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: vendorid
|
|
||||||
array_relationships:
|
|
||||||
- name: documents
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on:
|
|
||||||
column: invoiceid
|
|
||||||
table:
|
|
||||||
schema: public
|
|
||||||
name: documents
|
|
||||||
- name: invoicelines
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on:
|
|
||||||
column: invoiceid
|
|
||||||
table:
|
|
||||||
schema: public
|
|
||||||
name: invoicelines
|
|
||||||
- name: parts_orders
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on:
|
|
||||||
column: returnfrominvoice
|
|
||||||
table:
|
|
||||||
schema: public
|
|
||||||
name: parts_orders
|
|
||||||
insert_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
check:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
columns:
|
|
||||||
- created_at
|
|
||||||
- date
|
|
||||||
- due_date
|
|
||||||
- exported
|
|
||||||
- exported_at
|
|
||||||
- federal_tax_rate
|
|
||||||
- id
|
|
||||||
- invoice_number
|
|
||||||
- is_credit_memo
|
|
||||||
- jobid
|
|
||||||
- local_tax_rate
|
|
||||||
- state_tax_rate
|
|
||||||
- total
|
|
||||||
- updated_at
|
|
||||||
- vendorid
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- created_at
|
|
||||||
- date
|
|
||||||
- due_date
|
|
||||||
- exported
|
|
||||||
- exported_at
|
|
||||||
- federal_tax_rate
|
|
||||||
- id
|
|
||||||
- invoice_number
|
|
||||||
- is_credit_memo
|
|
||||||
- jobid
|
|
||||||
- local_tax_rate
|
|
||||||
- state_tax_rate
|
|
||||||
- total
|
|
||||||
- updated_at
|
|
||||||
- vendorid
|
|
||||||
filter:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
allow_aggregations: true
|
|
||||||
update_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- created_at
|
|
||||||
- date
|
|
||||||
- due_date
|
|
||||||
- exported
|
|
||||||
- exported_at
|
|
||||||
- federal_tax_rate
|
|
||||||
- id
|
|
||||||
- invoice_number
|
|
||||||
- is_credit_memo
|
|
||||||
- jobid
|
|
||||||
- local_tax_rate
|
|
||||||
- state_tax_rate
|
|
||||||
- total
|
|
||||||
- updated_at
|
|
||||||
- vendorid
|
|
||||||
filter:
|
|
||||||
job:
|
|
||||||
bodyshop:
|
|
||||||
associations:
|
|
||||||
_and:
|
|
||||||
- user:
|
|
||||||
authid:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- active:
|
|
||||||
_eq: true
|
|
||||||
check: null
|
|
||||||
- table:
|
- table:
|
||||||
schema: public
|
schema: public
|
||||||
name: job_conversations
|
name: job_conversations
|
||||||
@@ -1961,6 +1961,14 @@ tables:
|
|||||||
schema: public
|
schema: public
|
||||||
name: jobs
|
name: jobs
|
||||||
object_relationships:
|
object_relationships:
|
||||||
|
- name: bill
|
||||||
|
using:
|
||||||
|
manual_configuration:
|
||||||
|
remote_table:
|
||||||
|
schema: public
|
||||||
|
name: bills
|
||||||
|
column_mapping:
|
||||||
|
id: jobid
|
||||||
- name: bodyshop
|
- name: bodyshop
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: shopid
|
foreign_key_constraint_on: shopid
|
||||||
@@ -1973,14 +1981,6 @@ tables:
|
|||||||
- name: employee_refinish_rel
|
- name: employee_refinish_rel
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: employee_refinish
|
foreign_key_constraint_on: employee_refinish
|
||||||
- name: invoice
|
|
||||||
using:
|
|
||||||
manual_configuration:
|
|
||||||
remote_table:
|
|
||||||
schema: public
|
|
||||||
name: invoices
|
|
||||||
column_mapping:
|
|
||||||
id: jobid
|
|
||||||
- name: owner
|
- name: owner
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: ownerid
|
foreign_key_constraint_on: ownerid
|
||||||
@@ -2002,6 +2002,13 @@ tables:
|
|||||||
table:
|
table:
|
||||||
schema: public
|
schema: public
|
||||||
name: available_jobs
|
name: available_jobs
|
||||||
|
- name: bills
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: jobid
|
||||||
|
table:
|
||||||
|
schema: public
|
||||||
|
name: bills
|
||||||
- name: cccontracts
|
- name: cccontracts
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -2023,13 +2030,6 @@ tables:
|
|||||||
table:
|
table:
|
||||||
schema: public
|
schema: public
|
||||||
name: documents
|
name: documents
|
||||||
- name: invoices
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on:
|
|
||||||
column: jobid
|
|
||||||
table:
|
|
||||||
schema: public
|
|
||||||
name: invoices
|
|
||||||
- name: job_conversations
|
- name: job_conversations
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -3298,7 +3298,7 @@ tables:
|
|||||||
schema: public
|
schema: public
|
||||||
name: parts_orders
|
name: parts_orders
|
||||||
object_relationships:
|
object_relationships:
|
||||||
- name: invoice
|
- name: bill
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: returnfrominvoice
|
foreign_key_constraint_on: returnfrominvoice
|
||||||
- name: job
|
- name: job
|
||||||
@@ -4019,7 +4019,7 @@ tables:
|
|||||||
column: vendorid
|
column: vendorid
|
||||||
table:
|
table:
|
||||||
schema: public
|
schema: public
|
||||||
name: invoices
|
name: bills
|
||||||
- name: parts_orders
|
- name: parts_orders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -4142,7 +4142,7 @@ tables:
|
|||||||
functions:
|
functions:
|
||||||
- function:
|
- function:
|
||||||
schema: public
|
schema: public
|
||||||
name: search_invoices
|
name: search_bills
|
||||||
- function:
|
- function:
|
||||||
schema: public
|
schema: public
|
||||||
name: search_jobs
|
name: search_jobs
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ require("dotenv").config({
|
|||||||
|
|
||||||
exports.default = async (req, res) => {
|
exports.default = async (req, res) => {
|
||||||
const BearerToken = req.headers.authorization;
|
const BearerToken = req.headers.authorization;
|
||||||
const { invoices: invoicesToQuery } = req.body;
|
const { bills: billsToQuery } = req.body;
|
||||||
|
|
||||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -25,13 +25,13 @@ exports.default = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: BearerToken })
|
.setHeaders({ Authorization: BearerToken })
|
||||||
.request(queries.QUERY_INVOICES_FOR_PAYABLES_EXPORT, {
|
.request(queries.QUERY_BILLS_FOR_PAYABLES_EXPORT, {
|
||||||
invoices: invoicesToQuery,
|
bills: billsToQuery,
|
||||||
});
|
});
|
||||||
const { invoices } = result;
|
const { bills } = result;
|
||||||
|
|
||||||
const QbXmlToExecute = [];
|
const QbXmlToExecute = [];
|
||||||
invoices.map((i) => {
|
bills.map((i) => {
|
||||||
QbXmlToExecute.push({
|
QbXmlToExecute.push({
|
||||||
id: i.id,
|
id: i.id,
|
||||||
okStatusCodes: ["0"],
|
okStatusCodes: ["0"],
|
||||||
@@ -48,27 +48,24 @@ exports.default = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateBill = (invoice) => {
|
const generateBill = (bill) => {
|
||||||
const billQbxmlObj = {
|
const billQbxmlObj = {
|
||||||
QBXML: {
|
QBXML: {
|
||||||
QBXMLMsgsRq: {
|
QBXMLMsgsRq: {
|
||||||
"@onError": "continueOnError",
|
"@onError": "continueOnError",
|
||||||
[`${invoice.is_credit_memo ? "VendorCreditAddRq" : "BillAddRq"}`]: {
|
[`${bill.is_credit_memo ? "VendorCreditAddRq" : "BillAddRq"}`]: {
|
||||||
[`${invoice.is_credit_memo ? "VendorCreditAdd" : "BillAdd"}`]: {
|
[`${bill.is_credit_memo ? "VendorCreditAdd" : "BillAdd"}`]: {
|
||||||
VendorRef: {
|
VendorRef: {
|
||||||
FullName: invoice.vendor.name,
|
FullName: bill.vendor.name,
|
||||||
},
|
},
|
||||||
TxnDate: invoice.date,
|
TxnDate: bill.date,
|
||||||
DueDate: invoice.due_date,
|
DueDate: bill.due_date,
|
||||||
RefNumber: invoice.invoice_number,
|
RefNumber: bill.bill_number,
|
||||||
Memo: `RO ${invoice.job.ro_number || ""} OWNER ${
|
Memo: `RO ${bill.job.ro_number || ""} OWNER ${
|
||||||
invoice.job.ownr_fn || ""
|
bill.job.ownr_fn || ""
|
||||||
} ${invoice.job.ownr_ln || ""} ${invoice.job.ownr_co_nm || ""}`,
|
} ${bill.job.ownr_ln || ""} ${bill.job.ownr_co_nm || ""}`,
|
||||||
ExpenseLineAdd: invoice.invoicelines.map((il) =>
|
ExpenseLineAdd: bill.billlines.map((il) =>
|
||||||
generateBillLine(
|
generateBillLine(il, bill.job.bodyshop.md_responsibility_centers)
|
||||||
il,
|
|
||||||
invoice.job.bodyshop.md_responsibility_centers
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -90,15 +87,15 @@ const generateBill = (invoice) => {
|
|||||||
return billQbxml_Full;
|
return billQbxml_Full;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateBillLine = (invoiceLine, responsibilityCenters) => {
|
const generateBillLine = (billLine, responsibilityCenters) => {
|
||||||
return {
|
return {
|
||||||
AccountRef: {
|
AccountRef: {
|
||||||
FullName: responsibilityCenters.costs.find(
|
FullName: responsibilityCenters.costs.find(
|
||||||
(c) => c.name === invoiceLine.cost_center
|
(c) => c.name === billLine.cost_center
|
||||||
).accountname,
|
).accountname,
|
||||||
},
|
},
|
||||||
Amount: Dinero({
|
Amount: Dinero({
|
||||||
amount: Math.round(invoiceLine.actual_cost * 100),
|
amount: Math.round(billLine.actual_cost * 100),
|
||||||
}).toFormat(DineroQbFormat),
|
}).toFormat(DineroQbFormat),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports.QUERY_INVOICES_FOR_PAYABLES_EXPORT = `
|
exports.QUERY_BILLS_FOR_PAYABLES_EXPORT = `
|
||||||
query QUERY_INVOICES_FOR_PAYABLES_EXPORT($invoices: [uuid!]!) {
|
query QUERY_BILLS_FOR_PAYABLES_EXPORT($bills: [uuid!]!) {
|
||||||
invoices(where: {id: {_in: $invoices}}) {
|
bills(where: {id: {_in: $bills}}) {
|
||||||
id
|
id
|
||||||
date
|
date
|
||||||
due_date
|
due_date
|
||||||
@@ -128,7 +128,7 @@ query QUERY_INVOICES_FOR_PAYABLES_EXPORT($invoices: [uuid!]!) {
|
|||||||
md_responsibility_centers
|
md_responsibility_centers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invoicelines{
|
billlines{
|
||||||
id
|
id
|
||||||
cost_center
|
cost_center
|
||||||
actual_cost
|
actual_cost
|
||||||
|
|||||||
Reference in New Issue
Block a user