Skip to content

Commit

Permalink
Merge branch 'release-0.2.0' into fix/prashanth-etl-role-map-1594
Browse files Browse the repository at this point in the history
  • Loading branch information
prv-proton authored Jan 4, 2025
2 parents 6b62173 + 1d72287 commit c34a898
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""add update_count_transfers_in_progress db function and update existing counts
Revision ID: 9329e38396e1
Revises: d9cdd9fca0ce
Create Date: 2024-12-30 13:54:09.361644
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "9329e38396e1"
down_revision = "d9cdd9fca0ce"
branch_labels = None
depends_on = None


def upgrade() -> None:
# Create or replace the trigger function without considering Draft transfers
op.execute(
"""
CREATE OR REPLACE FUNCTION update_count_transfers_in_progress()
RETURNS TRIGGER AS $$
BEGIN
-- Update count_transfers_in_progress for from_organization_id and to_organization_id
UPDATE organization o
SET count_transfers_in_progress = (
SELECT COUNT(DISTINCT t.transfer_id)
FROM transfer t
WHERE
t.current_status_id IN (3, 4)
AND (t.from_organization_id = o.organization_id OR t.to_organization_id = o.organization_id)
)
WHERE o.organization_id = COALESCE(NEW.from_organization_id, OLD.from_organization_id)
OR o.organization_id = COALESCE(NEW.to_organization_id, OLD.to_organization_id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
"""
)

# Create the trigger
op.execute(
"""
CREATE TRIGGER update_count_transfers_in_progress_trigger
AFTER INSERT OR UPDATE OR DELETE ON transfer
FOR EACH ROW
EXECUTE FUNCTION update_count_transfers_in_progress();
"""
)

# Update existing counts for all organizations by aggregating both sent and received transfers without double-counting
op.execute(
"""
UPDATE organization o
SET count_transfers_in_progress = COALESCE(sub.total_transfer_count, 0)
FROM (
SELECT
org.organization_id,
COUNT(DISTINCT t.transfer_id) AS total_transfer_count
FROM
organization org
LEFT JOIN transfer t ON org.organization_id = t.from_organization_id
OR org.organization_id = t.to_organization_id
WHERE
t.current_status_id IN (3, 4)
GROUP BY
org.organization_id
) sub
WHERE
o.organization_id = sub.organization_id;
"""
)


def downgrade() -> None:
# Drop the trigger
op.execute(
"DROP TRIGGER IF EXISTS update_count_transfers_in_progress_trigger ON transfer;"
)
# Drop the trigger function
op.execute("DROP FUNCTION IF EXISTS update_count_transfers_in_progress();")
20 changes: 9 additions & 11 deletions backend/lcfs/web/api/organizations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,23 @@ async def get_organization_types(
return await service.get_organization_types()


# TODO review security of this endpoint around returning balances
# for all organizations
@router.get(
"/names/",
response_model=List[OrganizationSummaryResponseSchema],
status_code=status.HTTP_200_OK,
)
@cache(expire=1) # cache for 1 hour
@view_handler(["*"])
@cache(expire=1) # Cache for 1 hour
@view_handler(
[RoleEnum.GOVERNMENT]
) # Ensure only government can access this endpoint because it returns balances
async def get_organization_names(
request: Request, service: OrganizationsService = Depends()
request: Request,
only_registered: bool = Query(True),
service: OrganizationsService = Depends(),
):
"""Fetch all organization names"""

# Set the default sorting order
"""Fetch all organization names."""
order_by = ("name", "asc")

# Call the service with only_registered set to True to fetch only registered organizations
return await service.get_organization_names(True, order_by)
return await service.get_organization_names(only_registered, order_by)


@router.get(
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/hooks/useOrganizations.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ export const useOrganizationStatuses = (options) => {
})
}

