Compare commits

..

1 Commits

Author SHA1 Message Date
Dave Richer
2c8f5c7184 feature/IO-3060-Realtime-Notification-System: Weird sql Lind endings 2025-01-15 11:11:03 -08:00
38 changed files with 11301 additions and 11862 deletions

1
.gitattributes vendored
View File

@@ -67,6 +67,7 @@
*.rb text eol=lf *.rb text eol=lf
*.java text eol=lf *.java text eol=lf
*.php text eol=lf *.php text eol=lf
*.sql text eol=lf
# Git configuration files # Git configuration files
.gitattributes text eol=lf .gitattributes text eol=lf

View File

@@ -6369,27 +6369,6 @@
<folder_node> <folder_node>
<name>md_parts_scan</name> <name>md_parts_scan</name>
<children> <children>
<concept_node>
<name>caseInsensitive</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>expression</name> <name>expression</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -6411,27 +6390,6 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>field</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>flags</name> <name>flags</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -6453,48 +6411,6 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>operation</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>value</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> </children>
</folder_node> </folder_node>
<concept_node> <concept_node>
@@ -12071,158 +11987,6 @@
</concept_node> </concept_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>operations</name>
<children>
<concept_node>
<name>contains</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>ends_with</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>equals</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>greater_than</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>less_than</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>not_equals</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>starts_with</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> <folder_node>
<name>successes</name> <name>successes</name>
<children> <children>
@@ -23367,27 +23131,6 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>alt_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> <concept_node>
<name>amount</name> <name>amount</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -23493,27 +23236,6 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>include_in_part_cnt</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>
<folder_node> <folder_node>
<name>lbr_types</name> <name>lbr_types</name>
<children> <children>

View File

