{
+ setLoading(true);
+ try {
+ await GenerateDocument(
+ {
+ name: Templates.parts_invoice_label_single.key,
+ variables: {
+ id: billid,
+ },
+ },
+ {},
+ "p"
+ );
+ } catch (e) {
+ console.warn("Warning: Error generating a document.");
+ }
+ setLoading(false);
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/client/src/components/contract-cars/contract-cars.component.jsx b/client/src/components/contract-cars/contract-cars.component.jsx
index 541d6d7c3..6162ae7af 100644
--- a/client/src/components/contract-cars/contract-cars.component.jsx
+++ b/client/src/components/contract-cars/contract-cars.component.jsx
@@ -35,6 +35,15 @@ export default function ContractsCarsComponent({
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => {t(record.status)}
,
},
+ {
+ title: t("courtesycars.fields.readiness"),
+ dataIndex: "readiness",
+ key: "readiness",
+ sorter: (a, b) => alphaSort(a.readiness, b.readiness),
+ sortOrder:
+ state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
+ render: (text, record) => t(record.readiness),
+ },
{
title: t("courtesycars.fields.year"),
dataIndex: "year",
diff --git a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx
index fbc163c32..1e95960a9 100644
--- a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx
+++ b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx
@@ -8,6 +8,7 @@ import { useTranslation } from "react-i18next";
import { CHECK_CC_FLEET_NUMBER } from "../../graphql/courtesy-car.queries";
import { DateFormatter } from "../../utils/DateFormatter";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
+import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
//import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
@@ -214,6 +215,12 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
>
+
+
+
{
step={null}
style={{ marginLeft: "2rem", marginRight: "2rem" }}
{...props}
+ tooltip={{
+ formatter: (value) => {
+ switch (value) {
+ case 0:
+ return t("courtesycars.labels.fuel.empty");
+ case 13:
+ return t("courtesycars.labels.fuel.18");
+ case 25:
+ return t("courtesycars.labels.fuel.14");
+ case 38:
+ return t("courtesycars.labels.fuel.38");
+ case 50:
+ return t("courtesycars.labels.fuel.12");
+ case 63:
+ return t("courtesycars.labels.fuel.58");
+ case 75:
+ return t("courtesycars.labels.fuel.34");
+ case 88:
+ return t("courtesycars.labels.fuel.78");
+ case 100:
+ return t("courtesycars.labels.fuel.full");
+ default:
+ return value;
+ }
+ },
+ }}
/>
);
};
diff --git a/client/src/components/courtesy-car-readiness-select/courtesy-car-readiness-select.component.jsx b/client/src/components/courtesy-car-readiness-select/courtesy-car-readiness-select.component.jsx
new file mode 100644
index 000000000..9dd1fd514
--- /dev/null
+++ b/client/src/components/courtesy-car-readiness-select/courtesy-car-readiness-select.component.jsx
@@ -0,0 +1,35 @@
+import { Select } from "antd";
+import React, { forwardRef, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+const { Option } = Select;
+
+const CourtesyCarReadinessComponent = ({ value, onChange }, ref) => {
+ const [option, setOption] = useState(value);
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ if (value !== option && onChange) {
+ onChange(option);
+ }
+ }, [value, option, onChange]);
+
+ return (
+
+ );
+};
+export default forwardRef(CourtesyCarReadinessComponent);
diff --git a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx
index b833291e5..b11d57f5a 100644
--- a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx
+++ b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx
@@ -90,6 +90,26 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
);
},
},
+ {
+ title: t("courtesycars.fields.readiness"),
+ dataIndex: "readiness",
+ key: "readiness",
+ sorter: (a, b) => alphaSort(a.readiness, b.readiness),
+ filters: [
+ {
+ text: t("courtesycars.readiness.ready"),
+ value: "courtesycars.readiness.ready",
+ },
+ {
+ text: t("courtesycars.readiness.notready"),
+ value: "courtesycars.readiness.notready",
+ },
+ ],
+ onFilter: (value, record) => value.includes(record.readiness),
+ sortOrder:
+ state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
+ render: (text, record) => t(record.readiness),
+ },
{
title: t("courtesycars.fields.year"),
dataIndex: "year",
@@ -130,6 +150,36 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
sortOrder:
state.sortedInfo.columnKey === "plate" && state.sortedInfo.order,
},
+ {
+ title: t("courtesycars.fields.fuel"),
+ dataIndex: "fuel",
+ key: "fuel",
+ sorter: (a, b) => alphaSort(a.fuel, b.fuel),
+ sortOrder:
+ state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
+ render: (text, record) => {
+ switch (record.fuel) {
+ case 100:
+ return t("courtesycars.labels.fuel.full");
+ case 88:
+ return t("courtesycars.labels.fuel.78");
+ case 63:
+ return t("courtesycars.labels.fuel.58");
+ case 50:
+ return t("courtesycars.labels.fuel.12");
+ case 38:
+ return t("courtesycars.labels.fuel.34");
+ case 25:
+ return t("courtesycars.labels.fuel.14");
+ case 13:
+ return t("courtesycars.labels.fuel.18");
+ case 0:
+ return t("courtesycars.labels.fuel.empty");
+ default:
+ return record.fuel;
+ }
+ },
+ },
{
title: t("courtesycars.labels.outwith"),
dataIndex: "outwith",
diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
index a5dd99f6f..30bb98560 100644
--- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
+++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
@@ -1,8 +1,8 @@
import {
+ BranchesOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
WarningFilled,
- BranchesOutlined,
} from "@ant-design/icons";
import { Card, Col, Row, Space, Tag, Tooltip } from "antd";
import React, { useState } from "react";
@@ -222,6 +222,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
{`${job.v_vin || t("general.labels.na")}`}
+
+ {job.regie_number || t("general.labels.na")}
+
diff --git a/client/src/components/production-list-table/production-list-print.component.jsx b/client/src/components/production-list-table/production-list-print.component.jsx
index b198fcf2a..a4ffea279 100644
--- a/client/src/components/production-list-table/production-list-print.component.jsx
+++ b/client/src/components/production-list-table/production-list-print.component.jsx
@@ -1,83 +1,126 @@
-import { Button, Dropdown } from "antd";
-import React, { useState } from "react";
-import { TemplateList } from "../../utils/TemplateConstants";
-import { useTranslation } from "react-i18next";
-import { GenerateDocument } from "../../utils/RenderTemplate";
+import {Button, Dropdown} from "antd";
+import React, {useState} from "react";
+import {TemplateList} from "../../utils/TemplateConstants";
+import {useTranslation} from "react-i18next";
+import {GenerateDocument} from "../../utils/RenderTemplate";
+import {connect} from "react-redux";
+import {createStructuredSelector} from "reselect";
+import {selectBodyshop} from "../../redux/user/user.selectors";
-import { connect } from "react-redux";
-import { createStructuredSelector } from "reselect";
-import { selectBodyshop } from "../../redux/user/user.selectors";
const ProdTemplates = TemplateList("production");
const {
- production_by_technician_one,
- production_by_category_one,
- production_by_repair_status_one,
+ production_by_technician_one,
+ production_by_category_one,
+ production_by_repair_status_one,
} = TemplateList("special");
const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
+ bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
- mapStateToProps,
- mapDispatchToProps
+ mapStateToProps,
+ mapDispatchToProps
)(ProductionListPrint);
-export function ProductionListPrint({ bodyshop }) {
- const { t } = useTranslation();
- const [loading, setLoading] = useState(false);
- const menu = {
- items: [
- ...Object.keys(ProdTemplates).map((key) => ({
- key: key,
- label: ProdTemplates[key].title,
- })),
- {
- key: "production_by_technician_one",
- label: t("reportcenter.templates.production_by_technician_one"),
- children: bodyshop.employees
- .filter((e) => e.active)
- .map((e) => ({
- key: e.id,
- label: `${e.first_name} ${e.last_name}`,
- })),
- },
- {
- key: "production_by_category_one",
- label: t("reportcenter.templates.production_by_category_one"),
- children: bodyshop.md_categories.map((e) => ({
- key: e,
- label: e,
- })),
- },
- {
- key: "production_by_repair_status_one",
- label: t("reportcenter.templates.production_by_repair_status_one"),
- children: bodyshop.md_ro_statuses.production_statuses.map((e) => ({
- key: e,
- label: e,
- })),
- },
- ],
- onClick: async (e) => {
- setLoading(true);
- await GenerateDocument(
- {
- name: ProdTemplates[e.key].key,
- // variables: { id: contract.id },
- },
- {},
- "p"
- );
- setLoading(false);
- },
- }
- return (
-
-
-
- );
+export function ProductionListPrint({bodyshop}) {
+ const {t} = useTranslation();
+ const [loading, setLoading] = useState(false);
+
+ const menu = {
+ items: [
+ ...Object.keys(ProdTemplates).map((key) => {
+ return {
+ key: key,
+ label: ProdTemplates[key].title,
+ onClick: async () => {
+ setLoading(true);
+ await GenerateDocument(
+ {
+ name: ProdTemplates[key].key,
+ // variables: { id: contract.id },
+ },
+ {},
+ "p"
+ );
+ setLoading(false);
+ }
+ };
+ }),
+ {
+ key: key,
+ label: t("reportcenter.templates.production_by_technician_one"),
+ children: bodyshop.employees
+ .filter((e) => e.active)
+ .map((e) => {
+ return {
+ key: e.id,
+ label: `${e.first_name} ${e.last_name}`,
+ onClick: async () => {
+ setLoading(true);
+ await GenerateDocument(
+ {
+ name: production_by_technician_one.key,
+ variables: {id: e.id},
+ },
+ {},
+ "p"
+ );
+ setLoading(false);
+ }
+ };
+ })
+ },
+ {
+ label: t("reportcenter.templates.production_by_category_one"),
+ children: bodyshop.md_categories.map((e) => {
+ return {
+ key: e,
+ label: e,
+ onClick: async () => {
+ setLoading(true);
+ await GenerateDocument(
+ {
+ name: production_by_category_one.key,
+ variables: {category: e},
+ },
+ {},
+ "p"
+ );
+ setLoading(false);
+ }
+ };
+ })
+ },
+ {
+ label: t("reportcenter.templates.production_by_repair_status_one"),
+ children: bodyshop.md_ro_statuses.production_statuses.map((e) => {
+ return {
+ key: e,
+ label: e,
+ onClick: async () => {
+ setLoading(true);
+ await GenerateDocument(
+ {
+ name: production_by_repair_status_one.key,
+ variables: {status: e},
+ },
+ {},
+ "p"
+ );
+ setLoading(false);
+ }
+ };
+ })
+ }
+ ]
+ };
+
+ return (
+
+
+ );
}
diff --git a/client/src/graphql/courtesy-car.queries.js b/client/src/graphql/courtesy-car.queries.js
index a5bcbea55..4f7bcd0ca 100644
--- a/client/src/graphql/courtesy-car.queries.js
+++ b/client/src/graphql/courtesy-car.queries.js
@@ -30,15 +30,15 @@ export const QUERY_AVAILABLE_CC = gql`
fuel
id
make
- model
- plate
- status
- year
- dailycost
mileage
+ model
notes
nextservicekm
nextservicedate
+ plate
+ readiness
+ status
+ year
}
}
`;
@@ -68,19 +68,20 @@ export const QUERY_ALL_CC = gql`
insuranceexpires
leaseenddate
make
+ mileage
model
nextservicedate
nextservicekm
notes
plate
purchasedate
+ readiness
registrationexpires
serviceenddate
servicestartdate
status
vin
year
- mileage
cccontracts(
where: { status: { _eq: "contracts.status.out" } }
order_by: { contract_date: desc }
@@ -90,10 +91,10 @@ export const QUERY_ALL_CC = gql`
scheduledreturn
job {
id
- ro_number
ownr_fn
ownr_ln
ownr_co_nm
+ ro_number
}
}
}
@@ -119,19 +120,20 @@ export const QUERY_CC_BY_PK = gql`
insuranceexpires
leaseenddate
make
+ mileage
model
nextservicedate
nextservicekm
notes
plate
purchasedate
+ readiness
registrationexpires
serviceenddate
servicestartdate
status
vin
year
- mileage
cccontracts_aggregate {
aggregate {
count(distinct: true)
@@ -139,21 +141,20 @@ export const QUERY_CC_BY_PK = gql`
}
cccontracts(offset: $offset, limit: $limit, order_by: $order) {
agreementnumber
+ driver_fn
+ driver_ln
id
- status
- start
- scheduledreturn
kmstart
kmend
- driver_ln
- driver_fn
+ scheduledreturn
+ start
+ status
job {
- ro_number
-
+ id
ownr_ln
ownr_fn
ownr_co_nm
- id
+ ro_number
}
}
}
diff --git a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx
index ba2bb5501..80d357616 100644
--- a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx
+++ b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx
@@ -1,6 +1,6 @@
import { useMutation, useQuery } from "@apollo/client";
import { Form, notification } from "antd";
-import dayjs from "../../utils/day";
+import dayjs from "dayjs";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -14,6 +14,7 @@ import {
setSelectedHeader,
} from "../../redux/application/application.actions";
import { CreateRecentItem } from "../../utils/create-recent-item";
+import UndefinedToNull from "./../../utils/undefinedtonull";
import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component";
import NotFound from "../../components/not-found/not-found.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
@@ -112,7 +113,10 @@ export function CourtesyCarDetailPageContainer({
setSaveLoading(true);
const result = await updateCourtesyCar({
- variables: { cc: { ...values }, ccId: ccId },
+ variables: {
+ cc: { ...UndefinedToNull(values, ["readiness"]) },
+ ccId: ccId,
+ },
refetchQueries: ["QUERY_CC_BY_PK"],
awaitRefetchQueries: true,
});
diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx
index 15af524ed..dfe83358c 100644
--- a/client/src/pages/jobs-create/jobs-create.container.jsx
+++ b/client/src/pages/jobs-create/jobs-create.container.jsx
@@ -1,6 +1,6 @@
-import _ from "lodash";
import { useLazyQuery, useMutation } from "@apollo/client";
import { Form, notification } from "antd";
+import _ from "lodash";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -90,6 +90,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
{},
values,
{ date_open: new Date() },
+ { date_estimated: new Date() },
{
vehicle:
state.vehicle.selectedid || state.vehicle.none
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index b96b555db..09798f0a5 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -214,6 +214,7 @@
"new": "New Bill",
"noneselected": "No bill selected.",
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
+ "printlabels": "Print Labels",
"retailtotal": "Bills Retail Total",
"savewithdiscrepancy": "You are about to save this bill with a discrepancy. The system will continue to use the calculated amount using the bill lines. Press cancel to return to the bill.",
"state_tax": "Provincial/State Tax",
@@ -785,6 +786,7 @@
"notes": "Notes",
"plate": "Plate Number",
"purchasedate": "Purchase Date",
+ "readiness": "Readiness",
"registrationexpires": "Registration Expires On",
"serviceenddate": "Usage End Date",
"servicestartdate": "Usage Start Date",
@@ -821,6 +823,10 @@
},
"successes": {
"saved": "Courtesy Car saved successfully."
+ },
+ "readiness": {
+ "notready": "Not Ready",
+ "ready": "Ready"
}
},
"csi": {
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index f68cf4a41..da9f6b4e0 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -214,6 +214,7 @@
"new": "",
"noneselected": "",
"onlycmforinvoiced": "",
+ "printlabels": "",
"retailtotal": "",
"savewithdiscrepancy": "",
"state_tax": "",
@@ -785,6 +786,7 @@
"notes": "",
"plate": "",
"purchasedate": "",
+ "readiness": "",
"registrationexpires": "",
"serviceenddate": "",
"servicestartdate": "",
@@ -821,6 +823,10 @@
},
"successes": {
"saved": ""
+ },
+ "readiness": {
+ "notready": "",
+ "ready": ""
}
},
"csi": {
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index d0e44b704..a4c1dc686 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -214,6 +214,7 @@
"new": "",
"noneselected": "",
"onlycmforinvoiced": "",
+ "printlabels": "",
"retailtotal": "",
"savewithdiscrepancy": "",
"state_tax": "",
@@ -785,6 +786,7 @@
"notes": "",
"plate": "",
"purchasedate": "",
+ "readiness": "",
"registrationexpires": "",
"serviceenddate": "",
"servicestartdate": "",
@@ -821,6 +823,10 @@
},
"successes": {
"saved": ""
+ },
+ "readiness": {
+ "notready": "",
+ "ready": ""
}
},
"csi": {
diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml
index d94a97af0..216ac8c48 100644
--- a/hasura/metadata/tables.yaml
+++ b/hasura/metadata/tables.yaml
@@ -1388,60 +1388,62 @@
- active:
_eq: true
columns:
- - id
- - created_at
- - updated_at
- bodyshopid
- - make
- - model
- - year
- - plate
- color
- - vin
- - fleetnumber
- - purchasedate
- - servicestartdate
- - serviceenddate
- - leaseenddate
- - status
- - nextservicekm
- - nextservicedate
- - damage
- - notes
- - fuel
- - registrationexpires
- - insuranceexpires
+ - created_at
- dailycost
+ - damage
+ - fleetnumber
+ - fuel
+ - id
+ - insuranceexpires
+ - leaseenddate
+ - make
- mileage
+ - model
+ - nextservicedate
+ - nextservicekm
+ - notes
+ - plate
+ - purchasedate
+ - readiness
+ - registrationexpires
+ - serviceenddate
+ - servicestartdate
+ - status
+ - updated_at
+ - vin
+ - year
select_permissions:
- role: user
permission:
columns:
+ - bodyshopid
+ - color
+ - created_at
+ - dailycost
+ - damage
+ - fleetnumber
+ - fuel
+ - id
- insuranceexpires
- leaseenddate
+ - make
+ - mileage
+ - model
- nextservicedate
+ - nextservicekm
+ - notes
+ - plate
- purchasedate
+ - readiness
- registrationexpires
- serviceenddate
- servicestartdate
- - dailycost
- - fuel
- - mileage
- - nextservicekm
- - color
- - damage
- - fleetnumber
- - make
- - model
- - notes
- - plate
- status
+ - updated_at
- vin
- year
- - created_at
- - updated_at
- - bodyshopid
- - id
filter:
bodyshop:
associations:
@@ -1456,31 +1458,32 @@
- role: user
permission:
columns:
+ - bodyshopid
+ - color
+ - created_at
+ - dailycost
+ - damage
+ - fleetnumber
+ - fuel
+ - id
- insuranceexpires
- leaseenddate
+ - make
+ - mileage
+ - model
- nextservicedate
+ - nextservicekm
+ - notes
+ - plate
- purchasedate
+ - readiness
- registrationexpires
- serviceenddate
- servicestartdate
- - dailycost
- - fuel
- - mileage
- - nextservicekm
- - color
- - damage
- - fleetnumber
- - make
- - model
- - notes
- - plate
- status
+ - updated_at
- vin
- year
- - created_at
- - updated_at
- - bodyshopid
- - id
filter:
bodyshop:
associations:
diff --git a/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql
new file mode 100644
index 000000000..5e741dcc7
--- /dev/null
+++ b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/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"."courtesycars" add column "readiness" text
+-- null;
diff --git a/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql
new file mode 100644
index 000000000..4f5339ede
--- /dev/null
+++ b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql
@@ -0,0 +1,2 @@
+alter table "public"."courtesycars" add column "readiness" text
+ null;