export const useOrganizationNames = (options) => {
export const useOrganizationNames = (onlyRegistered = true, options) => {
const client = useApiService()

return useQuery({
queryKey: ['organization-names'],
queryFn: async () => (await client.get('/organizations/names/')).data,
...options
queryKey: ['organization-names', onlyRegistered],
queryFn: async () => {
const response = await client.get(`/organizations/names/?only_registered=${onlyRegistered}`)
return response.data
},
...options,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
useCreateUpdateInitiativeAgreement,
useInitiativeAgreement
} from '@/hooks/useInitiativeAgreement'
import { useRegExtOrgs } from '@/hooks/useOrganizations'
import { useOrganizationNames } from '@/hooks/useOrganizations'
import { useOrganizationBalance } from '@/hooks/useOrganization'
import { useTransactionMutation } from '../transactionMutation'
import { TRANSACTION_STATUSES } from '@/constants/statuses'
Expand Down Expand Up @@ -110,7 +110,7 @@ vi.mock('@fortawesome/react-fontawesome', () => ({

// Mock the hooks
vi.mock('@/hooks/useOrganizations', () => ({
useRegExtOrgs: vi.fn().mockReturnValue({
useOrganizationNames: vi.fn().mockReturnValue({
data: [
{
organizationId: 1,
Expand Down Expand Up @@ -281,7 +281,7 @@ describe('AddEditViewTransaction Component Tests', () => {
state: null
})

useRegExtOrgs.mockReturnValue({
useOrganizationNames.mockReturnValue({
data: [
{
organizationId: 1,
Expand Down Expand Up @@ -356,7 +356,7 @@ describe('AddEditViewTransaction Component Tests', () => {
mutate: vi.fn(),
isLoading: false
})
useRegExtOrgs.mockReturnValue({
useOrganizationNames.mockReturnValue({
data: [],
isLoading: false,
isFetched: true,
Expand Down Expand Up @@ -425,7 +425,7 @@ describe('AddEditViewTransaction Component Tests', () => {
isLoadingError: false
})

useRegExtOrgs.mockReturnValue({
useOrganizationNames.mockReturnValue({
data: [],
isLoading: false,
isFetched: true,
Expand Down Expand Up @@ -500,7 +500,7 @@ describe('AddEditViewTransaction Component Tests', () => {
isLoading: false
})

useRegExtOrgs.mockReturnValue({
useOrganizationNames.mockReturnValue({
data: [],
isLoading: false,
isFetched: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@mui/material'
import { dateFormatter, numberFormatter } from '@/utils/formatters'
import { useFormContext, Controller } from 'react-hook-form'
import { useRegExtOrgs } from '@/hooks/useOrganizations'
import { useOrganizationNames } from '@/hooks/useOrganizations'
import { useOrganizationBalance } from '@/hooks/useOrganization'
import Loading from '@/components/Loading'
import {
Expand All @@ -34,7 +34,7 @@ export const TransactionDetails = ({ transactionId, isEditable }) => {
control
} = useFormContext()

const { data: orgData } = useRegExtOrgs()
const { data: orgData } = useOrganizationNames(false)
const organizations =
orgData?.map((org) => ({
value: parseInt(org.organizationId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
import { TransactionDetails } from '../TransactionDetails'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ThemeProvider } from '@mui/material'
import { useRegExtOrgs } from '@/hooks/useOrganizations'
import { useOrganizationNames } from '@/hooks/useOrganizations'
import { useOrganizationBalance } from '@/hooks/useOrganization'
import theme from '@/themes'
import { FormProvider, useForm } from 'react-hook-form'
Expand Down Expand Up @@ -65,7 +65,7 @@ describe('TransactionDetails Component', () => {
beforeEach(() => {
vi.clearAllMocks()

useRegExtOrgs.mockReturnValue({
useOrganizationNames.mockReturnValue({
data: mockOrganizations,
isLoading: false
})
Expand Down

0 comments on commit c34a898

Please sign in to comment.