Merge release / update

This commit is contained in:
Dave Richer
2024-03-11 09:50:20 -04:00
52 changed files with 416 additions and 237 deletions

View File

@@ -59,7 +59,7 @@ Filters can make use of reflection to pre-fill select boxes, the following is an
"type": "internal", "type": "internal",
"name": "special.job_statuses" "name": "special.job_statuses"
} }
}, }
``` ```
in this example, a reflector with the type 'internal' (all types at the moment require this, and it is used for future functionality), with a name of `special.job_statuses` in this example, a reflector with the type 'internal' (all types at the moment require this, and it is used for future functionality), with a name of `special.job_statuses`
@@ -74,9 +74,13 @@ The following cases are available
- `special.employees` - This will reflect the employees `bodyshop.employees` - `special.employees` - This will reflect the employees `bodyshop.employees`
- `special.first_names` - This will reflect the first names `bodyshop.employees` - `special.first_names` - This will reflect the first names `bodyshop.employees`
- `special.last_names` - This will reflect the last names `bodyshop.employees` - `special.last_names` - This will reflect the last names `bodyshop.employees`
- `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources - `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources`
- `special.class`- This will reflect the class `bodyshop.md_classes` - `special.class`- This will reflect the class `bodyshop.md_classes`
- - `special.lost_sale_reasons` - This will reflect the lost sale reasons `bodyshop.md_lost_sale_reasons`
- `special.alt_transports` - This will reflect the alternative transports `bodyshop.appt_alt_transport`
- `special.payment_types` - This will reflect the payment types `bodyshop.md_payment_types`
- `special.payment_payers` - This is a special case with a key value set of [Customer, Insurance]
### Path without brackets, multi level ### Path without brackets, multi level
`"name": "jobs.joblines.mod_lb_hrs",` `"name": "jobs.joblines.mod_lb_hrs",`
@@ -156,6 +160,7 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
- Do not add the ability to filter things that are already filtered as part of the original query, this would be - Do not add the ability to filter things that are already filtered as part of the original query, this would be
redundant and could cause issues. redundant and could cause issues.
- Do not add the ability to filter on things like FK constraints, must like the above example. - Do not add the ability to filter on things like FK constraints, must like the above example.
- *INHERITANCE CAVEAT* If you have a filters file on a parent report that has a child that you do not want the filters inherited from, you must place a blank filters file (valid json so {}) on the child report level. This will than fetch the child filters, which are empty and move along, versus inheriting the parent filters.
## Sorters ## Sorters

View File

@@ -1,21 +1,20 @@
import {Card, Checkbox, Input, Space, Table} from "antd"; import {Card, Checkbox, Input, Space, Table} from "antd";import queryString from "query-string";
import React, {useState} from "react"; import React, {useState} from "react";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
import {connect } from "react-redux";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { createStructuredSelector } from "reselect";
import {alphaSort, dateSort} from "../../utils/sorters";
import PayableExportButton from "../payable-export-button/payable-export-button.component";
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
import {DateFormatter} from "../../utils/DateFormatter";
import queryString from "query-string";
import {logImEXEvent} from "../../firebase/firebase.utils"; import {logImEXEvent} from "../../firebase/firebase.utils";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; import { selectBodyshop } from "../../redux/user/user.selectors";
import {connect} from "react-redux"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import {createStructuredSelector} from "reselect"; import {DateFormatter} from "../../utils/DateFormatter";
import {selectBodyshop} from "../../redux/user/user.selectors"; import { pageLimit } from "../../utils/config";
import {alphaSort, dateSort} from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component"; import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
import PayableExportButton from "../payable-export-button/payable-export-button.component";
import BillMarkSelectedExported from "../payable-mark-selected-exported/payable-mark-selected-exported.component"; import BillMarkSelectedExported from "../payable-mark-selected-exported/payable-mark-selected-exported.component";
import {pageLimit} from "../../utils/config"; import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -147,7 +146,7 @@ export function AccountingPayablesTableComponent({
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",
key: "actions", key: "actions",
sorter: (a, b) => a.clm_total - b.clm_total,
render: (text, record) => ( render: (text, record) => (
<PayableExportButton <PayableExportButton

View File

@@ -8,14 +8,16 @@ import {logImEXEvent} from "../../firebase/firebase.utils";
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 {DateFormatter, DateTimeFormatter} from "../../utils/DateFormatter"; import {DateFormatter, DateTimeFormatter} from "../../utils/DateFormatter";
import {pageLimit } from "../../utils/config";
import {alphaSort, dateSort} from "../../utils/sorters"; import {alphaSort, dateSort} from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component"; import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import PaymentExportButton from "../payment-export-button/payment-export-button.component"; import PaymentExportButton from "../payment-export-button/payment-export-button.component";
import PaymentMarkSelectedExported from "../payment-mark-selected-exported/payment-mark-selected-exported.component"; import PaymentMarkSelectedExported from "../payment-mark-selected-exported/payment-mark-selected-exported.component";
import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component"; import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -75,7 +77,11 @@ export function AccountingPayablesTableComponent({
dataIndex: "owner", dataIndex: "owner",
key: "owner", key: "owner",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln), sorter: (a, b) =>
alphaSort(
OwnerNameDisplayFunction(a.job),
OwnerNameDisplayFunction(b.job)
),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
@@ -94,7 +100,9 @@ export function AccountingPayablesTableComponent({
title: t("payments.fields.amount"), title: t("payments.fields.amount"),
dataIndex: "amount", dataIndex: "amount",
key: "amount", key: "amount",
render: (text, record) => ( sorter: (a, b) => a.amount - b.amount,
sortOrder:
state.sortedInfo.columnKey === "amount" && state.sortedInfo.order,render: (text, record) => (
<CurrencyFormatter>{record.amount}</CurrencyFormatter> <CurrencyFormatter>{record.amount}</CurrencyFormatter>
), ),
}, },
@@ -111,19 +119,21 @@ export function AccountingPayablesTableComponent({
{ {
title: t("payments.fields.created_at"), title: t("payments.fields.created_at"),
dataIndex: "created_at", dataIndex: "created_at",
key: "created_at", key: "created_at",sorter: (a, b) => dateSort(a.created_at, b.created_at),
sortOrder:
state.sortedInfo.columnKey === "created_at" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<DateTimeFormatter>{record.created_at}</DateTimeFormatter> <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
), ),
}, },
{ //{
title: t("payments.fields.exportedat"), // title: t("payments.fields.exportedat"),
dataIndex: "exportedat", // dataIndex: "exportedat",
key: "exportedat", // key: "exportedat",
render: (text, record) => ( // render: (text, record) => (
<DateTimeFormatter>{record.exportedat}</DateTimeFormatter> // <DateTimeFormatter>{record.exportedat}</DateTimeFormatter>
), // ),
}, //},
{ {
title: t("exportlogs.labels.attempts"), title: t("exportlogs.labels.attempts"),
dataIndex: "attempts", dataIndex: "attempts",
@@ -137,7 +147,7 @@ export function AccountingPayablesTableComponent({
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",
key: "actions", key: "actions",
sorter: (a, b) => a.clm_total - b.clm_total,
render: (text, record) => ( render: (text, record) => (
<PaymentExportButton <PaymentExportButton

View File

@@ -4,17 +4,19 @@ import {useTranslation} from "react-i18next";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {logImEXEvent} from "../../firebase/firebase.utils"; import {logImEXEvent} from "../../firebase/firebase.utils";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import {alphaSort, dateSort} from "../../utils/sorters"; import {alphaSort, dateSort, statusSort } from "../../utils/sorters";
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component"; import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component"; import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {createStructuredSelector} from "reselect"; import {createStructuredSelector} from "reselect";
import {selectBodyshop} from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
import {DateFormatter} from "../../utils/DateFormatter"; import {DateFormatter} from "../../utils/DateFormatter";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component"; import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -63,7 +65,7 @@ export function AccountingReceivablesTableComponent({
title: t("jobs.fields.status"), title: t("jobs.fields.status"),
dataIndex: "status", dataIndex: "status",
key: "status", key: "status",
sorter: (a, b) => a.status - b.status, sorter: (a, b) => statusSort(a, b, bodyshop.md_ro_statuses.statuses),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
}, },
@@ -83,7 +85,8 @@ export function AccountingReceivablesTableComponent({
title: t("jobs.fields.owner"), title: t("jobs.fields.owner"),
dataIndex: "owner", dataIndex: "owner",
key: "owner", key: "owner",
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) =>
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
@@ -103,7 +106,15 @@ export function AccountingReceivablesTableComponent({
dataIndex: "vehicle", dataIndex: "vehicle",
key: "vehicle", key: "vehicle",
ellipsis: true, ellipsis: true,
render: (text, record) => { sorter: (a, b) =>
alphaSort(
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
a.v_model_desc || ""
}`,
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
),
sortOrder:
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,render: (text, record) => {
return record.vehicleid ? ( return record.vehicleid ? (
<Link to={"/manage/vehicles/" + record.vehicleid}> <Link to={"/manage/vehicles/" + record.vehicleid}>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${

View File

@@ -12,8 +12,8 @@ import { createStructuredSelector } from "reselect";
const mapStateToProps = createStructuredSelector({}); const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({ jobid, operation })), dispatch(insertAuditTrail({ jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton); export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton);
@@ -51,7 +51,8 @@ export function BillDeleteButton({ bill, jobid, callback, insertAuditTrail }) {
insertAuditTrail({ insertAuditTrail({
jobid: jobid, jobid: jobid,
operation: AuditTrailMapping.billdeleted(bill.invoice_number), operation: AuditTrailMapping.billdeleted(bill.invoice_number),
}); type: "billdeleted",
});
if (callback && typeof callback === "function") callback(bill.id); if (callback && typeof callback === "function") callback(bill.id);
} else { } else {

View File

@@ -30,8 +30,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPartsOrderContext: (context) => setPartsOrderContext: (context) =>
dispatch(setModalContext({context: context, modal: "partsOrder"})), dispatch(setModalContext({context: context, modal: "partsOrder"})),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
@@ -145,7 +145,8 @@ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail,
jobid: bill.jobid, jobid: bill.jobid,
billid: search.billid, billid: search.billid,
operation: AuditTrailMapping.billupdated(bill.invoice_number), operation: AuditTrailMapping.billupdated(bill.invoice_number),
}); type: "billupdated",
});
await refetch(); await refetch();
form.setFieldsValue(transformData(data)); form.setFieldsValue(transformData(data));

View File

@@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPartsOrderContext: (context) => setPartsOrderContext: (context) =>
dispatch(setModalContext({context: context, modal: "partsOrder"})), dispatch(setModalContext({context: context, modal: "partsOrder"})),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(

View File

@@ -31,8 +31,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")), toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")),
insertAuditTrail: ({jobid, billid, operation}) => insertAuditTrail: ({jobid, billid, operation, type}) =>
dispatch(insertAuditTrail({jobid, billid, operation})), dispatch(insertAuditTrail({jobid, billid, operation, type })),
}); });
const Templates = TemplateList("job_special"); const Templates = TemplateList("job_special");
@@ -165,7 +165,7 @@ function BillEnterModalContainer({
mod_lbr_ty: key, mod_lbr_ty: key,
hours: adjustmentsToInsert[key].toFixed(1), hours: adjustmentsToInsert[key].toFixed(1),
}), }),
}); type: "jobmodifylbradj",});
}); });
const jobUpdate = client.mutate({ const jobUpdate = client.mutate({
@@ -314,7 +314,8 @@ function BillEnterModalContainer({
operation: AuditTrailMapping.billposted( operation: AuditTrailMapping.billposted(
r1.data.insert_bills.returning[0].invoice_number r1.data.insert_bills.returning[0].invoice_number
), ),
}); type: "billposted",
});
if (enterAgain) { if (enterAgain) {
form.resetFields(); form.resetFields();

View File

@@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type})),
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")), toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")),
}); });
@@ -88,7 +88,7 @@ const CardPaymentModalComponent = ({
insertAuditTrail({ insertAuditTrail({
jobid: payment.jobid, jobid: payment.jobid,
operation: AuditTrailMapping.failedpayment(), operation: AuditTrailMapping.failedpayment(),
}) type: "failedpayment",})
); );
}); });
}; };

