Successful 2tier and 3 tier export of invoices. BOD-83 BOD-131
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.6.1">
|
<babeledit_project be_version="2.6.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -7374,6 +7374,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>export</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>gotojob</name>
|
<name>gotojob</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export default connect(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response2 = await axios.post(
|
const response2 = await axios.post(
|
||||||
"http://localhost:1337/qb/receivables",
|
"http://e9c5a8ed9079.ngrok.io/qb/receivables",
|
||||||
response.data,
|
response.data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export function JobsCloseLabmatAllocationButton({
|
|||||||
allocation,
|
allocation,
|
||||||
setAllocations,
|
setAllocations,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
|
invoiced
|
||||||
}) {
|
}) {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [state, setState] = useState({ center: "", amount: 0 });
|
const [state, setState] = useState({ center: "", amount: 0 });
|
||||||
@@ -87,7 +88,7 @@ export function JobsCloseLabmatAllocationButton({
|
|||||||
<Button
|
<Button
|
||||||
onClick={handleAllocate}
|
onClick={handleAllocate}
|
||||||
disabled={
|
disabled={
|
||||||
state.amount === 0 || state.center === "" || remainingAmount === 0
|
state.amount === 0 || state.center === "" || remainingAmount === 0 || invoiced
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("jobs.actions.allocate")}
|
{t("jobs.actions.allocate")}
|
||||||
@@ -95,9 +96,9 @@ export function JobsCloseLabmatAllocationButton({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{visible ? (
|
{visible ? (
|
||||||
<CloseCircleFilled onClick={() => setVisible(false)} />
|
<CloseCircleFilled onClick={() => setVisible(false)} disabled={invoiced} />
|
||||||
) : (
|
) : (
|
||||||
<PlusCircleFilled onClick={() => setVisible(true)} />
|
<PlusCircleFilled onClick={() => setVisible(true)} disabled={invoiced}/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ export default function JobsCloseLabMatAllocationTags({
|
|||||||
allocationKey,
|
allocationKey,
|
||||||
allocation,
|
allocation,
|
||||||
setAllocations,
|
setAllocations,
|
||||||
|
invoiced,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{allocation.allocations.map((a, idx) => (
|
{allocation.allocations.map((a, idx) => (
|
||||||
<Tag
|
<Tag
|
||||||
closable
|
closable={!invoiced} //Value is whether it is invoiced.
|
||||||
visible
|
visible
|
||||||
color='green'
|
color="green"
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setAllocations((state) => {
|
setAllocations((state) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export function JobsCloseAutoAllocate({
|
|||||||
setLabmatAllocations,
|
setLabmatAllocations,
|
||||||
partsAllocations,
|
partsAllocations,
|
||||||
setPartsAllocations,
|
setPartsAllocations,
|
||||||
|
invoiced
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const handleAllocate = () => {
|
const handleAllocate = () => {
|
||||||
@@ -62,6 +63,6 @@ export function JobsCloseAutoAllocate({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Button onClick={handleAllocate}>{t("jobs.actions.autoallocate")}</Button>;
|
return <Button onClick={handleAllocate} disabled={invoiced}>{t("jobs.actions.autoallocate")}</Button>;
|
||||||
}
|
}
|
||||||
export default connect(mapStateToProps, null)(JobsCloseAutoAllocate);
|
export default connect(mapStateToProps, null)(JobsCloseAutoAllocate);
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { Button } from "antd";
|
||||||
|
import axios from "axios";
|
||||||
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { auth } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
|
export default function JobsCloseExportButton({ jobId, disabled }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleQbxml = async () => {
|
||||||
|
const response = await axios.post(
|
||||||
|
"/accounting/qbxml/receivables",
|
||||||
|
{ jobId: jobId },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log("handle -> XML", response);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response2 = await axios.post(
|
||||||
|
"http://e9c5a8ed9079.ngrok.io/qb/receivables",
|
||||||
|
response.data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken(true)}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log("handle -> result", response2);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error, JSON.stringify(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button onClick={handleQbxml} disabled={disabled} type="dashed">
|
||||||
|
{t("jobs.actions.export")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ export default function JobCloseLabMatAllocation({
|
|||||||
labmatAllocations,
|
labmatAllocations,
|
||||||
setLabmatAllocations,
|
setLabmatAllocations,
|
||||||
labMatTotalAllocation,
|
labMatTotalAllocation,
|
||||||
|
invoiced
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ export default function JobCloseLabMatAllocation({
|
|||||||
<td>
|
<td>
|
||||||
<AllocationButton
|
<AllocationButton
|
||||||
allocationKey={alloc}
|
allocationKey={alloc}
|
||||||
|
invoiced={invoiced}
|
||||||
remainingAmount={labmatAllocations[alloc].total
|
remainingAmount={labmatAllocations[alloc].total
|
||||||
.subtract(
|
.subtract(
|
||||||
Dinero({
|
Dinero({
|
||||||
@@ -69,6 +71,7 @@ export default function JobCloseLabMatAllocation({
|
|||||||
<td>
|
<td>
|
||||||
<AllocationTags
|
<AllocationTags
|
||||||
allocationKey={alloc}
|
allocationKey={alloc}
|
||||||
|
invoiced={invoiced}
|
||||||
allocation={labmatAllocations[alloc]}
|
allocation={labmatAllocations[alloc]}
|
||||||
setAllocations={setLabmatAllocations}
|
setAllocations={setLabmatAllocations}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export default function JobsClosePartsAllocation({
|
|||||||
partsAllocations,
|
partsAllocations,
|
||||||
setPartsAllocations,
|
setPartsAllocations,
|
||||||
partsAllocatedTotal,
|
partsAllocatedTotal,
|
||||||
|
invoiced,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ export default function JobsClosePartsAllocation({
|
|||||||
<td>
|
<td>
|
||||||
<AllocationButton
|
<AllocationButton
|
||||||
allocationKey={alloc}
|
allocationKey={alloc}
|
||||||
|
invoiced={invoiced}
|
||||||
remainingAmount={partsAllocations[alloc].total
|
remainingAmount={partsAllocations[alloc].total
|
||||||
.subtract(
|
.subtract(
|
||||||
Dinero({
|
Dinero({
|
||||||
@@ -68,6 +70,7 @@ export default function JobsClosePartsAllocation({
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<AllocationTags
|
<AllocationTags
|
||||||
|
invoiced={invoiced}
|
||||||
allocationKey={alloc}
|
allocationKey={alloc}
|
||||||
allocation={partsAllocations[alloc]}
|
allocation={partsAllocations[alloc]}
|
||||||
setAllocations={setPartsAllocations}
|
setAllocations={setPartsAllocations}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ export function JobsCloseSaveButton({
|
|||||||
jobTotals,
|
jobTotals,
|
||||||
labMatAllocations,
|
labMatAllocations,
|
||||||
partsAllocations,
|
partsAllocations,
|
||||||
|
setInvoicedState,
|
||||||
|
disabled,
|
||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -38,9 +40,23 @@ export function JobsCloseSaveButton({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
update_jobs: {
|
||||||
|
returning: {
|
||||||
|
id: jobId,
|
||||||
|
date_invoiced: new Date(),
|
||||||
|
status: bodyshop.md_ro_statuses.default_invoiced || "Invoiced*",
|
||||||
|
invoice_allocation: {
|
||||||
|
labMatAllocations,
|
||||||
|
partsAllocations,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (!!!result.errors) {
|
if (!!!result.errors) {
|
||||||
notification["success"]({ message: t("jobs.successes.invoiced") });
|
notification["success"]({ message: t("jobs.successes.invoiced") });
|
||||||
|
setInvoicedState(true);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.invoicing", {
|
message: t("jobs.errors.invoicing", {
|
||||||
@@ -54,10 +70,10 @@ export function JobsCloseSaveButton({
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={suspenseAmount > 0}
|
disabled={suspenseAmount > 0 || disabled}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
{t("general.actions.close")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -755,11 +755,6 @@ export const QUERY_ALL_JOBS_PAGINATED = gql`
|
|||||||
export const QUERY_JOB_CLOSE_DETAILS = gql`
|
export const QUERY_JOB_CLOSE_DETAILS = gql`
|
||||||
query QUERY_JOB_CLOSE_DETAILS($id: uuid!) {
|
query QUERY_JOB_CLOSE_DETAILS($id: uuid!) {
|
||||||
jobs_by_pk(id: $id) {
|
jobs_by_pk(id: $id) {
|
||||||
po_number
|
|
||||||
special_coverage_policy
|
|
||||||
scheduled_delivery
|
|
||||||
converted
|
|
||||||
est_number
|
|
||||||
ro_number
|
ro_number
|
||||||
clm_total
|
clm_total
|
||||||
inproduction
|
inproduction
|
||||||
@@ -769,26 +764,12 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
|||||||
v_model_desc
|
v_model_desc
|
||||||
v_make_desc
|
v_make_desc
|
||||||
v_color
|
v_color
|
||||||
|
invoice_allocation
|
||||||
ins_co_id
|
ins_co_id
|
||||||
policy_no
|
policy_no
|
||||||
loss_date
|
|
||||||
clm_no
|
clm_no
|
||||||
area_of_damage
|
|
||||||
ins_co_nm
|
ins_co_nm
|
||||||
ins_addr1
|
|
||||||
ins_city
|
|
||||||
ins_ct_ln
|
|
||||||
ins_ct_fn
|
|
||||||
ins_ea
|
|
||||||
ins_ph1
|
|
||||||
est_co_nm
|
|
||||||
est_ct_fn
|
|
||||||
est_ct_ln
|
|
||||||
pay_date
|
|
||||||
est_ph1
|
|
||||||
est_ea
|
|
||||||
regie_number
|
regie_number
|
||||||
scheduled_completion
|
|
||||||
id
|
id
|
||||||
ded_amt
|
ded_amt
|
||||||
ded_status
|
ded_status
|
||||||
@@ -819,20 +800,6 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
|||||||
ownr_zip
|
ownr_zip
|
||||||
ownr_ctry
|
ownr_ctry
|
||||||
ownr_ph1
|
ownr_ph1
|
||||||
owner {
|
|
||||||
id
|
|
||||||
ownr_fn
|
|
||||||
ownr_ln
|
|
||||||
ownr_ea
|
|
||||||
ownr_addr1
|
|
||||||
ownr_addr2
|
|
||||||
ownr_city
|
|
||||||
ownr_st
|
|
||||||
ownr_zip
|
|
||||||
ownr_ctry
|
|
||||||
ownr_ph1
|
|
||||||
}
|
|
||||||
labor_rate_desc
|
|
||||||
rate_atp
|
rate_atp
|
||||||
rate_la1
|
rate_la1
|
||||||
rate_la2
|
rate_la2
|
||||||
@@ -857,18 +824,10 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
|||||||
rate_mapa
|
rate_mapa
|
||||||
rate_mash
|
rate_mash
|
||||||
rate_matd
|
rate_matd
|
||||||
actual_completion
|
status
|
||||||
scheduled_delivery
|
|
||||||
actual_delivery
|
|
||||||
date_invoiced
|
|
||||||
date_closed
|
|
||||||
date_exported
|
|
||||||
status
|
|
||||||
owner_owing
|
owner_owing
|
||||||
joblines {
|
joblines {
|
||||||
id
|
id
|
||||||
unq_seq
|
|
||||||
line_ind
|
|
||||||
tax_part
|
tax_part
|
||||||
line_desc
|
line_desc
|
||||||
prt_dsmk_p
|
prt_dsmk_p
|
||||||
@@ -885,7 +844,6 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
|||||||
lbr_amt
|
lbr_amt
|
||||||
op_code_desc
|
op_code_desc
|
||||||
}
|
}
|
||||||
cieca_ttl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -8,33 +8,76 @@ import Dinero from "dinero.js";
|
|||||||
import JobsCloseTotals from "../../components/jobs-close-totals/jobs-close-totals.component";
|
import JobsCloseTotals from "../../components/jobs-close-totals/jobs-close-totals.component";
|
||||||
import JobsCloseAutoAllocate from "../../components/jobs-close-auto-allocate/jobs-close-auto-allocate.component";
|
import JobsCloseAutoAllocate from "../../components/jobs-close-auto-allocate/jobs-close-auto-allocate.component";
|
||||||
import JobsCloseSaveButton from "../../components/jobs-close-save-button/jobs-close-save-button.component";
|
import JobsCloseSaveButton from "../../components/jobs-close-save-button/jobs-close-save-button.component";
|
||||||
|
import JobsCloseExportButton from "../../components/jobs-close-export-button/jobs-close-export-button.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function JobsCloseComponent({ job, bodyshop, jobTotals }) {
|
export function JobsCloseComponent({ job, bodyshop, jobTotals }) {
|
||||||
|
const [invoiced, setInvoiced] = useState(!!job.invoice_allocation);
|
||||||
const [labmatAllocations, setLabmatAllocations] = useState(
|
const [labmatAllocations, setLabmatAllocations] = useState(
|
||||||
Object.keys(jobTotals.rates).reduce((acc, val) => {
|
!!job.invoice_allocation && !!job.invoice_allocation.labMatAllocations
|
||||||
acc[val] = jobTotals.rates[val];
|
? Object.keys(job.invoice_allocation.labMatAllocations).reduce(
|
||||||
if (val.includes("subtotal")) return acc;
|
(acc, val) => {
|
||||||
//Not a subtotal - therefore can be allocated.
|
if (val.includes("subtotal")) {
|
||||||
acc[val].allocations = [];
|
acc[val] = Dinero(job.invoice_allocation.labMatAllocations[val]);
|
||||||
return acc;
|
} else {
|
||||||
}, {})
|
acc[val] = {
|
||||||
|
...job.invoice_allocation.labMatAllocations[val],
|
||||||
|
total: Dinero(
|
||||||
|
job.invoice_allocation.labMatAllocations[val].total
|
||||||
|
),
|
||||||
|
allocations: job.invoice_allocation.labMatAllocations[
|
||||||
|
val
|
||||||
|
].allocations.map((item) => {
|
||||||
|
return { ...item, amount: Dinero(item.amount) };
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
: Object.keys(jobTotals.rates).reduce((acc, val) => {
|
||||||
|
acc[val] = jobTotals.rates[val];
|
||||||
|
if (val.includes("subtotal")) return acc;
|
||||||
|
//Not a subtotal - therefore can be allocated.
|
||||||
|
acc[val].allocations = [];
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
);
|
);
|
||||||
|
|
||||||
const [partsAllocations, setPartsAllocations] = useState({
|
const [partsAllocations, setPartsAllocations] = useState(
|
||||||
...Object.keys(jobTotals.parts.parts.list).reduce((acc, val) => {
|
!!job.invoice_allocation && !!job.invoice_allocation.partsAllocations
|
||||||
acc[val] = { ...jobTotals.parts.parts.list[val], allocations: [] };
|
? Object.keys(job.invoice_allocation.partsAllocations).reduce(
|
||||||
|
(acc, val) => {
|
||||||
|
acc[val] = {
|
||||||
|
...job.invoice_allocation.partsAllocations[val],
|
||||||
|
total: Dinero(job.invoice_allocation.partsAllocations[val].total),
|
||||||
|
allocations: job.invoice_allocation.partsAllocations[
|
||||||
|
val
|
||||||
|
].allocations.map((item) => {
|
||||||
|
return { ...item, amount: Dinero(item.amount) };
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
: {
|
||||||
|
...Object.keys(jobTotals.parts.parts.list).reduce((acc, val) => {
|
||||||
|
acc[val] = { ...jobTotals.parts.parts.list[val], allocations: [] };
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {}),
|
||||||
pas: {
|
pas: {
|
||||||
...jobTotals.parts.sublets,
|
...jobTotals.parts.sublets,
|
||||||
allocations: [],
|
allocations: [],
|
||||||
},
|
},
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const labmatAllocatedTotalsArray = Object.keys(labmatAllocations)
|
const labmatAllocatedTotalsArray = Object.keys(labmatAllocations)
|
||||||
.filter((i) => !i.includes("subtotal"))
|
.filter((i) => !i.includes("subtotal"))
|
||||||
@@ -61,6 +104,8 @@ export function JobsCloseComponent({ job, bodyshop, jobTotals }) {
|
|||||||
<div>
|
<div>
|
||||||
<JobsCloseSaveButton
|
<JobsCloseSaveButton
|
||||||
jobId={job.id}
|
jobId={job.id}
|
||||||
|
invoiced={invoiced}
|
||||||
|
setInvoicedState={setInvoiced}
|
||||||
partsAllocations={partsAllocations}
|
partsAllocations={partsAllocations}
|
||||||
labMatAllocations={labmatAllocations}
|
labMatAllocations={labmatAllocations}
|
||||||
jobTotals={jobTotals}
|
jobTotals={jobTotals}
|
||||||
@@ -69,6 +114,7 @@ export function JobsCloseComponent({ job, bodyshop, jobTotals }) {
|
|||||||
.subtract(partsAllocatedTotal)
|
.subtract(partsAllocatedTotal)
|
||||||
.getAmount()}
|
.getAmount()}
|
||||||
/>
|
/>
|
||||||
|
<JobsCloseExportButton jobId={job.id} disabled={!invoiced} />
|
||||||
<JobsCloseTotals
|
<JobsCloseTotals
|
||||||
jobTotals={jobTotals}
|
jobTotals={jobTotals}
|
||||||
labMatTotal={labmatAllocatedTotal}
|
labMatTotal={labmatAllocatedTotal}
|
||||||
@@ -79,16 +125,19 @@ export function JobsCloseComponent({ job, bodyshop, jobTotals }) {
|
|||||||
setLabmatAllocations={setLabmatAllocations}
|
setLabmatAllocations={setLabmatAllocations}
|
||||||
partsAllocations={partsAllocations}
|
partsAllocations={partsAllocations}
|
||||||
setPartsAllocations={setPartsAllocations}
|
setPartsAllocations={setPartsAllocations}
|
||||||
|
invoiced={invoiced}
|
||||||
/>
|
/>
|
||||||
<JobsCloseLaborMaterialAllocation
|
<JobsCloseLaborMaterialAllocation
|
||||||
labmatAllocations={labmatAllocations}
|
labmatAllocations={labmatAllocations}
|
||||||
setLabmatAllocations={setLabmatAllocations}
|
setLabmatAllocations={setLabmatAllocations}
|
||||||
labMatTotalAllocation={labmatAllocatedTotal}
|
labMatTotalAllocation={labmatAllocatedTotal}
|
||||||
|
invoiced={invoiced}
|
||||||
/>
|
/>
|
||||||
<JobsClosePartsAllocation
|
<JobsClosePartsAllocation
|
||||||
partsAllocations={partsAllocations}
|
partsAllocations={partsAllocations}
|
||||||
setPartsAllocations={setPartsAllocations}
|
setPartsAllocations={setPartsAllocations}
|
||||||
partsAllocatedTotal={partsAllocatedTotal}
|
partsAllocatedTotal={partsAllocatedTotal}
|
||||||
|
invoiced={invoiced}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -500,6 +500,7 @@
|
|||||||
"autoallocate": "Auto Allocate",
|
"autoallocate": "Auto Allocate",
|
||||||
"changestatus": "Change Status",
|
"changestatus": "Change Status",
|
||||||
"convert": "Convert",
|
"convert": "Convert",
|
||||||
|
"export": "Export",
|
||||||
"gotojob": "Go to Job",
|
"gotojob": "Go to Job",
|
||||||
"manualnew": "Create New Job Manually",
|
"manualnew": "Create New Job Manually",
|
||||||
"postInvoices": "Post Invoices",
|
"postInvoices": "Post Invoices",
|
||||||
|
|||||||
@@ -500,6 +500,7 @@
|
|||||||
"autoallocate": "",
|
"autoallocate": "",
|
||||||
"changestatus": "Cambiar Estado",
|
"changestatus": "Cambiar Estado",
|
||||||
"convert": "Convertir",
|
"convert": "Convertir",
|
||||||
|
"export": "",
|
||||||
"gotojob": "",
|
"gotojob": "",
|
||||||
"manualnew": "",
|
"manualnew": "",
|
||||||
"postInvoices": "Contabilizar facturas",
|
"postInvoices": "Contabilizar facturas",
|
||||||
|
|||||||
@@ -500,6 +500,7 @@
|
|||||||
"autoallocate": "",
|
"autoallocate": "",
|
||||||
"changestatus": "Changer le statut",
|
"changestatus": "Changer le statut",
|
||||||
"convert": "Convertir",
|
"convert": "Convertir",
|
||||||
|
"export": "",
|
||||||
"gotojob": "",
|
"gotojob": "",
|
||||||
"manualnew": "",
|
"manualnew": "",
|
||||||
"postInvoices": "Poster des factures",
|
"postInvoices": "Poster des factures",
|
||||||
|
|||||||
@@ -31,17 +31,16 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
//Is this a two tier, or 3 tier setup?
|
//Is this a two tier, or 3 tier setup?
|
||||||
const isThreeTier = bodyshop.accountingconfig.tiers === 3;
|
const isThreeTier = bodyshop.accountingconfig.tiers === 3;
|
||||||
|
|
||||||
QbXmlToExecute.push(
|
|
||||||
generateCustomerQbxml(jobs_by_pk, bodyshop, isThreeTier)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isThreeTier) {
|
if (isThreeTier) {
|
||||||
QbXmlToExecute.push(generateJobQbxml(jobs_by_pk, bodyshop, 2));
|
QbXmlToExecute.push(
|
||||||
QbXmlToExecute.push(generateJobQbxml(jobs_by_pk, bodyshop, 3));
|
generateSourceCustomerQbxml(jobs_by_pk, bodyshop) // Create the source customer.
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
QbXmlToExecute.push(generateJobQbxml(jobs_by_pk, bodyshop, isThreeTier, 2));
|
||||||
|
QbXmlToExecute.push(generateJobQbxml(jobs_by_pk, bodyshop, isThreeTier, 3));
|
||||||
|
//Generate the actual invoice.
|
||||||
|
QbXmlToExecute.push(generateInvoiceQbxml(jobs_by_pk, bodyshop));
|
||||||
|
|
||||||
console.log(QbXmlToExecute);
|
|
||||||
res.status(200).json(QbXmlToExecute);
|
res.status(200).json(QbXmlToExecute);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
console.log("error", error);
|
||||||
@@ -49,31 +48,21 @@ exports.default = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateCustomerQbxml = (jobs_by_pk, bodyshop, isThreeTier) => {
|
const generateSourceCustomerQbxml = (jobs_by_pk, bodyshop) => {
|
||||||
const customerQbxmlObj = {
|
const customerQbxmlObj = {
|
||||||
QBXML: {
|
QBXML: {
|
||||||
QBXMLMsgsRq: {
|
QBXMLMsgsRq: {
|
||||||
"@onError": "continueOnError",
|
"@onError": "continueOnError",
|
||||||
CustomerAddRq: {
|
CustomerAddRq: {
|
||||||
CustomerAdd: {
|
CustomerAdd: {
|
||||||
Name: isThreeTier
|
Name: jobs_by_pk.ins_co_nm,
|
||||||
? jobs_by_pk.ins_co_nm
|
BillAddress: {
|
||||||
: jobs_by_pk.ownr_co_nm
|
Addr1: jobs_by_pk.ownr_addr1,
|
||||||
? `${jobs_by_pk.ownr_co_nm} - ${jobs_by_pk.ownr_ln || ""} ${
|
Addr2: jobs_by_pk.ownr_addr2,
|
||||||
jobs_by_pk.ownr_fn || ""
|
City: jobs_by_pk.ownr_city,
|
||||||
} #${jobs_by_pk.owner.accountingid || ""}`
|
State: jobs_by_pk.ownr_st,
|
||||||
: `${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""} #${
|
PostalCode: jobs_by_pk.ownrzip,
|
||||||
jobs_by_pk.owner.accountingid || ""
|
},
|
||||||
}`,
|
|
||||||
BillAddress: isThreeTier
|
|
||||||
? null
|
|
||||||
: {
|
|
||||||
Addr1: jobs_by_pk.ownr_addr1,
|
|
||||||
Addr2: jobs_by_pk.ownr_addr2,
|
|
||||||
City: jobs_by_pk.ownr_city,
|
|
||||||
State: jobs_by_pk.ownr_st,
|
|
||||||
PostalCode: jobs_by_pk.ownrzip,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -93,15 +82,35 @@ const generateCustomerQbxml = (jobs_by_pk, bodyshop, isThreeTier) => {
|
|||||||
return customerQbxml_Full;
|
return customerQbxml_Full;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateJobQbxml = (jobs_by_pk, bodyshop, isThreeTier, tierLevel) => {
|
const generateSourceTier = (jobs_by_pk) => {
|
||||||
const tier1Name = jobs_by_pk.ownr_co_nm;
|
return jobs_by_pk.ins_co_nm;
|
||||||
const tier2Name = jobs_by_pk.ownr_co_nm
|
};
|
||||||
|
const generateJobTier = (jobs_by_pk) => {
|
||||||
|
return jobs_by_pk.ro_number;
|
||||||
|
};
|
||||||
|
const generateOwnerTier = (jobs_by_pk) => {
|
||||||
|
return jobs_by_pk.ownr_co_nm
|
||||||
? `${jobs_by_pk.ownr_co_nm} - ${jobs_by_pk.ownr_ln || ""} ${
|
? `${jobs_by_pk.ownr_co_nm} - ${jobs_by_pk.ownr_ln || ""} ${
|
||||||
jobs_by_pk.ownr_fn || ""
|
jobs_by_pk.ownr_fn || ""
|
||||||
} #${jobs_by_pk.owner.accountingid || ""}`
|
} #${jobs_by_pk.owner.accountingid || ""}`
|
||||||
: `${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""} #${
|
: `${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""} #${
|
||||||
jobs_by_pk.owner.accountingid || ""
|
jobs_by_pk.owner.accountingid || ""
|
||||||
}`;
|
}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateJobQbxml = (jobs_by_pk, bodyshop, isThreeTier, tierLevel) => {
|
||||||
|
let Name;
|
||||||
|
let ParentRefName;
|
||||||
|
|
||||||
|
if (tierLevel === 2) {
|
||||||
|
Name = generateOwnerTier(jobs_by_pk);
|
||||||
|
ParentRefName = isThreeTier ? generateSourceTier(jobs_by_pk) : null;
|
||||||
|
} else if (tierLevel === 3) {
|
||||||
|
Name = generateJobTier(jobs_by_pk);
|
||||||
|
ParentRefName = isThreeTier
|
||||||
|
? `${jobs_by_pk.ins_co_nm}:${generateOwnerTier(jobs_by_pk)}`
|
||||||
|
: generateOwnerTier(jobs_by_pk);
|
||||||
|
}
|
||||||
|
|
||||||
const jobQbxmlObj = {
|
const jobQbxmlObj = {
|
||||||
QBXML: {
|
QBXML: {
|
||||||
@@ -109,10 +118,12 @@ const generateJobQbxml = (jobs_by_pk, bodyshop, isThreeTier, tierLevel) => {
|
|||||||
"@onError": "continueOnError",
|
"@onError": "continueOnError",
|
||||||
CustomerAddRq: {
|
CustomerAddRq: {
|
||||||
CustomerAdd: {
|
CustomerAdd: {
|
||||||
Name: tierLevel === 2 ? null : null,
|
Name: Name,
|
||||||
ParentRef: {
|
ParentRef: ParentRefName
|
||||||
FullName: tierLevel === 2 ? null : null,
|
? {
|
||||||
},
|
FullName: ParentRefName,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -128,6 +139,7 @@ const generateJobQbxml = (jobs_by_pk, bodyshop, isThreeTier, tierLevel) => {
|
|||||||
.end({ pretty: true });
|
.end({ pretty: true });
|
||||||
|
|
||||||
const jobQbxml_Full = addQbxmlHeader(jobQbxml_partial);
|
const jobQbxml_Full = addQbxmlHeader(jobQbxml_partial);
|
||||||
|
console.log("jobQbxml_Full", jobQbxml_Full);
|
||||||
return jobQbxml_Full;
|
return jobQbxml_Full;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,6 +182,46 @@ const generateInvoiceQbxml = (jobs_by_pk, bodyshop) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Add tax lines
|
||||||
|
const job_totals = JSON.parse(jobs_by_pk.job_totals);
|
||||||
|
|
||||||
|
const federal_tax = Dinero(job_totals.totals.federal_tax);
|
||||||
|
const state_tax = Dinero(job_totals.totals.state_tax);
|
||||||
|
const local_tax = Dinero(job_totals.totals.local_tax);
|
||||||
|
|
||||||
|
if (federal_tax.getAmount() > 0) {
|
||||||
|
InvoiceLineAdd.push({
|
||||||
|
ItemRef: {
|
||||||
|
FullName: bodyshop.md_responsibility_centers.taxes.federal.accountitem,
|
||||||
|
},
|
||||||
|
Desc: bodyshop.md_responsibility_centers.taxes.federal.accountdesc,
|
||||||
|
//Quantity: 1,
|
||||||
|
Amount: federal_tax.toFormat(DineroQbFormat),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_tax.getAmount() > 0) {
|
||||||
|
InvoiceLineAdd.push({
|
||||||
|
ItemRef: {
|
||||||
|
FullName: bodyshop.md_responsibility_centers.taxes.state.accountitem,
|
||||||
|
},
|
||||||
|
Desc: bodyshop.md_responsibility_centers.taxes.state.accountdesc,
|
||||||
|
//Quantity: 1,
|
||||||
|
Amount: state_tax.toFormat(DineroQbFormat),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_tax.getAmount() > 0) {
|
||||||
|
InvoiceLineAdd.push({
|
||||||
|
ItemRef: {
|
||||||
|
FullName: bodyshop.md_responsibility_centers.taxes.local.accountitem,
|
||||||
|
},
|
||||||
|
Desc: bodyshop.md_responsibility_centers.taxes.local.accountdesc,
|
||||||
|
//Quantity: 1,
|
||||||
|
Amount: local_tax.toFormat(DineroQbFormat),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const invoiceQbxmlObj = {
|
const invoiceQbxmlObj = {
|
||||||
QBXML: {
|
QBXML: {
|
||||||
QBXMLMsgsRq: {
|
QBXMLMsgsRq: {
|
||||||
@@ -177,13 +229,14 @@ const generateInvoiceQbxml = (jobs_by_pk, bodyshop) => {
|
|||||||
InvoiceAddRq: {
|
InvoiceAddRq: {
|
||||||
InvoiceAdd: {
|
InvoiceAdd: {
|
||||||
CustomerRef: {
|
CustomerRef: {
|
||||||
//This can equal the Customer or the Customer Job.
|
|
||||||
FullName:
|
FullName:
|
||||||
bodyshop.accountingconfig.tiers === 3
|
bodyshop.accountingconfig.tiers === 3
|
||||||
? "3tier"
|
? `${generateSourceTier(jobs_by_pk)}:${generateOwnerTier(
|
||||||
: bodyshop.accountingconfig.twotierpref === "name"
|
jobs_by_pk
|
||||||
? "2tiername"
|
)}:${generateJobTier(jobs_by_pk)}`
|
||||||
: "2tiersource",
|
: `${generateOwnerTier(jobs_by_pk)}:${generateJobTier(
|
||||||
|
jobs_by_pk
|
||||||
|
)}`,
|
||||||
},
|
},
|
||||||
TxnDate: new Date(),
|
TxnDate: new Date(),
|
||||||
RefNumber: jobs_by_pk.ro_number,
|
RefNumber: jobs_by_pk.ro_number,
|
||||||
@@ -234,7 +287,7 @@ const generateInvoiceLine = (job, allocation, responsibilityCenters) => {
|
|||||||
//Rate: 100,
|
//Rate: 100,
|
||||||
Amount: DineroAmount.toFormat(DineroQbFormat),
|
Amount: DineroAmount.toFormat(DineroQbFormat),
|
||||||
SalesTaxCodeRef: {
|
SalesTaxCodeRef: {
|
||||||
FullName: "Z",
|
FullName: "E",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($id: uuid!) {
|
|||||||
date_invoiced
|
date_invoiced
|
||||||
ro_number
|
ro_number
|
||||||
clm_total
|
clm_total
|
||||||
|
clm_no
|
||||||
invoice_allocation
|
invoice_allocation
|
||||||
ownerid
|
ownerid
|
||||||
ownr_ln
|
ownr_ln
|
||||||
|
|||||||
Reference in New Issue
Block a user