diff --git a/client/src/components/bill-form/bill-form.component.jsx b/client/src/components/bill-form/bill-form.component.jsx
index 3ff123743..eb0d3a789 100644
--- a/client/src/components/bill-form/bill-form.component.jsx
+++ b/client/src/components/bill-form/bill-form.component.jsx
@@ -1,6 +1,6 @@
import Icon, { UploadOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client";
-import { MdOpenInNew } from "react-icons/md";
+import { useTreatments } from "@splitsoftware/splitio-react";
import {
Alert,
Divider,
@@ -14,12 +14,14 @@ import {
} from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
+import { MdOpenInNew } from "react-icons/md";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
+import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
@@ -28,8 +30,6 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import BillFormLines from "./bill-form.lines.component";
import { CalculateBillTotal } from "./bill-form.totals.utility";
-import { useTreatments } from "@splitsoftware/splitio-react";
-import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -58,6 +58,11 @@ export function BillFormComponent({
{},
bodyshop.imexshopid
);
+ const { ClosingPeriod } = useTreatments(
+ ["ClosingPeriod"],
+ {},
+ bodyshop.imexshopid
+ );
const handleVendorSelect = (props, opt) => {
setDiscount(opt.discount);
@@ -259,6 +264,27 @@ export function BillFormComponent({
required: true,
//message: t("general.validation.required"),
},
+ ({ getFieldValue }) => ({
+ validator(rule, value) {
+ if (
+ ClosingPeriod.treatment === "on" &&
+ bodyshop.accountingconfig.ClosingPeriod
+ ) {
+ if (
+ Date.parse(value).valueOf() >=
+ Date.parse(bodyshop.accountingconfig.ClosingPeriod[0]).valueOf() &&
+ Date.parse(value).valueOf() <=
+ Date.parse(bodyshop.accountingconfig.ClosingPeriod[1]).valueOf()
+ ) {
+ return Promise.resolve();
+ } else {
+ return Promise.reject(t("bills.validation.closingperiod"));
+ }
+ } else {
+ return Promise.resolve();
+ }
+ },
+ }),
]}
>
diff --git a/client/src/components/shop-info/shop-info.container.jsx b/client/src/components/shop-info/shop-info.container.jsx
index fec10877c..dd254a4cb 100644
--- a/client/src/components/shop-info/shop-info.container.jsx
+++ b/client/src/components/shop-info/shop-info.container.jsx
@@ -1,14 +1,14 @@
-import React, { useEffect, useState } from "react";
-import ShopInfoComponent from "./shop-info.component";
+import { useMutation, useQuery } from "@apollo/client";
import { Form, notification } from "antd";
-import { useQuery, useMutation } from "@apollo/client";
-import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
-import LoadingSpinner from "../loading-spinner/loading-spinner.component";
-import AlertComponent from "../alert/alert.component";
+import moment from "moment";
+import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
+import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
+import AlertComponent from "../alert/alert.component";
import FormsFieldChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
-import moment from "moment";
+import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import ShopInfoComponent from "./shop-info.component";
export default function ShopInfoContainer() {
const [form] = Form.useForm();
const { t } = useTranslation();
@@ -52,13 +52,28 @@ export default function ShopInfoContainer() {
onFinish={handleFinish}
initialValues={
data
- ? {
- ...data.bodyshops[0],
- schedule_start_time: moment(
- data.bodyshops[0].schedule_start_time
- ),
- schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
- }
+ ? data.bodyshops[0].accountingconfig.ClosingPeriod
+ ? {
+ ...data.bodyshops[0],
+ accountingconfig: {
+ ...data.bodyshops[0].accountingconfig,
+ ClosingPeriod: [
+ moment(data.bodyshops[0].accountingconfig.ClosingPeriod[0]),
+ moment(data.bodyshops[0].accountingconfig.ClosingPeriod[1]),
+ ],
+ },
+ schedule_start_time: moment(
+ data.bodyshops[0].schedule_start_time
+ ),
+ schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
+ }
+ : {
+ ...data.bodyshops[0],
+ schedule_start_time: moment(
+ data.bodyshops[0].schedule_start_time
+ ),
+ schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
+ }
: null
}
>
diff --git a/client/src/components/shop-info/shop-info.general.component.jsx b/client/src/components/shop-info/shop-info.general.component.jsx
index 99245c76e..ebf2accaf 100644
--- a/client/src/components/shop-info/shop-info.general.component.jsx
+++ b/client/src/components/shop-info/shop-info.general.component.jsx
@@ -1,6 +1,8 @@
import { DeleteFilled } from "@ant-design/icons";
+import { useTreatments } from "@splitsoftware/splitio-react";
import {
Button,
+ DatePicker,
Form,
Input,
InputNumber,
@@ -9,8 +11,13 @@ import {
Space,
Switch,
} from "antd";
+import momentTZ from "moment-timezone";
import React from "react";
import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import DatePickerRanges from "../../utils/DatePickerRanges";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import PhoneFormItem, {
@@ -18,12 +25,22 @@ import PhoneFormItem, {
} from "../form-items-formatted/phone-form-item.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
-
-import momentTZ from "moment-timezone";
const timeZonesList = momentTZ.tz.names();
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+export default connect(mapStateToProps, mapDispatchToProps)(ShopInfoGeneral);
-export default function ShopInfoGeneral({ form }) {
+export function ShopInfoGeneral({ form, bodyshop }) {
const { t } = useTranslation();
+ const { ClosingPeriod } = useTreatments(
+ ["ClosingPeriod"],
+ {},
+ bodyshop && bodyshop.imexshopid
+ );
return (
@@ -392,6 +409,20 @@ export default function ShopInfoGeneral({ form }) {
>
+ {ClosingPeriod.treatment === "on" && (
+ <>
+
+
+
+ >
+ )}
{
setLoading(true);
@@ -250,14 +255,42 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
},
({ getFieldValue }) => ({
validator(_, value) {
- if (!bodyshop.cdk_dealerid) return Promise.resolve();
- if (!value || moment(value).isSameOrAfter(moment(), "day")) {
- return Promise.resolve();
+ if (!bodyshop.cdk_dealerid) {
+ if (
+ ClosingPeriod.treatment === "on" &&
+ bodyshop.accountingconfig.ClosingPeriod
+ ) {
+ if (
+ Date.parse(value).valueOf() >=
+ Date.parse(
+ bodyshop.accountingconfig.ClosingPeriod[0]
+ ).valueOf() &&
+ Date.parse(value).valueOf() <=
+ Date.parse(
+ bodyshop.accountingconfig.ClosingPeriod[1]
+ ).valueOf()
+ ) {
+ return Promise.resolve();
+ } else {
+ return Promise.reject(
+ new Error(t("jobs.labels.closingperiod"))
+ );
+ }
+ } else {
+ return Promise.resolve();
+ }
+ } else {
+ if (
+ !value ||
+ moment(value).isSameOrAfter(moment(), "day")
+ ) {
+ return Promise.resolve();
+ } else {
+ return Promise.reject(
+ new Error(t("jobs.labels.dms.invoicedatefuture"))
+ );
+ }
}
-
- return Promise.reject(
- new Error(t("jobs.labels.dms.invoicedatefuture"))
- );
},
}),
]}
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index f28b5c3c0..866eba157 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -223,6 +223,7 @@
"reexport": "Bill marked for re-export."
},
"validation": {
+ "closingperiod": "This Bill Date is outside of the Closing Period.",
"inventoryquantity": "Quantity must be greater than or equal to what has been added to inventory ({{number}}).",
"manualinhouse": "Manual posting to the in house vendor is restricted. ",
"unique_invoice_number": "This invoice number has already been entered for this vendor."
@@ -262,6 +263,7 @@
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
"city": "City",
+ "closingperiod": "Closing Period",
"country": "Country",
"dailybodytarget": "Scoreboard - Daily Body Target",
"dailypainttarget": "Scoreboard - Daily Paint Target",
@@ -1688,6 +1690,7 @@
"checklists": "Checklists",
"closeconfirm": "Are you sure you want to close this job? This cannot be easily undone.",
"closejob": "Close Job {{ro_number}}",
+ "closingperiod": "This Invoice Date is outside of the Closing Period.",
"contracts": "CC Contracts",
"convertedtolabor": "Lines Converted to Labor",
"cost": "Cost",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 1987de28a..7c419a5f2 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -223,6 +223,7 @@
"reexport": ""
},
"validation": {
+ "closingperiod": "",
"inventoryquantity": "",
"manualinhouse": "",
"unique_invoice_number": ""
@@ -262,6 +263,7 @@
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
"city": "",
+ "closingperiod": "",
"country": "",
"dailybodytarget": "",
"dailypainttarget": "",
@@ -1688,6 +1690,7 @@
"checklists": "",
"closeconfirm": "",
"closejob": "",
+ "closingperiod": "",
"contracts": "",
"convertedtolabor": "",
"cost": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 0230fbbdd..5e390aaa4 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -223,6 +223,7 @@
"reexport": ""
},
"validation": {
+ "closingperiod": "",
"inventoryquantity": "",
"manualinhouse": "",
"unique_invoice_number": ""
@@ -262,6 +263,7 @@
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
"city": "",
+ "closingperiod": "",
"country": "",
"dailybodytarget": "",
"dailypainttarget": "",
@@ -1688,6 +1690,7 @@
"checklists": "",
"closeconfirm": "",
"closejob": "",
+ "closingperiod": "",
"contracts": "",
"convertedtolabor": "",
"cost": "",