diff --git a/backend/lcfs/web/api/transaction/schema.py b/backend/lcfs/web/api/transaction/schema.py index 34a44b441..ad0d8411e 100644 --- a/backend/lcfs/web/api/transaction/schema.py +++ b/backend/lcfs/web/api/transaction/schema.py @@ -1,6 +1,6 @@ from typing import Optional, List -from pydantic import ConfigDict +from pydantic import ConfigDict, Field from lcfs.web.api.base import BaseSchema from datetime import datetime from enum import Enum diff --git a/backend/lcfs/web/api/transfer/schema.py b/backend/lcfs/web/api/transfer/schema.py index 858accf73..889437c8a 100644 --- a/backend/lcfs/web/api/transfer/schema.py +++ b/backend/lcfs/web/api/transfer/schema.py @@ -3,7 +3,7 @@ from typing import Optional, List from datetime import date, datetime from enum import Enum -from pydantic import ConfigDict +from pydantic import ConfigDict, Field class TransferRecommendationEnumSchema(str, Enum): diff --git a/frontend/src/views/AllocationAgreements/AddEditAllocationAgreements.jsx b/frontend/src/views/AllocationAgreements/AddEditAllocationAgreements.jsx index ebf346e27..6a79fd45e 100644 --- a/frontend/src/views/AllocationAgreements/AddEditAllocationAgreements.jsx +++ b/frontend/src/views/AllocationAgreements/AddEditAllocationAgreements.jsx @@ -65,7 +65,24 @@ export const AddEditAllocationAgreements = () => { severity: location.state.severity || 'info' }) } - }, [location.state]) + }, [location.state?.message, location.state?.severity]) + + const validate = (params, validationFn, errorMessage, alertRef, field = null) => { + const value = field ? params.node?.data[field] : params; + + if (field && params.colDef.field !== field) { + return true; + } + + if (!validationFn(value)) { + alertRef.current?.triggerAlert({ + message: errorMessage, + severity: 'error', + }); + return false; + } + return true; // Proceed with the update + }; const onGridReady = useCallback( async (params) => { @@ -156,6 +173,22 @@ export const AddEditAllocationAgreements = () => { async (params) => { if (params.oldValue === params.newValue) return + const isValid = validate( + params, + (value) => { + return value !== null && !isNaN(value) && value > 0; + }, + 'Quantity supplied must be greater than 0.', + alertRef, + 'quantity', + ); + + if (!isValid) { + return + } + + if (!isValid) return + params.node.updateData({ ...params.node.data, validationStatus: 'pending' diff --git a/frontend/src/views/AllocationAgreements/_schema.jsx b/frontend/src/views/AllocationAgreements/_schema.jsx index c1a878878..e9d6e29d6 100644 --- a/frontend/src/views/AllocationAgreements/_schema.jsx +++ b/frontend/src/views/AllocationAgreements/_schema.jsx @@ -435,7 +435,8 @@ export const allocationAgreementColDefs = (optionsData, errors) => [ headerName: i18n.t( 'allocationAgreement:allocationAgreementColLabels.quantity' ), - valueFormatter, + editor: NumberEditor, + valueFormatter: (params) => valueFormatter({ value: params.value }), cellEditor: NumberEditor, cellEditorParams: { precision: 0, diff --git a/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx b/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx index ec29c0e2f..4badf3167 100644 --- a/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx +++ b/frontend/src/views/FuelSupplies/AddEditFuelSupplies.jsx @@ -58,13 +58,30 @@ export const AddEditFuelSupplies = () => { ) useEffect(() => { - if (location.state?.message) { + if (location?.state?.message) { alertRef.current?.triggerAlert({ message: location.state.message, severity: location.state.severity || 'info' }) } - }, [location.state]) + }, [location?.state?.message, location?.state?.severity]); + + const validate = (params, validationFn, errorMessage, alertRef, field = null) => { + const value = field ? params.node?.data[field] : params; + + if (field && params.colDef.field !== field) { + return true; + } + + if (!validationFn(value)) { + alertRef.current?.triggerAlert({ + message: errorMessage, + severity: 'error', + }); + return false; + } + return true; // Proceed with the update + }; const onGridReady = useCallback( async (params) => { @@ -152,6 +169,20 @@ export const AddEditFuelSupplies = () => { async (params) => { if (params.oldValue === params.newValue) return + const isValid = validate( + params, + (value) => { + return value !== null && !isNaN(value) && value > 0; + }, + 'Quantity supplied must be greater than 0.', + alertRef, + 'quantity', + ); + + if (!isValid) { + return + } + params.node.updateData({ ...params.node.data, validationStatus: 'pending' diff --git a/frontend/src/views/FuelSupplies/_schema.jsx b/frontend/src/views/FuelSupplies/_schema.jsx index 0dc792d73..5939d074b 100644 --- a/frontend/src/views/FuelSupplies/_schema.jsx +++ b/frontend/src/views/FuelSupplies/_schema.jsx @@ -104,7 +104,6 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ params.data.provisionOfTheAct = null params.data.fuelCode = null params.data.fuelCodeId = null - params.data.quantity = 0 params.data.units = fuelType?.unit params.data.unrecognized = fuelType?.unrecognized } @@ -178,7 +177,6 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ params.data.eer = null params.data.provisionOfTheAct = null params.data.fuelCode = null - params.data.quantity = 0 } return true }, @@ -382,7 +380,7 @@ export const fuelSupplyColDefs = (optionsData, errors, warnings) => [ field: 'quantity', headerComponent: RequiredHeader, headerName: i18n.t('fuelSupply:fuelSupplyColLabels.quantity'), - valueFormatter, + valueFormatter: (params) => valueFormatter({ value: params.value }), cellEditor: NumberEditor, cellEditorParams: { precision: 0, diff --git a/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx b/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx index 2df027624..5d8073495 100644 --- a/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx +++ b/frontend/src/views/NotionalTransfers/AddEditNotionalTransfers.jsx @@ -39,13 +39,30 @@ export const AddEditNotionalTransfers = () => { const navigate = useNavigate() useEffect(() => { - if (location.state?.message) { + if (location?.state?.message) { alertRef.triggerAlert({ message: location.state.message, severity: location.state.severity || 'info' }) } - }, [location.state]) + }, [location?.state?.message, location?.state?.severity]); + + const validate = (params, validationFn, errorMessage, alertRef, field = null) => { + const value = field ? params.node?.data[field] : params; + + if (field && params.colDef.field !== field) { + return true; + } + + if (!validationFn(value)) { + alertRef.current?.triggerAlert({ + message: errorMessage, + severity: 'error', + }); + return false; + } + return true; // Proceed with the update + }; const onGridReady = (params) => { const ensureRowIds = (rows) => { @@ -98,6 +115,20 @@ export const AddEditNotionalTransfers = () => { async (params) => { if (params.oldValue === params.newValue) return + const isValid = validate( + params, + (value) => { + return value !== null && !isNaN(value) && value > 0; + }, + 'Quantity supplied must be greater than 0.', + alertRef, + 'quantity', + ); + + if (!isValid) { + return + } + // Initialize updated data with 'pending' status params.node.updateData({ ...params.node.data, diff --git a/frontend/src/views/NotionalTransfers/_schema.jsx b/frontend/src/views/NotionalTransfers/_schema.jsx index 38673f676..6064debe4 100644 --- a/frontend/src/views/NotionalTransfers/_schema.jsx +++ b/frontend/src/views/NotionalTransfers/_schema.jsx @@ -140,7 +140,7 @@ export const notionalTransferColDefs = (optionsData, errors) => [ min: 0, showStepperButtons: false }, - valueFormatter, + valueFormatter: (params) => valueFormatter({ value: params.value }), cellStyle: (params) => StandardCellErrors(params, errors) } ] diff --git a/frontend/src/views/OtherUses/AddEditOtherUses.jsx b/frontend/src/views/OtherUses/AddEditOtherUses.jsx index 08d9f250a..d3fc18ec8 100644 --- a/frontend/src/views/OtherUses/AddEditOtherUses.jsx +++ b/frontend/src/views/OtherUses/AddEditOtherUses.jsx @@ -81,6 +81,23 @@ export const AddEditOtherUses = () => { return ciOfFuel }, []) + const validate = (params, validationFn, errorMessage, alertRef, field = null) => { + const value = field ? params.node?.data[field] : params; + + if (field && params.colDef.field !== field) { + return true; + } + + if (!validationFn(value)) { + alertRef.current?.triggerAlert({ + message: errorMessage, + severity: 'error', + }); + return false; + } + return true; // Proceed with the update + }; + const onGridReady = (params) => { const ensureRowIds = (rows) => { return rows.map((row) => { @@ -201,6 +218,21 @@ export const AddEditOtherUses = () => { const onCellEditingStopped = useCallback( async (params) => { if (params.oldValue === params.newValue) return + + const isValid = validate( + params, + (value) => { + return value !== null && !isNaN(value) && value > 0; + }, + 'Quantity supplied must be greater than 0.', + alertRef, + 'quantitySupplied', + ); + + if (!isValid) { + return + } + params.data.complianceReportId = complianceReportId params.data.validationStatus = 'pending' diff --git a/frontend/src/views/OtherUses/_schema.jsx b/frontend/src/views/OtherUses/_schema.jsx index 03ce751fb..401b6db61 100644 --- a/frontend/src/views/OtherUses/_schema.jsx +++ b/frontend/src/views/OtherUses/_schema.jsx @@ -209,11 +209,10 @@ export const otherUsesColDefs = (optionsData, errors) => [ headerName: i18n.t('otherUses:otherUsesColLabels.quantitySupplied'), headerComponent: RequiredHeader, cellEditor: NumberEditor, - valueFormatter, + valueFormatter: (params) => valueFormatter({ value: params.value }), type: 'numericColumn', cellEditorParams: { precision: 0, - min: 0, showStepperButtons: false }, cellStyle: (params) => StandardCellErrors(params, errors),