View File

@@ -4,7 +4,7 @@ import {
PauseCircleOutlined, PauseCircleOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Card, Space, Switch, Table, Tooltip, Typography } from "antd"; import { Card, Space, Switch, Table, Tooltip, Typography } from "antd";
import moment from "moment"; import dayjs from "../../../utils/day";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
@@ -74,7 +74,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
} }
}); });
appt.sort(function (a, b) { appt.sort(function (a, b) {
return new moment(a.start) - new moment(b.start); return dayjs(a.start) - dayjs(b.start);
}); });
const tvFontSize = 16; const tvFontSize = 16;
@@ -419,7 +419,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
return ( return (
<Card <Card
title={t("dashboard.titles.scheduledindate", { title={t("dashboard.titles.scheduledindate", {
date: moment().startOf("day").format("MM/DD/YYYY"), date: dayjs().startOf("day").format("MM/DD/YYYY"),
})} })}
extra={ extra={
<Space> <Space>
@@ -449,9 +449,9 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) {
} }
export const DashboardScheduledInTodayGql = ` export const DashboardScheduledInTodayGql = `
scheduled_in_today: appointments(where: {start: {_gte: "${moment() scheduled_in_today: appointments(where: {start: {_gte: "${dayjs()
.startOf("day") .startOf("day")
.toISOString()}", _lte: "${moment() .toISOString()}", _lte: "${dayjs()
.endOf("day") .endOf("day")
.toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) { .toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) {
canceled canceled

View File

@@ -53,7 +53,7 @@ export default function ScheduleEventContainer({bodyshop, event, refetch}) {
insertAuditTrail({ insertAuditTrail({
jobid: event.job.id, jobid: event.job.id,
operation: AuditTrailMapping.appointmentcancel(lost_sale_reason), operation: AuditTrailMapping.appointmentcancel(lost_sale_reason),
}) type: "appointmentcancel",})
); );
} }
if (!!jobUpdate.errors) { if (!!jobUpdate.errors) {

View File

@@ -28,8 +28,8 @@ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function JobChecklistForm({ export function JobChecklistForm({
@@ -183,7 +183,7 @@ export function JobChecklistForm({
(type === "intake" && bodyshop.md_ro_statuses.default_arrived) || (type === "intake" && bodyshop.md_ro_statuses.default_arrived) ||
(type === "deliver" && bodyshop.md_ro_statuses.default_delivered) (type === "deliver" && bodyshop.md_ro_statuses.default_delivered)
), ),
}); type: "jobchecklist",});
} else { } else {
notification["error"]({ notification["error"]({
message: t("checklist.errors.complete", { message: t("checklist.errors.complete", {

View File

@@ -15,8 +15,8 @@ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
@@ -47,7 +47,8 @@ export function JobEmployeeAssignmentsContainer({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobassignmentchange(operation, name), operation: AuditTrailMapping.jobassignmentchange(operation, name),
}); type: "jobassignmentchange",
});
if (!!result.errors) { if (!!result.errors) {
notification["error"]({ notification["error"]({
@@ -77,7 +78,7 @@ export function JobEmployeeAssignmentsContainer({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobassignmentremoved(operation), operation: AuditTrailMapping.jobassignmentremoved(operation),
}); type: "jobassignmentremoved",});
setLoading(false); setLoading(false);
}; };

View File

@@ -17,8 +17,8 @@ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
@@ -102,7 +102,7 @@ export function JobLineConvertToLabor({
hours: calculateAdjustment({mod_lbr_ty, job, jobline}).toFixed(1), hours: calculateAdjustment({mod_lbr_ty, job, jobline}).toFixed(1),
mod_lbr_ty, mod_lbr_ty,
}), }),
}); type: "jobmodifylbradj",});
setLoading(false); setLoading(false);
setVisibility(false); setVisibility(false);
}; };

View File

@@ -14,8 +14,8 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus);
@@ -32,7 +32,7 @@ export function JobsAdminStatus({insertAuditTrail, bodyshop, job}) {
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_jobstatuschange(status), operation: AuditTrailMapping.admin_jobstatuschange(status),
}); type: "admin_jobstatuschange",});
// refetch(); // refetch();
}) })
.catch((error) => { .catch((error) => {

View File

@@ -20,8 +20,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
@@ -57,7 +57,7 @@ export function JobsAdminDatesChange({insertAuditTrail, job}) {
? DateTimeFormat(changedAuditFields[key]) ? DateTimeFormat(changedAuditFields[key])
: changedAuditFields[key] : changedAuditFields[key]
), ),
}); type: "admin_jobfieldchange",});
}); });
if (!!!result.errors) { if (!!!result.errors) {

View File

@@ -24,8 +24,8 @@ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
@@ -60,7 +60,7 @@ export function JobAdminMarkReexport({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_jobmarkforreexport(), operation: AuditTrailMapping.admin_jobmarkforreexport(),
}); type: "admin_jobmarkforreexport",});
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.saving", { message: t("jobs.errors.saving", {
@@ -100,7 +100,7 @@ export function JobAdminMarkReexport({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_jobmarkexported(), operation: AuditTrailMapping.admin_jobmarkexported(),
}); type: "admin_jobmarkexported",});
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.saving", { message: t("jobs.errors.saving", {
@@ -125,7 +125,7 @@ export function JobAdminMarkReexport({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_jobuninvoice(), operation: AuditTrailMapping.admin_jobuninvoice(),
}); type: "admin_jobuninvoice",});
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.saving", { message: t("jobs.errors.saving", {

