@@ -2354,6 +2354,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>is_credit_memo_short</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>local_tax_rate</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -26589,6 +26610,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>parts_received</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>parts_tax_rates</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -31189,6 +31231,37 @@
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>owner</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>noownerinfo</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>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>owners</name>
|
||||
<children>
|
||||
@@ -34925,6 +34998,27 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<concept_node>
|
||||
<name>lag_time_ro</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>mechanical_authorization</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36487,6 +36581,58 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<folder_node>
|
||||
<name>bodyshop</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>qbo_departmentid</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>qbo_usa</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>
|
||||
</children>
|
||||
</folder_node>
|
||||
<concept_node>
|
||||
<name>cardsettings</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36844,6 +36990,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>stickyheader</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>sublets</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -4,40 +4,40 @@
|
||||
"private": true,
|
||||
"proxy": "http://localhost:4000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.6",
|
||||
"@apollo/client": "^3.5.10",
|
||||
"@asseinfo/react-kanban": "^2.2.0",
|
||||
"@craco/craco": "^6.4.3",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.1",
|
||||
"@sentry/react": "^6.16.1",
|
||||
"@sentry/tracing": "^6.16.1",
|
||||
"@splitsoftware/splitio-react": "^1.3.0",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
||||
"@sentry/react": "^6.19.3",
|
||||
"@sentry/tracing": "^6.19.3",
|
||||
"@splitsoftware/splitio-react": "^1.3.1-rc.1",
|
||||
"@stripe/react-stripe-js": "^1.7.0",
|
||||
"@stripe/stripe-js": "^1.22.0",
|
||||
"@tanem/react-nprogress": "^3.0.82",
|
||||
"antd": "^4.17.4",
|
||||
"@stripe/stripe-js": "^1.26.0",
|
||||
"@tanem/react-nprogress": "^4.0.12",
|
||||
"antd": "^4.19.3",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"axios": "^0.24.0",
|
||||
"axios": "^0.26.1",
|
||||
"craco-less": "^1.20.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"dotenv": "^16.0.0",
|
||||
"enquire-js": "^0.2.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"exifr": "^7.1.3",
|
||||
"firebase": "^9.6.1",
|
||||
"graphql": "^16.2.0",
|
||||
"i18next": "^21.6.3",
|
||||
"i18next-browser-languagedetector": "^6.1.2",
|
||||
"jsoneditor": "^9.5.8",
|
||||
"firebase": "^9.6.10",
|
||||
"graphql": "^16.3.0",
|
||||
"i18next": "^21.6.14",
|
||||
"i18next-browser-languagedetector": "^6.1.4",
|
||||
"jsoneditor": "^9.7.4",
|
||||
"jsreport-browser-client-dist": "^1.3.0",
|
||||
"libphonenumber-js": "^1.9.44",
|
||||
"logrocket": "^2.1.2",
|
||||
"markerjs2": "^2.17.2",
|
||||
"libphonenumber-js": "^1.9.50",
|
||||
"logrocket": "^2.2.1",
|
||||
"markerjs2": "^2.20.0",
|
||||
"moment-business-days": "^1.2.0",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"phone": "^3.1.10",
|
||||
"phone": "^3.1.14",
|
||||
"preval.macro": "^5.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^7.0.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"query-string": "^7.1.1",
|
||||
"rc-queue-anim": "^2.0.0",
|
||||
"rc-scroll-anim": "^2.7.6",
|
||||
"react": "^17.0.2",
|
||||
@@ -45,41 +45,42 @@
|
||||
"react-color": "^2.19.3",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-drag-listview": "^0.1.8",
|
||||
"react-drag-listview": "^0.1.9",
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-layout": "^1.3.0",
|
||||
"react-i18next": "^11.15.1",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^11.16.2",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-number-format": "^4.9.0",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-number-format": "^4.9.1",
|
||||
"react-redux": "^7.2.7",
|
||||
"react-resizable": "^3.0.4",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-sticky": "^6.0.3",
|
||||
"react-sublime-video": "^0.2.5",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"recharts": "^2.1.8",
|
||||
"recharts": "^2.1.9",
|
||||
"redux": "^4.1.2",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-state-sync": "^3.1.2",
|
||||
"reselect": "^4.1.5",
|
||||
"sass": "^1.45.0",
|
||||
"socket.io-client": "^4.4.0",
|
||||
"styled-components": "^5.3.3",
|
||||
"sass": "^1.49.10",
|
||||
"socket.io-client": "^4.4.1",
|
||||
"styled-components": "^5.3.5",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
"web-vitals": "^2.1.2",
|
||||
"workbox-background-sync": "^6.4.2",
|
||||
"workbox-broadcast-update": "^6.4.2",
|
||||
"workbox-cacheable-response": "^6.4.2",
|
||||
"workbox-core": "^6.4.2",
|
||||
"workbox-expiration": "^6.4.2",
|
||||
"workbox-google-analytics": "^6.4.2",
|
||||
"workbox-navigation-preload": "^6.4.2",
|
||||
"workbox-precaching": "^6.4.2",
|
||||
"workbox-range-requests": "^6.4.2",
|
||||
"workbox-routing": "^6.4.2",
|
||||
"workbox-strategies": "^6.4.2",
|
||||
"workbox-streams": "^6.4.2",
|
||||
"web-vitals": "^2.1.4",
|
||||
"workbox-background-sync": "^6.5.2",
|
||||
"workbox-broadcast-update": "^6.5.2",
|
||||
"workbox-cacheable-response": "^6.5.2",
|
||||
"workbox-core": "^6.5.2",
|
||||
"workbox-expiration": "^6.5.2",
|
||||
"workbox-google-analytics": "^6.5.2",
|
||||
"workbox-navigation-preload": "^6.5.2",
|
||||
"workbox-precaching": "^6.5.2",
|
||||
"workbox-range-requests": "^6.5.2",
|
||||
"workbox-routing": "^6.5.2",
|
||||
"workbox-strategies": "^6.5.2",
|
||||
"workbox-streams": "^6.5.2",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -116,11 +117,11 @@
|
||||
"react-error-overlay": "6.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sentry/webpack-plugin": "^1.18.3",
|
||||
"@sentry/webpack-plugin": "^1.18.8",
|
||||
"@testing-library/cypress": "^8.0.2",
|
||||
"cypress": "^9.1.1",
|
||||
"cypress": "^9.5.3",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"react-error-overlay": "6.0.9",
|
||||
"react-error-overlay": "6.0.10",
|
||||
"redux-logger": "^3.0.6",
|
||||
"source-map-explorer": "^2.5.2"
|
||||
}
|
||||
|
||||
@@ -162,10 +162,19 @@ export function AccountingPayablesTableComponent({
|
||||
const dataSource = state.search
|
||||
? payments.filter(
|
||||
(v) =>
|
||||
(v.vendor.name || "")
|
||||
(v.paymentnum || "")
|
||||
.toLowerCase()
|
||||
.includes(state.search.toLowerCase()) ||
|
||||
(v.invoice_number || "")
|
||||
((v.job && v.job.ro_number) || "")
|
||||
.toLowerCase()
|
||||
.includes(state.search.toLowerCase()) ||
|
||||
((v.job && v.job.ownr_fn) || "")
|
||||
.toLowerCase()
|
||||
.includes(state.search.toLowerCase()) ||
|
||||
((v.job && v.job.ownr_ln) || "")
|
||||
.toLowerCase()
|
||||
.includes(state.search.toLowerCase()) ||
|
||||
((v.job && v.job.ownr_co_nm) || "")
|
||||
.toLowerCase()
|
||||
.includes(state.search.toLowerCase())
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
||||
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
|
||||
|
||||
@@ -12,6 +12,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -62,6 +63,18 @@ export function AccountingReceivablesTableComponent({
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.date_invoiced"),
|
||||
dataIndex: "date_invoiced",
|
||||
key: "date_invoiced",
|
||||
sorter: (a, b) => dateSort(a.date_invoiced, b.date_invoiced),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "date_invoiced" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<DateFormatter>{record.date_invoiced}</DateFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.owner"),
|
||||
dataIndex: "owner",
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function JobReconciliationBillsTable({
|
||||
dataIndex: "line_desc",
|
||||
key: "line_desc",
|
||||
ellipsis: true,
|
||||
minWidth: "65rem",
|
||||
width: "10rem",
|
||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||
@@ -72,11 +72,11 @@ export default function JobReconciliationBillsTable({
|
||||
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.is_credit_memo"),
|
||||
title: t("bills.fields.is_credit_memo_short"),
|
||||
dataIndex: "is_credit_memo",
|
||||
key: "is_credit_memo",
|
||||
sorter: (a, b) => a.bill.is_credit_memo - b.bill.is_credit_memo,
|
||||
width: "8rem",
|
||||
width: "3rem",
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "is_credit_memo" &&
|
||||
state.sortedInfo.order,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
@@ -23,8 +22,8 @@ import FormItemPhone, {
|
||||
} from "../form-items-formatted/phone-form-item.component";
|
||||
import Car from "../job-damage-visual/job-damage-visual.component";
|
||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -220,15 +219,8 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Divider
|
||||
orientation="left"
|
||||
type="horizontal"
|
||||
style={{ marginTop: ".8rem", float: "right" }}
|
||||
>
|
||||
{t("jobs.forms.appraiserinfo")}
|
||||
</Divider>
|
||||
|
||||
<FormRow noDivider>
|
||||
<FormRow header={t("jobs.forms.appraiserinfo")}>
|
||||
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
|
||||
@@ -63,10 +63,11 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
|
||||
${job.v_make_desc || ""}
|
||||
${job.v_model_desc || ""}`.trim();
|
||||
console.log(
|
||||
"🚀 ~ file: jobs-detail-header.component.jsx ~ line 64 ~ vehicleTitle",
|
||||
vehicleTitle.length
|
||||
);
|
||||
|
||||
const ownerTitle = `${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
||||
job.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
|
||||
return (
|
||||
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
|
||||
<Col {...colSpan}>
|
||||
@@ -159,9 +160,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
style={{ height: "100%" }}
|
||||
title={
|
||||
<Link to={disabled ? "#" : `/manage/owners/${job.owner.id}`}>
|
||||
{`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
||||
job.ownr_co_nm || ""
|
||||
}`}
|
||||
{ownerTitle.length > 0
|
||||
? ownerTitle
|
||||
: t("owner.labels.noownerinfo")}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -425,8 +425,6 @@ export function PartsOrderListTableComponent({
|
||||
placement="right"
|
||||
onClose={() => handleOnRowClick(null)}
|
||||
visible={selectedpartsorder}
|
||||
//getContainer={false}
|
||||
style={{ position: "absolute" }}
|
||||
closable
|
||||
width={drawerPercentage}
|
||||
>
|
||||
|
||||
@@ -61,20 +61,22 @@ export default function ProductionBoardCard(
|
||||
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||
)}
|
||||
<span style={{ fontWeight: "bolder" }}>
|
||||
{card.ro_number || t("general.labels.na")}
|
||||
<Link
|
||||
to={
|
||||
technician
|
||||
? `/tech/joblookup?selected=${card.id}`
|
||||
: `/manage/jobs/${card.id}`
|
||||
}
|
||||
>
|
||||
{card.ro_number || t("general.labels.na")}
|
||||
</Link>
|
||||
</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
technician ? (
|
||||
<Link to={`/tech/joblookup?selected=${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
)
|
||||
<Link to={{ search: `?selected=${card.id}` }}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Row>
|
||||
|
||||
@@ -131,6 +131,13 @@ export default function ProductionBoardKanbanCardSettings({
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.stickyheader")}
|
||||
name="stickyheader"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import Board, { moveCard } from "@asseinfo/react-kanban";
|
||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Grid, notification, Button, PageHeader, Space, Statistic } from "antd";
|
||||
import { Button, Grid, notification, PageHeader, Space, Statistic } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Sticky, StickyContainer } from "react-sticky";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
||||
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
||||
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
||||
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
||||
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
|
||||
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
|
||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
technician: selectTechnician,
|
||||
@@ -183,9 +184,52 @@ export function ProductionBoardKanbanComponent({
|
||||
: standardSizes[selectedBreakpoint[0]]
|
||||
: "250";
|
||||
|
||||
const stickyHeader = {
|
||||
renderColumnHeader: ({ title }) => (
|
||||
<Sticky>
|
||||
{({
|
||||
style,
|
||||
|
||||
// the following are also available but unused in this example
|
||||
isSticky,
|
||||
wasSticky,
|
||||
distanceFromTop,
|
||||
distanceFromBottom,
|
||||
calculatedHeight,
|
||||
}) => (
|
||||
<div
|
||||
className="react-kanban-column-header"
|
||||
style={{ ...style, zIndex: "99", backgroundColor: "#ddd" }}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
</Sticky>
|
||||
),
|
||||
};
|
||||
|
||||
const cardSettings =
|
||||
associationSettings &&
|
||||
associationSettings.kanban_settings &&
|
||||
Object.keys(associationSettings.kanban_settings).length > 0
|
||||
? associationSettings.kanban_settings
|
||||
: {
|
||||
ats: true,
|
||||
clm_no: true,
|
||||
compact: false,
|
||||
ownr_nm: true,
|
||||
sublets: true,
|
||||
ins_co_nm: true,
|
||||
production_note: true,
|
||||
employeeassignments: true,
|
||||
scheduled_completion: true,
|
||||
stickyheader: false,
|
||||
};
|
||||
|
||||
return (
|
||||
<Container width={width}>
|
||||
<IndefiniteLoading loading={isMoving} />
|
||||
|
||||
<PageHeader
|
||||
title={
|
||||
<Space>
|
||||
@@ -215,34 +259,19 @@ export function ProductionBoardKanbanComponent({
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
<Board
|
||||
children={boardLanes}
|
||||
disableCardDrag={isMoving}
|
||||
renderCard={(card) =>
|
||||
ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
bodyshop,
|
||||
associationSettings &&
|
||||
associationSettings.kanban_settings &&
|
||||
Object.keys(associationSettings.kanban_settings).length > 0
|
||||
? associationSettings.kanban_settings
|
||||
: {
|
||||
ats: true,
|
||||
clm_no: true,
|
||||
compact: false,
|
||||
ownr_nm: true,
|
||||
sublets: true,
|
||||
ins_co_nm: true,
|
||||
production_note: true,
|
||||
employeeassignments: true,
|
||||
scheduled_completion: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
onCardDragEnd={handleDragEnd}
|
||||
/>
|
||||
<ProductionListDetailComponent jobs={data} />
|
||||
<StickyContainer>
|
||||
<Board
|
||||
style={{ height: "100%" }}
|
||||
children={boardLanes}
|
||||
disableCardDrag={isMoving}
|
||||
{...(cardSettings.stickyheader && stickyHeader)}
|
||||
renderCard={(card) =>
|
||||
ProductionBoardCard(technician, card, bodyshop, cardSettings)
|
||||
}
|
||||
onCardDragEnd={handleDragEnd}
|
||||
/>
|
||||
</StickyContainer>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import ProductionListColumnStatus from "./production-list-columns.status.compone
|
||||
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
||||
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
|
||||
|
||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
return [
|
||||
@@ -96,7 +97,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<ProductionListDate record={record} field="actual_in" time/>
|
||||
<ProductionListDate record={record} field="actual_in" time />
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -477,6 +478,14 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.labels.parts_received"),
|
||||
dataIndex: "parts_received",
|
||||
key: "parts_received",
|
||||
render: (text, record) => (
|
||||
<ProductionListColumnPartsReceived record={record} />
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
export default r;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMemo } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ProductionListColumnPartsReceived);
|
||||
|
||||
export function ProductionListColumnPartsReceived({ bodyshop, record }) {
|
||||
const amount = useMemo(() => {
|
||||
const amount = record.joblines_status.reduce(
|
||||
(acc, val) => {
|
||||
acc.total += val.count;
|
||||
acc.received =
|
||||
val.status === bodyshop.md_order_statuses.default_received
|
||||
? acc.received + val.count
|
||||
: acc.received;
|
||||
return acc;
|
||||
},
|
||||
{ total: 0, received: 0 }
|
||||
);
|
||||
|
||||
return {
|
||||
...amount,
|
||||
percent:
|
||||
amount.total !== 0
|
||||
? ((amount.received / amount.total) * 100).toFixed(0) + "%"
|
||||
: "N/A",
|
||||
};
|
||||
}, [record, bodyshop.md_order_statuses]);
|
||||
|
||||
return `${amount.percent} (${amount.received}/${amount.total})`;
|
||||
}
|
||||
@@ -88,12 +88,6 @@ export function ProductionListTable({
|
||||
);
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
console.log(
|
||||
"🚀 ~ file: production-list-table.component.jsx ~ line 91 ~ pagination, filters, sorter",
|
||||
pagination,
|
||||
filters,
|
||||
sorter
|
||||
);
|
||||
setState({
|
||||
...state,
|
||||
filteredInfo: filters,
|
||||
|
||||
@@ -163,6 +163,27 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item shouldUpdate noStyle>
|
||||
{() => (
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.qbo_usa")}
|
||||
shouldUpdate
|
||||
valuePropName="checked"
|
||||
name={["accountingconfig", "qbo_usa"]}
|
||||
>
|
||||
<Switch
|
||||
disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.qbo_departmentid")}
|
||||
name={["accountingconfig", "qbo_departmentid"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.accountingtiers")}
|
||||
rules={[
|
||||
|
||||
@@ -146,6 +146,11 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
|
||||
employee_refinish
|
||||
employee_prep
|
||||
employee_csr
|
||||
joblines_status{
|
||||
part_type
|
||||
status
|
||||
count
|
||||
}
|
||||
labhrs: joblines_aggregate(
|
||||
where: {
|
||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||
@@ -219,6 +224,11 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
|
||||
employee_refinish
|
||||
employee_prep
|
||||
employee_csr
|
||||
joblines_status{
|
||||
part_type
|
||||
status
|
||||
count
|
||||
}
|
||||
labhrs: joblines_aggregate(
|
||||
where: {
|
||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||
@@ -294,6 +304,11 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
||||
employee_prep
|
||||
employee_csr
|
||||
suspended
|
||||
joblines_status{
|
||||
part_type
|
||||
status
|
||||
count
|
||||
}
|
||||
labhrs: joblines_aggregate(
|
||||
where: {
|
||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
confirmPasswordReset,
|
||||
signInWithEmailAndPassword,
|
||||
signOut,
|
||||
sendPasswordResetEmail,
|
||||
} from "firebase/auth";
|
||||
import { doc } from "firebase/firestore";
|
||||
import i18next from "i18next";
|
||||
@@ -223,16 +224,16 @@ export function* signInSuccessSaga({ payload }) {
|
||||
export function* onSendPasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmail
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
sendPasswordResetEmail
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
}
|
||||
export function* sendPasswordResetEmail({ payload }) {
|
||||
export function* sendPasswordResetEmailSaga({ payload }) {
|
||||
try {
|
||||
yield sendPasswordResetEmail(payload, {
|
||||
yield sendPasswordResetEmail(auth, payload, {
|
||||
url: "https://imex.online/passwordreset",
|
||||
});
|
||||
|
||||
@@ -269,7 +270,7 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
try {
|
||||
console.log("Setting shop timezone.");
|
||||
// moment.tz.setDefault(payload.timezone);
|
||||
// moment.tz.setDefault(payload.timezone);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
"federal_tax_rate": "Federal Tax Rate",
|
||||
"invoice_number": "Invoice Number",
|
||||
"is_credit_memo": "Credit Memo?",
|
||||
"is_credit_memo_short": "CM",
|
||||
"local_tax_rate": "Local Tax Rate",
|
||||
"ro_number": "RO Number",
|
||||
"state_tax_rate": "Provincial/State Tax Rate",
|
||||
@@ -1563,6 +1564,7 @@
|
||||
"override_header": "Override estimate header on import?",
|
||||
"ownerassociation": "Owner Association",
|
||||
"parts": "Parts",
|
||||
"parts_received": "Parts Rec.",
|
||||
"parts_tax_rates": "Parts Tax rates",
|
||||
"partsfilter": "Parts Only",
|
||||
"partssubletstotal": "Parts & Sublets Total",
|
||||
@@ -1842,6 +1844,11 @@
|
||||
"updated": "Note updated successfully."
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"labels": {
|
||||
"noownerinfo": "No owner information."
|
||||
}
|
||||
},
|
||||
"owners": {
|
||||
"actions": {
|
||||
"update": "Update Selected Records"
|
||||
@@ -2078,6 +2085,7 @@
|
||||
"labels": "Labels",
|
||||
"position": "Starting Position"
|
||||
},
|
||||
"lag_time_ro": "Lag Time",
|
||||
"mechanical_authorization": "Mechanical Authorization",
|
||||
"mpi_animal_checklist": "MPI - Animal Checklist",
|
||||
"mpi_eglass_auth": "MPI - eGlass Auth",
|
||||
@@ -2170,6 +2178,12 @@
|
||||
"ats": "Alternative Transportation",
|
||||
"bodyhours": "B",
|
||||
"bodypriority": "B/P",
|
||||
"bodyshop": {
|
||||
"labels": {
|
||||
"qbo_departmentid": "QBO Department ID",
|
||||
"qbo_usa": "QBO USA"
|
||||
}
|
||||
},
|
||||
"cardsettings": "Card Settings",
|
||||
"clm_no": "Claim Number",
|
||||
"comment": "Comment",
|
||||
@@ -2187,6 +2201,7 @@
|
||||
"refinishhours": "R",
|
||||
"scheduled_completion": "Scheduled Completion",
|
||||
"selectview": "Select a View",
|
||||
"stickyheader": "Sticky Header (BETA)",
|
||||
"sublets": "Sublets",
|
||||
"totalhours": "Total Hrs ",
|
||||
"touchtime": "T/T",
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
"federal_tax_rate": "",
|
||||
"invoice_number": "",
|
||||
"is_credit_memo": "",
|
||||
"is_credit_memo_short": "",
|
||||
"local_tax_rate": "",
|
||||
"ro_number": "",
|
||||
"state_tax_rate": "",
|
||||
@@ -1563,6 +1564,7 @@
|
||||
"override_header": "¿Anular encabezado estimado al importar?",
|
||||
"ownerassociation": "",
|
||||
"parts": "Partes",
|
||||
"parts_received": "",
|
||||
"parts_tax_rates": "",
|
||||
"partsfilter": "",
|
||||
"partssubletstotal": "",
|
||||
@@ -1842,6 +1844,11 @@
|
||||
"updated": "Nota actualizada con éxito."
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"labels": {
|
||||
"noownerinfo": ""
|
||||
}
|
||||
},
|
||||
"owners": {
|
||||
"actions": {
|
||||
"update": ""
|
||||
@@ -2078,6 +2085,7 @@
|
||||
"labels": "",
|
||||
"position": ""
|
||||
},
|
||||
"lag_time_ro": "",
|
||||
"mechanical_authorization": "",
|
||||
"mpi_animal_checklist": "",
|
||||
"mpi_eglass_auth": "",
|
||||
@@ -2170,6 +2178,12 @@
|
||||
"ats": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"bodyshop": {
|
||||
"labels": {
|
||||
"qbo_departmentid": "",
|
||||
"qbo_usa": ""
|
||||
}
|
||||
},
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"comment": "",
|
||||
@@ -2187,6 +2201,7 @@
|
||||
"refinishhours": "",
|
||||
"scheduled_completion": "",
|
||||
"selectview": "",
|
||||
"stickyheader": "",
|
||||
"sublets": "",
|
||||
"totalhours": "",
|
||||
"touchtime": "",
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
"federal_tax_rate": "",
|
||||
"invoice_number": "",
|
||||
"is_credit_memo": "",
|
||||
"is_credit_memo_short": "",
|
||||
"local_tax_rate": "",
|
||||
"ro_number": "",
|
||||
"state_tax_rate": "",
|
||||
@@ -1563,6 +1564,7 @@
|
||||
"override_header": "Remplacer l'en-tête d'estimation à l'importation?",
|
||||
"ownerassociation": "",
|
||||
"parts": "les pièces",
|
||||
"parts_received": "",
|
||||
"parts_tax_rates": "",
|
||||
"partsfilter": "",
|
||||
"partssubletstotal": "",
|
||||
@@ -1842,6 +1844,11 @@
|
||||
"updated": "Remarque mise à jour avec succès."
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"labels": {
|
||||
"noownerinfo": ""
|
||||
}
|
||||
},
|
||||
"owners": {
|
||||
"actions": {
|
||||
"update": ""
|
||||
@@ -2078,6 +2085,7 @@
|
||||
"labels": "",
|
||||
"position": ""
|
||||
},
|
||||
"lag_time_ro": "",
|
||||
"mechanical_authorization": "",
|
||||
"mpi_animal_checklist": "",
|
||||
"mpi_eglass_auth": "",
|
||||
@@ -2170,6 +2178,12 @@
|
||||
"ats": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"bodyshop": {
|
||||
"labels": {
|
||||
"qbo_departmentid": "",
|
||||
"qbo_usa": ""
|
||||
}
|
||||
},
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"comment": "",
|
||||
@@ -2187,6 +2201,7 @@
|
||||
"refinishhours": "",
|
||||
"scheduled_completion": "",
|
||||
"selectview": "",
|
||||
"stickyheader": "",
|
||||
"sublets": "",
|
||||
"totalhours": "",
|
||||
"touchtime": "",
|
||||
|
||||
@@ -464,6 +464,14 @@ export const TemplateList = (type, context) => {
|
||||
disabled: false,
|
||||
group: "post",
|
||||
},
|
||||
lag_time_ro: {
|
||||
title: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||
description: "CASL Authorization",
|
||||
subject: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||
key: "lag_time_ro",
|
||||
disabled: false,
|
||||
group: "ro",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "job_special"
|
||||
|
||||
1399
client/yarn.lock
1399
client/yarn.lock
File diff suppressed because it is too large
Load Diff
2
logs/IM_1234_30032022_080308.xml
Normal file
2
logs/IM_1234_30032022_080308.xml
Normal file
File diff suppressed because one or more lines are too long
2
logs/IM_1234_30032022_080358.xml
Normal file
2
logs/IM_1234_30032022_080358.xml
Normal file
File diff suppressed because one or more lines are too long
30873
logs/oAuthClient-log.log
30873
logs/oAuthClient-log.log
File diff suppressed because one or more lines are too long
@@ -611,6 +611,32 @@ exports.default = function ({
|
||||
}
|
||||
}
|
||||
|
||||
//QB USA with GST
|
||||
//This was required for the No. 1 Collision Group.
|
||||
if (
|
||||
bodyshop.accountingconfig &&
|
||||
bodyshop.accountingconfig.qbo &&
|
||||
bodyshop.accountingconfig.qbo_usa &&
|
||||
bodyshop.region_config.includes("CA_")
|
||||
) {
|
||||
InvoiceLineAdd.push({
|
||||
DetailType: "SalesItemLineDetail",
|
||||
Amount: Dinero(jobs_by_pk.job_totals.totals.federal_tax).toFormat(
|
||||
DineroQbFormat
|
||||
),
|
||||
SalesItemLineDetail: {
|
||||
...(jobs_by_pk.class
|
||||
? { ClassRef: { value: classes[jobs_by_pk.class] } }
|
||||
: {}),
|
||||
ItemRef: {
|
||||
value:
|
||||
items[bodyshop.md_responsibility_centers.taxes.federal.accountitem],
|
||||
},
|
||||
Qty: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return InvoiceLineAdd;
|
||||
};
|
||||
|
||||
@@ -626,7 +652,7 @@ const findTaxCode = ({ local, state, federal }, taxcode) => {
|
||||
} else if (t.length > 1) {
|
||||
return "Multiple Tax Codes Match";
|
||||
} else {
|
||||
return "No Tax Code Matches";
|
||||
return "";
|
||||
}
|
||||
};
|
||||
exports.findTaxCode = findTaxCode;
|
||||
|
||||
@@ -174,6 +174,55 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
||||
req
|
||||
);
|
||||
|
||||
const lines = bill.billlines.map((il) =>
|
||||
generateBillLine(
|
||||
il,
|
||||
accounts,
|
||||
bill.job.class,
|
||||
bill.job.bodyshop.md_responsibility_centers.sales_tax_codes,
|
||||
classes,
|
||||
taxCodes,
|
||||
bill.job.bodyshop.md_responsibility_centers.costs
|
||||
)
|
||||
);
|
||||
|
||||
//QB USA with GST
|
||||
//This was required for the No. 1 Collision Group.
|
||||
if (
|
||||
bill.job.bodyshop.accountingconfig &&
|
||||
bill.job.bodyshop.accountingconfig.qbo &&
|
||||
bill.job.bodyshop.accountingconfig.qbo_usa &&
|
||||
bill.job.bodyshop.region_config.includes("CA_")
|
||||
) {
|
||||
lines.push({
|
||||
DetailType: "AccountBasedExpenseLineDetail",
|
||||
|
||||
AccountBasedExpenseLineDetail: {
|
||||
...(bill.job.class
|
||||
? { ClassRef: { value: classes[bill.job.class] } }
|
||||
: {}),
|
||||
AccountRef: {
|
||||
value:
|
||||
accounts[
|
||||
bill.job.bodyshop.md_responsibility_centers.taxes.federal
|
||||
.accountdesc
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
Amount: Dinero({
|
||||
amount: Math.round(
|
||||
bill.billlines.reduce((acc, val) => {
|
||||
return acc + val.actual_cost * val.quantity;
|
||||
}, 0) * 100
|
||||
),
|
||||
})
|
||||
.percentage(bill.federal_tax_rate)
|
||||
|
||||
.toFormat(DineroQbFormat),
|
||||
});
|
||||
}
|
||||
|
||||
const billQbo = {
|
||||
VendorRef: {
|
||||
value: vendor.Id,
|
||||
@@ -192,17 +241,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
||||
//...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}),
|
||||
|
||||
PrivateNote: `RO ${bill.job.ro_number || ""}`,
|
||||
Line: bill.billlines.map((il) =>
|
||||
generateBillLine(
|
||||
il,
|
||||
accounts,
|
||||
bill.job.class,
|
||||
bill.job.bodyshop.md_responsibility_centers.sales_tax_codes,
|
||||
classes,
|
||||
taxCodes,
|
||||
bill.job.bodyshop.md_responsibility_centers.costs
|
||||
)
|
||||
),
|
||||
Line: lines,
|
||||
};
|
||||
logger.log("qbo-payable-objectlog", "DEBUG", req.user.email, bill.id, {
|
||||
billQbo,
|
||||
@@ -282,7 +321,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req) {
|
||||
url: urlBuilder(
|
||||
qbo_realmId,
|
||||
"query",
|
||||
`select * From Account where AccountType = 'Cost of Goods Sold'`
|
||||
`select * From Account where AccountType in ('Cost of Goods Sold', 'Other Current Liability')`
|
||||
),
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
||||
@@ -455,6 +455,25 @@ async function InsertInvoice(
|
||||
CustomerRef: {
|
||||
value: parentTierRef.Id,
|
||||
},
|
||||
...(bodyshop.accountingconfig.qbo_departmentid &&
|
||||
bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && {
|
||||
DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid },
|
||||
}),
|
||||
|
||||
...(bodyshop.accountingconfig &&
|
||||
bodyshop.accountingconfig.qbo &&
|
||||
bodyshop.accountingconfig.qbo_usa &&
|
||||
bodyshop.region_config.includes("CA_") && {
|
||||
TxnTaxDetail: {
|
||||
TxnTaxCodeRef: {
|
||||
value:
|
||||
taxCodes[
|
||||
bodyshop.md_responsibility_centers.taxes.state.accountitem
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
...(bodyshop.accountingconfig.printlater
|
||||
? { PrintStatus: "NeedToPrint" }
|
||||
: {}),
|
||||
|
||||
@@ -39,7 +39,7 @@ exports.default = async (req, res) => {
|
||||
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
||||
|
||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
||||
const start = req.body.start; //YYYY-MM-DD
|
||||
const { start, end } = req.body; //YYYY-MM-DD
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
try {
|
||||
@@ -58,6 +58,7 @@ exports.default = async (req, res) => {
|
||||
start: start
|
||||
? moment(start).startOf("day")
|
||||
: moment().subtract(3, "days").startOf("day"),
|
||||
...(end && { end: moment(end).startOf("day") }),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -184,6 +185,11 @@ exports.default = async (req, res) => {
|
||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
//Level 2
|
||||
|
||||
if (!job.job_totals) {
|
||||
errorCallback({ job, error: { toString: () => "No job totals for RO." } });
|
||||
return {};
|
||||
}
|
||||
|
||||
const repairCosts = CreateCosts(job);
|
||||
|
||||
try {
|
||||
|
||||
@@ -111,6 +111,11 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
ro_number
|
||||
clm_total
|
||||
clm_no
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
v_make_desc
|
||||
v_vin
|
||||
plate_no
|
||||
ownerid
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
@@ -176,6 +181,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
bodyshops(where: {associations: {active: {_eq: true}}}) {
|
||||
id
|
||||
md_responsibility_centers
|
||||
region_config
|
||||
accountingconfig
|
||||
md_ins_cos
|
||||
timezone
|
||||
@@ -389,6 +395,8 @@ query QUERY_BILLS_FOR_PAYABLES_EXPORT($bills: [uuid!]!) {
|
||||
bodyshop{
|
||||
md_responsibility_centers
|
||||
timezone
|
||||
region_config
|
||||
accountingconfig
|
||||
}
|
||||
}
|
||||
billlines{
|
||||
@@ -550,7 +558,7 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
|
||||
}
|
||||
}`;
|
||||
|
||||
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) {
|
||||
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!, $end: timestamptz) {
|
||||
bodyshops_by_pk(id: $bodyshopid){
|
||||
|
||||
id
|
||||
@@ -568,7 +576,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop
|
||||
jc_hourly_rates
|
||||
timezone
|
||||
}
|
||||
jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) {
|
||||
jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {shopid: {_eq: $bodyshopid}}]}) {
|
||||
id
|
||||
ro_number
|
||||
status
|
||||
|
||||
Reference in New Issue
Block a user