From de082870073020a0cff6423827a2cb35568f29ef Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 05:28:30 -0800 Subject: [PATCH 1/8] Fix: LCFS - backend filter logic on the Compliance Report index #1809 --- .../lcfs/web/api/compliance_report/repo.py | 45 +++++++++++---- frontend/src/hooks/useComplianceReports.js | 42 ++++++++++++++ .../ComplianceReports/ComplianceReports.jsx | 55 +++++++------------ 3 files changed, 95 insertions(+), 47 deletions(-) diff --git a/backend/lcfs/web/api/compliance_report/repo.py b/backend/lcfs/web/api/compliance_report/repo.py index 7dd40de22..e2b5ba1c9 100644 --- a/backend/lcfs/web/api/compliance_report/repo.py +++ b/backend/lcfs/web/api/compliance_report/repo.py @@ -6,7 +6,7 @@ from fastapi import Depends from sqlalchemy import func, select, and_, asc, desc, update from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy.orm import joinedload, contains_eager +from sqlalchemy.orm import joinedload, contains_eager, aliased from lcfs.db.dependencies import get_async_db_session from lcfs.db.models.compliance import CompliancePeriod @@ -364,8 +364,6 @@ async def get_reports_paginated( # Base query conditions conditions = [] sub_conditions = [] - if organization_id: - sub_conditions.append(ComplianceReport.organization_id == organization_id) if pagination.filters and len(pagination.filters) > 0: self.apply_sub_filters(pagination, sub_conditions) @@ -376,19 +374,37 @@ async def get_reports_paginated( limit = pagination.size # Build the main query - subquery = ( + latest_version_subquery = ( select( ComplianceReport.compliance_report_group_uuid, func.max(ComplianceReport.version).label("latest_version"), ) - .where(and_(*sub_conditions)) .group_by(ComplianceReport.compliance_report_group_uuid) ) + if organization_id: + latest_version_subquery = latest_version_subquery.where(ComplianceReport.organization_id == organization_id) + latest_version_subquery = latest_version_subquery.subquery() + cr_alias = aliased(ComplianceReport) - subquery = subquery.join( - ComplianceReportStatus, - ComplianceReport.current_status_id - == ComplianceReportStatus.compliance_report_status_id, + subquery = ( + select( + cr_alias.compliance_report_group_uuid, + cr_alias.version.label('latest_version'), + ) + .join( + latest_version_subquery, + and_( + cr_alias.compliance_report_group_uuid + == latest_version_subquery.c.compliance_report_group_uuid, + cr_alias.version == latest_version_subquery.c.latest_version, + ), + ) + .join( + ComplianceReportStatus, + cr_alias.current_status_id + == ComplianceReportStatus.compliance_report_status_id, + ) + .where(and_(*sub_conditions)) ) subquery = subquery.subquery() @@ -448,6 +464,7 @@ async def get_reports_paginated( query = query.order_by(sort_method(order.field)) # Execute query with offset and limit for pagination + print(query) query_result = ( (await self.db.execute(query.offset(offset).limit(limit))) .unique() @@ -753,10 +770,16 @@ def aggregate_quantities( for record in records: # Check if record matches fossil_derived filter - if isinstance(record, FuelSupply) and record.fuel_type.fossil_derived == fossil_derived: + if ( + isinstance(record, FuelSupply) + and record.fuel_type.fossil_derived == fossil_derived + ): fuel_category = self._format_category(record.fuel_category.category) fuel_quantities[fuel_category] += record.quantity - elif isinstance(record, OtherUses) and record.fuel_type.fossil_derived == fossil_derived: + elif ( + isinstance(record, OtherUses) + and record.fuel_type.fossil_derived == fossil_derived + ): fuel_category = self._format_category(record.fuel_category.category) fuel_quantities[fuel_category] += record.quantity_supplied diff --git a/frontend/src/hooks/useComplianceReports.js b/frontend/src/hooks/useComplianceReports.js index 10d4590bb..1c94513bd 100644 --- a/frontend/src/hooks/useComplianceReports.js +++ b/frontend/src/hooks/useComplianceReports.js @@ -1,6 +1,8 @@ import { apiRoutes } from '@/constants/routes' import { useApiService } from '@/services/useApiService' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { useCurrentUser } from './useCurrentUser' +import { roles } from '@/constants/roles' export const useCompliancePeriod = (options) => { const client = useApiService() @@ -158,3 +160,43 @@ export const useCreateSupplementalReport = (reportID, options) => { } }) } + +export const useGetComplianceReportList = ( + { page = 1, size = 10, sortOrders = [], filters = [] } = {}, + options +) => { + const client = useApiService() + const { data: currentUser, hasRoles } = useCurrentUser() + + return useQuery({ + queryKey: ['compliance-reports-list', page, size, sortOrders, filters], + queryFn: async () => { + if (hasRoles(roles.supplier)) { + return ( + await client.post( + apiRoutes.getOrgComplianceReports.replace( + ':orgID', + currentUser?.organization?.organizationId + ), + { + page, + size, + sortOrders, + filters + } + ) + ).data + } else { + return ( + await client.post(apiRoutes.getComplianceReports, { + page, + size, + sortOrders, + filters + }) + ).data + } + }, + ...options + }) +} diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index cdf5b0b6a..a1c0f60f4 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -1,21 +1,21 @@ import { Stack } from '@mui/material' import BCBox from '@/components/BCBox' import BCAlert from '@/components/BCAlert' -import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate } from 'react-router-dom' import { Role } from '@/components/Role' import { roles } from '@/constants/roles' -import { apiRoutes, ROUTES } from '@/constants/routes' +import { ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses' import { useCurrentUser } from '@/hooks/useCurrentUser' -import { useCreateComplianceReport } from '@/hooks/useComplianceReports' -import { defaultSortModel, reportsColDefs } from './components/_schema' +import { useCreateComplianceReport, useGetComplianceReportList } from '@/hooks/useComplianceReports' +import { reportsColDefs } from './components/_schema' import { NewComplianceReportButton } from './components/NewComplianceReportButton' import BCTypography from '@/components/BCTypography' import { ClearFiltersButton } from '@/components/ClearFiltersButton' import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' +import { BCGridViewer } from '@/components/BCDataGrid/BCGridViewer' export const ComplianceReports = () => { const { t } = useTranslation(['common', 'report']) @@ -23,28 +23,16 @@ export const ComplianceReports = () => { const [isButtonLoading, setIsButtonLoading] = useState(false) const [resetGridFn, setResetGridFn] = useState(null) const [alertSeverity, setAlertSeverity] = useState('info') - const [gridKey, setGridKey] = useState(`compliance-reports-grid`) const gridRef = useRef() const alertRef = useRef() const navigate = useNavigate() const location = useLocation() - const newButtonRef = useRef(null); + const newButtonRef = useRef(null) const { hasRoles, data: currentUser } = useCurrentUser() - const gridOptions = useMemo( - () => ({ - overlayNoRowsTemplate: t('report:noReportsFound') - }), - [t] - ) - const getRowId = useCallback( - (params) => params.data.complianceReportId.toString(), - [] - ) - - const handleGridKey = useCallback(() => { - setGridKey('reports-grid') + const getRowId = useCallback((params) => { + return `${params.data.compliancePeriod.description}-${params.data.complianceReportId}` }, []) useEffect(() => { @@ -156,25 +144,20 @@ export const ComplianceReports = () => { }} /> - From d82d0c7f279a65f85af6463d43f8aa46ab178ca5 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 05:39:15 -0800 Subject: [PATCH 2/8] test case fix --- .../ComplianceReports/__tests__/ComplianceReports.test.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/views/ComplianceReports/__tests__/ComplianceReports.test.jsx b/frontend/src/views/ComplianceReports/__tests__/ComplianceReports.test.jsx index 9575816fe..b0aa27ff4 100644 --- a/frontend/src/views/ComplianceReports/__tests__/ComplianceReports.test.jsx +++ b/frontend/src/views/ComplianceReports/__tests__/ComplianceReports.test.jsx @@ -54,8 +54,8 @@ vi.mock('../components/NewComplianceReportButton', () => ({ ) })) -vi.mock('@/components/BCDataGrid/BCDataGridServer', () => ({ - default: () =>
BCDataGridServer
+vi.mock('@/components/BCDataGrid/BCGridViewer', () => ({ + BCGridViewer: () =>
BCGridViewer
})) describe('ComplianceReports', () => { @@ -99,7 +99,7 @@ describe('ComplianceReports', () => { expect(screen.getByText('New Report')).toBeInTheDocument() }) - it('renders the BCDataGridServer', () => { + it('renders the BCGridViewer', () => { customRender() expect(screen.getByTestId('bc-data-grid')).toBeInTheDocument() }) From 806e8c7cc6d3abe1d07d4d1bfbb01b408a7e1e1b Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 05:58:29 -0800 Subject: [PATCH 3/8] update default sort order --- backend/lcfs/web/api/compliance_report/repo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/lcfs/web/api/compliance_report/repo.py b/backend/lcfs/web/api/compliance_report/repo.py index e2b5ba1c9..9587fce95 100644 --- a/backend/lcfs/web/api/compliance_report/repo.py +++ b/backend/lcfs/web/api/compliance_report/repo.py @@ -444,6 +444,9 @@ async def get_reports_paginated( ) # Apply sorting from pagination + if len(pagination.sort_orders) < 1: + field = get_field_for_filter(ComplianceReport, "update_date") + query = query.order_by(desc(field)) for order in pagination.sort_orders: sort_method = asc if order.direction == "asc" else desc if order.field == "status": From 3de960799c82570363e9cd9f112472b737edc71c Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 06:15:16 -0800 Subject: [PATCH 4/8] remove debug print --- backend/lcfs/web/api/compliance_report/repo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/lcfs/web/api/compliance_report/repo.py b/backend/lcfs/web/api/compliance_report/repo.py index 9587fce95..da99ed64f 100644 --- a/backend/lcfs/web/api/compliance_report/repo.py +++ b/backend/lcfs/web/api/compliance_report/repo.py @@ -467,7 +467,6 @@ async def get_reports_paginated( query = query.order_by(sort_method(order.field)) # Execute query with offset and limit for pagination - print(query) query_result = ( (await self.db.execute(query.offset(offset).limit(limit))) .unique() From a9d98b2947ab9674686abae49259203d769d6ab0 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 06:18:01 -0800 Subject: [PATCH 5/8] . --- .../views/ComplianceReports/ComplianceReports.jsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index a1c0f60f4..fd242a65e 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -9,7 +9,10 @@ import { roles } from '@/constants/roles' import { ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses' import { useCurrentUser } from '@/hooks/useCurrentUser' -import { useCreateComplianceReport, useGetComplianceReportList } from '@/hooks/useComplianceReports' +import { + useCreateComplianceReport, + useGetComplianceReportList +} from '@/hooks/useComplianceReports' import { reportsColDefs } from './components/_schema' import { NewComplianceReportButton } from './components/NewComplianceReportButton' import BCTypography from '@/components/BCTypography' @@ -31,9 +34,10 @@ export const ComplianceReports = () => { const newButtonRef = useRef(null) const { hasRoles, data: currentUser } = useCurrentUser() - const getRowId = useCallback((params) => { - return `${params.data.compliancePeriod.description}-${params.data.complianceReportId}` - }, []) + const getRowId = useCallback( + (params) => params.data.complianceReportGroupUuid, + [] + ) useEffect(() => { if (location.state?.message) { From c1f99e745af2943e485d45b2f5694849499efbb2 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 07:03:09 -0800 Subject: [PATCH 6/8] . --- frontend/src/components/BCDataGrid/BCGridViewer.jsx | 1 + frontend/src/views/ComplianceReports/ComplianceReports.jsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/BCDataGrid/BCGridViewer.jsx b/frontend/src/components/BCDataGrid/BCGridViewer.jsx index 9fbac791b..4768d86e0 100644 --- a/frontend/src/components/BCDataGrid/BCGridViewer.jsx +++ b/frontend/src/components/BCDataGrid/BCGridViewer.jsx @@ -61,6 +61,7 @@ export const BCGridViewer = ({ const columnState = JSON.parse(localStorage.getItem(`${gridKey}-column`)) if (filterState) { params.api.setFilterModel(filterState) + setFilterModel(filterState) } if (columnState) { params.api.applyColumnState({ diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index fd242a65e..c72b0e282 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -150,7 +150,7 @@ export const ComplianceReports = () => { Date: Thu, 30 Jan 2025 07:51:19 -0800 Subject: [PATCH 7/8] Organization users view fix --- backend/lcfs/web/api/organization/services.py | 7 ------- .../Organizations/ViewOrganization/ViewOrganization.jsx | 3 ++- .../src/views/Organizations/ViewOrganization/_schema.js | 8 ++++++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/backend/lcfs/web/api/organization/services.py b/backend/lcfs/web/api/organization/services.py index 9371c6347..7d5dfe27a 100644 --- a/backend/lcfs/web/api/organization/services.py +++ b/backend/lcfs/web/api/organization/services.py @@ -120,13 +120,6 @@ async def get_organization_users_list( """ Get all users for the organization """ - # Add Organization and status to filter - if (pagination.filters is None) or (len(pagination.filters) == 0): - pagination.filters.append( - FilterModel( - filter_type="text", field="is_active", type="equals", filter=status - ) - ) pagination.filters.append( FilterModel( filter_type="number", diff --git a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx index 1761d5fcb..34386c088 100644 --- a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx +++ b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx @@ -19,7 +19,7 @@ import { import { constructAddress } from '@/utils/constructAddress' import { phoneNumberFormatter } from '@/utils/formatters' import { useLocation, useNavigate, useParams } from 'react-router-dom' -import { defaultSortModel, getUserColumnDefs } from './_schema' +import { defaultFilterModel, defaultSortModel, getUserColumnDefs } from './_schema' import { Role } from '@/components/Role' import { roles } from '@/constants/roles' import { ORGANIZATION_STATUSES } from '@/constants/statuses' @@ -284,6 +284,7 @@ export const ViewOrganization = () => { getRowId={getRowId} gridOptions={gridOptions} defaultSortModel={defaultSortModel} + defaultFilterModel={defaultFilterModel} handleGridKey={handleGridKey} defaultColDef={defaultColDef} enableCopyButton={false} diff --git a/frontend/src/views/Organizations/ViewOrganization/_schema.js b/frontend/src/views/Organizations/ViewOrganization/_schema.js index 6ae02aa94..6671101ca 100644 --- a/frontend/src/views/Organizations/ViewOrganization/_schema.js +++ b/frontend/src/views/Organizations/ViewOrganization/_schema.js @@ -72,3 +72,11 @@ export const getUserColumnDefs = (t) => { } export const defaultSortModel = [{ field: 'firstName', direction: 'asc' }] +export const defaultFilterModel = [ + { + field: 'isActive', + filterType: 'text', + type: 'equals', + filter: 'Active' + } +] From fb073d0270bcd9684821ce7c6f09504ee1bda717 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Thu, 30 Jan 2025 08:07:46 -0800 Subject: [PATCH 8/8] revert default filter --- .../Organizations/ViewOrganization/ViewOrganization.jsx | 3 +-- .../src/views/Organizations/ViewOrganization/_schema.js | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx index 34386c088..1761d5fcb 100644 --- a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx +++ b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx @@ -19,7 +19,7 @@ import { import { constructAddress } from '@/utils/constructAddress' import { phoneNumberFormatter } from '@/utils/formatters' import { useLocation, useNavigate, useParams } from 'react-router-dom' -import { defaultFilterModel, defaultSortModel, getUserColumnDefs } from './_schema' +import { defaultSortModel, getUserColumnDefs } from './_schema' import { Role } from '@/components/Role' import { roles } from '@/constants/roles' import { ORGANIZATION_STATUSES } from '@/constants/statuses' @@ -284,7 +284,6 @@ export const ViewOrganization = () => { getRowId={getRowId} gridOptions={gridOptions} defaultSortModel={defaultSortModel} - defaultFilterModel={defaultFilterModel} handleGridKey={handleGridKey} defaultColDef={defaultColDef} enableCopyButton={false} diff --git a/frontend/src/views/Organizations/ViewOrganization/_schema.js b/frontend/src/views/Organizations/ViewOrganization/_schema.js index 6671101ca..6ae02aa94 100644 --- a/frontend/src/views/Organizations/ViewOrganization/_schema.js +++ b/frontend/src/views/Organizations/ViewOrganization/_schema.js @@ -72,11 +72,3 @@ export const getUserColumnDefs = (t) => { } export const defaultSortModel = [{ field: 'firstName', direction: 'asc' }] -export const defaultFilterModel = [ - { - field: 'isActive', - filterType: 'text', - type: 'equals', - filter: 'Active' - } -]