View File

@@ -10,8 +10,8 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({}); const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminRemoveAR); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminRemoveAR);
@@ -34,7 +34,7 @@ export function JobsAdminRemoveAR({insertAuditTrail, job}) {
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_job_remove_from_ar(value), operation: AuditTrailMapping.admin_job_remove_from_ar(value),
}); type: "admin_job_remove_from_ar",});
setSwitchValue(value); setSwitchValue(value);
} else { } else {
notification["error"]({ notification["error"]({

View File

@@ -14,8 +14,8 @@ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminUnvoid); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminUnvoid);
@@ -46,7 +46,7 @@ export function JobsAdminUnvoid({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.admin_jobunvoid(), operation: AuditTrailMapping.admin_jobunvoid(),
}); type: "admin_jobunvoid",});
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.saving", { message: t("jobs.errors.saving", {

View File

@@ -38,8 +38,8 @@ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({ jobid, operation, type })),
}); });
export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,}) { export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,}) {
@@ -177,10 +177,11 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,
}); });
//Job has been inserted. Clean up the available jobs record. //Job has been inserted. Clean up the available jobs record.
insertAuditTrail({ insertAuditTrail({
jobid: r.data.insert_jobs.returning[0].id, jobid: r.data.insert_jobs.returning[0].id,
operation: AuditTrailMapping.jobimported(), operation: AuditTrailMapping.jobimported(),
}); type: "jobimported",
});
deleteJob({ deleteJob({
variables: {id: estData.id}, variables: {id: estData.id},
@@ -325,24 +326,25 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,
setInsertLoading(false); setInsertLoading(false);
}); });
await insertNote({ await insertNote({
variables: { variables: {
noteInput: [ noteInput: [
{ {
jobid: selectedJob, jobid: selectedJob,
created_by: currentUser.email, created_by: currentUser.email,
audit: true, audit: true,
text: t("jobs.labels.supplementnote"), text: t("jobs.labels.supplementnote"),
}, },
], ],
}, },
}); });
insertAuditTrail({ insertAuditTrail({
jobid: selectedJob, jobid: selectedJob,
operation: AuditTrailMapping.jobsupplement(), operation: AuditTrailMapping.jobsupplement(),
}); type: "jobsupplement",
} });
}; }
};
const owner = const owner =
estDataRaw.data && estDataRaw.data &&

View File