@@ -85,17 +85,6 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, payments,
sortOrder: state.sortedInfo.columnKey === "amount" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "amount" && state.sortedInfo.order,
render: (text, record) => <CurrencyFormatter>{record.amount}</CurrencyFormatter> render: (text, record) => <CurrencyFormatter>{record.amount}</CurrencyFormatter>
}, },
{
title: t("payments.fields.type"),
dataIndex: "type",
key: "type",
sorter: (a, b) => a.type.localeCompare(b.type),
sortOrder: state.sortedInfo.columnKey === "type" && state.sortedInfo.order,
filters: bodyshop.md_payment_types.map((s) => {
return { text: s, value: [s] };
}),
onFilter: (value, record) => value.includes(record.type)
},
{ {
title: t("payments.fields.memo"), title: t("payments.fields.memo"),
dataIndex: "memo", dataIndex: "memo",

View File

@@ -1,30 +1,30 @@
import { AlertFilled } from "@ant-design/icons"; import { AlertFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Divider, Dropdown, Form, Input, notification, Popover, Select, Space } from "antd"; import { Button, Divider, Dropdown, Form, Input, notification, Popover, Select, Space } from "antd";
import parsePhoneNumber from "libphonenumber-js"; import parsePhoneNumber from "libphonenumber-js";
import dayjs from "../../utils/day";
import queryString from "query-string"; import queryString from "query-string";
import React, { useContext, useState } from "react"; import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import dayjs from "../../utils/day";
import { GenerateDocument } from "../../utils/RenderTemplate"; import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component"; import DataLabel from "../data-label/data-label.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component"; import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
import ScheduleAtChange from "./job-at-change.component"; import ScheduleAtChange from "./job-at-change.component";
import ScheduleEventColor from "./schedule-event.color.component"; import ScheduleEventColor from "./schedule-event.color.component";
import ScheduleEventNote from "./schedule-event.note.component"; import ScheduleEventNote from "./schedule-event.note.component";
import { useMutation } from "@apollo/client";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -127,7 +127,6 @@ export function ScheduleEventComponent({
<DataLabel label={t("jobs.fields.ownr_ph2")}> <DataLabel label={t("jobs.fields.ownr_ph2")}>
<ChatOpenButton phone={event.job && event.job.ownr_ph2} jobid={event.job.id} /> <ChatOpenButton phone={event.job && event.job.ownr_ph2} jobid={event.job.id} />
</DataLabel> </DataLabel>
<DataLabel hideIfNull label={t("jobs.fields.loss_of_use")}>{(event.job && event.job.loss_of_use) || ""}</DataLabel>
<DataLabel label={t("jobs.fields.alt_transport")}> <DataLabel label={t("jobs.fields.alt_transport")}>
{(event.job && event.job.alt_transport) || ""} {(event.job && event.job.alt_transport) || ""}
<ScheduleAtChange job={event && event.job} /> <ScheduleAtChange job={event && event.job} />

View File

@@ -519,7 +519,6 @@ export function JobLinesComponent({
{selectedLines.length > 0 && ` (${selectedLines.length})`} {selectedLines.length > 0 && ` (${selectedLines.length})`}
</Button> </Button>
<Button <Button
id="job-lines-order-parts-button"
disabled={(job && !job.converted) || (selectedLines.length > 0 ? false : true) || jobRO || technician} disabled={(job && !job.converted) || (selectedLines.length > 0 ? false : true) || jobRO || technician}
onClick={() => { onClick={() => {
setPartsOrderContext({ setPartsOrderContext({
@@ -542,7 +541,6 @@ export function JobLinesComponent({
{selectedLines.length > 0 && ` (${selectedLines.length})`} {selectedLines.length > 0 && ` (${selectedLines.length})`}
</Button> </Button>
<Button <Button
id="job-lines-filter-parts-only-button"
onClick={() => { onClick={() => {
setState((state) => ({ setState((state) => ({
...state, ...state,
@@ -556,7 +554,7 @@ export function JobLinesComponent({
<FilterFilled /> {t("jobs.actions.filterpartsonly")} <FilterFilled /> {t("jobs.actions.filterpartsonly")}
</Button> </Button>
<Dropdown menu={markMenu} trigger={["click"]}> <Dropdown menu={markMenu} trigger={["click"]}>
<Button id="repair-data-mark-button">{t("jobs.actions.mark")}</Button> <Button>{t("jobs.actions.mark")}</Button>
</Dropdown> </Dropdown>
<Button <Button
disabled={jobRO || technician} disabled={jobRO || technician}

View File

@@ -192,23 +192,6 @@ export function JobLinesUpsertModalComponent({ bodyshop, open, jobLine, handleCa
<Form.Item label={t("joblines.fields.tax_part")} name="tax_part" valuePropName="checked" initialValue={true}> <Form.Item label={t("joblines.fields.tax_part")} name="tax_part" valuePropName="checked" initialValue={true}>
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item dependencies={[["act_price"]]} noStyle>
{() => {
if (form.getFieldValue("act_price") === 0) {
return (
<Form.Item
label={t("joblines.fields.include_in_part_cnt")}
name="include_in_part_cnt"
valuePropName="checked"
>
<Switch />
</Form.Item>
);
} else {
return null;
}
}}
</Form.Item>
</LayoutFormRow> </LayoutFormRow>
</Form> </Form>
</Modal> </Modal>

View File

@@ -173,7 +173,7 @@ export function JobsCloseExportButton({
} }
}); });
if (!jobUpdateResponse.errors) { if (!!!jobUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "jobsuccessexport", key: "jobsuccessexport",
@@ -222,7 +222,7 @@ export function JobsCloseExportButton({
}; };
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled}>
{t("jobs.actions.export")} {t("jobs.actions.export")}
</Button> </Button>
); );

View File

@@ -982,7 +982,7 @@ export function JobsDetailRatesParts({ jobRO, expanded, required = true, form })
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("jobs.labels.cieca_pfo")}> <LayoutFormRow>
<Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt"> <Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} /> <InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item> </Form.Item>

View File

@@ -10,8 +10,8 @@ import { auth, logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_JOBS } from "../../graphql/jobs.queries"; import { UPDATE_JOBS } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import client from "../../utils/GraphQLClient"; import client from "../../utils/GraphQLClient";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -165,7 +165,7 @@ export function JobsExportAllButton({
} }
}); });
if (!jobUpdateResponse.errors) { if (!!!jobUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "jobsuccessexport", key: "jobsuccessexport",
@@ -213,13 +213,13 @@ export function JobsExportAllButton({
}) })
); );
if (completedCallback) completedCallback([]); if (!!completedCallback) completedCallback([]);
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
}; };
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled || jobIds?.length > 10} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled || jobIds?.length > 10}>
{t("jobs.actions.exportselected")} {t("jobs.actions.exportselected")}
</Button> </Button>
); );

View File

@@ -1,5 +1,6 @@
import { EditFilled } from "@ant-design/icons"; import { EditFilled } from "@ant-design/icons";
import { Alert, Card, Col, Row, Space, Table, Typography } from "antd"; import { Alert, Card, Col, Row, Space, Table, Typography } from "antd";
import _ from "lodash";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -8,11 +9,11 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component"; import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component";
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
import "./labor-allocations-table.styles.scss"; import "./labor-allocations-table.styles.scss";
import { CalculateAllocationsTotals } from "./labor-allocations-table.utility"; import { CalculateAllocationsTotals } from "./labor-allocations-table.utility";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
technician: selectTechnician technician: selectTechnician
@@ -64,7 +65,6 @@ export function LaborAllocationsTable({
key: "total", key: "total",
sorter: (a, b) => a.total - b.total, sorter: (a, b) => a.total - b.total,
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
align: "right",
render: (text, record) => record.total.toFixed(1) render: (text, record) => record.total.toFixed(1)
}, },
{ {
@@ -73,7 +73,6 @@ export function LaborAllocationsTable({
key: "hrs_claimed", key: "hrs_claimed",
sorter: (a, b) => a.claimed - b.claimed, sorter: (a, b) => a.claimed - b.claimed,
sortOrder: state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order,
align: "right",
render: (text, record) => record.claimed && record.claimed.toFixed(1) render: (text, record) => record.claimed && record.claimed.toFixed(1)
}, },
{ {
@@ -82,7 +81,6 @@ export function LaborAllocationsTable({
key: "adjustments", key: "adjustments",
sorter: (a, b) => a.adjustments - b.adjustments, sorter: (a, b) => a.adjustments - b.adjustments,
sortOrder: state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order,
align: "right",
render: (text, record) => ( render: (text, record) => (
<Space wrap> <Space wrap>
{record.adjustments.toFixed(1)} {record.adjustments.toFixed(1)}
@@ -102,17 +100,17 @@ export function LaborAllocationsTable({
{ {
title: t("jobs.labels.difference"), title: t("jobs.labels.difference"),
dataIndex: "difference", dataIndex: "difference",
key: "difference", key: "difference",
sorter: (a, b) => a.difference - b.difference, sorter: (a, b) => a.difference - b.difference,
sortOrder: state.sortedInfo.columnKey === "difference" && state.sortedInfo.order, sortOrder: state.sortedInfo.columnKey === "difference" && state.sortedInfo.order,
align: "right",
render: (text, record) => ( render: (text, record) => (
<strong <strong
style={{ style={{
color: record.difference.toFixed(1) >= 0 ? "green" : "red" color: record.difference >= 0 ? "green" : "red"
}} }}
> >
{(Math.abs(record.difference) < 0.05 ? 0 : record.difference).toFixed(1)} {_.round(record.difference, 1)}
</strong> </strong>
) )
} }
@@ -131,6 +129,7 @@ export function LaborAllocationsTable({
ellipsis: true, ellipsis: true,
render: (text, record) => `${record.op_code_desc || ""}${record.alt_partm ? ` ${record.alt_partm}` : ""}` render: (text, record) => `${record.op_code_desc || ""}${record.alt_partm ? ` ${record.alt_partm}` : ""}`
}, },
{ {
title: t("joblines.fields.act_price"), title: t("joblines.fields.act_price"),
dataIndex: "act_price", dataIndex: "act_price",
@@ -188,7 +187,7 @@ export function LaborAllocationsTable({
{ hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 } { hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 }
); );
if (Math.abs(summary.difference.toFixed(1)) !== 0 && typeof warningCallback === "function") { if (summary.difference !== 0 && typeof warningCallback === "function") {
warningCallback({ key: "labor", warning: t("jobs.labels.outstandinghours") }); warningCallback({ key: "labor", warning: t("jobs.labels.outstandinghours") });
} }
@@ -218,21 +217,19 @@ export function LaborAllocationsTable({
summary={() => ( summary={() => (
<Table.Summary.Row> <Table.Summary.Row>
<Table.Summary.Cell> <Table.Summary.Cell>
<Typography.Title level={4} style={{ margin: 0, lineHeight: 1 }}> <Typography.Title level={4}>{t("general.labels.totals")}</Typography.Title>
{t("general.labels.totals")}
</Typography.Title>
</Table.Summary.Cell> </Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.hrs_total.toFixed(1)}</Table.Summary.Cell> <Table.Summary.Cell>{summary.hrs_total.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.hrs_claimed.toFixed(1)}</Table.Summary.Cell> <Table.Summary.Cell>{summary.hrs_claimed.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.adjustments.toFixed(1)}</Table.Summary.Cell> <Table.Summary.Cell>{summary.adjustments.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right"> <Table.Summary.Cell>
<Typography.Text <Typography.Text
style={{ style={{
fontWeight: "bold", fontWeight: "bold",
color: summary.difference.toFixed(1) >= 0 ? "green" : "red" color: summary.difference >= 0 ? "green" : "red"
}} }}
> >
{(Math.abs(summary.difference) < 0.05 ? 0 : summary.difference).toFixed(1)} {summary.difference.toFixed(1)}
</Typography.Text> </Typography.Text>
</Table.Summary.Cell> </Table.Summary.Cell>
</Table.Summary.Row> </Table.Summary.Row>
@@ -264,10 +261,11 @@ export function LaborAllocationsTable({
</Card> </Card>
</Col> </Col>
)} )}
{showWarning && Math.abs(summary.difference.toFixed(1)) !== 0 && ( {showWarning && summary.difference !== 0 && (
<Alert style={{ margin: "8px 0px" }} type="warning" message={t("jobs.labels.outstandinghours")} /> <Alert style={{ margin: "8px 0px" }} type="warning" message={t("jobs.labels.outstandinghours")} />
)} )}
</Row> </Row>
); );
} }
export default connect(mapStateToProps, null)(LaborAllocationsTable); export default connect(mapStateToProps, null)(LaborAllocationsTable);

View File

@@ -38,11 +38,7 @@ export default function OwnerFindModalContainer({
}, [callSearchowners, modalProps.open, owner]); }, [callSearchowners, modalProps.open, owner]);
return ( return (
<Modal <Modal title={t("owners.labels.existing_owners")} width={"80%"} {...modalProps}>
title={<span id="owner-find-modal-title">{t("owners.labels.existing_owners")}</span>}
width={"80%"}
{...modalProps}
>
{loading ? <LoadingSpinner /> : null} {loading ? <LoadingSpinner /> : null}
{error ? <AlertComponent message={error.message} type="error" /> : null} {error ? <AlertComponent message={error.message} type="error" /> : null}
{owner ? ( {owner ? (

View File

@@ -48,7 +48,7 @@ export function PayableExportAll({
let PartnerResponse; let PartnerResponse;
setLoading(true); setLoading(true);
if (loadingCallback) loadingCallback(true); if (!!loadingCallback) loadingCallback(true);
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
PartnerResponse = await axios.post(`/qbo/payables`, { PartnerResponse = await axios.post(`/qbo/payables`, {
bills: billids, bills: billids,
@@ -85,7 +85,7 @@ export function PayableExportAll({
notification["error"]({ notification["error"]({
message: t("bills.errors.exporting-partner") message: t("bills.errors.exporting-partner")
}); });
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
return; return;
} }
@@ -152,7 +152,7 @@ export function PayableExportAll({
} }
} }
}); });
if (!billUpdateResponse.errors) { if (!!!billUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "billsuccessexport", key: "billsuccessexport",
@@ -187,8 +187,8 @@ export function PayableExportAll({
}); });
await Promise.all(proms); await Promise.all(proms);
if (completedCallback) completedCallback([]); if (!!completedCallback) completedCallback([]);
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
}; };
@@ -200,7 +200,7 @@ export function PayableExportAll({
); );
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled || billids?.length > 10} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled || billids?.length > 10}>
{t("jobs.actions.exportselected")} {t("jobs.actions.exportselected")}
</Button> </Button>
); );

View File

@@ -46,7 +46,7 @@ export function PayableExportButton({
logImEXEvent("accounting_export_payable"); logImEXEvent("accounting_export_payable");
setLoading(true); setLoading(true);
if (loadingCallback) loadingCallback(true); if (!!loadingCallback) loadingCallback(true);
//Check if it's a QBO Setup. //Check if it's a QBO Setup.
let PartnerResponse; let PartnerResponse;
@@ -88,7 +88,7 @@ export function PayableExportButton({
notification["error"]({ notification["error"]({
message: t("bills.errors.exporting-partner") message: t("bills.errors.exporting-partner")
}); });
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
return; return;
} }
@@ -149,7 +149,7 @@ export function PayableExportButton({
} }
} }
}); });
if (!billUpdateResponse.errors) { if (!!!billUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "billsuccessexport", key: "billsuccessexport",
@@ -186,7 +186,7 @@ export function PayableExportButton({
} }
} }
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
}; };
@@ -198,7 +198,7 @@ export function PayableExportButton({
); );
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled}>
{t("jobs.actions.export")} {t("jobs.actions.export")}
</Button> </Button>
); );

View File

@@ -55,7 +55,7 @@ export function PaymentExportButton({
} else { } else {
//Default is QBD //Default is QBD
if (loadingCallback) loadingCallback(true); if (!!loadingCallback) loadingCallback(true);
let QbXmlResponse; let QbXmlResponse;
try { try {
@@ -88,7 +88,7 @@ export function PaymentExportButton({
notification["error"]({ notification["error"]({
message: t("payments.errors.exporting-partner") message: t("payments.errors.exporting-partner")
}); });
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
return; return;
} }
@@ -148,7 +148,7 @@ export function PaymentExportButton({
} }
} }
}); });
if (!paymentUpdateResponse.errors) { if (!!!paymentUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "paymentsuccessexport", key: "paymentsuccessexport",
@@ -184,12 +184,12 @@ export function PaymentExportButton({
) )
]); ]);
} }
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
}; };
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled}>
{t("jobs.actions.export")} {t("jobs.actions.export")}
</Button> </Button>
); );

View File

@@ -44,7 +44,7 @@ export function PaymentsExportAllButton({
const handleQbxml = async () => { const handleQbxml = async () => {
setLoading(true); setLoading(true);
if (loadingCallback) loadingCallback(true); if (!!loadingCallback) loadingCallback(true);
let PartnerResponse; let PartnerResponse;
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
PartnerResponse = await axios.post(`/qbo/payments`, { PartnerResponse = await axios.post(`/qbo/payments`, {
@@ -76,7 +76,7 @@ export function PaymentsExportAllButton({
notification["error"]({ notification["error"]({
message: t("payments.errors.exporting-partner") message: t("payments.errors.exporting-partner")
}); });
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
return; return;
} }
@@ -140,7 +140,7 @@ export function PaymentsExportAllButton({
} }
} }
}); });
if (!paymentUpdateResponse.errors) { if (!!!paymentUpdateResponse.errors) {
notification.open({ notification.open({
type: "success", type: "success",
key: "paymentsuccessexport", key: "paymentsuccessexport",
@@ -174,13 +174,13 @@ export function PaymentsExportAllButton({
); );
}); });
await Promise.all(proms); await Promise.all(proms);
if (completedCallback) completedCallback([]); if (!!completedCallback) completedCallback([]);
if (loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);
setLoading(false); setLoading(false);
}; };
return ( return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled || paymentIds?.length > 10} type="primary"> <Button onClick={handleQbxml} loading={loading} disabled={disabled || paymentIds?.length > 10}>
{t("jobs.actions.exportselected")} {t("jobs.actions.exportselected")}
</Button> </Button>
); );

View File

@@ -35,7 +35,6 @@ const ret = {
"bills:reexport": 3, "bills:reexport": 3,
"employees:page": 5, "employees:page": 5,
"employee_teams:page": 5,
"owners:list": 2, "owners:list": 2,
"owners:detail": 3, "owners:detail": 3,
@@ -68,9 +67,6 @@ const ret = {
"timetickets:list": 3, "timetickets:list": 3,
"timetickets:edit": 4, "timetickets:edit": 4,
"timetickets:shiftedit": 5, "timetickets:shiftedit": 5,
"timetickets:editcommitted": 5,
"ttapprovals:view": 5,
"ttapprovals:approve": 5,
"users:editaccess": 4, "users:editaccess": 4,

View File

@@ -555,7 +555,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name={["md_email_cc", "parts_order"]} name={["md_email_cc", "parts_order"]}
label={t("bodyshop.fields.md_email_cc", { template: "parts_orders" })} label={t("bodyshop.fields.md_email_cc", { template: "parts_order" })}
rules={[ rules={[
{ {
//message: t("general.validation.required"), //message: t("general.validation.required"),
@@ -567,7 +567,9 @@ export function ShopInfoGeneral({ form, bodyshop }) {
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name={["md_email_cc", "parts_return_slip"]} name={["md_email_cc", "parts_return_slip"]}
label={t("bodyshop.fields.md_email_cc", { template: "parts_returns" })} label={t("bodyshop.fields.md_email_cc", {
template: "parts_return_slip"
})}
rules={[ rules={[
{ {
//message: t("general.validation.required"), //message: t("general.validation.required"),
@@ -1259,7 +1261,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
key={`${index}prt_dsmk_p`} key={`${index}prt_dsmk_p`}
name={[field.name, "prt_dsmk_p"]} name={[field.name, "prt_dsmk_p"]}
> >
<InputNumber precision={0} min={-100} max={100} /> <InputNumber precision={0} min={0} max={100} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("joblines.fields.ah_detail_line")} label={t("joblines.fields.ah_detail_line")}

View File

@@ -73,7 +73,6 @@ export const QUERY_PAYMENTS_FOR_EXPORT = gql`
transactionid transactionid
paymentnum paymentnum
date date
type
exportlogs { exportlogs {
id id
successful successful

View File

@@ -49,7 +49,6 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
est_ct_fn est_ct_fn
est_ct_ln est_ct_ln
comment comment
loss_of_use
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) { labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
aggregate { aggregate {
sum { sum {

View File

@@ -238,7 +238,6 @@ export const UPDATE_JOB_LINE = gql`
convertedtolbr convertedtolbr
convertedtolbr_data convertedtolbr_data
assigned_team assigned_team
include_in_part_cnt
} }
} }
} }

View File

@@ -581,7 +581,6 @@ export const GET_JOB_BY_PK = gql`
status status
tax_part tax_part
unq_seq unq_seq
include_in_part_cnt
} }
kmin kmin
kmout kmout

View File

@@ -256,6 +256,15 @@
} }
}, },
"bodyshop": { "bodyshop": {
"operations": {
"starts_with": "Starts With",
"contains": "Contains",
"ends_with": "Ends With",
"equals": "Equals",
"not_equals": "Not Equals",
"greater_than": "Greater Than",
"less_than": "Less Than"
},
"actions": { "actions": {
"add_task_preset": "Add Task Preset", "add_task_preset": "Add Task Preset",
"addapptcolor": "Add Appointment Color", "addapptcolor": "Add Appointment Color",
@@ -357,7 +366,7 @@
"md_ccc_rates": "Courtesy Car Contract Rate Presets", "md_ccc_rates": "Courtesy Car Contract Rate Presets",
"md_classes": "Classes", "md_classes": "Classes",
"md_ded_notes": "Deductible Notes", "md_ded_notes": "Deductible Notes",
"md_email_cc": "Auto Email CC: $t(parts_orders.labels.{{template}})", "md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})",
"md_from_emails": "Additional From Emails", "md_from_emails": "Additional From Emails",
"md_functionality_toggles": { "md_functionality_toggles": {
"parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue" "parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue"
@@ -379,12 +388,10 @@
"md_lost_sale_reasons": "Lost Sale Reasons", "md_lost_sale_reasons": "Lost Sale Reasons",
"md_parts_order_comment": "Parts Orders Comments", "md_parts_order_comment": "Parts Orders Comments",
"md_parts_scan": { "md_parts_scan": {
"caseInsensitive": "Case Insensitive",
"expression": "",
"field": "Field", "field": "Field",
"flags": "",
"operation": "Operation", "operation": "Operation",
"value": "Value" "value": "Value",
"caseInsensitive": "Case Insensitive"
}, },
"md_payment_types": "Payment Types", "md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources", "md_referral_sources": "Referral Sources",
@@ -629,7 +636,7 @@
"target_touchtime": "Target Touch Time", "target_touchtime": "Target Touch Time",
"timezone": "Timezone", "timezone": "Timezone",
"tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs", "tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs",
"tt_enforce_hours_for_tech_console": "Restrict Claimable Hours", "tt_enforce_hours_for_tech_console": "Restrict Claimable hours from Tech Console",
"use_fippa": "Conceal Customer Information on Generated Documents?", "use_fippa": "Conceal Customer Information on Generated Documents?",
"use_paint_scale_data": "Use Paint Scale Data for Job Costing?", "use_paint_scale_data": "Use Paint Scale Data for Job Costing?",
"uselocalmediaserver": "Use Local Media Server?", "uselocalmediaserver": "Use Local Media Server?",
@@ -714,15 +721,6 @@
"task-presets": "Task Presets", "task-presets": "Task Presets",
"workingdays": "Working Days" "workingdays": "Working Days"
}, },
"operations": {
"contains": "Contains",
"ends_with": "Ends With",
"equals": "Equals",
"greater_than": "Greater Than",
"less_than": "Less Than",
"not_equals": "Not Equals",
"starts_with": "Starts With"
},
"successes": { "successes": {
"areyousure": "Are you sure you want to continue?", "areyousure": "Are you sure you want to continue?",
"defaultviewcreated": "Default view created successfully.", "defaultviewcreated": "Default view created successfully.",
@@ -1436,13 +1434,11 @@
"act_price_before_ppc": "Original Part Price", "act_price_before_ppc": "Original Part Price",
"adjustment": "Adjustment", "adjustment": "Adjustment",
"ah_detail_line": "Mark as Detail Labor Line (Autohouse Only)", "ah_detail_line": "Mark as Detail Labor Line (Autohouse Only)",
"alt_partno": "Alt Part #",
"amount": "Amount", "amount": "Amount",
"assigned_team": "Team", "assigned_team": "Team",
"assigned_team_name": "Team {{name}}", "assigned_team_name": "Team {{name}}",
"create_ppc": "Create PPC?", "create_ppc": "Create PPC?",
"db_price": "List Price", "db_price": "List Price",
"include_in_part_cnt": "Include in Parts Status Count",
"lbr_types": { "lbr_types": {
"LA1": "LA1", "LA1": "LA1",
"LA2": "LA2", "LA2": "LA2",
@@ -1467,6 +1463,7 @@
"mod_lbr_ty": "Labor Type", "mod_lbr_ty": "Labor Type",
"notes": "Notes", "notes": "Notes",
"oem_partno": "OEM Part #", "oem_partno": "OEM Part #",
"alt_partno": "Alt Part #",
"op_code_desc": "Op Code Description", "op_code_desc": "Op Code Description",
"part_qty": "Qty.", "part_qty": "Qty.",
"part_type": "Part Type", "part_type": "Part Type",
@@ -2056,7 +2053,7 @@
"parts": "Parts", "parts": "Parts",
"parts_lines": "Parts Lines", "parts_lines": "Parts Lines",
"parts_received": "Parts Rec.", "parts_received": "Parts Rec.",
"parts_tax_rates": "Profile - Parts", "parts_tax_rates": "Parts Tax rates",
"partsfilter": "Parts Only", "partsfilter": "Parts Only",
"partssubletstotal": "Parts & Sublets Total", "partssubletstotal": "Parts & Sublets Total",
"partstotal": "Parts Total (ex. Taxes)", "partstotal": "Parts Total (ex. Taxes)",
@@ -2532,7 +2529,6 @@
"orderhistory": "Order History", "orderhistory": "Order History",
"parts_order": "Parts Order", "parts_order": "Parts Order",
"parts_orders": "Parts Orders", "parts_orders": "Parts Orders",
"parts_returns": "Parts Returns",
"print": "Show Printed Form", "print": "Show Printed Form",
"receive": "Receive Parts Order", "receive": "Receive Parts Order",
"removefrompartsqueue": "Unqueue from Parts Queue?", "removefrompartsqueue": "Unqueue from Parts Queue?",
@@ -3081,7 +3077,7 @@
"purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)", "purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)",
"purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)", "purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)",
"purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)", "purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)",
"purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)","purchases_by_date_excel": "Purchases by Date - Excel", "purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)",
"purchases_by_date_range_detail": "Purchases by Date - Detail", "purchases_by_date_range_detail": "Purchases by Date - Detail",
"purchases_by_date_range_summary": "Purchases by Date - Summary", "purchases_by_date_range_summary": "Purchases by Date - Summary",
"purchases_by_ro_detail_date": "Purchases by RO - Detail", "purchases_by_ro_detail_date": "Purchases by RO - Detail",

View File

@@ -256,6 +256,15 @@
} }
}, },
"bodyshop": { "bodyshop": {
"operations": {
"starts_with": "",
"contains": "",
"ends_with": "",
"equals": "",
"not_equals": "",
"greater_than": "",
"less_than": ""
},
"actions": { "actions": {
"add_task_preset": "", "add_task_preset": "",
"addapptcolor": "", "addapptcolor": "",
@@ -379,12 +388,10 @@
"md_lost_sale_reasons": "", "md_lost_sale_reasons": "",
"md_parts_order_comment": "", "md_parts_order_comment": "",
"md_parts_scan": { "md_parts_scan": {
"caseInsensitive": "",
"expression": "",
"field": "", "field": "",
"flags": "",
"operation": "", "operation": "",
"value": "" "value": "",
"caseInsensitive": ""
}, },
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
@@ -714,15 +721,6 @@
"task-presets": "", "task-presets": "",
"workingdays": "" "workingdays": ""
}, },
"operations": {
"contains": "",
"ends_with": "",
"equals": "",
"greater_than": "",
"less_than": "",
"not_equals": "",
"starts_with": ""
},
"successes": { "successes": {
"areyousure": "", "areyousure": "",
"defaultviewcreated": "", "defaultviewcreated": "",
@@ -1436,13 +1434,11 @@
"act_price_before_ppc": "", "act_price_before_ppc": "",
"adjustment": "", "adjustment": "",
"ah_detail_line": "", "ah_detail_line": "",
"alt_partno": "",
"amount": "", "amount": "",
"assigned_team": "", "assigned_team": "",
"assigned_team_name": "", "assigned_team_name": "",
"create_ppc": "", "create_ppc": "",
"db_price": "Precio de base de datos", "db_price": "Precio de base de datos",
"include_in_part_cnt": "",
"lbr_types": { "lbr_types": {
"LA1": "", "LA1": "",
"LA2": "", "LA2": "",
@@ -1467,6 +1463,7 @@
"mod_lbr_ty": "Tipo de trabajo", "mod_lbr_ty": "Tipo de trabajo",
"notes": "", "notes": "",
"oem_partno": "OEM parte #", "oem_partno": "OEM parte #",
"alt_partno": "",
"op_code_desc": "", "op_code_desc": "",
"part_qty": "", "part_qty": "",
"part_type": "Tipo de parte", "part_type": "Tipo de parte",
@@ -2532,7 +2529,6 @@
"orderhistory": "Historial de pedidos", "orderhistory": "Historial de pedidos",
"parts_order": "", "parts_order": "",
"parts_orders": "", "parts_orders": "",
"parts_returns": "",
"print": "Mostrar formulario impreso", "print": "Mostrar formulario impreso",
"receive": "", "receive": "",
"removefrompartsqueue": "", "removefrompartsqueue": "",
@@ -3082,7 +3078,6 @@
"purchase_return_ratio_grouped_by_vendor_summary": "", "purchase_return_ratio_grouped_by_vendor_summary": "",
"purchases_by_cost_center_detail": "", "purchases_by_cost_center_detail": "",
"purchases_by_cost_center_summary": "", "purchases_by_cost_center_summary": "",
"purchases_by_date_excel": "",
"purchases_by_date_range_detail": "", "purchases_by_date_range_detail": "",
"purchases_by_date_range_summary": "", "purchases_by_date_range_summary": "",
"purchases_by_ro_detail_date": "", "purchases_by_ro_detail_date": "",

View File

@@ -256,6 +256,15 @@
} }
}, },
"bodyshop": { "bodyshop": {
"operations": {
"starts_with": "",
"contains": "",
"ends_with": "",
"equals": "",
"not_equals": "",
"greater_than": "",
"less_than": ""
},
"actions": { "actions": {
"add_task_preset": "", "add_task_preset": "",
"addapptcolor": "", "addapptcolor": "",
@@ -379,12 +388,10 @@
"md_lost_sale_reasons": "", "md_lost_sale_reasons": "",
"md_parts_order_comment": "", "md_parts_order_comment": "",
"md_parts_scan": { "md_parts_scan": {
"caseInsensitive": "",
"expression": "",
"field": "", "field": "",
"flags": "",
"operation": "", "operation": "",
"value": "" "value": "",
"caseInsensitive": ""
}, },
"md_payment_types": "", "md_payment_types": "",
"md_referral_sources": "", "md_referral_sources": "",
@@ -714,15 +721,6 @@
"task-presets": "", "task-presets": "",
"workingdays": "" "workingdays": ""
}, },
"operations": {
"contains": "",
"ends_with": "",
"equals": "",
"greater_than": "",
"less_than": "",
"not_equals": "",
"starts_with": ""
},
"successes": { "successes": {
"areyousure": "", "areyousure": "",
"defaultviewcreated": "", "defaultviewcreated": "",
@@ -1436,13 +1434,11 @@
"act_price_before_ppc": "", "act_price_before_ppc": "",
"adjustment": "", "adjustment": "",
"ah_detail_line": "", "ah_detail_line": "",
"alt_partno": "",
"amount": "", "amount": "",
"assigned_team": "", "assigned_team": "",
"assigned_team_name": "", "assigned_team_name": "",
"create_ppc": "", "create_ppc": "",
"db_price": "Prix de la base de données", "db_price": "Prix de la base de données",
"include_in_part_cnt": "",
"lbr_types": { "lbr_types": {
"LA1": "", "LA1": "",
"LA2": "", "LA2": "",
@@ -1467,6 +1463,7 @@
"mod_lbr_ty": "Type de travail", "mod_lbr_ty": "Type de travail",
"notes": "", "notes": "",
"oem_partno": "Pièce OEM #", "oem_partno": "Pièce OEM #",
"alt_partno": "",
"op_code_desc": "", "op_code_desc": "",
"part_qty": "", "part_qty": "",
"part_type": "Type de pièce", "part_type": "Type de pièce",
@@ -2532,7 +2529,6 @@
"orderhistory": "Historique des commandes", "orderhistory": "Historique des commandes",
"parts_order": "", "parts_order": "",
"parts_orders": "", "parts_orders": "",
"parts_returns": "",
"print": "Afficher le formulaire imprimé", "print": "Afficher le formulaire imprimé",
"receive": "", "receive": "",
"removefrompartsqueue": "", "removefrompartsqueue": "",
@@ -3082,7 +3078,6 @@
"purchase_return_ratio_grouped_by_vendor_summary": "", "purchase_return_ratio_grouped_by_vendor_summary": "",
"purchases_by_cost_center_detail": "", "purchases_by_cost_center_detail": "",
"purchases_by_cost_center_summary": "", "purchases_by_cost_center_summary": "",
"purchases_by_date_excel": "",
"purchases_by_date_range_detail": "", "purchases_by_date_range_detail": "",
"purchases_by_date_range_summary": "", "purchases_by_date_range_summary": "",
"purchases_by_ro_detail_date": "", "purchases_by_ro_detail_date": "",

View File

@@ -1444,8 +1444,7 @@ export const TemplateList = (type, context) => {
object: i18n.t("reportcenter.labels.objects.jobs"), object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_exported") field: i18n.t("jobs.fields.date_exported")
}, },
group: "sales", group: "sales"
featureNameRestricted: "export"
}, },
gsr_by_estimator: { gsr_by_estimator: {
title: i18n.t("reportcenter.templates.gsr_by_estimator"), title: i18n.t("reportcenter.templates.gsr_by_estimator"),
@@ -1866,8 +1865,7 @@ export const TemplateList = (type, context) => {
object: i18n.t("reportcenter.labels.objects.jobs"), object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_open") field: i18n.t("jobs.fields.date_open")
}, },
group: "jobs", group: "jobs"
featureNameRestricted: "bills"
}, },
psr_by_make: { psr_by_make: {
title: i18n.t("reportcenter.templates.psr_by_make"), title: i18n.t("reportcenter.templates.psr_by_make"),
@@ -1903,8 +1901,7 @@ export const TemplateList = (type, context) => {
object: i18n.t("reportcenter.labels.objects.parts_orders"), object: i18n.t("reportcenter.labels.objects.parts_orders"),
field: i18n.t("parts_orders.fields.order_date") field: i18n.t("parts_orders.fields.order_date")
}, },
group: "jobs", group: "jobs"
featureNameRestricted: "bills"
}, },
returns_grouped_by_vendor_detailed: { returns_grouped_by_vendor_detailed: {
title: i18n.t("reportcenter.templates.returns_grouped_by_vendor_detailed"), title: i18n.t("reportcenter.templates.returns_grouped_by_vendor_detailed"),
@@ -1916,8 +1913,7 @@ export const TemplateList = (type, context) => {
object: i18n.t("reportcenter.labels.objects.parts_orders"), object: i18n.t("reportcenter.labels.objects.parts_orders"),
field: i18n.t("parts_orders.fields.order_date") field: i18n.t("parts_orders.fields.order_date")
}, },
group: "jobs", group: "jobs"
featureNameRestricted: "bills"
}, },
scheduled_parts_list: { scheduled_parts_list: {
title: i18n.t("reportcenter.templates.scheduled_parts_list"), title: i18n.t("reportcenter.templates.scheduled_parts_list"),
@@ -2229,19 +2225,7 @@ export const TemplateList = (type, context) => {
field: i18n.t("jobs.fields.date_open") field: i18n.t("jobs.fields.date_open")
}, },
group: "jobs" group: "jobs"
}, }
purchases_by_date_excel: {
title: i18n.t("reportcenter.templates.purchases_by_date_excel"),
subject: i18n.t("reportcenter.templates.purchases_by_date_excel"),
key: "purchases_by_date_excel",
reporttype: "excel",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.bills"),
field: i18n.t("bills.fields.date")
},
group: "purchases"
},
} }
: {}), : {}),
...(!type || type === "courtesycarcontract" ...(!type || type === "courtesycarcontract"

View File

@@ -2997,7 +2997,6 @@
- est_seq - est_seq
- glass_flag - glass_flag
- id - id
- include_in_part_cnt
- ioucreated - ioucreated
- jobid - jobid
- lbr_amt - lbr_amt
@@ -3067,7 +3066,6 @@
- est_seq - est_seq
- glass_flag - glass_flag
- id - id
- include_in_part_cnt
- ioucreated - ioucreated
- jobid - jobid
- lbr_amt - lbr_amt
@@ -3148,7 +3146,6 @@
- est_seq - est_seq
- glass_flag - glass_flag
- id - id
- include_in_part_cnt
- ioucreated - ioucreated
- jobid - jobid
- lbr_amt - lbr_amt

View File

@@ -1,4 +0,0 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."joblines" add column "include_in_part_cnt" boolean
-- not null default 'false';

View File

@@ -1,2 +0,0 @@
alter table "public"."joblines" add column "include_in_part_cnt" boolean
not null default 'false';

View File

@@ -1,10 +0,0 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE VIEW "public"."joblines_status" AS
-- SELECT j.jobid,
-- j.status,
-- count(1) AS count,
-- j.part_type
-- FROM joblines j
-- WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND ((j.part_qty)::numeric <> (0)::numeric) AND ((j.act_price <> (0)::numeric) OR (j.include_in_part_cnt is TRUE))AND (j.removed IS FALSE))
-- GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,8 +0,0 @@
CREATE OR REPLACE VIEW "public"."joblines_status" AS
SELECT j.jobid,
j.status,
count(1) AS count,
j.part_type
FROM joblines j
WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND ((j.part_qty)::numeric <> (0)::numeric) AND ((j.act_price <> (0)::numeric) OR (j.include_in_part_cnt is TRUE))AND (j.removed IS FALSE))
GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,10 +0,0 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE VIEW "public"."joblines_status" AS
-- SELECT j.jobid,
-- j.status,
-- count(1) AS count,
-- j.part_type
-- FROM joblines j
-- WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND ((j.part_qty)::numeric <> (0)::numeric) AND ((j.act_price <> (0)::numeric) OR (j.include_in_part_cnt is TRUE))AND (j.removed IS FALSE))
-- GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -1,8 +0,0 @@
CREATE OR REPLACE VIEW "public"."joblines_status" AS
SELECT j.jobid,
j.status,
count(1) AS count,
j.part_type
FROM joblines j
WHERE ((j.part_type IS NOT NULL) AND (j.part_type <> 'PAE'::text) AND (j.part_type <> 'PAS'::text) AND (j.part_type <> 'PASL'::text) AND ((j.part_qty)::numeric <> (0)::numeric) AND ((j.act_price <> (0)::numeric) OR (j.include_in_part_cnt is TRUE))AND (j.removed IS FALSE))
GROUP BY j.jobid, j.status, j.part_type;

View File

@@ -329,8 +329,7 @@ const main = async () => {
main().catch((error) => { main().catch((error) => {
logger.log(`Main-API-Error: Something was not caught in the application.`, "error", "api", null, { logger.log(`Main-API-Error: Something was not caught in the application.`, "error", "api", null, {
error: error.message, error: error.message,
errorjson: JSON.stringify(error), errorjson: JSON.stringify(error)
stack: error.stack
}); });
// Note: If we want the app to crash on all uncaught async operations, we would // Note: If we want the app to crash on all uncaught async operations, we would
// need to put a `process.exit(1);` here // need to put a `process.exit(1);` here

View File

@@ -3,4 +3,3 @@ exports.autohouse = require("./autohouse").default;
exports.chatter = require("./chatter").default; exports.chatter = require("./chatter").default;
exports.claimscorp = require("./claimscorp").default; exports.claimscorp = require("./claimscorp").default;
exports.kaizen = require("./kaizen").default; exports.kaizen = require("./kaizen").default;
exports.usageReport = require("./usageReport").default;

View File

@@ -1,90 +0,0 @@
const path = require("path");
require("dotenv").config({
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
});
const client = require("../graphql-client/graphql-client").client;
const emailer = require("../email/sendemail");
const moment = require("moment-timezone");
const converter = require("json-2-csv");
const logger = require("../utils/logger");
const queries = require("../graphql-client/queries");
const InstanceMgr = require("../utils/instanceMgr").default;
exports.default = async (req, res) => {
try {
logger.log("usage-report-email-start", "debug", req?.user?.email, null, {});
if (InstanceMgr({ rome: false, imex: true })) {
//Disable for ImEX at the moment.
res.sendStatus(403);
logger.log("usage-report-email-forbidden", "warn", req?.user?.email, null, {});
return;
}
if (process.env.NODE_ENV !== "production") {
res.sendStatus(403);
return;
}
// Validate using autohouse token header.
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
res.sendStatus(401);
logger.log("usage-report-email-forbidden", "warn", req?.user?.email, null, {});
return;
}
//Query the usage data.
const queryResults = await client.request(queries.STATUS_UPDATE, {
today: moment().startOf("day").subtract(7, "days"),
period: moment().subtract(90, "days").startOf("day")
});
//Massage the data.
const shopList = queryResults.bodyshops.map((shop) => ({
"Shop Name": shop.shopname,
"Days Since Creation": moment().diff(moment(shop.created_at), "days"),
"Jobs Created": shop.jobs_created.aggregate.count,
"Jobs Updated": shop.jobs_updated.aggregate.count,
"Owners Created": shop.owners_created.aggregate.count,
"Owners Updated": shop.owners_updated.aggregate.count,
"Vehicles Created": shop.vehicles_created.aggregate.count,
"Vehicles Updated": shop.vehicles_updated.aggregate.count,
"Tasks Created": shop.tasks_created.aggregate.count,
"Tasks Updated": shop.tasks_updated.aggregate.count
}));
const csv = converter.json2csv(shopList, { emptyFieldValue: "" });
emailer
.sendTaskEmail({
to: ["patrick.fic@convenient-brands.com", "bradley.rhoades@convenient-brands.com"],
subject: `RO Usage Report - ${moment().format("MM/DD/YYYY")}`,
text: `
Usage Report for ${moment().format("MM/DD/YYYY")} for Rome Online Customers.
Notes:
- Days Since Creation: The number of days since the shop was created. Only shops created in the last 90 days are included.
- Updated values should be higher than created values.
- Counts are inclusive of the last 7 days of data.
`,
attachments: [{ filename: `RO Usage Report ${moment().format("MM/DD/YYYY")}.csv`, content: csv }]
})
.then(() => {
logger.log("usage-report-email-success", "debug", req?.user?.email, null, {
csv
});
})
.catch((error) => {
logger.log("usage-report-email-send-error", "ERROR", req?.user?.email, null, {
error: error.message,
stack: error.stack
});
});
res.sendStatus(200);
return;
} catch (error) {
logger.log("usage-report-email-error", "ERROR", req?.user?.email, null, {
error: error.message,
stack: error.stack
});
res.status(500).json({ error: error.message, stack: error.stack });
}
};

View File

@@ -2617,76 +2617,3 @@ exports.CREATE_CONVERSATION = `mutation CREATE_CONVERSATION($conversation: [conv
} }
} }
`; `;
exports.STATUS_UPDATE = `query STATUS_UPDATE($period: timestamptz!, $today: timestamptz!) {
bodyshops(where: { created_at: { _gte: $period } }) {
shopname
id
created_at
jobs_created: jobs_aggregate(where: { created_at: { _gte: $today } }) {
aggregate {
count
}
}
jobs_updated: jobs_aggregate(where: { updated_at: { _gte: $today } }) {
aggregate {
count
}
}
owners_created: owners_aggregate(where: { created_at: { _gte: $today } }) {
aggregate {
count
}
}
owners_updated: owners_aggregate(where: { updated_at: { _gte: $today } }) {
aggregate {
count
}
}
vehicles_created: vehicles_aggregate(
where: { created_at: { _gte: $today } }
) {
aggregate {
count
}
}
vehicles_updated: vehicles_aggregate(
where: { updated_at: { _gte: $today } }
) {
aggregate {
count
}
}
tasks_created: tasks_aggregate(where: { created_at: { _gte: $today } }) {
aggregate {
count
}
}
tasks_updated: tasks_aggregate(where: { updated_at: { _gte: $today } }) {
aggregate {
count
}
}
jobs {
parts_orders_created: parts_orders_aggregate(
where: { created_at: { _gte: $today } }
) {
aggregate {
count
}
}
parts_orders_updated: parts_orders_aggregate(
where: { updated_at: { _gte: $today } }
) {
aggregate {
count
}
}
}
}
}
`

View File

@@ -1,11 +1,10 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
const { autohouse, claimscorp, chatter, kaizen, usageReport } = require("../data/data"); const { autohouse, claimscorp, chatter, kaizen } = require("../data/data");
router.post("/ah", autohouse); router.post("/ah", autohouse);
router.post("/cc", claimscorp); router.post("/cc", claimscorp);
router.post("/chatter", chatter); router.post("/chatter", chatter);
router.post("/kaizen", kaizen); router.post("/kaizen", kaizen);
router.post("/usagereport", usageReport);
module.exports = router; module.exports = router;

View File

@@ -41,7 +41,7 @@ exports.taskHandler = async (req, res) => {
return res.status(200).send(csv); return res.status(200).send(csv);
} catch (error) { } catch (error) {
res.status(500).json({ error: error.message, stack: error.stack }); res.status(500).json({ error: error.message, stack: error.stackTrace });
} }
}; };