Skip to content

Commit

Permalink
Merge branch 'develop' into feat/197-lfo-review-facilities-page
Browse files Browse the repository at this point in the history
  • Loading branch information
acatchpole authored Jan 27, 2025
2 parents b49a3d0 + 83d6e16 commit 9f0b8c7
Show file tree
Hide file tree
Showing 152 changed files with 4,203 additions and 815 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# [1.19.0](https://github.com/bcgov/cas-registration/compare/v1.18.0...v1.19.0) (2025-01-22)

### Bug Fixes

- Add previously missed default emissions to alumina source types ([9568534](https://github.com/bcgov/cas-registration/commit/9568534f11ecb4940c550ab80b4df5760ace6630))
- Block start button from redirecting if async doesn't return operation number ([aa99553](https://github.com/bcgov/cas-registration/commit/aa99553c399ef3c6643aae5c4cad332ffed1da7b))
- filter out the Facilities crumb from the breadcrumb component and update tests ([a920690](https://github.com/bcgov/cas-registration/commit/a9206904d92adf9f7e9a645871728c9b4cf68b4c))

### Features

- api endpoint to change a report version's report type ([83ee6dd](https://github.com/bcgov/cas-registration/commit/83ee6ddf8cf7562caf99c112da061bb1336d1577))
- create external transfers pages ([42f138e](https://github.com/bcgov/cas-registration/commit/42f138e98d170f62852ce84689d622dc6a44c622))

# [1.18.0](https://github.com/bcgov/cas-registration/compare/v1.17.1...v1.18.0) (2025-01-14)

### Bug Fixes
Expand Down
6 changes: 6 additions & 0 deletions bc_obps/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ pythontests_coverage: ## run Python tests with coverage
pythontests_coverage:
$(POETRY_RUN) pytest --cov=. --cov-config=.coveragerc --cov-report=term-missing --no-cov-on-fail


.PHONY: pythontests_parallel
pythontests_parallel: ## run Python tests in parallel for faster execution
pythontests_parallel:
$(POETRY_RUN) pytest -n auto

.PHONY: clear_db
clear_db: ## Clear all data in the datbase
clear_db:
Expand Down
10 changes: 8 additions & 2 deletions bc_obps/bc_obps/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,37 @@
# Application definition

INSTALLED_APPS = [
# Django apps
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Third-party apps
'simple_history',
"corsheaders",
"localflavor",
# Local apps
"registration.apps.RegistrationConfig",
"reporting.apps.ReportingConfig",
"common.apps.CommonConfig",
"rls.apps.RlsConfig",
]


MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"registration.middleware.kubernetes_middleware.KubernetesHealthCheckMiddleware",
"registration.middleware.kubernetes_health_check.KubernetesHealthCheckMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"registration.middleware.current_user_middleware.CurrentUserMiddleware",
"registration.middleware.current_user.CurrentUserMiddleware",
# RlsMiddleware must be after CurrentUserMiddleware(it depends on current_user attribute)
"rls.middleware.rls.RlsMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
'simple_history.middleware.HistoryRequestMiddleware',
Expand Down
12 changes: 12 additions & 0 deletions bc_obps/common/migrations/0031_V1_19_0.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 5.0.11 on 2025-01-22 21:03

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('common', '0030_V1_18_0'),
]

operations = []
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ class TestEndpointPermissions(TestCase):
{"method": "get", "endpoint_name": "list_user_operators"},
{"method": "get", "endpoint_name": "list_user_operators"},
{"method": "get", "endpoint_name": "list_transfer_events"},
{"method": "get", "endpoint_name": "get_transfer_event", "kwargs": {"transfer_id": mock_uuid}},
],
"approved_authorized_roles": [
{
Expand Down Expand Up @@ -564,6 +565,8 @@ class TestEndpointPermissions(TestCase):
],
"cas_analyst": [
{"method": "post", "endpoint_name": "create_transfer_event"},
{"method": "patch", "endpoint_name": "update_transfer_event", "kwargs": {"transfer_id": mock_uuid}},
{"method": "delete", "endpoint_name": "delete_transfer_event", "kwargs": {"transfer_id": mock_uuid}},
],
}

Expand Down
17 changes: 17 additions & 0 deletions bc_obps/common/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from typing import Optional

from django.apps import apps
from django.core.management import call_command
from decimal import Decimal


def reset_dashboard_data() -> None:
Expand All @@ -26,3 +29,17 @@ def reset_dashboard_data() -> None:
# Load the fixtures
for fixture in fixture_files:
call_command('loaddata', fixture)


def format_decimal(value: Decimal, decimal_places: int = 2) -> Optional[Decimal]:
"""
Formats a Decimal or numeric value to the specified number of decimal places
without rounding (truncates the extra digits).
"""
if value is None:
return None
try:
quantize_value = Decimal(f"1.{'0' * decimal_places}")
return value.quantize(quantize_value)
except (ValueError, TypeError):
raise ValueError(f"Cannot format the provided value: {value}")
1 change: 0 additions & 1 deletion bc_obps/mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ exclude = (?x)
tests/ |
migrations/ |
commands/ |
registration/middleware/ |
# Exclude files
^.*apps\.py$ |
^.*manage\.py$ |
Expand Down
1 change: 1 addition & 0 deletions bc_obps/registration/api/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@
from .user import user_profile, user_app_role
from ._users import user_id
from . import transfer_events
from ._transfer_events import transfer_id
7 changes: 4 additions & 3 deletions bc_obps/registration/api/v2/_contacts/contact_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
from registration.constants import CONTACT_TAGS
from registration.models.contact import Contact
from registration.schema.v1.contact import ContactIn, ContactOut
from service.contact_service import ContactService, ContactWithPlacesAssigned
from common.api.utils import get_current_user_guid
from registration.decorators import handle_http_errors
from registration.api.router import router
from registration.schema.generic import Message
from service.contact_service_v2 import ContactServiceV2, ContactWithPlacesAssigned
from service.contact_service import ContactService
from service.error_service.custom_codes_4xx import custom_codes_4xx


@router.get(
"/contacts/{contact_id}",
response={200: ContactOut, custom_codes_4xx: Message},
response={200: ContactWithPlacesAssigned, custom_codes_4xx: Message},
tags=CONTACT_TAGS,
description="""Retrieves the details of a specific contact by its ID. The endpoint checks if the current user is authorized to access the contact.
Industry users can only access contacts that are associated with their own operator. If an unauthorized user attempts to access the contact, an error is raised.""",
Expand All @@ -23,7 +24,7 @@
)
@handle_http_errors()
def get_contact(request: HttpRequest, contact_id: int) -> Tuple[Literal[200], Optional[ContactWithPlacesAssigned]]:
return 200, ContactService.get_with_places_assigned(get_current_user_guid(request), contact_id)
return 200, ContactServiceV2.get_with_places_assigned_v2(contact_id)


@router.put(
Expand Down
8 changes: 6 additions & 2 deletions bc_obps/registration/api/v2/_operations/operation_id.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from typing import Literal, Tuple
from uuid import UUID
from registration.schema.v2.operation import OperationOutV2, OperationInformationIn, OperationOutWithDocuments
from registration.schema.v2.operation import (
OperationInformationInUpdate,
OperationOutV2,
OperationOutWithDocuments,
)
from common.permissions import authorize
from django.http import HttpRequest
from registration.constants import OPERATION_TAGS
Expand Down Expand Up @@ -57,6 +61,6 @@ def get_operation_with_documents(request: HttpRequest, operation_id: UUID) -> Tu
)
@handle_http_errors()
def update_operation(
request: HttpRequest, operation_id: UUID, payload: OperationInformationIn
request: HttpRequest, operation_id: UUID, payload: OperationInformationInUpdate
) -> Tuple[Literal[200], Operation]:
return 200, OperationServiceV2.update_operation(get_current_user_guid(request), payload, operation_id)
53 changes: 53 additions & 0 deletions bc_obps/registration/api/v2/_transfer_events/transfer_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import Literal, Tuple
from uuid import UUID
from django.http import HttpRequest
from ninja.types import DictStrAny
from registration.constants import TRANSFER_EVENT_TAGS
from registration.models import TransferEvent
from common.api.utils import get_current_user_guid
from common.permissions import authorize
from registration.decorators import handle_http_errors
from registration.api.router import router
from registration.schema.generic import Message
from registration.schema.v2.transfer_event import TransferEventOut, TransferEventUpdateIn
from service.error_service.custom_codes_4xx import custom_codes_4xx
from service.transfer_event_service import TransferEventService


@router.get(
"/transfer-events/{uuid:transfer_id}",
response={200: TransferEventOut, custom_codes_4xx: Message},
tags=TRANSFER_EVENT_TAGS,
description="""Retrieves the details of a specific transfer event by its ID. The endpoint checks if the current user is authorized to access the transfer event.""",
auth=authorize("authorized_irc_user"),
)
@handle_http_errors()
def get_transfer_event(request: HttpRequest, transfer_id: UUID) -> Tuple[Literal[200], TransferEvent]:
return 200, TransferEventService.get_if_authorized(get_current_user_guid(request), transfer_id)


@router.delete(
"/transfer-events/{uuid:transfer_id}",
response={200: DictStrAny, custom_codes_4xx: Message},
tags=TRANSFER_EVENT_TAGS,
description="""Deletes a transfer event by its ID.""",
auth=authorize("cas_analyst"),
)
@handle_http_errors()
def delete_transfer_event(request: HttpRequest, transfer_id: UUID) -> Tuple[Literal[200], DictStrAny]:
TransferEventService.delete_transfer_event(get_current_user_guid(request), transfer_id)
return 200, {"success": True}


@router.patch(
"/transfer-events/{uuid:transfer_id}",
response={200: TransferEventOut, custom_codes_4xx: Message},
tags=TRANSFER_EVENT_TAGS,
description="""Updates the details of an existing transfer event by its ID.""",
auth=authorize("cas_analyst"),
)
@handle_http_errors()
def update_transfer_event(
request: HttpRequest, transfer_id: UUID, payload: TransferEventUpdateIn
) -> Tuple[Literal[200], TransferEvent]:
return 200, TransferEventService.update_transfer_event(get_current_user_guid(request), transfer_id, payload)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from django.http import HttpRequest
from uuid import UUID
from registration.constants import USER_OPERATOR_TAGS
from service.user_operator_service import UserOperatorService
from common.api.utils import get_current_user_guid
from registration.decorators import handle_http_errors
from registration.schema.v1 import (
Expand All @@ -14,6 +13,7 @@
from registration.models import UserOperator
from service.error_service.custom_codes_4xx import custom_codes_4xx
from registration.api.router import router
from service.user_operator_service_v2 import UserOperatorServiceV2


@router.put(
Expand All @@ -29,4 +29,6 @@
def update_user_operator_status(
request: HttpRequest, user_operator_id: UUID, payload: UserOperatorStatusUpdate
) -> Tuple[Literal[200], UserOperator]:
return 200, UserOperatorService.update_status(user_operator_id, payload, get_current_user_guid(request))
return 200, UserOperatorServiceV2.update_status_and_create_contact(
user_operator_id, payload, get_current_user_guid(request)
)
2 changes: 1 addition & 1 deletion bc_obps/registration/api/v2/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
def list_operations(
request: HttpRequest,
filters: OperationTimelineFilterSchema = Query(...),
sort_field: Optional[str] = "created_at",
sort_field: Optional[str] = "operation__created_at",
sort_order: Optional[Literal["desc", "asc"]] = "desc",
paginate_result: bool = Query(True, description="Whether to paginate the results"),
) -> QuerySet[OperationDesignatedOperatorTimeline]:
Expand Down
8 changes: 8 additions & 0 deletions bc_obps/registration/fixtures/mock/address.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,13 @@
"province": "ON",
"postal_code": "N2L 3G1"
}
},
{
"model": "registration.address",
"pk": 21,
"fields": {
"street_address": "Incomplete address",
"municipality": "Grove"
}
}
]
40 changes: 19 additions & 21 deletions bc_obps/registration/fixtures/mock/contact.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"pk": 1,
"fields": {
"business_role": "Operation Representative",
"first_name": "John",
"last_name": "Doe",
"first_name": "Alice",
"last_name": "Art",
"position_title": "Manager",
"address": 1,
"email": "john.doe@example.com",
"email": "alice.art@example.com",
"phone_number": "+16044011234"
}
},
Expand All @@ -17,11 +17,11 @@
"pk": 2,
"fields": {
"business_role": "Operation Representative",
"first_name": "Jane",
"last_name": "Smith",
"first_name": "Althea",
"last_name": "Ark",
"position_title": "Manager",
"address": 2,
"email": "jane.smith@example.com",
"email": "althea.ark@example.com",
"phone_number": "+16044011234"
}
},
Expand All @@ -30,11 +30,11 @@
"pk": 3,
"fields": {
"business_role": "Operation Representative",
"first_name": "Alice",
"last_name": "Johnson",
"first_name": "Bill",
"last_name": "Blue",
"position_title": "Manager",
"address": 3,
"email": "alice.johnson@example.com",
"email": "bill.blue@example.com",
"phone_number": "+16044011235"
}
},
Expand All @@ -56,11 +56,10 @@
"pk": 5,
"fields": {
"business_role": "Operation Representative",
"first_name": "Carol",
"last_name": "Davis",
"first_name": "Blair",
"last_name": "Balloons - no address",
"position_title": "Manager",
"address": 5,
"email": "[email protected]",
"email": "[email protected]",
"phone_number": "+16044011237"
}
},
Expand All @@ -69,11 +68,11 @@
"pk": 6,
"fields": {
"business_role": "Operation Representative",
"first_name": "Dave",
"last_name": "Evans",
"first_name": "Bart",
"last_name": "Banker - incomplete address",
"position_title": "Manager",
"address": 6,
"email": "dave.evans@example.com",
"address": 21,
"email": "bart.banker@example.com",
"phone_number": "+16044011238"
}
},
Expand Down Expand Up @@ -135,9 +134,8 @@
"fields": {
"business_role": "Operation Representative",
"first_name": "Ivy",
"last_name": "Jones",
"last_name": "Jones - no address",
"position_title": "Manager",
"address": 11,
"email": "[email protected]",
"phone_number": "+16044011243"
}
Expand All @@ -148,9 +146,9 @@
"fields": {
"business_role": "Operation Representative",
"first_name": "Jack",
"last_name": "King",
"last_name": "King - incomplete address",
"position_title": "Manager",
"address": 12,
"address": 21,
"email": "[email protected]",
"phone_number": "+16044011244"
}
Expand Down
Loading

0 comments on commit 9f0b8c7

Please sign in to comment.