@@ -107,6 +131,13 @@ export function BillFormComponent({
onBlur={() => {
if (form.getFieldValue("jobid") !== null) {
loadLines({ variables: { id: form.getFieldValue("jobid") } });
+ if (form.getFieldValue("vendorid") !== null)
+ loadOutstandingReturns({
+ variables: {
+ jobId: form.getFieldValue("jobid"),
+ vendorId: form.getFieldValue("vendorid"),
+ },
+ });
}
}}
/>
@@ -228,8 +259,22 @@ export function BillFormComponent({
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
+ if (
+ value === true &&
+ getFieldValue("jobid") &&
+ getFieldValue("vendorid")
+ ) {
+ loadOutstandingReturns({
+ variables: {
+ jobId: form.getFieldValue("jobid"),
+ vendorId: form.getFieldValue("vendorid"),
+ },
+ });
+ }
+
if (
!bodyshop.bill_allow_post_to_closed &&
+ job &&
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
job.status === bodyshop.md_ro_statuses.default_exported ||
job.status === bodyshop.md_ro_statuses.default_void) &&
diff --git a/client/src/components/bill-form/bill-form.container.jsx b/client/src/components/bill-form/bill-form.container.jsx
index 9c4b578d0..4fe056667 100644
--- a/client/src/components/bill-form/bill-form.container.jsx
+++ b/client/src/components/bill-form/bill-form.container.jsx
@@ -6,6 +6,8 @@ import { GET_JOB_LINES_TO_ENTER_BILL } from "../../graphql/jobs-lines.queries";
import { SEARCH_VENDOR_AUTOCOMPLETE } from "../../graphql/vendors.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import BillFormComponent from "./bill-form.component";
+import BillCmdReturnsTableComponent from "../bill-cm-returns-table/bill-cm-returns-table.component";
+import { QUERY_UNRECEIVED_LINES } from "../../graphql/parts-orders.queries";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -27,20 +29,34 @@ export function BillFormContainer({
GET_JOB_LINES_TO_ENTER_BILL
);
+ const [loadOutstandingReturns, { loading: returnLoading, data: returnData }] =
+ useLazyQuery(QUERY_UNRECEIVED_LINES);
+
return (
-
+ <>
+
+ {!billEdit && (
+
+ )}
+ >
);
}
export default connect(mapStateToProps, null)(BillFormContainer);
diff --git a/client/src/components/bills-list-table/bills-list-table.component.jsx b/client/src/components/bills-list-table/bills-list-table.component.jsx
index d15b29a20..ed4fb70e6 100644
--- a/client/src/components/bills-list-table/bills-list-table.component.jsx
+++ b/client/src/components/bills-list-table/bills-list-table.component.jsx
@@ -59,7 +59,6 @@ export function BillsListTableComponent({
record.is_credit_memo || record.vendorid === bodyshop.inhousevendorid
}
onClick={() => {
- console.log(record);
setPartsOrderContext({
actions: {},
context: {
diff --git a/client/src/components/parts-order-cm-received/parts-order-cm-received.component.jsx b/client/src/components/parts-order-cm-received/parts-order-cm-received.component.jsx
new file mode 100644
index 000000000..ed08ea3ea
--- /dev/null
+++ b/client/src/components/parts-order-cm-received/parts-order-cm-received.component.jsx
@@ -0,0 +1,66 @@
+import { useMutation } from "@apollo/client";
+import { Checkbox, notification, Space, Spin } from "antd";
+import React, { useState } from "react";
+import { useTranslation } from "react-i18next";
+import { MUTATION_UPDATE_PO_CM_REECEIVED } from "../../graphql/parts-orders.queries";
+
+export default function PartsOrderCmReceived({
+ checked,
+ orderLineId,
+ partsOrderId,
+}) {
+ const [updateLine] = useMutation(MUTATION_UPDATE_PO_CM_REECEIVED);
+ const { t } = useTranslation();
+
+ const [loading, setLoading] = useState(false);
+
+ const handleChange = async (e) => {
+ setLoading(true);
+ const result = await updateLine({
+ variables: {
+ partsLineId: orderLineId,
+ partsOrder: { cm_received: e.target.checked },
+ },
+ update(cache) {
+ cache.modify({
+ id: cache.identify({
+ id: partsOrderId,
+ __typename: "parts_orders",
+ }),
+
+ fields: {
+ parts_order_lines(ex, { readField }) {
+ console.log(ex);
+ return ex.map((lineref) => {
+ if (orderLineId.id !== readField("id", lineref)) {
+ lineref.cm_received = e.target.checked;
+ }
+ return lineref;
+ });
+ },
+ },
+ });
+ },
+ });
+
+ if (!!!result.errors) {
+ notification["success"]({
+ message: t("parts_orders.successes.line_updated"),
+ });
+ } else {
+ notification["error"]({
+ message: t("parts_orders.errors.saving", {
+ error: JSON.stringify(result.errors),
+ }),
+ });
+ }
+ setLoading(false);
+ };
+
+ return (
+
+
+ {loading && }
+
+ );
+}
diff --git a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
index 4c3ad5b64..a554b7f0c 100644
--- a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
+++ b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
@@ -29,6 +29,7 @@ import { alphaSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
import DataLabel from "../data-label/data-label.component";
import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component";
+import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component";
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
import PrintWrapper from "../print-wrapper/print-wrapper.component";
@@ -346,6 +347,23 @@ export function PartsOrderListTableComponent({
dataIndex: "status",
key: "status",
},
+
+ ...(selectedPartsOrderRecord && selectedPartsOrderRecord.return
+ ? [
+ {
+ title: t("parts_orders.fields.cm_received"),
+ dataIndex: "cm_received",
+ key: "cm_received",
+ render: (text, record) => (
+
+ ),
+ },
+ ]
+ : []),
{
title: t("parts_orders.fields.backordered_on"),
dataIndex: "backordered_on",
diff --git a/client/src/components/parts-order-modal/parts-order-modal.container.jsx b/client/src/components/parts-order-modal/parts-order-modal.container.jsx
index 3b6003b65..b449b3881 100644
--- a/client/src/components/parts-order-modal/parts-order-modal.container.jsx
+++ b/client/src/components/parts-order-modal/parts-order-modal.container.jsx
@@ -305,6 +305,7 @@ export function PartsOrderModalContainer({
quantity: value.part_qty,
job_line_id: isReturn ? value.joblineid : value.id,
part_type: value.part_type,
+ ...(isReturn && { cm_received: false }),
});
return acc;
}, [])
diff --git a/client/src/graphql/bills.queries.js b/client/src/graphql/bills.queries.js
index 14900f2e0..dd6e95715 100644
--- a/client/src/graphql/bills.queries.js
+++ b/client/src/graphql/bills.queries.js
@@ -86,6 +86,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
job_line_id
part_type
cost
+ cm_received
jobline {
id
part_type
@@ -124,7 +125,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
applicable_taxes
deductedfromlbr
lbr_adjustment
- jobline{
+ jobline {
oem_partno
part_type
}
@@ -164,7 +165,7 @@ export const QUERY_BILL_BY_PK = gql`
cost_center
quantity
joblineid
- jobline{
+ jobline {
oem_partno
part_type
}
diff --git a/client/src/graphql/parts-orders.queries.js b/client/src/graphql/parts-orders.queries.js
index 82641d1a9..e95537021 100644
--- a/client/src/graphql/parts-orders.queries.js
+++ b/client/src/graphql/parts-orders.queries.js
@@ -72,7 +72,7 @@ export const QUERY_PARTS_ORDER_OEC = gql`
part_type
}
job {
- bodyshop{
+ bodyshop {
shopname
bill_tax_rates
}
@@ -292,6 +292,22 @@ export const DELETE_PARTS_ORDER = gql`
}
`;
+export const MUTATION_UPDATE_PO_CM_REECEIVED = gql`
+ mutation MUTATION_UPDATE_PO_CM_REECEIVED(
+ $partsLineId: uuid!
+ $partsOrder: parts_order_lines_set_input
+ ) {
+ update_parts_order_lines(
+ where: { id: { _eq: $partsLineId } }
+ _set: $partsOrder
+ ) {
+ returning {
+ id
+ cm_received
+ }
+ }
+ }
+`;
export const MUTATION_UPDATE_BO_ETA = gql`
mutation MUTATION_UPDATE_BO_ETA(
$partsLineId: uuid!
@@ -339,3 +355,36 @@ export const MUTATION_BACKORDER_PART_LINE = gql`
}
}
`;
+
+export const QUERY_UNRECEIVED_LINES = gql`
+ query QUERY_UNRECEIVED_LINES($jobId: uuid!, $vendorId: uuid!) {
+ parts_order_lines(
+ where: {
+ parts_order: { jobid: { _eq: $jobId }, vendorid: { _eq: $vendorId } }
+ cm_received: { _neq: true }
+ }
+ ) {
+ cm_received
+ id
+ line_desc
+ quantity
+ act_price
+ cost
+ oem_partno
+ }
+ }
+`;
+
+export const MUTATION_MARK_RETURN_RECEIVED = gql`
+ mutation MUTATION_MARK_RETURN_RECEIVED($partsLineIds: [uuid!]!) {
+ update_parts_order_lines(
+ where: { id: { _in: $partsLineIds } }
+ _set: { cm_received: true }
+ ) {
+ returning {
+ id
+ cm_received
+ }
+ }
+ }
+`;
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 477f35ffd..04e2b15ce 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -1927,12 +1927,14 @@
"associatedbills": "This parts order cannot",
"backordering": "Error backordering part {{message}}.",
"creating": "Error encountered when creating parts order. ",
- "oec": "Error creating EMS files for OEC. {{error}}"
+ "oec": "Error creating EMS files for OEC. {{error}}",
+ "saving": "Error saving parts order. {{error}}."
},
"fields": {
"act_price": "Price",
"backordered_eta": "B.O. ETA",
"backordered_on": "B.O. On",
+ "cm_received": "CM Received?",
"comments": "Comments",
"cost": "Cost",
"db_price": "List Price",
@@ -1955,6 +1957,7 @@
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ",
"email": "Send by Email",
"inthisorder": "Parts in this Order",
+ "mark_as_received": "Mark as Received?",
"newpartsorder": "New Parts Order",
"notyetordered": "This part has not yet been ordered.",
"oec": "Order via OEC",
@@ -1966,6 +1969,7 @@
},
"successes": {
"created": "Parts order created successfully. ",
+ "line_updated": "Parts return line updated.",
"received": "Parts order received.",
"return_created": "Parts return created successfully."
}
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 399f2ecde..ff26b7553 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -1927,12 +1927,14 @@
"associatedbills": "",
"backordering": "",
"creating": "Se encontró un error al crear el pedido de piezas.",
- "oec": ""
+ "oec": "",
+ "saving": ""
},
"fields": {
"act_price": "",
"backordered_eta": "",
"backordered_on": "",
+ "cm_received": "",
"comments": "",
"cost": "",
"db_price": "",
@@ -1955,6 +1957,7 @@
"confirmdelete": "",
"email": "Enviar por correo electrónico",
"inthisorder": "Partes en este pedido",
+ "mark_as_received": "",
"newpartsorder": "",
"notyetordered": "",
"oec": "",
@@ -1966,6 +1969,7 @@
},
"successes": {
"created": "Pedido de piezas creado con éxito.",
+ "line_updated": "",
"received": "",
"return_created": ""
}
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 126ef607d..4db541931 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -1927,12 +1927,14 @@
"associatedbills": "",
"backordering": "",
"creating": "Erreur rencontrée lors de la création de la commande de pièces.",
- "oec": ""
+ "oec": "",
+ "saving": ""
},
"fields": {
"act_price": "",
"backordered_eta": "",
"backordered_on": "",
+ "cm_received": "",
"comments": "",
"cost": "",
"db_price": "",
@@ -1955,6 +1957,7 @@
"confirmdelete": "",
"email": "Envoyé par email",
"inthisorder": "Pièces dans cette commande",
+ "mark_as_received": "",
"newpartsorder": "",
"notyetordered": "",
"oec": "",
@@ -1966,6 +1969,7 @@
},
"successes": {
"created": "Commande de pièces créée avec succès.",
+ "line_updated": "",
"received": "",
"return_created": ""
}
diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml
index c997574f7..068dc44aa 100644
--- a/hasura/metadata/tables.yaml
+++ b/hasura/metadata/tables.yaml
@@ -3839,6 +3839,7 @@
- act_price
- backordered_eta
- backordered_on
+ - cm_received
- cost
- created_at
- db_price
@@ -3859,6 +3860,7 @@
- act_price
- backordered_eta
- backordered_on
+ - cm_received
- cost
- created_at
- db_price
@@ -3890,6 +3892,7 @@
- act_price
- backordered_eta
- backordered_on
+ - cm_received
- cost
- created_at
- db_price
diff --git a/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/down.sql b/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/down.sql
new file mode 100644
index 000000000..d62220f8e
--- /dev/null
+++ b/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/down.sql
@@ -0,0 +1,4 @@
+-- Could not auto-generate a down migration.
+-- Please write an appropriate down migration for the SQL below:
+-- alter table "public"."parts_order_lines" add column "cm_received" boolean
+-- null;
diff --git a/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/up.sql b/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/up.sql
new file mode 100644
index 000000000..3d0f94473
--- /dev/null
+++ b/hasura/migrations/1650411256291_alter_table_public_parts_order_lines_add_column_cm_received/up.sql
@@ -0,0 +1,2 @@
+alter table "public"."parts_order_lines" add column "cm_received" boolean
+ null;
diff --git a/hasura/migrations/1650565856092_run_sql_migration/down.sql b/hasura/migrations/1650565856092_run_sql_migration/down.sql
new file mode 100644
index 000000000..cadec1492
--- /dev/null
+++ b/hasura/migrations/1650565856092_run_sql_migration/down.sql
@@ -0,0 +1,5 @@
+-- Could not auto-generate a down migration.
+-- Please write an appropriate down migration for the SQL below:
+-- CREATE INDEX idx_pol_cm_received ON parts_order_lines(cm_received);
+-- CREATE INDEX idx_pol_orderid ON parts_order_lines(orderid);
+-- CREATE INDEX idx_parts_order_jobid ON parts_orders(jobid);
diff --git a/hasura/migrations/1650565856092_run_sql_migration/up.sql b/hasura/migrations/1650565856092_run_sql_migration/up.sql
new file mode 100644
index 000000000..38bb7435c
--- /dev/null
+++ b/hasura/migrations/1650565856092_run_sql_migration/up.sql
@@ -0,0 +1,3 @@
+CREATE INDEX idx_pol_cm_received ON parts_order_lines(cm_received);
+CREATE INDEX idx_pol_orderid ON parts_order_lines(orderid);
+CREATE INDEX idx_parts_order_jobid ON parts_orders(jobid);