IO-3515 set po context, update confidence UI showing
This commit is contained in:
@@ -5,6 +5,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext";
|
||||
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { FaWandMagicSparkles } from "react-icons/fa6";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
billEnterModal: selectBillEnterModal,
|
||||
@@ -19,7 +20,8 @@ function BillEnterAiScan({
|
||||
form,
|
||||
fileInputRef,
|
||||
scanLoading,
|
||||
setScanLoading
|
||||
setScanLoading,
|
||||
setIsAiScan
|
||||
}) {
|
||||
const notification = useNotification();
|
||||
|
||||
@@ -59,8 +61,6 @@ function BillEnterAiScan({
|
||||
}
|
||||
// If status is IN_PROGRESS, continue polling
|
||||
} catch (error) {
|
||||
console.error("Error polling job status:", error);
|
||||
|
||||
// Stop polling on error
|
||||
if (pollingIntervalRef.current) {
|
||||
clearInterval(pollingIntervalRef.current);
|
||||
@@ -86,11 +86,12 @@ function BillEnterAiScan({
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
setScanLoading(true);
|
||||
setIsAiScan(true);
|
||||
const formdata = new FormData();
|
||||
formdata.append("billScan", file);
|
||||
formdata.append("jobid", billEnterModal.context.job.id);
|
||||
formdata.append("bodyshopid", bodyshop.id);
|
||||
formdata.append("partsorderid", "3dd26419-a139-4399-af4e-43eeb6f0dbad");
|
||||
formdata.append("partsorderid", billEnterModal.context.parts_order?.id);
|
||||
//formdata.append("skipTextract", "true"); // For testing purposes
|
||||
axios
|
||||
.post("/ai/bill-ocr", formdata)
|
||||
@@ -123,7 +124,6 @@ function BillEnterAiScan({
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("*** ~ BillEnterModalContainer ~ error:", error);
|
||||
setScanLoading(false);
|
||||
notification.error({
|
||||
title: "AI Scan Failed",
|
||||
@@ -137,9 +137,9 @@ function BillEnterAiScan({
|
||||
/>
|
||||
<Button
|
||||
onClick={() => {
|
||||
console.log("Fields Object", form.getFieldsValue());
|
||||
fileInputRef.current?.click();
|
||||
}}
|
||||
icon={<FaWandMagicSparkles />}
|
||||
loading={scanLoading}
|
||||
disabled={scanLoading}
|
||||
>
|
||||
|
||||
@@ -52,6 +52,7 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
const [updateInventoryLines] = useMutation(UPDATE_INVENTORY_LINES);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [scanLoading, setScanLoading] = useState(false);
|
||||
const [isAiScan, setIsAiScan] = useState(false);
|
||||
const client = useApolloClient();
|
||||
const [generateLabel, setGenerateLabel] = useLocalStorage("enter_bill_generate_label", false);
|
||||
const notification = useNotification();
|
||||
@@ -59,12 +60,13 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
const pollingIntervalRef = useRef(null);
|
||||
|
||||
const {
|
||||
treatments: { Enhanced_Payroll, Imgproxy }
|
||||
treatments: { Enhanced_Payroll, Imgproxy, Bill_OCR_AI }
|
||||
} = useTreatmentsWithConfig({
|
||||
attributes: {},
|
||||
names: ["Enhanced_Payroll", "Imgproxy"],
|
||||
names: ["Enhanced_Payroll", "Imgproxy", "Bill_OCR_AI"],
|
||||
splitKey: bodyshop.imexshopid
|
||||
});
|
||||
console.log("*** ~ BillEnterModalContainer ~ Bill_OCR_AI:", Bill_OCR_AI);
|
||||
|
||||
const formValues = useMemo(() => {
|
||||
return {
|
||||
@@ -382,6 +384,7 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
vendorid: values.vendorid,
|
||||
billlines: []
|
||||
});
|
||||
setIsAiScan(false);
|
||||
// form.resetFields();
|
||||
} else {
|
||||
toggleModalVisible();
|
||||
@@ -398,6 +401,7 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
pollingIntervalRef.current = null;
|
||||
}
|
||||
setScanLoading(false);
|
||||
setIsAiScan(false);
|
||||
toggleModalVisible();
|
||||
}
|
||||
};
|
||||
@@ -422,6 +426,7 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
pollingIntervalRef.current = null;
|
||||
}
|
||||
setScanLoading(false);
|
||||
setIsAiScan(false);
|
||||
}
|
||||
}, [billEnterModal.open, form, formValues]);
|
||||
|
||||
@@ -437,7 +442,22 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t("bills.labels.new")}
|
||||
title={
|
||||
<Space size="large">
|
||||
{t("bills.labels.new")}
|
||||
{Bill_OCR_AI.treatment === "on" && (
|
||||
<BillEnterAiScan
|
||||
fileInputRef={fileInputRef}
|
||||
form={form}
|
||||
pollingIntervalRef={pollingIntervalRef}
|
||||
setPollingIntervalRef={setPollingIntervalRef}
|
||||
scanLoading={scanLoading}
|
||||
setScanLoading={setScanLoading}
|
||||
setIsAiScan={setIsAiScan}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
width={"98%"}
|
||||
open={billEnterModal.open}
|
||||
okText={t("general.actions.save")}
|
||||
@@ -450,14 +470,6 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
}}
|
||||
footer={
|
||||
<Space>
|
||||
<BillEnterAiScan
|
||||
fileInputRef={fileInputRef}
|
||||
form={form}
|
||||
pollingIntervalRef={pollingIntervalRef}
|
||||
setPollingIntervalRef={setPollingIntervalRef}
|
||||
scanLoading={scanLoading}
|
||||
setScanLoading={setScanLoading}
|
||||
/>
|
||||
<Checkbox checked={generateLabel} onChange={(e) => setGenerateLabel(e.target.checked)}>
|
||||
{t("bills.labels.generatepartslabel")}
|
||||
</Checkbox>
|
||||
@@ -491,7 +503,11 @@ function BillEnterModalContainer({ billEnterModal, toggleModalVisible, bodyshop,
|
||||
}}
|
||||
>
|
||||
<RbacWrapper action="bills:enter">
|
||||
<BillFormContainer form={form} disableInvNumber={billEnterModal.context.disableInvNumber} />
|
||||
<BillFormContainer
|
||||
form={form}
|
||||
isAiScan={isAiScan}
|
||||
disableInvNumber={billEnterModal.context.disableInvNumber}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -43,7 +43,8 @@ export function BillFormComponent({
|
||||
loadOutstandingReturns,
|
||||
loadInventory,
|
||||
preferredMake,
|
||||
disableInHouse
|
||||
disableInHouse,
|
||||
isAiScan
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const client = useApolloClient();
|
||||
@@ -452,6 +453,7 @@ export function BillFormComponent({
|
||||
responsibilityCenters={responsibilityCenters}
|
||||
disabled={disabled}
|
||||
billEdit={billEdit}
|
||||
isAiScan={isAiScan}
|
||||
/>
|
||||
)}
|
||||
<Divider titlePlacement="left" style={{ display: billEdit ? "none" : null }}>
|
||||
|
||||
@@ -15,7 +15,7 @@ const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableInvNumber, disableInHouse }) {
|
||||
export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableInvNumber, disableInHouse,isAiScan }) {
|
||||
const {
|
||||
treatments: { Simple_Inventory }
|
||||
} = useTreatmentsWithConfig({
|
||||
@@ -50,6 +50,7 @@ export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableI
|
||||
loadOutstandingReturns={loadOutstandingReturns}
|
||||
loadInventory={loadInventory}
|
||||
preferredMake={lineData ? lineData.jobs_by_pk.v_make_desc : null}
|
||||
isAiScan={isAiScan}
|
||||
/>
|
||||
{!billEdit && <BillCmdReturnsTableComponent form={form} returnLoading={returnLoading} returnData={returnData} />}
|
||||
{Simple_Inventory.treatment === "on" && (
|
||||
|
||||
@@ -30,7 +30,8 @@ export function BillEnterModalLinesComponent({
|
||||
discount,
|
||||
form,
|
||||
responsibilityCenters,
|
||||
billEdit
|
||||
billEdit,
|
||||
isAiScan
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { setFieldsValue, getFieldsValue, getFieldValue } = form;
|
||||
@@ -140,6 +141,29 @@ export function BillEnterModalLinesComponent({
|
||||
|
||||
const columns = (remove) => {
|
||||
return [
|
||||
...(isAiScan
|
||||
? [
|
||||
{
|
||||
title: t("billlines.fields.confidence"),
|
||||
dataIndex: "confidence",
|
||||
editable: true,
|
||||
width: "5rem",
|
||||
formItemProps: (field) => ({
|
||||
key: `${field.index}confidence`,
|
||||
name: [field.name, "confidence"],
|
||||
label: t("billlines.fields.confidence")
|
||||
}),
|
||||
formInput: (record) => {
|
||||
const confidenceValue = getFieldValue(["billlines", record.name, "confidence"]);
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
<ConfidenceDisplay value={confidenceValue} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
title: t("billlines.fields.jobline"),
|
||||
dataIndex: "joblineid",
|
||||
@@ -213,25 +237,7 @@ export function BillEnterModalLinesComponent({
|
||||
}),
|
||||
formInput: () => <Input.TextArea disabled={disabled} autoSize tabIndex={0} />
|
||||
},
|
||||
{
|
||||
title: t("billlines.fields.confidence"),
|
||||
dataIndex: "confidence",
|
||||
editable: true,
|
||||
width: "5rem",
|
||||
formItemProps: (field) => ({
|
||||
key: `${field.index}confidence`,
|
||||
name: [field.name, "confidence"],
|
||||
label: t("billlines.fields.confidence")
|
||||
}),
|
||||
formInput: (record) => {
|
||||
const confidenceValue = getFieldValue(["billlines", record.name, "confidence"]);
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
<ConfidenceDisplay value={confidenceValue} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: t("billlines.fields.quantity"),
|
||||
dataIndex: "quantity",
|
||||
|
||||
@@ -187,6 +187,7 @@ export function PartsOrderListTableDrawerComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job,
|
||||
parts_order: { id: record.id },
|
||||
bill: {
|
||||
vendorid: record.vendor.id,
|
||||
is_credit_memo: record.return,
|
||||
|
||||
@@ -162,6 +162,7 @@ export function PartsOrderListTableComponent({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job,
|
||||
parts_order: { id: record.id },
|
||||
bill: {
|
||||
vendorid: record.vendor.id,
|
||||
is_credit_memo: record.return,
|
||||
|
||||
@@ -10,8 +10,14 @@ const { Option } = Select;
|
||||
const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, preferredMake, showPhone, ref }) => {
|
||||
const [option, setOption] = useState(value);
|
||||
|
||||
// Sync internal state when value prop changes (e.g., from form.setFieldsValue)
|
||||
useEffect(() => {
|
||||
if (value !== option) {
|
||||
setOption(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("*** ~ VendorSearchSelect ~ USEEFFECT:", value, option);
|
||||
if (value !== option && onChange) {
|
||||
if (value && !option) {
|
||||
onChange(value);
|
||||
|
||||
Reference in New Issue
Block a user