@@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) { export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) {
@@ -35,7 +35,7 @@ export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) {
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobstatuschange(status), operation: AuditTrailMapping.jobstatuschange(status),
}); type: "jobstatuschange",});
// refetch(); // refetch();
}) })
.catch((error) => { .catch((error) => {

View File

@@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({ jobid, operation })), dispatch(insertAuditTrail({ jobid, operation, type })),
}); });
function updateJobCache(items) { function updateJobCache(items) {
@@ -192,7 +192,7 @@ export function JobsCloseExportButton({
insertAuditTrail({ insertAuditTrail({
jobid: jobId, jobid: jobId,
operation: AuditTrailMapping.jobexported(), operation: AuditTrailMapping.jobexported(),
}); type: "jobexported",});
updateJobCache( updateJobCache(
jobUpdateResponse.data.update_jobs.returning.map((job) => job.id) jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
); );
@@ -216,7 +216,7 @@ export function JobsCloseExportButton({
}); });
insertAuditTrail({ insertAuditTrail({
jobid: jobId, jobid: jobId,
operation: AuditTrailMapping.jobexported(), operation: AuditTrailMapping.jobexported(),type: "jobexported",
}); });
updateJobCache([ updateJobCache([
...new Set( ...new Set(

View File

@@ -17,8 +17,8 @@ const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly, jobRO: selectJobReadOnly,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function JobsConvertButton({ export function JobsConvertButton({
@@ -70,7 +70,8 @@ export function JobsConvertButton({
operation: AuditTrailMapping.jobconverted( operation: AuditTrailMapping.jobconverted(
res.data.update_jobs.returning[0].ro_number res.data.update_jobs.returning[0].ro_number
), ),
}); type: "jobconverted",
});
setOpen(false); setOpen(false);
} }

View File

@@ -29,6 +29,7 @@ export default function AddToProduction(
insertAuditTrail({ insertAuditTrail({
jobid: jobId, jobid: jobId,
operation: AuditTrailMapping.jobinproductionchange(!remove), operation: AuditTrailMapping.jobinproductionchange(!remove),
type: "jobinproductionchange",
}) })
); );
if (completionCallback) completionCallback(); if (completionCallback) completionCallback();
@@ -40,8 +41,4 @@ export default function AddToProduction(
}), }),
}); });
}); });
//insert the new job. call the callback with the returned ID when done.
return;
} }

View File

@@ -48,8 +48,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setModalContext({context: context, modal: "timeTicket"})), dispatch(setModalContext({context: context, modal: "timeTicket"})),
setCardPaymentContext: (context) => setCardPaymentContext: (context) =>
dispatch(setModalContext({context: context, modal: "cardPayment"})), dispatch(setModalContext({context: context, modal: "cardPayment"})),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({ jobid, operation, type })),
setEmailOptions: (e) => dispatch(setEmailOptions(e)), setEmailOptions: (e) => dispatch(setEmailOptions(e)),
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)), openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
setMessage: (text) => dispatch(setMessage(text)), setMessage: (text) => dispatch(setMessage(text)),
@@ -240,6 +240,7 @@ export function JobsDetailHeaderActions({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobvoid(), operation: AuditTrailMapping.jobvoid(),
type: "jobvoid",
}); });
return; return;
} }
@@ -461,6 +462,7 @@ export function JobsDetailHeaderActions({
? !job.production_vars.alert ? !job.production_vars.alert
: true, : true,
}, },
type: "alertToggle",
}, },
}, },
}); });
@@ -490,6 +492,7 @@ export function JobsDetailHeaderActions({
operation: AuditTrailMapping.jobsuspend( operation: AuditTrailMapping.jobsuspend(
!!job.suspended ? !job.suspended : true !!job.suspended ? !job.suspended : true
), ),
type: "jobsuspend",
}); });
}; };
@@ -521,6 +524,7 @@ export function JobsDetailHeaderActions({
jobid: job.id, jobid: job.id,
operation: operation:
AuditTrailMapping.appointmentcancel(lost_sale_reason), AuditTrailMapping.appointmentcancel(lost_sale_reason),
type: "appointmentcancel",
}); });
} }

View File

@@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({ jobid, operation })), dispatch(insertAuditTrail({ jobid, operation, type })),
}); });
function updateJobCache(items) { function updateJobCache(items) {
@@ -189,6 +189,7 @@ export function JobsExportAllButton({
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobexported(), operation: AuditTrailMapping.jobexported(),
type: "jobexported",
}); });
}); });
updateJobCache( updateJobCache(
@@ -230,6 +231,7 @@ export function JobsExportAllButton({
insertAuditTrail({ insertAuditTrail({
jobid: successfulTransactionsSet[0], jobid: successfulTransactionsSet[0],
operation: AuditTrailMapping.jobexported(), operation: AuditTrailMapping.jobexported(),
type: "jobexported",
}); });
} }
updateJobCache(successfulTransactionsSet); updateJobCache(successfulTransactionsSet);

View File

@@ -16,6 +16,7 @@ import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import { OwnerNameDisplayFunction } from "./../owner-name-display/owner-name-display.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -142,7 +143,8 @@ export function JobsList({bodyshop}) {
ellipsis: true, ellipsis: true,
responsive: ["md"], responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) =>
alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
@@ -187,7 +189,8 @@ export function JobsList({bodyshop}) {
key: "status", key: "status",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status), sorter: (a, b) =>
statusSort(a.status, b.status, bodyshop.md_ro_statuses.active_statuses),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: filter?.status || null, filteredValue: filter?.status || null,
@@ -218,7 +221,15 @@ export function JobsList({bodyshop}) {
dataIndex: "vehicle", dataIndex: "vehicle",
key: "vehicle", key: "vehicle",
ellipsis: true, ellipsis: true,
render: (text, record) => { sorter: (a, b) =>
alphaSort(
`${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
a.v_model_desc || ""
}`,
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
),
sortOrder:
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,render: (text, record) => {
return record.vehicleid ? ( return record.vehicleid ? (
<Link <Link
to={"/manage/vehicles/" + record.vehicleid} to={"/manage/vehicles/" + record.vehicleid}
@@ -265,7 +276,9 @@ export function JobsList({bodyshop}) {
dataIndex: "ins_co_nm", dataIndex: "ins_co_nm",
key: "ins_co_nm", key: "ins_co_nm",
ellipsis: true, ellipsis: true,
filteredValue: filter?.ins_co_nm || null, sorter: (a, b) => alphaSort(a.ins_co_nm, b.ins_co_nm),
sortOrder:
state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,filteredValue: filter?.ins_co_nm || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -301,7 +314,13 @@ export function JobsList({bodyshop}) {
dataIndex: "jobs.labels.estimator", dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator", key: "jobs.labels.estimator",
ellipsis: true, ellipsis: true,
responsive: ["xl"], responsive: ["xl"],sorter: (a, b) =>
alphaSort(
`${a.est_ct_fn || ""} ${a.est_ct_ln || ""}`.trim(),
`${b.est_ct_fn || ""} ${b.est_ct_ln || ""}`.trim()
),
sortOrder:
state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order,
filterSearch: true, filterSearch: true,
filteredValue: filter?.estimator || null, filteredValue: filter?.estimator || null,
filters: filters:

View File

@@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobNotesContainer); export default connect(mapStateToProps, mapDispatchToProps)(JobNotesContainer);
@@ -46,7 +46,7 @@ export function JobNotesContainer({jobId, insertAuditTrail}) {
insertAuditTrail({ insertAuditTrail({
jobid: jobId, jobid: jobId,
operation: AuditTrailMapping.jobnotedeleted(), operation: AuditTrailMapping.jobnotedeleted(),
}); type: "jobnotedeleted",});
}); });
setDeleteLoading(false); setDeleteLoading(false);
}; };

View File

@@ -21,8 +21,8 @@ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
@@ -77,7 +77,7 @@ export function LaborAllocationsAdjustmentEdit({
values.hours - values.hours -
((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1), ((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1),
}), }),
}); type: "jobmodifylbradj",});
} }
setLoading(false); setLoading(false);
setOpen(false); setOpen(false);

