Added parts backorder + receiving for orders BOD-159
This commit is contained in:
24
_reference/SampleMetadata.md
Normal file
24
_reference/SampleMetadata.md
Normal file
File diff suppressed because one or more lines are too long
@@ -14513,6 +14513,53 @@
|
||||
<folder_node>
|
||||
<name>parts_orders</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>actions</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>backordered</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>receive</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>errors</name>
|
||||
<children>
|
||||
@@ -14689,6 +14736,69 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>oem_partno</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>order_date</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>order_number</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>quantity</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -14710,6 +14820,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>status</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
|
||||
@@ -8,6 +8,8 @@ import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import queryString from "query-string";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPartsOrderContext: (context) =>
|
||||
@@ -22,7 +24,6 @@ export function InvoicesListTableComponent({
|
||||
job,
|
||||
loading,
|
||||
invoicesQuery,
|
||||
selectedInvoice,
|
||||
handleOnRowClick,
|
||||
setPartsOrderContext,
|
||||
setInvoiceEnterContext,
|
||||
@@ -32,6 +33,8 @@ export function InvoicesListTableComponent({
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
});
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const selectedInvoice = search.invoiceid;
|
||||
|
||||
const invoices = invoicesQuery.data ? invoicesQuery.data.invoices : [];
|
||||
const { refetch } = invoicesQuery;
|
||||
@@ -91,7 +94,8 @@ export function InvoicesListTableComponent({
|
||||
render: (text, record) => (
|
||||
<div>
|
||||
<Link
|
||||
to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}>
|
||||
to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}
|
||||
>
|
||||
<Button>{t("invoices.actions.edit")}</Button>
|
||||
</Link>
|
||||
<Button
|
||||
@@ -116,7 +120,8 @@ export function InvoicesListTableComponent({
|
||||
isReturn: true,
|
||||
},
|
||||
})
|
||||
}>
|
||||
}
|
||||
>
|
||||
{t("invoices.actions.return")}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -232,11 +237,11 @@ export function InvoicesListTableComponent({
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<Table
|
||||
size='small'
|
||||
size="small"
|
||||
scroll={{ x: "50%", y: "40rem" }}
|
||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||
columns={columns}
|
||||
rowKey='id'
|
||||
rowKey="id"
|
||||
dataSource={record.invoicelines}
|
||||
/>
|
||||
</div>
|
||||
@@ -246,9 +251,9 @@ export function InvoicesListTableComponent({
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
size='small'
|
||||
size="small"
|
||||
title={() => (
|
||||
<div className='imex-table-header'>
|
||||
<div className="imex-table-header">
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
@@ -260,7 +265,8 @@ export function InvoicesListTableComponent({
|
||||
job,
|
||||
},
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Button>
|
||||
<Button
|
||||
@@ -273,10 +279,11 @@ export function InvoicesListTableComponent({
|
||||
(invoicesQuery.data && invoicesQuery.data.invoices) || [],
|
||||
},
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.reconcile")}
|
||||
</Button>{" "}
|
||||
<div className='imex-table-header__search'>
|
||||
<div className="imex-table-header__search">
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
@@ -290,7 +297,7 @@ export function InvoicesListTableComponent({
|
||||
expandedRowRender={rowExpander}
|
||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||
columns={columns}
|
||||
rowKey='id'
|
||||
rowKey="id"
|
||||
dataSource={invoices}
|
||||
onChange={handleTableChange}
|
||||
expandable={{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Dropdown, Input, Menu, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -11,6 +12,8 @@ import AllocationsAssignmentContainer from "../allocations-assignment/allocation
|
||||
import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
||||
import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
|
||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||
import queryString from "query-string";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setJobLineEditContext: (context) =>
|
||||
@@ -35,6 +38,9 @@ export function JobLinesComponent({
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const history = useHistory();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "#",
|
||||
@@ -213,7 +219,8 @@ export function JobLinesComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: record,
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("general.actions.edit")}
|
||||
</Button>
|
||||
<AllocationsAssignmentContainer
|
||||
@@ -237,9 +244,9 @@ export function JobLinesComponent({
|
||||
|
||||
const markMenu = (
|
||||
<Menu onClick={handleMark}>
|
||||
<Menu.Item key='PAA'>PAA</Menu.Item>
|
||||
<Menu.Item key='PAN'>PAN</Menu.Item>
|
||||
<Menu.Item key='PAL'>PAL</Menu.Item>
|
||||
<Menu.Item key="PAA">PAA</Menu.Item>
|
||||
<Menu.Item key="PAN">PAN</Menu.Item>
|
||||
<Menu.Item key="PAL">PAL</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -248,16 +255,19 @@ export function JobLinesComponent({
|
||||
<PartsOrderModalContainer />
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey='id'
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
size='small'
|
||||
size="small"
|
||||
pagination={{ position: "top", defaultPageSize: 50 }}
|
||||
dataSource={jobLines}
|
||||
onChange={handleTableChange}
|
||||
scroll={{ x: true, y: "40rem" }}
|
||||
title={() => {
|
||||
return (
|
||||
<div className='imex-table-header'>
|
||||
<div className="imex-table-header">
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<Button
|
||||
disabled={selectedLines.length > 0 ? false : true}
|
||||
onClick={() => {
|
||||
@@ -268,7 +278,8 @@ export function JobLinesComponent({
|
||||
linesToOrder: selectedLines,
|
||||
},
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("parts.actions.order")}
|
||||
</Button>
|
||||
<Dropdown overlay={markMenu} trigger={["click"]}>
|
||||
@@ -284,10 +295,11 @@ export function JobLinesComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: { jobid: jobId },
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("joblines.actions.new")}
|
||||
</Button>
|
||||
<div className='imex-table-header__search'>
|
||||
<div className="imex-table-header__search">
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
@@ -300,11 +312,16 @@ export function JobLinesComponent({
|
||||
);
|
||||
}}
|
||||
expandedRowRender={(record) => (
|
||||
<div style={{ margin: 0 }}>
|
||||
<div>
|
||||
<strong>{t("parts_orders.labels.orderhistory")}</strong>
|
||||
{record.parts_order_lines.map((item) => (
|
||||
<div key={item.id}>
|
||||
{`${item.parts_order.order_number || ""} from `}
|
||||
<Link
|
||||
to={`/manage/jobs/${jobId}?tab=partssublet&partsorderid=${item.parts_order.id}`}
|
||||
>
|
||||
{item.parts_order.order_number || ""}
|
||||
</Link>
|
||||
-
|
||||
<Link to={`/manage/shop/vendors/${item.parts_order.vendor.id}`}>
|
||||
{item.parts_order.vendor.name || ""}
|
||||
</Link>
|
||||
|
||||
@@ -44,7 +44,8 @@ export function JobsCloseExportButton({ bodyshop, jobId, disabled }) {
|
||||
let PartnerResponse;
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
// "http://localhost:1337/qb/",
|
||||
"http://b47e67f9cbe3.ngrok.io/qb/",
|
||||
QbXmlResponse.data,
|
||||
{
|
||||
headers: {
|
||||
|
||||
@@ -21,6 +21,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(setModalContext({ context: context, modal: "schedule" })),
|
||||
setInvoiceEnterContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "invoiceEnter" })),
|
||||
setPaymentContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||
});
|
||||
|
||||
export function JobsDetailHeaderActions({
|
||||
@@ -29,12 +31,13 @@ export function JobsDetailHeaderActions({
|
||||
refetch,
|
||||
setScheduleContext,
|
||||
setInvoiceEnterContext,
|
||||
setPaymentContext,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const client = useApolloClient();
|
||||
const history = useHistory();
|
||||
const statusmenu = (
|
||||
<Menu key='popovermenu'>
|
||||
<Menu key="popovermenu">
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
setScheduleContext({
|
||||
@@ -44,30 +47,43 @@ export function JobsDetailHeaderActions({
|
||||
job: job,
|
||||
},
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.schedule")}
|
||||
</Menu.Item>
|
||||
|
||||
<Menu.Item key='cccontract'>
|
||||
<Menu.Item
|
||||
key="enterpayments"
|
||||
onClick={() => {
|
||||
setPaymentContext({
|
||||
actions: {},
|
||||
context: { jobId: job.id },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("menus.header.enterpayment")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key="cccontract">
|
||||
<Link
|
||||
to={{
|
||||
pathname: "/manage/courtesycars/contracts/new",
|
||||
state: { jobId: job.id },
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("menus.jobsactions.newcccontract")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key='addtoproduction'
|
||||
key="addtoproduction"
|
||||
disabled={!!!job.converted || !!job.inproduction}
|
||||
onClick={() => AddToProduction(client, job.id, refetch)}>
|
||||
onClick={() => AddToProduction(client, job.id, refetch)}
|
||||
>
|
||||
{t("jobs.actions.addtoproduction")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key='duplicatejob'>
|
||||
<Menu.Item key="duplicatejob">
|
||||
<Popconfirm
|
||||
title={t("jobs.labels.duplicateconfirm")}
|
||||
okText='Yes'
|
||||
cancelText='No'
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onConfirm={() =>
|
||||
DuplicateJob(
|
||||
@@ -79,12 +95,13 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
)
|
||||
}
|
||||
getPopupContainer={(trigger) => trigger.parentNode}>
|
||||
getPopupContainer={(trigger) => trigger.parentNode}
|
||||
>
|
||||
{t("menus.jobsactions.duplicate")}
|
||||
</Popconfirm>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key='postinvoices'
|
||||
key="postinvoices"
|
||||
onClick={() => {
|
||||
setInvoiceEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
@@ -92,14 +109,16 @@ export function JobsDetailHeaderActions({
|
||||
job: job,
|
||||
},
|
||||
});
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.postInvoices")}
|
||||
</Menu.Item>
|
||||
<Menu.Item key='closejob'>
|
||||
<Menu.Item key="closejob">
|
||||
<Link
|
||||
to={{
|
||||
pathname: `/manage/jobs/${job.id}/close`,
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{t("menus.jobsactions.closejob")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
@@ -108,10 +127,11 @@ export function JobsDetailHeaderActions({
|
||||
);
|
||||
return (
|
||||
<Dropdown
|
||||
className='imex-flex-row__margin'
|
||||
className="imex-flex-row__margin"
|
||||
overlay={statusmenu}
|
||||
trigger={["click"]}
|
||||
key='changestatus'>
|
||||
key="changestatus"
|
||||
>
|
||||
<Button>
|
||||
{t("general.labels.actions")} <DownCircleFilled />
|
||||
</Button>
|
||||
|
||||
@@ -4,6 +4,7 @@ import AlertComponent from "../alert/alert.component";
|
||||
import InvoicesListTableComponent from "../invoices-list-table/invoices-list-table.component";
|
||||
import JobInvoicesTotalsComponent from "../job-invoices-total/job-invoices-total.component";
|
||||
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
||||
import { PartsOrderListTableComponent } from "../parts-order-list-table/parts-order-list-table.component";
|
||||
const tableCol = {
|
||||
xs: {
|
||||
span: 24,
|
||||
@@ -25,22 +26,29 @@ const totalsCol = {
|
||||
export default function JobsDetailPliComponent({
|
||||
job,
|
||||
invoicesQuery,
|
||||
handleOnRowClick,
|
||||
handleInvoiceOnRowClick,
|
||||
handlePartsOrderOnRowClick,
|
||||
selectedInvoice,
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<PartsOrderModal />
|
||||
{invoicesQuery.error ? (
|
||||
<AlertComponent message={invoicesQuery.error.message} type='error' />
|
||||
<AlertComponent message={invoicesQuery.error.message} type="error" />
|
||||
) : null}
|
||||
<Row>
|
||||
<Col {...tableCol}>
|
||||
<PartsOrderListTableComponent
|
||||
job={job}
|
||||
loading={invoicesQuery.loading}
|
||||
handleOnRowClick={handlePartsOrderOnRowClick}
|
||||
selectedInvoice={selectedInvoice}
|
||||
invoicesQuery={invoicesQuery}
|
||||
/>
|
||||
<InvoicesListTableComponent
|
||||
job={job}
|
||||
loading={invoicesQuery.loading}
|
||||
handleOnRowClick={handleOnRowClick}
|
||||
selectedInvoice={selectedInvoice}
|
||||
handleOnRowClick={handleInvoiceOnRowClick}
|
||||
invoicesQuery={invoicesQuery}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function JobsDetailPliContainer({ job }) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const history = useHistory();
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
const handleInvoiceOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.invoiceid = record.id;
|
||||
@@ -25,12 +25,24 @@ export default function JobsDetailPliContainer({ job }) {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePartsOrderOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.partsorderid = record.id;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.partsorderid;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<JobsDetailPliComponent
|
||||
job={job}
|
||||
invoicesQuery={invoicesQuery}
|
||||
handleOnRowClick={handleOnRowClick}
|
||||
selectedInvoice={search.invoiceid}
|
||||
handleInvoiceOnRowClick={handleInvoiceOnRowClick}
|
||||
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "antd";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { MUTATION_BACKORDER_PART_LINE } from "../../graphql/parts-orders.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
export function PartsOrderLineBackorderButton({
|
||||
partsOrderStatus,
|
||||
partsLineId,
|
||||
jobLineId,
|
||||
bodyshop,
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [backorderLine] = useMutation(MUTATION_BACKORDER_PART_LINE);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isAlreadyBackordered =
|
||||
bodyshop.md_order_statuses.default_bo === partsOrderStatus;
|
||||
|
||||
const handleOnClick = async () => {
|
||||
setLoading(true);
|
||||
|
||||
const result = await backorderLine({
|
||||
variables: {
|
||||
jobLineId,
|
||||
partsLineId,
|
||||
status: isAlreadyBackordered
|
||||
? bodyshop.md_order_statuses.default_received || "Received*"
|
||||
: bodyshop.md_order_statuses.default_bo || "Backordered*",
|
||||
},
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Button loading={loading} onClick={handleOnClick}>
|
||||
{isAlreadyBackordered
|
||||
? t("parts_orders.actions.receive")
|
||||
: t("parts_orders.actions.backordered")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(PartsOrderLineBackorderButton);
|
||||
@@ -0,0 +1,215 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Input, Table } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function PartsOrderListTableComponent({
|
||||
job,
|
||||
loading,
|
||||
invoicesQuery,
|
||||
|
||||
handleOnRowClick,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
});
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const selectedpartsorder = search.partsorderid;
|
||||
|
||||
const parts_orders = invoicesQuery.data
|
||||
? invoicesQuery.data.parts_orders
|
||||
: [];
|
||||
const { refetch } = invoicesQuery;
|
||||
const columns = [
|
||||
{
|
||||
title: t("vendors.fields.name"),
|
||||
dataIndex: "vendorname",
|
||||
key: "vendorname",
|
||||
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.order_number"),
|
||||
dataIndex: "order_number",
|
||||
key: "order_number",
|
||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "invoice_number" &&
|
||||
state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.order_date"),
|
||||
dataIndex: "order_date",
|
||||
key: "order_date",
|
||||
sorter: (a, b) => a.order_date - b.order_date,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "order_date" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<DateFormatter>{record.order_date}</DateFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.deliver_by"),
|
||||
dataIndex: "deliver_by",
|
||||
key: "deliver_by",
|
||||
sorter: (a, b) => a.deliver_by - b.deliver_by,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "deliver_by" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<DateFormatter>{record.deliver_by}</DateFormatter>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
const rowExpander = (record) => {
|
||||
const columns = [
|
||||
{
|
||||
title: t("parts_orders.fields.line_desc"),
|
||||
dataIndex: "line_desc",
|
||||
key: "line_desc",
|
||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.db_price"),
|
||||
dataIndex: "db_price",
|
||||
key: "db_price",
|
||||
sorter: (a, b) => a.db_price - b.db_price,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "db_price" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatter>{record.db_price}</CurrencyFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.act_price"),
|
||||
dataIndex: "act_price",
|
||||
key: "act_price",
|
||||
sorter: (a, b) => a.act_price - b.act_price,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatter>{record.act_price}</CurrencyFormatter>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: t("parts_orders.fields.oem_partno"),
|
||||
dataIndex: "oem_partno",
|
||||
key: "oem_partno",
|
||||
sorter: (a, b) => alphaSort(a.oem_partno, b.oem_partno),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "oem_partno" && state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.line_remarks"),
|
||||
dataIndex: "line_remarks",
|
||||
key: "line_remarks",
|
||||
},
|
||||
{
|
||||
title: t("parts_orders.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<div>
|
||||
<PartsOrderLineBackorderButton
|
||||
partsOrderStatus={record.status}
|
||||
partsLineId={record.id}
|
||||
jobLineId={record.job_line_id}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
size="small"
|
||||
scroll={{ x: "50%", y: "40rem" }}
|
||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={record.parts_order_lines}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
size="small"
|
||||
title={() => (
|
||||
<div className="imex-table-header">
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
|
||||
<div className="imex-table-header__search">
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
scroll={{ x: "50%", y: "40rem" }}
|
||||
expandedRowRender={rowExpander}
|
||||
pagination={{ position: "top", defaultPageSize: 25 }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={parts_orders}
|
||||
onChange={handleTableChange}
|
||||
expandable={{
|
||||
expandedRowKeys: [selectedpartsorder],
|
||||
onExpand: (expanded, record) => {
|
||||
handleOnRowClick(expanded ? record : null);
|
||||
},
|
||||
}}
|
||||
rowSelection={{
|
||||
onSelect: (record) => {
|
||||
handleOnRowClick(record);
|
||||
},
|
||||
selectedRowKeys: [selectedpartsorder],
|
||||
type: "radio",
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
return {
|
||||
onClick: (event) => {
|
||||
handleOnRowClick(record);
|
||||
}, // click row
|
||||
onDoubleClick: (event) => {}, // double click row
|
||||
onContextMenu: (event) => {}, // right button click row
|
||||
onMouseEnter: (event) => {}, // mouse enter row
|
||||
onMouseLeave: (event) => {}, // mouse leave row
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(PartsOrderListTableComponent);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useElements, useStripe, CardElement } from "@stripe/react-stripe-js";
|
||||
import { Form, Modal, notification } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -37,6 +37,7 @@ function InvoiceEnterModalContainer({
|
||||
const elements = useElements();
|
||||
const { t } = useTranslation();
|
||||
const { context, actions, visible } = paymentModal;
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const stripeStateArr = useState({
|
||||
error: null,
|
||||
@@ -118,6 +119,10 @@ function InvoiceEnterModalContainer({
|
||||
toggleModalVisible();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) form.resetFields();
|
||||
}, [visible, form]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t("payments.labels.new")}
|
||||
|
||||
@@ -36,11 +36,6 @@ export function ProductionBoardKanbanComponent({ data, bodyshop }) {
|
||||
bodyshop.md_ro_statuses.production_statuses,
|
||||
]);
|
||||
|
||||
const findById = (id) => {
|
||||
return id;
|
||||
//return (data && data.find((x) => x.id === id).ro_number) || null;
|
||||
};
|
||||
|
||||
const client = useApolloClient();
|
||||
|
||||
const handleDragEnd = async (card, source, destination) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { Button, Form, Input, InputNumber, Select, Row, Col } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { Button, Col, Form, Input, InputNumber, Row } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
//TODO Fix up styles.
|
||||
export default function ShopInfoSchedulingComponent({ form }) {
|
||||
|
||||
@@ -38,7 +38,32 @@ export const QUERY_ALL_INVOICES_PAGINATED = gql`
|
||||
`;
|
||||
|
||||
export const QUERY_INVOICES_BY_JOBID = gql`
|
||||
query QUERY_INVOICES_BY_JOBID($jobid: uuid!) {
|
||||
query QUERY_PARTS_INVOICES_BY_JOBID($jobid: uuid!) {
|
||||
parts_orders(
|
||||
where: { jobid: { _eq: $jobid } }
|
||||
order_by: { order_date: desc }
|
||||
) {
|
||||
id
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
}
|
||||
order_date
|
||||
deliver_by
|
||||
parts_order_lines {
|
||||
id
|
||||
act_price
|
||||
db_price
|
||||
line_desc
|
||||
oem_partno
|
||||
status
|
||||
line_remarks
|
||||
quantity
|
||||
job_line_id
|
||||
}
|
||||
order_number
|
||||
user_email
|
||||
}
|
||||
invoices(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||
id
|
||||
vendorid
|
||||
|
||||
@@ -9,3 +9,30 @@ export const INSERT_NEW_PARTS_ORDERS = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const MUTATION_BACKORDER_PART_LINE = gql`
|
||||
mutation MUTATION_BACKORDER_PART_LINE(
|
||||
$jobLineId: uuid!
|
||||
$partsLineId: uuid!
|
||||
$status: String!
|
||||
) {
|
||||
update_parts_order_lines(
|
||||
where: { id: { _eq: $partsLineId } }
|
||||
_set: { status: $status }
|
||||
) {
|
||||
returning {
|
||||
status
|
||||
id
|
||||
}
|
||||
}
|
||||
update_joblines(
|
||||
where: { id: { _eq: $jobLineId } }
|
||||
_set: { status: $status }
|
||||
) {
|
||||
returning {
|
||||
status
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -899,6 +899,10 @@
|
||||
}
|
||||
},
|
||||
"parts_orders": {
|
||||
"actions": {
|
||||
"backordered": "Backordered",
|
||||
"receive": "Receive"
|
||||
},
|
||||
"errors": {
|
||||
"creating": "Error encountered when creating parts order. "
|
||||
},
|
||||
@@ -910,7 +914,11 @@
|
||||
"line_desc": "Line Description",
|
||||
"line_remarks": "Remarks",
|
||||
"lineremarks": "Line Remarks",
|
||||
"quantity": "Qty."
|
||||
"oem_partno": "Part #",
|
||||
"order_date": "Order Date",
|
||||
"order_number": "Order Number",
|
||||
"quantity": "Qty.",
|
||||
"status": "Status"
|
||||
},
|
||||
"labels": {
|
||||
"email": "Send by Email",
|
||||
|
||||
@@ -899,6 +899,10 @@
|
||||
}
|
||||
},
|
||||
"parts_orders": {
|
||||
"actions": {
|
||||
"backordered": "",
|
||||
"receive": ""
|
||||
},
|
||||
"errors": {
|
||||
"creating": "Se encontró un error al crear el pedido de piezas."
|
||||
},
|
||||
@@ -910,7 +914,11 @@
|
||||
"line_desc": "",
|
||||
"line_remarks": "",
|
||||
"lineremarks": "Comentarios de línea",
|
||||
"quantity": ""
|
||||
"oem_partno": "",
|
||||
"order_date": "",
|
||||
"order_number": "",
|
||||
"quantity": "",
|
||||
"status": ""
|
||||
},
|
||||
"labels": {
|
||||
"email": "Enviar por correo electrónico",
|
||||
|
||||
@@ -899,6 +899,10 @@
|
||||
}
|
||||
},
|
||||
"parts_orders": {
|
||||
"actions": {
|
||||
"backordered": "",
|
||||
"receive": ""
|
||||
},
|
||||
"errors": {
|
||||
"creating": "Erreur rencontrée lors de la création de la commande de pièces."
|
||||
},
|
||||
@@ -910,7 +914,11 @@
|
||||
"line_desc": "",
|
||||
"line_remarks": "",
|
||||
"lineremarks": "Remarques sur la ligne",
|
||||
"quantity": ""
|
||||
"oem_partno": "",
|
||||
"order_date": "",
|
||||
"order_number": "",
|
||||
"quantity": "",
|
||||
"status": ""
|
||||
},
|
||||
"labels": {
|
||||
"email": "Envoyé par email",
|
||||
|
||||
@@ -36,22 +36,20 @@
|
||||
data = data.replace(/\s/g, " ");
|
||||
var track = data.match(/(.*?\?)(.*?\?)(.*?\?)/);
|
||||
var res1 = track[1].match(
|
||||
/(\%)([A-Z]{2})([^\^]{0,13})\^?([^\^]{0,35})\^?([^\^]{0,60})\^?\s*?\?/
|
||||
/(%)([A-Z]{2})([^^]{0,13})\^?([^^]{0,35})\^?([^^]{0,60})\^?\s*?\?/
|
||||
);
|
||||
var res2 = track[2].match(
|
||||
/(;)(\d{6})(\d{0,13})(\=)(\d{4})(\d{8})(\d{0,5})\=?\?/
|
||||
/(;)(\d{6})(\d{0,13})(=)(\d{4})(\d{8})(\d{0,5})=?\?/
|
||||
);
|
||||
var res3 = track[3].match(
|
||||
/(\#|\%|\+)(\d|\!|\")(\d|\s|.)([0-9A-Z ]{11})([0-9A-Z ]{2})([0-9A-Z ]{10})([0-9A-Z ]{4})([12MF ]{1})([0-9A-Z ]{3})([0-9A-Z ]{3})([0-9A-Z ]{3})([0-9A-Z ]{3})(.*?)\?/
|
||||
/(#|%|\+)(\d|!|")(\d|\s|.)([0-9A-Z ]{11})([0-9A-Z ]{2})([0-9A-Z ]{10})([0-9A-Z ]{4})([12MF ]{1})([0-9A-Z ]{3})([0-9A-Z ]{3})([0-9A-Z ]{3})([0-9A-Z ]{3})(.*?)\?/
|
||||
);
|
||||
var state = res1[2];
|
||||
return {
|
||||
state: state,
|
||||
city: res1[3],
|
||||
name: (function () {
|
||||
var res = res1[4].match(
|
||||
/([^\$]{0,35})\$?([^\$]{0,35})?\$?([^\$]{0,35})?/
|
||||
);
|
||||
var res = res1[4].match(/([^$]{0,35})\$?([^$]{0,35})?\$?([^$]{0,35})?/);
|
||||
if (!res) return;
|
||||
return {
|
||||
last: res[1],
|
||||
@@ -90,13 +88,12 @@
|
||||
switch (Number(res3[8])) {
|
||||
case 1:
|
||||
return "MALE";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
return "FEMALE";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "MISSING/INVALID";
|
||||
break;
|
||||
}
|
||||
})(),
|
||||
height: res3[9],
|
||||
@@ -452,7 +449,7 @@
|
||||
var parsedData = {};
|
||||
var res = data.match(parseRegex);
|
||||
|
||||
for (var i = 1; i < res.length; i++) {
|
||||
for (i = 1; i < res.length; i++) {
|
||||
if (res[i] !== undefined) {
|
||||
parsedData[String(res[i]).substring(0, 3)] = res[i].substring(3).trim();
|
||||
}
|
||||
@@ -525,10 +522,10 @@
|
||||
switch (Number(parsedData.DBC)) {
|
||||
case 1:
|
||||
return "MALE";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
return "FEMALE";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (parsedData.DBC[0] === "M") {
|
||||
return "MALE";
|
||||
@@ -536,7 +533,6 @@
|
||||
return "FEMALE";
|
||||
}
|
||||
return "MISSING/INVALID";
|
||||
break;
|
||||
}
|
||||
})(),
|
||||
height: undefined,
|
||||
|
||||
@@ -1 +1 @@
|
||||
exports.DineroQbFormat = "0,0.00";
|
||||
exports.DineroQbFormat = "0.00";
|
||||
|
||||
@@ -72,13 +72,224 @@ exports.default = async (req, res) => {
|
||||
qbxml: generateInvoiceQbxml(jobs_by_pk, bodyshop),
|
||||
});
|
||||
|
||||
res.status(200).json(QbXmlToExecute);
|
||||
res.status(200).json([{ id: jobId, okStatusCodes: ["0"], qbxml: t }]);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
|
||||
const t = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<?qbxml version="13.0"?>
|
||||
<QBXML>
|
||||
<QBXMLMsgsRq onError="continueOnError">
|
||||
<CustomerAddRq>
|
||||
<CustomerAdd>
|
||||
<Name>Insurance Corporation of British Co</Name>
|
||||
<BillAddress>
|
||||
<Addr1>21291 122B AVE</Addr1>
|
||||
<City>MAPLE RIDGE</City>
|
||||
<State>BC</State>
|
||||
</BillAddress>
|
||||
</CustomerAdd>
|
||||
</CustomerAddRq>
|
||||
|
||||
<CustomerAddRq>
|
||||
<CustomerAdd>
|
||||
<Name>CLOVER LANDON #4</Name>
|
||||
<ParentRef>
|
||||
<FullName>Insurance Corporation of British Co</FullName>
|
||||
</ParentRef>
|
||||
</CustomerAdd>
|
||||
</CustomerAddRq>
|
||||
|
||||
<CustomerAddRq>
|
||||
<CustomerAdd>
|
||||
<Name>RO29</Name>
|
||||
<ParentRef>
|
||||
<FullName>Insurance Corporation of British Co:CLOVER LANDON #4</FullName>
|
||||
</ParentRef>
|
||||
</CustomerAdd>
|
||||
</CustomerAddRq>
|
||||
|
||||
<InvoiceAddRq>
|
||||
<InvoiceAdd>
|
||||
<CustomerRef>
|
||||
<FullName>Insurance Corporation of British Co:CLOVER LANDON #4:RO29</FullName>
|
||||
</CustomerRef>
|
||||
<TxnDate/>
|
||||
<RefNumber>RO29</RefNumber>
|
||||
<BillAddress>
|
||||
<Addr1>21291 122B AVE</Addr1>
|
||||
<City>MAPLE RIDGE</City>
|
||||
<State>BC</State>
|
||||
</BillAddress>
|
||||
<PONumber>BM27914-1-A</PONumber>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_PAA</FullName>
|
||||
</ItemRef>
|
||||
<Desc>Aftermarketd</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>1351.03</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_PAN</FullName>
|
||||
</ItemRef>
|
||||
<Desc>BODY SHOP SALES:PARTS:OEM</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>292.45</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_ATP</FullName>
|
||||
</ItemRef>
|
||||
<Desc>ATPd</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>144.09</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_LAB</FullName>
|
||||
</ItemRef>
|
||||
<Desc>BODY SHOP SALESLABOR:BODY</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>653.35</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_LAR</FullName>
|
||||
</ItemRef>
|
||||
<Desc>BODY SHOP SALES:LABOR:REFINISH</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>565.26</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_MAPA</FullName>
|
||||
</ItemRef>
|
||||
<Desc>paintd</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>347.66</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>BODY SHOP_MASH</FullName>
|
||||
</ItemRef>
|
||||
<Desc>shopd</Desc>
|
||||
<Quantity>1</Quantity>
|
||||
<Amount>54.38</Amount>
|
||||
<SalesTaxCodeRef>
|
||||
<FullName>E</FullName>
|
||||
</SalesTaxCodeRef>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>GST On Sales</FullName>
|
||||
</ItemRef>
|
||||
<Desc>Receiver General - GST</Desc>
|
||||
<Amount>170.41</Amount>
|
||||
</InvoiceLineAdd>
|
||||
<InvoiceLineAdd>
|
||||
<ItemRef>
|
||||
<FullName>PST On Sales</FullName>
|
||||
</ItemRef>
|
||||
<Desc>Ministry of Finance (BC)</Desc>
|
||||
<Amount>238.58</Amount>
|
||||
</InvoiceLineAdd>
|
||||
</InvoiceAdd>
|
||||
</InvoiceAddRq>
|
||||
</QBXMLMsgsRq>
|
||||
|
||||
</QBXML>
|
||||
`;
|
||||
|
||||
// exports.default = async (req, res) => {
|
||||
// const BearerToken = req.headers.authorization;
|
||||
// const { jobId } = req.body;
|
||||
|
||||
// const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||
// headers: {
|
||||
// Authorization: BearerToken,
|
||||
// },
|
||||
// });
|
||||
|
||||
// try {
|
||||
// const result = await client
|
||||
// .setHeaders({ Authorization: BearerToken })
|
||||
// .request(queries.QUERY_JOBS_FOR_RECEIVABLES_EXPORT, { id: jobId });
|
||||
// const { jobs_by_pk } = result;
|
||||
// const { bodyshop } = jobs_by_pk;
|
||||
// const QbXmlToExecute = [];
|
||||
|
||||
// //Is this a two tier, or 3 tier setup?
|
||||
// const isThreeTier = bodyshop.accountingconfig.tiers === 3;
|
||||
// const twoTierPref = bodyshop.accountingconfig.twotierpref;
|
||||
|
||||
// if (isThreeTier) {
|
||||
// QbXmlToExecute.push({
|
||||
// id: jobId,
|
||||
// okStatusCodes: ["0", "3100"],
|
||||
// qbxml: generateSourceCustomerQbxml(jobs_by_pk, bodyshop), // Create the source customer.
|
||||
// });
|
||||
// }
|
||||
|
||||
// QbXmlToExecute.push({
|
||||
// id: jobId,
|
||||
// okStatusCodes: ["0", "3100"],
|
||||
// qbxml: generateJobQbxml(
|
||||
// jobs_by_pk,
|
||||
// bodyshop,
|
||||
// isThreeTier,
|
||||
// 2,
|
||||
// twoTierPref
|
||||
// ),
|
||||
// });
|
||||
|
||||
// QbXmlToExecute.push({
|
||||
// id: jobId,
|
||||
// okStatusCodes: ["0", "3100"],
|
||||
// qbxml: generateJobQbxml(
|
||||
// jobs_by_pk,
|
||||
// bodyshop,
|
||||
// isThreeTier,
|
||||
// 3,
|
||||
// twoTierPref
|
||||
// ),
|
||||
// });
|
||||
// //Generate the actual invoice.
|
||||
// QbXmlToExecute.push({
|
||||
// id: jobId,
|
||||
// okStatusCodes: ["0"],
|
||||
// qbxml: generateInvoiceQbxml(jobs_by_pk, bodyshop),
|
||||
// });
|
||||
|
||||
// res.status(200).json(QbXmlToExecute);
|
||||
// } catch (error) {
|
||||
// console.log("error", error);
|
||||
// res.status(400).send(JSON.stringify(error));
|
||||
// }
|
||||
// };
|
||||
|
||||
const generateSourceCustomerQbxml = (jobs_by_pk, bodyshop) => {
|
||||
const customerQbxmlObj = {
|
||||
QBXML: {
|
||||
@@ -129,7 +340,13 @@ const generateOwnerTier = (jobs_by_pk) => {
|
||||
}`;
|
||||
};
|
||||
|
||||
const generateJobQbxml = (jobs_by_pk, bodyshop, isThreeTier, tierLevel, twoTierPref) => {
|
||||
const generateJobQbxml = (
|
||||
jobs_by_pk,
|
||||
bodyshop,
|
||||
isThreeTier,
|
||||
tierLevel,
|
||||
twoTierPref
|
||||
) => {
|
||||
let Name;
|
||||
let ParentRefName;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user