From ba5571768326547ef4ad54afdc5286d70d0ac0aa Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 6 Jun 2022 15:43:35 -0700
Subject: [PATCH 1/9] IO-1663 Add time to production board.
---
.../production-list-columns.data.js | 45 ++++++++++--
...production-list-columns.date.component.jsx | 73 +++++++++----------
client/src/utils/DateFormatter.jsx | 5 ++
3 files changed, 77 insertions(+), 46 deletions(-)
diff --git a/client/src/components/production-list-columns/production-list-columns.data.js b/client/src/components/production-list-columns/production-list-columns.data.js
index d99f4e5a2..e09e98775 100644
--- a/client/src/components/production-list-columns/production-list-columns.data.js
+++ b/client/src/components/production-list-columns/production-list-columns.data.js
@@ -5,25 +5,26 @@ import moment from "moment";
import React from "react";
import { Link } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
+import { TimeFormatter } from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
import JobAltTransportChange from "../job-at-change/job-at-change.component";
+import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
+import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import ProductionListColumnAlert from "./production-list-columns.alert.component";
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
+import ProductionListColumnComment from "./production-list-columns.comment.component";
import ProductionListDate from "./production-list-columns.date.component";
import ProductionListColumnDetailPriority from "./production-list-columns.detailpriority.component";
import ProductionListEmployeeAssignment from "./production-list-columns.empassignment.component";
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
-import ProductionListColumnNote from "./production-list-columns.productionnote.component";
-import ProductionListColumnStatus from "./production-list-columns.status.component";
-import ProductionListColumnCategory from "./production-list-columns.status.category";
-import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
-import ProductionListColumnComment from "./production-list-columns.comment.component";
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
-import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
-import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
+import ProductionListColumnNote from "./production-list-columns.productionnote.component";
+import ProductionListColumnCategory from "./production-list-columns.status.category";
+import ProductionListColumnStatus from "./production-list-columns.status.component";
+import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
const r = ({ technician, state, activeStatuses, bodyshop }) => {
return [
@@ -105,6 +106,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
),
},
+ {
+ title: i18n.t("jobs.fields.actual_in") + " (HH:MM)",
+ dataIndex: "actual_in_time",
+ key: "actual_in_time",
+ ellipsis: true,
+
+ render: (text, record) => (
+ {record.actual_in}
+ ),
+ },
{
title: i18n.t("jobs.fields.scheduled_completion"),
dataIndex: "scheduled_completion",
@@ -124,6 +135,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
/>
),
},
+ {
+ title: i18n.t("jobs.fields.scheduled_completion") + " (HH:MM)",
+ dataIndex: "scheduled_completion_time",
+ key: "scheduled_completion_time",
+ ellipsis: true,
+
+ render: (text, record) => (
+ {record.scheduled_completion}
+ ),
+ },
{
title: i18n.t("jobs.fields.date_last_contacted"),
dataIndex: "date_last_contacted",
@@ -176,6 +197,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
/>
),
},
+ {
+ title: i18n.t("jobs.fields.scheduled_delivery") + " (HH:MM)",
+ dataIndex: "scheduled_delivery_time",
+ key: "scheduled_delivery_time",
+ ellipsis: true,
+
+ render: (text, record) => (
+ {record.scheduled_delivery}
+ ),
+ },
{
title: i18n.t("jobs.fields.ins_co_nm"),
dataIndex: "ins_co_nm",
diff --git a/client/src/components/production-list-columns/production-list-columns.date.component.jsx b/client/src/components/production-list-columns/production-list-columns.date.component.jsx
index 5927c99e2..4944d628b 100644
--- a/client/src/components/production-list-columns/production-list-columns.date.component.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.date.component.jsx
@@ -50,50 +50,45 @@ export default function ProductionListDate({
"production-completion-soon"));
}
return (
-
-
e.stopPropagation()}>
+ e.stopPropagation()}
- >
-
+ {time && (
+ e.stopPropagation()}
value={(record[field] && moment(record[field])) || null}
onChange={handleChange}
- format="MM/DD/YYYY"
- isDateOnly={!time}
+ minuteStep={15}
+ format="hh:mm a"
/>
- {time && (
- e.stopPropagation()}
- value={(record[field] && moment(record[field])) || null}
- onChange={handleChange}
- minuteStep={15}
- format="hh:mm a"
- />
- )}
-
-
- }
+ )}
+
+
+ }
+ >
+ setVisible(true)}
+ style={{
+ height: "19px",
+ }}
+ className={className}
>
-
setVisible(true)}
- style={{
- height: "19px",
- }}
- className={className}
- >
- {record[field]}
-
-
-
+ {record[field]}
+
+
);
}
diff --git a/client/src/utils/DateFormatter.jsx b/client/src/utils/DateFormatter.jsx
index 18c2e633d..134095c78 100644
--- a/client/src/utils/DateFormatter.jsx
+++ b/client/src/utils/DateFormatter.jsx
@@ -17,6 +17,11 @@ export function DateTimeFormatter(props) {
)
: null;
}
+export function TimeFormatter(props) {
+ return props.children
+ ? moment(props.children).format(props.format ? props.format : "hh:mm a")
+ : null;
+}
export function TimeAgoFormatter(props) {
const m = moment(props.children);
From d6c8d97715a16145e2c71be67991d29d400f12f1 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 6 Jun 2022 17:30:20 -0700
Subject: [PATCH 2/9] Add comments field to parts queue.
---
.../job-parts-queue-count.component.jsx | 4 ++--
.../production-list-columns.comment.component.jsx | 5 +++--
client/src/graphql/jobs.queries.js | 1 +
.../parts-queue/parts-queue.page.component.jsx | 14 ++++++++++++--
4 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
index 9ead0530c..fe394f301 100644
--- a/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
+++ b/client/src/components/job-parts-queue-count/job-parts-queue-count.component.jsx
@@ -11,7 +11,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export default connect(mapStateToProps, mapDispatchToProps)(JobPartsQueueCount);
-export function JobPartsQueueCount({ bodyshop, parts }) {
+export function JobPartsQueueCount({ bodyshop, parts, style }) {
const partsStatus = useMemo(() => {
if (!parts) return null;
return parts.reduce(
@@ -36,7 +36,7 @@ export function JobPartsQueueCount({ bodyshop, parts }) {
if (!parts) return null;
return (
-
+
{partsStatus.total}
diff --git a/client/src/components/production-list-columns/production-list-columns.comment.component.jsx b/client/src/components/production-list-columns/production-list-columns.comment.component.jsx
index fafccff93..d66f72c75 100644
--- a/client/src/components/production-list-columns/production-list-columns.comment.component.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.comment.component.jsx
@@ -1,6 +1,6 @@
import Icon from "@ant-design/icons";
import { useMutation } from "@apollo/client";
-import { Button, Input, Popover } from "antd";
+import { Button, Input, Popover, Tooltip } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { FaRegStickyNote } from "react-icons/fa";
@@ -69,10 +69,11 @@ export default function ProductionListColumnComment({ record }) {
cursor: "pointer",
overflow: "hidden",
textOverflow: "ellipsis",
+ display: "inline-block",
}}
>
- {record.comment || " "}
+ {record.comment || " "}
);
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index b5611eab7..eba649d29 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -85,6 +85,7 @@ export const QUERY_PARTS_QUEUE = gql`
vehicleid
ownerid
queued_for_parts
+ comment
joblines_status {
count
part_type
diff --git a/client/src/pages/parts-queue/parts-queue.page.component.jsx b/client/src/pages/parts-queue/parts-queue.page.component.jsx
index bc6bf2c03..492ee1955 100644
--- a/client/src/pages/parts-queue/parts-queue.page.component.jsx
+++ b/client/src/pages/parts-queue/parts-queue.page.component.jsx
@@ -11,6 +11,7 @@ import AlertComponent from "../../components/alert/alert.component";
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
+import ProductionListColumnComment from "../../components/production-list-columns/production-list-columns.comment.component";
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
@@ -228,9 +229,18 @@ export function PartsQueuePageComponent({ bodyshop }) {
dataIndex: "partsstatus",
key: "partsstatus",
render: (text, record) => (
-
+
),
},
+ {
+ title: t("jobs.fields.comment"),
+ dataIndex: "comment",
+ key: "comment",
+ render: (text, record) => ,
+ },
{
title: t("jobs.fields.queued_for_parts"),
dataIndex: "queued_for_parts",
@@ -247,7 +257,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
value: false,
},
],
- //onFilter: (value, record) => record.queued_for_parts === value,
+ onFilter: (value, record) => record.queued_for_parts === value,
render: (text, record) => (
Date: Tue, 7 Jun 2022 08:37:27 -0700
Subject: [PATCH 3/9] IO-1925 Change job costing to have negative sale on
adjustment.
---
server/job/job-costing.js | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/server/job/job-costing.js b/server/job/job-costing.js
index 5ccdeba0d..13f9201cc 100644
--- a/server/job/job-costing.js
+++ b/server/job/job-costing.js
@@ -781,33 +781,33 @@ function GenerateCostingData(job) {
//Push adjustments to bottom line.
if (job.adjustment_bottom_line) {
//Add to totals.
- const Adjustment = Dinero({ amount: job.adjustment_bottom_line * -100 }); //Need to invert, since this is being assigned as a cost.
- summaryData.totalLaborCost = summaryData.totalLaborCost.add(Adjustment);
- summaryData.totalCost = summaryData.totalCost.add(Adjustment);
+ const Adjustment = Dinero({ amount: job.adjustment_bottom_line * 100 }); //Need to invert, since this is being assigned as a cost.
+ summaryData.totalLaborSales = summaryData.totalLaborSales.add(Adjustment);
+ summaryData.totalSales = summaryData.totalSales.add(Adjustment);
//Add to lines.
costCenterData.push({
id: "Adj",
cost_center: "Adjustment",
- sale_labor: Dinero().toFormat(),
- sale_labor_dinero: Dinero(),
+ sale_labor: Adjustment.toFormat(),
+ sale_labor_dinero: Adjustment,
sale_parts: Dinero().toFormat(),
sale_parts_dinero: Dinero(),
sale_additional: Dinero(),
sale_additional_dinero: Dinero(),
sale_sublet: Dinero(),
sale_sublet_dinero: Dinero(),
- sales: Dinero().toFormat(),
- sales_dinero: Dinero(),
+ sales: Adjustment.toFormat(),
+ sales_dinero: Adjustment,
cost_parts: Dinero().toFormat(),
cost_parts_dinero: Dinero(),
- cost_labor: Adjustment.toFormat(),
- cost_labor_dinero: Adjustment,
+ cost_labor: Dinero().toFormat(), //Adjustment.toFormat(),
+ cost_labor_dinero: Dinero(), // Adjustment,
cost_additional: Dinero(),
cost_additional_dinero: Dinero(),
cost_sublet: Dinero(),
cost_sublet_dinero: Dinero(),
- costs: Adjustment.toFormat(),
- costs_dinero: Adjustment,
+ costs: Dinero().toFormat(),
+ costs_dinero: Dinero(),
gpdollars_dinero: Dinero(),
gpdollars: Dinero().toFormat(),
gppercent: formatGpPercent(0),
From 9491d5f06986249ae96177a97b6c1cc02569a361 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Tue, 7 Jun 2022 08:43:24 -0700
Subject: [PATCH 4/9] IO-1916 Resolve required labels on sign in.
---
.../components/sign-in-form/sign-in-form.component.jsx | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/client/src/components/sign-in-form/sign-in-form.component.jsx b/client/src/components/sign-in-form/sign-in-form.component.jsx
index da1c749f7..c964c0dc2 100644
--- a/client/src/components/sign-in-form/sign-in-form.component.jsx
+++ b/client/src/components/sign-in-form/sign-in-form.component.jsx
@@ -60,7 +60,10 @@ export function SignInComponent({
Date: Tue, 7 Jun 2022 08:55:07 -0700
Subject: [PATCH 5/9] IO-1862 Add option to remove from production on invoice
close.
---
.../src/pages/jobs-close/jobs-close.component.jsx | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx
index 697211ee6..6106a013a 100644
--- a/client/src/pages/jobs-close/jobs-close.component.jsx
+++ b/client/src/pages/jobs-close/jobs-close.component.jsx
@@ -10,6 +10,7 @@ import {
PageHeader,
InputNumber,
Input,
+ Switch,
} from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -42,7 +43,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
const [closeJob] = useMutation(UPDATE_JOB);
const [loading, setLoading] = useState(false);
- const handleFinish = async (values) => {
+ const handleFinish = async ({ removefromproduction, ...values }) => {
setLoading(true);
const result = await client.mutate({
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
@@ -63,6 +64,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
kmin: values.kmin,
kmout: values.kmout,
dms_allocation: values.dms_allocation,
+ ...(removefromproduction ? { inproduction: false } : {}),
},
},
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
@@ -248,6 +250,15 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
onlyFuture={!!bodyshop.cdk_dealerid}
/>
+ {!jobRO && (
+
+
+
+ )}
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
Date: Tue, 7 Jun 2022 08:59:28 -0700
Subject: [PATCH 6/9] IO-1732 Adjust tech job drawer width.
---
.../tech-lookup-jobs-drawer.component.jsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx
index 2d28099f0..02e62d274 100644
--- a/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx
+++ b/client/src/components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component.jsx
@@ -43,9 +43,9 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
xs: "100%",
sm: "100%",
md: "100%",
- lg: "70%",
- xl: "70%",
- xxl: "70%",
+ lg: "100%",
+ xl: "90%",
+ xxl: "85%",
};
const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]]
From fe5e2a247ae035fe05d16bb2f962e55922f3bf61 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Tue, 7 Jun 2022 11:41:27 -0700
Subject: [PATCH 7/9] IO-1914 Inventory bugfixes.
---
bodyshop_translations.babel | 21 +++++++++++
.../bill-delete-button.component.jsx | 24 +++++++++----
.../bill-form/bill-form.lines.component.jsx | 35 ++++++++++++-------
.../billline-add-inventory.component.jsx | 15 ++++----
client/src/redux/media/media.actions.js | 1 -
client/src/translations/en_us/common.json | 1 +
client/src/translations/es/common.json | 1 +
client/src/translations/fr/common.json | 1 +
8 files changed, 74 insertions(+), 25 deletions(-)
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 516cab7d9..31b297cd9 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -2181,6 +2181,27 @@
+
+ existinginventoryline
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
exporting
false
diff --git a/client/src/components/bill-delete-button/bill-delete-button.component.jsx b/client/src/components/bill-delete-button/bill-delete-button.component.jsx
index eee5f522b..b6cb19992 100644
--- a/client/src/components/bill-delete-button/bill-delete-button.component.jsx
+++ b/client/src/components/bill-delete-button/bill-delete-button.component.jsx
@@ -15,7 +15,8 @@ export default function BillDeleteButton({ bill }) {
setLoading(true);
const result = await deleteBill({
variables: { billId: bill.id },
- update(cache) {
+ update(cache, { errors }) {
+ if (errors) return;
cache.modify({
fields: {
bills(existingBills, { readField }) {
@@ -36,11 +37,22 @@ export default function BillDeleteButton({ bill }) {
if (!!!result.errors) {
notification["success"]({ message: t("bills.successes.deleted") });
} else {
- notification["error"]({
- message: t("bills.errors.deleting", {
- error: JSON.stringify(result.errors),
- }),
- });
+ //Check if it's an fkey violation.
+ const error = JSON.stringify(result.errors);
+
+ if (error.toLowerCase().includes("inventory_billid_fkey")) {
+ notification["error"]({
+ message: t("bills.errors.deleting", {
+ error: t("bills.errors.existinginventoryline"),
+ }),
+ });
+ } else {
+ notification["error"]({
+ message: t("bills.errors.deleting", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
}
setLoading(false);
diff --git a/client/src/components/bill-form/bill-form.lines.component.jsx b/client/src/components/bill-form/bill-form.lines.component.jsx
index 18d996d5a..71a0e3b72 100644
--- a/client/src/components/bill-form/bill-form.lines.component.jsx
+++ b/client/src/components/bill-form/bill-form.lines.component.jsx
@@ -485,22 +485,33 @@ export function BillEnterModalLinesComponent({
dataIndex: "actions",
render: (text, record) => (
-
-
-
- {() =>
- Simple_Inventory.treatment === "on" && (
+
+ {() => (
+
+
+ {Simple_Inventory.treatment === "on" && (
- )
- }
-
-
+ )}
+
+ )}
+
),
},
];
diff --git a/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx b/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx
index 2a6d76355..d2cbe92bc 100644
--- a/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx
+++ b/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx
@@ -64,9 +64,9 @@ export function BilllineAddInventory({
cost_center: billline.cost_center,
deductedfromlbr: billline.deductedfromlbr,
applicable_taxes: {
- local: false, //billline.applicable_taxes.local,
- state: false, //billline.applicable_taxes.state,
- federal: false, // billline.applicable_taxes.federal,
+ local: billline.applicable_taxes.local,
+ state: billline.applicable_taxes.state,
+ federal: billline.applicable_taxes.federal,
},
},
],
@@ -76,7 +76,9 @@ export function BilllineAddInventory({
const insertResult = await insertInventoryLine({
variables: {
- joblineId: billline.joblineid,
+ joblineId:
+ billline.joblineid === "noline" ? billline.id : billline.joblineid, //This will return null as there will be no jobline that has the id of the bill line.
+ //Unfortunately, we can't send null as the GQL syntax validation fails.
joblineStatus: bodyshop.md_order_statuses.default_returned,
inv: {
shopid: bodyshop.id,
@@ -99,8 +101,9 @@ export function BilllineAddInventory({
act_price: billline.actual_price,
cost: billline.actual_cost,
quantity: billline.quantity,
- job_line_id: billline.joblineid,
- part_type: billline.jobline.part_type,
+ job_line_id:
+ billline.joblineid === "noline" ? null : billline.joblineid,
+ part_type: billline.jobline && billline.jobline.part_type,
cm_received: true,
},
],
diff --git a/client/src/redux/media/media.actions.js b/client/src/redux/media/media.actions.js
index 1ff5e943c..3d0827123 100644
--- a/client/src/redux/media/media.actions.js
+++ b/client/src/redux/media/media.actions.js
@@ -6,7 +6,6 @@ export const getJobMedia = (jobid) => ({
});
export const getBillMedia = ({ jobid, invoice_number }) => {
- console.log("in the action");
return {
type: MediaActionTypes.GET_MEDIA_FOR_BILL,
payload: { jobid, invoice_number },
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index f283e1777..c55a48010 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -147,6 +147,7 @@
"errors": {
"creating": "Error adding bill. {{error}}",
"deleting": "Error deleting bill. {{error}}",
+ "existinginventoryline": "This bill cannot be deleted as it is tied to items in inventory.",
"exporting": "Error exporting payable(s). {{error}}",
"exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.",
"invalidro": "Not a valid RO.",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index b40b5175d..ca89fc4d9 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -147,6 +147,7 @@
"errors": {
"creating": "",
"deleting": "",
+ "existinginventoryline": "",
"exporting": "",
"exporting-partner": "",
"invalidro": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 6843f664f..bd63176f0 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -147,6 +147,7 @@
"errors": {
"creating": "",
"deleting": "",
+ "existinginventoryline": "",
"exporting": "",
"exporting-partner": "",
"invalidro": "",
From d32fd9e69711496b156c37993782740e71949113 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Tue, 7 Jun 2022 12:14:24 -0700
Subject: [PATCH 8/9] IO-1914 Consume from inventory screen.
---
bodyshop_translations.babel | 21 ++++++
.../bill-inventory-table.component.jsx | 14 +++-
.../inventory-bill-ro.component.jsx | 65 +++++++++++++++++++
.../inventory-list.component.jsx | 12 +++-
client/src/graphql/inventory.queries.js | 5 +-
client/src/translations/en_us/common.json | 1 +
client/src/translations/es/common.json | 1 +
client/src/translations/fr/common.json | 1 +
8 files changed, 115 insertions(+), 5 deletions(-)
create mode 100644 client/src/components/inventory-bill-ro/inventory-bill-ro.component.jsx
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 31b297cd9..4101a134e 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -17287,6 +17287,27 @@
+
+ addtoro
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
consumefrominventory
false
diff --git a/client/src/components/bill-inventory-table/bill-inventory-table.component.jsx b/client/src/components/bill-inventory-table/bill-inventory-table.component.jsx
index d8fb121d0..e9403a0f1 100644
--- a/client/src/components/bill-inventory-table/bill-inventory-table.component.jsx
+++ b/client/src/components/bill-inventory-table/bill-inventory-table.component.jsx
@@ -7,9 +7,11 @@ import "./bill-inventory-table.styles.scss";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
+import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
+ billEnterModal: selectBillEnterModal,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
@@ -17,6 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
export default connect(mapStateToProps, mapDispatchToProps)(BillInventoryTable);
export function BillInventoryTable({
+ billEnterModal,
bodyshop,
form,
billEdit,
@@ -28,11 +31,18 @@ export function BillInventoryTable({
useEffect(() => {
if (inventoryData) {
form.setFieldsValue({
- inventory: inventoryData.inventory,
+ inventory: billEnterModal.context.consumeinventoryid
+ ? inventoryData.inventory.map((i) => {
+ if (i.id === billEnterModal.context.consumeinventoryid)
+ i.consumefrominventory = true;
+ return i;
+ })
+ : inventoryData.inventory,
});
}
- }, [inventoryData, form]);
+ }, [inventoryData, form, billEnterModal.context.consumeinventoryid]);
+ console.log(form.getFieldsValue());
return (
prev.vendorid !== cur.vendorid}
diff --git a/client/src/components/inventory-bill-ro/inventory-bill-ro.component.jsx b/client/src/components/inventory-bill-ro/inventory-bill-ro.component.jsx
new file mode 100644
index 000000000..f83811ed7
--- /dev/null
+++ b/client/src/components/inventory-bill-ro/inventory-bill-ro.component.jsx
@@ -0,0 +1,65 @@
+import { Button } from "antd";
+import React from "react";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { setModalContext } from "../../redux/modals/modals.actions";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import moment from "moment";
+import { useTranslation } from "react-i18next";
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ setBillEnterContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "billEnter" })),
+});
+export default connect(mapStateToProps, mapDispatchToProps)(InventoryBillRo);
+export function InventoryBillRo({
+ bodyshop,
+ setBillEnterContext,
+ inventoryline,
+}) {
+ const { t } = useTranslation();
+ return (
+
+ );
+}
diff --git a/client/src/components/inventory-list/inventory-list.component.jsx b/client/src/components/inventory-list/inventory-list.component.jsx
index 58210eb94..95dcdea13 100644
--- a/client/src/components/inventory-list/inventory-list.component.jsx
+++ b/client/src/components/inventory-list/inventory-list.component.jsx
@@ -4,10 +4,11 @@ import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
-import { useHistory, useLocation } from "react-router-dom";
+import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
+import InventoryBillRo from "../inventory-bill-ro/inventory-bill-ro.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -75,7 +76,14 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
key: "consumedbyjob",
ellipsis: true,
- render: (text, record) => record.bill?.job?.ro_number,
+ render: (text, record) =>
+ record.bill?.job?.ro_number ? (
+
+ {record.bill?.job?.ro_number}
+
+ ) : (
+
+ ),
},
];
diff --git a/client/src/graphql/inventory.queries.js b/client/src/graphql/inventory.queries.js
index 51b713e92..51efcd3b8 100644
--- a/client/src/graphql/inventory.queries.js
+++ b/client/src/graphql/inventory.queries.js
@@ -42,7 +42,10 @@ export const UPDATE_INVENTORY_LINES = gql`
export const QUERY_OUTSTANDING_INVENTORY = gql`
query QUERY_OUTSTANDING_INVENTORY {
- inventory(where: { consumedbybillid: { _is_null: true } }) {
+ inventory(
+ where: { consumedbybillid: { _is_null: true } }
+ order_by: { line_desc: asc }
+ ) {
id
actual_cost
actual_price
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index c55a48010..c40bfe2be 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -1076,6 +1076,7 @@
"inventory": {
"actions": {
"addtoinventory": "Add to Inventory",
+ "addtoro": "Add to RO",
"consumefrominventory": "Consume from Inventory?"
},
"errors": {
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index ca89fc4d9..2793b4bf1 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -1076,6 +1076,7 @@
"inventory": {
"actions": {
"addtoinventory": "",
+ "addtoro": "",
"consumefrominventory": ""
},
"errors": {
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index bd63176f0..b7011de21 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -1076,6 +1076,7 @@
"inventory": {
"actions": {
"addtoinventory": "",
+ "addtoro": "",
"consumefrominventory": ""
},
"errors": {
From a1472cd9ff59e622e01b3b48698b44136bfb587b Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Tue, 7 Jun 2022 12:39:59 -0700
Subject: [PATCH 9/9] IO-1926 Add export log to mark as exported.
---
.../bill-mark-exported-button.component.jsx | 31 +++++++++++++++----
.../jobs-admin-mark-reexport.component.jsx | 29 +++++++++++++++--
...yable-mark-selected-exported.component.jsx | 27 ++++++++++++----
3 files changed, 73 insertions(+), 14 deletions(-)
diff --git a/client/src/components/bill-mark-exported-button/bill-mark-exported-button.component.jsx b/client/src/components/bill-mark-exported-button/bill-mark-exported-button.component.jsx
index d81244098..80fa1ae44 100644
--- a/client/src/components/bill-mark-exported-button/bill-mark-exported-button.component.jsx
+++ b/client/src/components/bill-mark-exported-button/bill-mark-exported-button.component.jsx
@@ -9,11 +9,14 @@ import { createStructuredSelector } from "reselect";
import {
selectAuthLevel,
selectBodyshop,
+ selectCurrentUser,
} from "../../redux/user/user.selectors";
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
+import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
authLevel: selectAuthLevel,
+ currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
@@ -24,9 +27,15 @@ export default connect(
mapDispatchToProps
)(BillMarkExportedButton);
-export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
+export function BillMarkExportedButton({
+ currentUser,
+ bodyshop,
+ authLevel,
+ bill,
+}) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
+ const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [updateBill] = useMutation(gql`
mutation UPDATE_BILL($billId: uuid!) {
@@ -46,6 +55,20 @@ export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
variables: { billId: bill.id },
});
+ await insertExportLog({
+ variables: {
+ logs: [
+ {
+ bodyshopid: bodyshop.id,
+ billid: bill.id,
+ successful: true,
+ message: t("general.labels.markedexported"),
+ useremail: currentUser.email,
+ },
+ ],
+ },
+ });
+
if (!result.errors) {
notification["success"]({
message: t("bills.successes.markexported"),
@@ -69,11 +92,7 @@ export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
if (hasAccess)
return (
-