View File

@@ -19,8 +19,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert")), toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert")),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function NoteUpsertModalContainer({ export function NoteUpsertModalContainer({
@@ -70,7 +70,7 @@ export function NoteUpsertModalContainer({
insertAuditTrail({ insertAuditTrail({
jobid: context.jobId, jobid: context.jobId,
operation: AuditTrailMapping.jobnoteupdated(), operation: AuditTrailMapping.jobnoteupdated(),
}); type: "jobnoteupdated",});
}); });
if (refetch) refetch(); if (refetch) refetch();
toggleModalVisible(); toggleModalVisible();
@@ -102,7 +102,7 @@ export function NoteUpsertModalContainer({
insertAuditTrail({ insertAuditTrail({
jobid: newJobId, jobid: newJobId,
operation: AuditTrailMapping.jobnoteadded(), operation: AuditTrailMapping.jobnoteadded(),
}); type: "jobnoteadded",});
}); });
} }
@@ -115,7 +115,7 @@ export function NoteUpsertModalContainer({
insertAuditTrail({ insertAuditTrail({
jobid: context.jobId, jobid: context.jobId,
operation: AuditTrailMapping.jobnoteadded(), operation: AuditTrailMapping.jobnoteadded(),
}); type: "jobnoteadded",});
} }
}; };

View File

