import Icon, { UploadOutlined } from "@ant-design/icons"; import { useApolloClient } from "@apollo/client/react"; import { useTreatmentsWithConfig } from "@splitsoftware/splitio-react"; import { Alert, Divider, Form, Input, Select, Space, Statistic, Switch, Upload } from "antd"; import { 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 { useNotification } from "../../contexts/Notifications/notificationContext.jsx"; import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries"; import { selectBodyshop } from "../../redux/user/user.selectors"; import dayjs from "../../utils/day"; import { bodyshopHasDmsKey } from "../../utils/dmsUtils.js"; import InstanceRenderManager from "../../utils/instanceRenderMgr"; import AlertComponent from "../alert/alert.component"; import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component"; import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx"; import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import JobSearchSelect from "../job-search-select/job-search-select.component"; 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"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapDispatchToProps = () => ({}); export function BillFormComponent({ bodyshop, disabled, form, vendorAutoCompleteOptions, lineData, responsibilityCenters, loadLines, billEdit, disableInvNumber, job, loadOutstandingReturns, loadInventory, preferredMake, disableInHouse, isAiScan }) { const { t } = useTranslation(); const client = useApolloClient(); const [discount, setDiscount] = useState(0); const notification = useNotification(); const jobIdFormWatch = Form.useWatch("jobid", form); const vendorIdFormWatch = Form.useWatch("vendorid", form); const { treatments: { Extended_Bill_Posting, ClosingPeriod } } = useTreatmentsWithConfig({ attributes: {}, names: ["Extended_Bill_Posting", "ClosingPeriod"], splitKey: bodyshop.imexshopid }); const handleVendorSelect = (props, opt) => { setDiscount(opt.discount); opt && !billEdit && loadOutstandingReturns({ variables: { jobId: form.getFieldValue("jobid"), vendorId: opt.value } }); }; const handleFederalTaxExemptSwitchToggle = (checked) => { // Early gate if (!checked) return; const values = form.getFieldsValue("billlines"); // Gate bill lines if (!values?.billlines?.length) return; const billlines = values.billlines.map((b) => { b.applicable_taxes.federal = false; return b; }); form.setFieldsValue({ billlines }); }; useEffect(() => { if (job) form.validateFields(["is_credit_memo"]); }, [job, form]); useEffect(() => { const vendorId = form.getFieldValue("vendorid"); if (vendorId && vendorAutoCompleteOptions) { const matchingVendors = vendorAutoCompleteOptions.filter((v) => v.id === vendorId); if (matchingVendors.length === 1) { setDiscount(matchingVendors[0].discount); } } const jobId = form.getFieldValue("jobid"); if (jobId) { loadLines({ variables: { id: jobId } }); if (form.getFieldValue("is_credit_memo") && vendorId && !billEdit) { loadOutstandingReturns({ variables: { jobId: jobId, vendorId: vendorId } }); } } if (vendorId === bodyshop.inhousevendorid && !billEdit) { loadInventory({ variables: {} }); } }, [ form, vendorIdFormWatch, billEdit, loadOutstandingReturns, loadInventory, setDiscount, vendorAutoCompleteOptions, loadLines, bodyshop.inhousevendorid ]); useEffect(() => { // When the jobid is set by AI scan, we need to reload the lines. This prevents having to hoist the apollo query. if (jobIdFormWatch !== null) { if (form.getFieldValue("jobid") !== null && form.getFieldValue("jobid") !== undefined) { loadLines({ variables: { id: form.getFieldValue("jobid") } }); if (form.getFieldValue("vendorid") !== null && form.getFieldValue("vendorid") !== undefined) { loadOutstandingReturns({ variables: { jobId: form.getFieldValue("jobid"), vendorId: form.getFieldValue("vendorid") } }); } } } }, [jobIdFormWatch, form]); return (
{ if (form.getFieldValue("jobid") !== null && form.getFieldValue("jobid") !== undefined) { loadLines({ variables: { id: form.getFieldValue("jobid") } }); if (form.getFieldValue("vendorid") !== null && form.getFieldValue("vendorid") !== undefined) { loadOutstandingReturns({ variables: { jobId: form.getFieldValue("jobid"), vendorId: form.getFieldValue("vendorid") } }); } } }} /> ({ validator(rule, value) { if (value && !getFieldValue(["isinhouse"]) && value === bodyshop.inhousevendorid) { return Promise.reject(t("bills.validation.manualinhouse")); } return Promise.resolve(); } }) ]} > {job && job.ious && job.ious.length > 0 && job.ious.map((iou) => ( {t("bills.labels.iouexists")} {iou.ro_number} } /> ))} ({ async validator(rule, value) { const vendorid = getFieldValue("vendorid"); if (vendorid && value) { const response = await client.query({ query: CHECK_BILL_INVOICE_NUMBER, variables: { invoice_number: value, vendorid: vendorid } }); if (response.data.bills_aggregate.aggregate.count === 0) { return Promise.resolve(); } else if ( response.data.bills_aggregate.nodes.length === 1 && response.data.bills_aggregate.nodes[0].id === form.getFieldValue("id") ) { return Promise.resolve(); } return Promise.reject(t("bills.validation.unique_invoice_number")); } else { return Promise.resolve(); } } }) ]} > ({ validator(rule, value) { if (ClosingPeriod.treatment === "on" && bodyshop.accountingconfig.ClosingPeriod) { if ( dayjs(value) .startOf("day") .isSameOrAfter(dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf("day")) && dayjs(value) .startOf("day") .isSameOrBefore(dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf("day")) ) { return Promise.resolve(); } else { return Promise.reject(t("bills.validation.closingperiod")); } } else { return Promise.resolve(); } } }) ]} > ({ validator(rule, value) { if (value === true && getFieldValue("jobid") && getFieldValue("vendorid")) { //Removed as this would cause an additional reload when validating the form on submit and clear the values. // 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) && (value === false || !value) ) { return Promise.reject(t("bills.labels.onlycmforinvoiced")); } return Promise.resolve(); } }) ]} > {!billEdit && (