@@ -1,19 +1,28 @@
import {useApolloClient, useMutation, useQuery} from "@apollo/client"; import { useMutation, useQuery, useApolloClient } from "@apollo/client";
import {Form, Modal, notification} from "antd"; import { Form, Modal, notification } from "antd";
import dayjs from "../../utils/day"; import dayjs from '../../utils/day';
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import {useTranslation} from "react-i18next"; import { useTranslation } from "react-i18next";
import {connect} from "react-redux"; import { connect } from "react-redux";
import {createStructuredSelector} from "reselect"; import { createStructuredSelector } from "reselect";
import {auth, logImEXEvent} from "../../firebase/firebase.utils"; import { logImEXEvent, auth } from "../../firebase/firebase.utils";
import {UPDATE_JOB_LINE_STATUS} from "../../graphql/jobs-lines.queries"; import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries";
import {INSERT_NEW_PARTS_ORDERS, QUERY_PARTS_ORDER_OEC,} from "../../graphql/parts-orders.queries"; import {
import {QUERY_ALL_VENDORS_FOR_ORDER} from "../../graphql/vendors.queries"; INSERT_NEW_PARTS_ORDERS,
import {insertAuditTrail} from "../../redux/application/application.actions"; QUERY_PARTS_ORDER_OEC,
import {setEmailOptions} from "../../redux/email/email.actions"; } from "../../graphql/parts-orders.queries";
import {setModalContext, toggleModalVisible,} from "../../redux/modals/modals.actions"; import { QUERY_ALL_VENDORS_FOR_ORDER } from "../../graphql/vendors.queries";
import {selectPartsOrder} from "../../redux/modals/modals.selectors"; import { insertAuditTrail } from "../../redux/application/application.actions";
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors"; import { setEmailOptions } from "../../redux/email/email.actions";
import {
setModalContext,
toggleModalVisible,
} from "../../redux/modals/modals.actions";
import { selectPartsOrder } from "../../redux/modals/modals.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import {GenerateDocument} from "../../utils/RenderTemplate"; import {GenerateDocument} from "../../utils/RenderTemplate";
import {TemplateList} from "../../utils/TemplateConstants"; import {TemplateList} from "../../utils/TemplateConstants";
@@ -36,8 +45,8 @@ const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("partsOrder")), toggleModalVisible: () => dispatch(toggleModalVisible("partsOrder")),
setBillEnterContext: (context) => setBillEnterContext: (context) =>
dispatch(setModalContext({context: context, modal: "billEnter"})), dispatch(setModalContext({context: context, modal: "billEnter"})),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function PartsOrderModalContainer({ export function PartsOrderModalContainer({
@@ -135,7 +144,8 @@ export function PartsOrderModalContainer({
: AuditTrailMapping.jobspartsorder( : AuditTrailMapping.jobspartsorder(
insertResult.data.insert_parts_orders.returning[0].order_number insertResult.data.insert_parts_orders.returning[0].order_number
), ),
}); type: isReturn ? "jobspartsreturn" : "jobspartsorder",
});
const jobLinesResult = await updateJobLines({ const jobLinesResult = await updateJobLines({
variables: { variables: {

View File

@@ -2,14 +2,17 @@ import {Button, Form, Input, Space} from "antd";
import {PageHeader} from "@ant-design/pro-layout"; import {PageHeader} from "@ant-design/pro-layout";
import React from "react"; import React from "react";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
selectAuthLevel,
selectBodyshop,
} from "../../redux/user/user.selectors";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component"; import FormItemEmail from "../form-items-formatted/email-form-item.component";
import PhoneFormItem, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component"; import PhoneFormItem, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component"; import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {selectAuthLevel, selectBodyshop,} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
authLevel: selectAuthLevel, authLevel: selectAuthLevel,
@@ -43,13 +46,16 @@ export function PhonebookFormComponent({
return ( return (
<div> <div>
<PageHeader <PageHeader
title={`${form.getFieldValue("firstname") || ""} ${ title={<Form.Item shouldUpdate>
{() =>`${form.getFieldValue("firstname") || ""} ${
form.getFieldValue("lastname") || "" form.getFieldValue("lastname") || ""
}${ }${
form.getFieldValue("company") form.getFieldValue("company")
? ` - ${form.getFieldValue("company")}` ? ` - ${form.getFieldValue("company")}`
: "" : ""}`
}`} }
</Form.Item>
}
extra={ extra={
<Space> <Space>
<Button <Button

View File

@@ -31,8 +31,8 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ProductionBoardKanbanComponent({ export function ProductionBoardKanbanComponent({
@@ -135,7 +135,8 @@ export function ProductionBoardKanbanComponent({
insertAuditTrail({ insertAuditTrail({
jobid: card.id, jobid: card.id,
operation: AuditTrailMapping.jobstatuschange(destination.toColumnId), operation: AuditTrailMapping.jobstatuschange(destination.toColumnId),
}); type: "jobstatuschange",
});
if (update.errors) { if (update.errors) {
notification["error"]({ notification["error"]({

View File

@@ -13,8 +13,8 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({}); const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ProductionListColumnAlert({record, insertAuditTrail}) { export function ProductionListColumnAlert({record, insertAuditTrail}) {
@@ -46,7 +46,7 @@ export function ProductionListColumnAlert({record, insertAuditTrail}) {
? !record.production_vars.alert ? !record.production_vars.alert
: true : true
), ),
}).then(() => { type: "alertToggle",}).then(() => {
if (record.refetch) record.refetch(); if (record.refetch) record.refetch();
}); });
}; };

View File

@@ -1,5 +1,5 @@
import {BranchesOutlined, PauseCircleOutlined} from "@ant-design/icons"; import {BranchesOutlined, PauseCircleOutlined} from "@ant-design/icons";
import {Space, Tooltip} from "antd"; import {Checkbox,Space, Tooltip} from "antd";
import i18n from "i18next"; import i18n from "i18next";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
@@ -10,7 +10,9 @@ import {onlyUnique} from "../../utils/arrayHelper";
import {alphaSort, dateSort, statusSort} from "../../utils/sorters"; import {alphaSort, dateSort, statusSort} from "../../utils/sorters";
import JobAltTransportChange from "../job-at-change/job-at-change.component"; import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component"; import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component"; import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import ProductionListColumnAlert from "./production-list-columns.alert.component"; import ProductionListColumnAlert from "./production-list-columns.alert.component";
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component"; import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
@@ -84,7 +86,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
<OwnerNameDisplay ownerObject={record}/> <OwnerNameDisplay ownerObject={record}/>
</Link> </Link>
), ),
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order, state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
}, },
@@ -95,8 +97,10 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
ellipsis: true, ellipsis: true,
sorter: (a, b) => sorter: (a, b) =>
alphaSort( alphaSort(
a.v_make_desc + a.v_model_desc, `${a.v_model_yr || ""} ${a.v_make_desc || ""} ${
b.v_make_desc + b.v_model_desc a.v_model_desc || ""
}`,
`${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}`
), ),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order, state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
@@ -291,7 +295,21 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
dataIndex: "special_coverage_policy", dataIndex: "special_coverage_policy",
key: "special_coverage_policy", key: "special_coverage_policy",
ellipsis: true, ellipsis: true,
}, sorter: (a, b) =>
Number(a.special_coverage_policy) - Number(b.special_coverage_policy),
sortOrder:
state.sortedInfo.columnKey === "special_coverage_policy" &&
state.sortedInfo.order,
filters: [
{ text: "True", value: true },
{ text: "False", value: false },
],
onFilter: (value, record) =>
value.includes(record.special_coverage_policy),
render: (text, record) => (
<Checkbox disabled checked={record.special_coverage_policy} />
),
},
{ {
title: i18n.t("jobs.fields.alt_transport"), title: i18n.t("jobs.fields.alt_transport"),
@@ -302,7 +320,16 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
sortOrder: sortOrder:
state.sortedInfo.columnKey === "alt_transport" && state.sortedInfo.columnKey === "alt_transport" &&
state.sortedInfo.order, state.sortedInfo.order,
render: (text, record) => ( filters:
(bodyshop &&
bodyshop.appt_alt_transport.map((s) => {
return {
text: s,
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.alt_transport),render: (text, record) => (
<div> <div>
{record.alt_transport} {record.alt_transport}
<JobAltTransportChange job={record}/> <JobAltTransportChange job={record}/>
@@ -382,7 +409,11 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
title: i18n.t("production.labels.alert"), title: i18n.t("production.labels.alert"),
dataIndex: "alert", dataIndex: "alert",
key: "alert", key: "alert",
sorter: (a, b) =>
Number(a.production_vars?.alert || false) -
Number(b.production_vars?.alert || false),
sortOrder:
state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
render: (text, record) => <ProductionListColumnAlert record={record}/>, render: (text, record) => <ProductionListColumnAlert record={record}/>,
}, },
{ {

View File

@@ -3,12 +3,12 @@ import {useMutation} from "@apollo/client";
import { import {
Button, Button,
Col, Col,
notification,
Popover, Popover,
Row, Row,
Select, Select,
Space, Space,
Spin, Spin,notification,
} from "antd"; } from "antd";
import React, {useState} from "react"; import React, {useState} from "react";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
@@ -25,8 +25,8 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ProductionListEmpAssignment({ export function ProductionListEmpAssignment({
@@ -56,7 +56,8 @@ export function ProductionListEmpAssignment({
insertAuditTrail({ insertAuditTrail({
jobid: record.id, jobid: record.id,
operation: AuditTrailMapping.jobassignmentchange(empAssignment, name), operation: AuditTrailMapping.jobassignmentchange(empAssignment, name),
}); type: "jobassignmentchange",
});
if (!!result.errors) { if (!!result.errors) {
notification["error"]({ notification["error"]({
@@ -84,7 +85,8 @@ export function ProductionListEmpAssignment({
insertAuditTrail({ insertAuditTrail({
jobid: record.id, jobid: record.id,
operation: AuditTrailMapping.jobassignmentremoved(empAssignment), operation: AuditTrailMapping.jobassignmentremoved(empAssignment),
}); type: "jobassignmentremoved",
});
if (!!result.errors) { if (!!result.errors) {
notification["error"]({ notification["error"]({

View File

@@ -12,8 +12,8 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ProductionListColumnCategory({record, bodyshop}) { export function ProductionListColumnCategory({record, bodyshop}) {

View File

@@ -5,16 +5,15 @@ import {connect} from "react-redux";
import {createStructuredSelector} from "reselect"; import {createStructuredSelector} from "reselect";
import {logImEXEvent} from "../../firebase/firebase.utils"; import {logImEXEvent} from "../../firebase/firebase.utils";
import {UPDATE_JOB} from "../../graphql/jobs.queries"; import {UPDATE_JOB} from "../../graphql/jobs.queries";
import {selectBodyshop} from "../../redux/user/user.selectors"; import {insertAuditTrail} from "../../redux/application/application.actions";import { selectBodyshop } from "../../redux/user/user.selectors";
import {insertAuditTrail} from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ProductionListColumnStatus({ export function ProductionListColumnStatus({
@@ -41,7 +40,8 @@ export function ProductionListColumnStatus({
insertAuditTrail({ insertAuditTrail({
jobid: record.id, jobid: record.id,
operation: AuditTrailMapping.jobstatuschange(key), operation: AuditTrailMapping.jobstatuschange(key),
}); type: "jobstatuschange",
});
setLoading(false); setLoading(false);
}; };

View File

@@ -142,7 +142,8 @@ function FiltersSection({filters, form, bodyshop}) {
return generateInternalReflections({ return generateInternalReflections({
bodyshop, bodyshop,
upperPath, upperPath,
finalPath finalPath,
t
}); });
}; };

View File

@@ -22,7 +22,6 @@ const generateOptionsFromArray = (bodyshop, path) => {
})), 'value'); })), 'value');
} }
/** /**
* Valid internal reflections * Valid internal reflections
* Note: This is intended for future functionality * Note: This is intended for future functionality
@@ -57,10 +56,34 @@ const generateOptionsFromObject = (bodyshop, path, labelPath, valuePath) => {
* Generate special reflections * Generate special reflections
* @param bodyshop * @param bodyshop
* @param finalPath * @param finalPath
* @param t - i18n
* @returns {{label: *, value: *}[]|{label: *, value: *}[]|{label: string, value: *}[]|*[]} * @returns {{label: *, value: *}[]|{label: *, value: *}[]|{label: string, value: *}[]|*[]}
*/ */
const generateSpecialReflections = (bodyshop, finalPath) => { const generateSpecialReflections = (bodyshop, finalPath, t) => {
switch (finalPath) { switch (finalPath) {
case 'payment_payers':
return [
{
label: t("payments.labels.customer"),
value: t("payments.labels.customer"),
},
{
label: t("payments.labels.insurance"),
value: t("payments.labels.insurance"),
},
// This is a weird one supposedly only used by one shop and could potentially be
// placed behind a SplitSDK
{
label: t("payments.labels.external"),
value: t("payments.labels.external"),
}
];
case 'payment_types':
return generateOptionsFromArray(bodyshop, 'md_payment_types');
case 'alt_transports':
return generateOptionsFromArray(bodyshop, 'appt_alt_transport');
case 'lost_sale_reasons':
return generateOptionsFromArray(bodyshop, 'md_lost_sale_reasons');
// Special case because Referral Sources is an Array, not an Object. // Special case because Referral Sources is an Array, not an Object.
case 'referral_source': case 'referral_source':
return generateOptionsFromArray(bodyshop, 'md_referral_sources'); return generateOptionsFromArray(bodyshop, 'md_referral_sources');
@@ -121,12 +144,13 @@ const generateBodyshopReflections = (bodyshop, finalPath) => {
* @param bodyshop * @param bodyshop
* @param upperPath * @param upperPath
* @param finalPath * @param finalPath
* @param t - i18n
* @returns {{label: *, value: *}[]|[]|{label: *, value: *}[]|{label: string, value: *}[]|{label: *, value: *}[]|*[]} * @returns {{label: *, value: *}[]|[]|{label: *, value: *}[]|{label: string, value: *}[]|{label: *, value: *}[]|*[]}
*/ */
const generateInternalReflections = ({bodyshop, upperPath, finalPath}) => { const generateInternalReflections = ({bodyshop, upperPath, finalPath, t}) => {
switch (upperPath) { switch (upperPath) {
case 'special': case 'special':
return generateSpecialReflections(bodyshop, finalPath); return generateSpecialReflections(bodyshop, finalPath, t);
case 'bodyshop': case 'bodyshop':
return generateBodyshopReflections(bodyshop, finalPath); return generateBodyshopReflections(bodyshop, finalPath);
default: default:

View File

@@ -30,8 +30,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("schedule")), toggleModalVisible: () => dispatch(toggleModalVisible("schedule")),
setEmailOptions: (e) => dispatch(setEmailOptions(e)), setEmailOptions: (e) => dispatch(setEmailOptions(e)),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function ScheduleJobModalContainer({ export function ScheduleJobModalContainer({
@@ -142,7 +142,7 @@ export function ScheduleJobModalContainer({
operation: AuditTrailMapping.appointmentinsert( operation: AuditTrailMapping.appointmentinsert(
DateTimeFormat(values.start) DateTimeFormat(values.start)
), ),
}); type: "appointmentinsert",});
} }
if (!!appt.errors) { if (!!appt.errors) {

View File

@@ -40,7 +40,7 @@ export const INSERT_AUDIT_TRAIL = gql`
bodyshopid bodyshopid
created created
operation operation
useremail typeuseremail
} }
} }
`; `;

View File

@@ -1866,7 +1866,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
ownr_co_nm ownr_co_nm
ownr_ph1 ownr_ph1
ownr_ph2 ownr_ph2
plate_no owneridplate_no
plate_st plate_st
v_vin v_vin
v_model_yr v_model_yr

View File

@@ -31,8 +31,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)), setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({ jobid, operation, type }) =>
dispatch(insertAuditTrail({ jobid, operation })), dispatch(insertAuditTrail({ jobid, operation, type })),
}); });
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer); export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
@@ -118,7 +118,7 @@ export function DmsContainer({
insertAuditTrail({ insertAuditTrail({
jobid: payload, jobid: payload,
operation: AuditTrailMapping.jobexported(), operation: AuditTrailMapping.jobexported(),
}); type: "jobexported",});
history("/manage/accounting/receivables"); history("/manage/accounting/receivables");
}); });

View File

@@ -12,7 +12,8 @@ import AlertComponent from "../../components/alert/alert.component";
import {QUERY_EXPORT_LOG_PAGINATED} from "../../graphql/accounting.queries"; import {QUERY_EXPORT_LOG_PAGINATED} from "../../graphql/accounting.queries";
import {selectBodyshop} from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import {DateTimeFormatter} from "../../utils/DateFormatter"; import {DateTimeFormatter} from "../../utils/DateFormatter";
import {pageLimit} from "../../utils/config"; import { pageLimit } from "../../utils/config";
import { alphaSort, dateSort } from "./../../utils/sorters";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -34,11 +35,42 @@ export function ExportLogsPageComponent({bodyshop}) {
limit: pageLimit, limit: pageLimit,
order: [ order: [
{ {
[sortcolumn || "created_at"]: sortorder ...(sortcolumn === "ro_number"
? {
job: {
[sortcolumn|| "created_at"]: sortorder
? sortorder === "descend" ? sortorder === "descend"
? "desc" ? "desc"
: "asc" : "asc"
: "desc", : "desc",},
}
: sortcolumn === "invoice_number"
? {
bill: {
[sortcolumn || "created_at"]: sortorder
? sortorder === "descend"
? "desc"
: "asc"
: "desc",
},
}
: sortcolumn === "paymentnum"
? {
payment: {
[sortcolumn || "created_at"]: sortorder
? sortorder === "descend"
? "desc"
: "asc"
: "desc",
},
}
: {
[sortcolumn || "created_at"]: sortorder
? sortorder === "descend"
? "desc"
: "asc"
: "desc",
}),
}, },
], ],
}, },
@@ -68,7 +100,8 @@ export function ExportLogsPageComponent({bodyshop}) {
title: t("general.labels.created_at"), title: t("general.labels.created_at"),
dataIndex: "created_at", dataIndex: "created_at",
key: "created_at", key: "created_at",
render: (text, record) => ( sorter: (a, b) => dateSort(a.created_at, b.created_at),
sortOrder: sortcolumn === "created_at" && sortorder,render: (text, record) => (
<DateTimeFormatter>{record.created_at}</DateTimeFormatter> <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
), ),
}, },
@@ -81,7 +114,8 @@ export function ExportLogsPageComponent({bodyshop}) {
title: t("jobs.fields.ro_number"), title: t("jobs.fields.ro_number"),
dataIndex: "ro_number", dataIndex: "ro_number",
key: "ro_number", key: "ro_number",
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => render: (text, record) =>
record.job && ( record.job && (
<Link to={`/manage/jobs/${record.job.id}`}> <Link to={`/manage/jobs/${record.job.id}`}>
@@ -93,7 +127,8 @@ export function ExportLogsPageComponent({bodyshop}) {
title: t("bills.fields.invoice_number"), title: t("bills.fields.invoice_number"),
dataIndex: "invoice_number", dataIndex: "invoice_number",
key: "invoice_number", key: "invoice_number",
render: (text, record) => sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
sortOrder: sortcolumn === "invoice_number" && sortorder,render: (text, record) =>
record.bill && ( record.bill && (
<Link to={"/manage/bills?billid=" + (record.bill && record.bill.id)}> <Link to={"/manage/bills?billid=" + (record.bill && record.bill.id)}>
{record.bill && record.bill.invoice_number} {record.bill && record.bill.invoice_number}
@@ -103,7 +138,8 @@ export function ExportLogsPageComponent({bodyshop}) {
{ {
title: t("payments.fields.paymentnum"), title: t("payments.fields.paymentnum"),
dataIndex: "paymentnum", dataIndex: "paymentnum",
key: "paymentnum", key: "paymentnum",sorter: (a, b) => alphaSort(a.paymentnum, b.paymentnum),
sortOrder: sortcolumn === "paymentnum" && sortorder,
render: (text, record) => render: (text, record) =>
record.payment && ( record.payment && (
<Link <Link
@@ -119,7 +155,13 @@ export function ExportLogsPageComponent({bodyshop}) {
{ {
title: t("general.labels.successful"), title: t("general.labels.successful"),
dataIndex: "successful", dataIndex: "successful",
key: "successful", key: "successful",sorter: (a, b) => Number(a.successful) - Number(b.successful),
sortOrder: sortcolumn === "successful" && sortorder,
filters: [
{ text: "True", value: true },
{ text: "False", value: false },
],
onFilter: (value, record) => record.successful === value,
render: (text, record) => ( render: (text, record) => (
<Checkbox disabled checked={record.successful}/> <Checkbox disabled checked={record.successful}/>
), ),

View File

@@ -48,11 +48,11 @@ const mapStateToProps = createStructuredSelector({
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail,}) { export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
const {t} = useTranslation(); const {t} = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
const client = useApolloClient(); const client = useApolloClient();
@@ -118,7 +118,7 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail,}) {
insertAuditTrail({ insertAuditTrail({
jobid: job.id, jobid: job.id,
operation: AuditTrailMapping.jobinvoiced(), operation: AuditTrailMapping.jobinvoiced(),
}); type: "jobinvoiced",});
// history.push(`/manage/jobs/${job.id}`); // history.push(`/manage/jobs/${job.id}`);
} else { } else {
setLoading(false); setLoading(false);

View File

@@ -23,6 +23,7 @@ import {createStructuredSelector} from "reselect";
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component"; import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component"; import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container"; import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container"; import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container"; import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
import JobSyncButton from "../../components/job-sync-button/job-sync-button.component"; import JobSyncButton from "../../components/job-sync-button/job-sync-button.component";
@@ -49,7 +50,6 @@ import {selectBodyshop} from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import UndefinedToNull from "../../utils/undefinedtonull"; import UndefinedToNull from "../../utils/undefinedtonull";
import {DateTimeFormat} from "./../../utils/DateFormatter"; import {DateTimeFormat} from "./../../utils/DateFormatter";
import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -58,8 +58,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) => setPrintCenterContext: (context) =>
dispatch(setModalContext({context: context, modal: "printCenter"})), dispatch(setModalContext({context: context, modal: "printCenter"})),
insertAuditTrail: ({jobid, operation}) => insertAuditTrail: ({jobid, operation, type}) =>
dispatch(insertAuditTrail({jobid, operation})), dispatch(insertAuditTrail({jobid, operation, type })),
}); });
export function JobsDetailPage({ export function JobsDetailPage({
@@ -172,7 +172,7 @@ export function JobsDetailPage({
? DateTimeFormat(changedAuditFields[key]) ? DateTimeFormat(changedAuditFields[key])
: changedAuditFields[key] : changedAuditFields[key]
), ),
}); type: "jobfieldchange",});
}); });
await refetch(); await refetch();
@@ -304,7 +304,7 @@ export function JobsDetailPage({
{ {
key: 'lifecycle', key: 'lifecycle',
icon: <BarsOutlined/>, icon: <BarsOutlined/>,
label: t('menus.jobsdetail.lifecycle'), label: t("menus.jobsdetail.lifecycle"),
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>, children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>,
}, },
{ {

View File

@@ -54,9 +54,9 @@ export const setOnline = (isOnline) => ({
payload: isOnline, payload: isOnline,
}); });
export const insertAuditTrail = ({jobid, billid, operation}) => ({ export const insertAuditTrail = ({jobid, billid, operation, type}) => ({
type: ApplicationActionTypes.INSERT_AUDIT_TRAIL, type: ApplicationActionTypes.INSERT_AUDIT_TRAIL,
payload: {jobid, billid, operation}, payload: {jobid, billid, operation, type },
}); });
export const setProblemJobs = (problemJobs) => ({ export const setProblemJobs = (problemJobs) => ({
type: ApplicationActionTypes.SET_PROBLEM_JOBS, type: ApplicationActionTypes.SET_PROBLEM_JOBS,

View File

@@ -263,7 +263,7 @@ export function* onInsertAuditTrail() {
} }
export function* insertAuditTrailSaga({ export function* insertAuditTrailSaga({
payload: {jobid, billid, operation}, payload: {jobid, billid, operation, type},
}) { }) {
const state = yield select(); const state = yield select();
const bodyshop = state.user.bodyshop; const bodyshop = state.user.bodyshop;
@@ -275,7 +275,7 @@ export function* insertAuditTrailSaga({
jobid, jobid,
billid, billid,
operation, operation,
useremail: currentUser.email, type,useremail: currentUser.email,
}, },
}; };
yield client.mutate({ yield client.mutate({

View File

@@ -259,28 +259,30 @@
- active: - active:
_eq: true _eq: true
columns: columns:
- id - billid
- bodyshopid
- created - created
- operation - id
- jobid
- new_val - new_val
- old_val - old_val
- operation
- type
- useremail - useremail
- bodyshopid
- jobid
- billid
select_permissions: select_permissions:
- role: user - role: user
permission: permission:
columns: columns:
- billid
- bodyshopid
- created
- id - id
- jobid
- new_val - new_val
- old_val - old_val
- operation - operation
- type
- useremail - useremail
- created
- billid
- bodyshopid
- jobid
filter: filter:
bodyshop: bodyshop:
associations: associations:

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."audit_trail" add column "type" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."audit_trail" add column "type" text
null;