-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2122 from uktrade/uat
prod release
- Loading branch information
Showing
19 changed files
with
921 additions
and
38 deletions.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
api/applications/migrations/0082_alter_goodonapplication_unit.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Generated by Django 4.2.13 on 2024-06-28 13:27 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("applications", "0081_rename_denial_denialmatchonapplication_denial_entity"), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name="goodonapplication", | ||
name="unit", | ||
field=models.CharField( | ||
blank=True, | ||
choices=[ | ||
("NAR", "Items"), | ||
("TON", "Tonnes"), | ||
("KGM", "Kilograms"), | ||
("GRM", "Grams"), | ||
("MGM", "Milligrams"), | ||
("MCG", "Micrograms"), | ||
("MTR", "Metres"), | ||
("MTK", "Square metres"), | ||
("MTQ", "Cubic metres"), | ||
("LTR", "Litres"), | ||
("MLT", "Millilitres"), | ||
("MCL", "Microlitres"), | ||
], | ||
default=None, | ||
max_length=50, | ||
null=True, | ||
), | ||
), | ||
] |
29 changes: 29 additions & 0 deletions
29
api/applications/migrations/0083_amend_existing_goodonapplication_unit_legacy_codes.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Generated by Django 4.2.13 on 2024-07-03 15:48 | ||
|
||
from django.db import migrations | ||
from api.staticdata.units.enums import Units | ||
|
||
|
||
def change_legacy_unit_codes(apps, schema_editor): | ||
GoodOnApplication = apps.get_model("applications", "GoodOnApplication") | ||
|
||
unit_mapping = { | ||
"MIM": Units.MGM, | ||
"MCM": Units.MCG, | ||
"MIR": Units.MLT, | ||
"MCR": Units.MCL, | ||
} | ||
|
||
for good_on_application in GoodOnApplication.objects.filter(unit__in=unit_mapping.keys()): | ||
legacy_unit = good_on_application.unit | ||
good_on_application.unit = unit_mapping[legacy_unit] | ||
good_on_application.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("applications", "0082_alter_goodonapplication_unit"), | ||
] | ||
|
||
operations = [migrations.RunPython(change_legacy_unit_codes, migrations.RunPython.noop)] |
60 changes: 60 additions & 0 deletions
60
...ications/migrations/tests/test_0083_amend_existing_goodonapplication_unit_legacy_codes.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import pytest | ||
from django_test_migrations.contrib.unittest_case import MigratorTestCase | ||
from api.staticdata.units.enums import Units | ||
|
||
|
||
def old_state_good_on_application_factory(self, unit): | ||
CaseStatus = self.old_state.apps.get_model("statuses", "CaseStatus") | ||
Good = self.old_state.apps.get_model("goods", "Good") | ||
GoodOnApplication = self.old_state.apps.get_model("applications", "GoodOnApplication") | ||
StandardApplication = self.old_state.apps.get_model("applications", "StandardApplication") | ||
Organisation = self.old_state.apps.get_model("organisations", "Organisation") | ||
Case = self.old_state.apps.get_model("cases", "Case") | ||
CaseType = self.old_state.apps.get_model("cases", "CaseType") | ||
|
||
case_status = CaseStatus.objects.get(status="submitted") | ||
case_type = CaseType.objects.get(type="application", reference="siel", sub_type="standard") | ||
|
||
organisation = Organisation.objects.create(name="test") | ||
case = Case.objects.create(case_type=case_type, organisation=organisation) | ||
application = StandardApplication.objects.create( | ||
organisation=organisation, case_type=case_type, case=case, status=case_status | ||
) | ||
good = Good.objects.create(name="test", organisation=organisation) | ||
good_on_application = GoodOnApplication.objects.create(application=application, good=good, unit=unit) | ||
return good_on_application | ||
|
||
|
||
@pytest.mark.django_db() | ||
class ChangeLegacyUnitCodesTestCase(MigratorTestCase): | ||
migrate_from = ("applications", "0082_alter_goodonapplication_unit") | ||
migrate_to = ("applications", "0083_amend_existing_goodonapplication_unit_legacy_codes") | ||
|
||
def prepare(self): | ||
|
||
self.expected_mappings = { | ||
"MIM": Units.MGM, | ||
"MCM": Units.MCG, | ||
"MIR": Units.MLT, | ||
"MCR": Units.MCL, | ||
"NAR": Units.NAR, | ||
} | ||
|
||
self.test_records = [ | ||
{ | ||
"id": old_state_good_on_application_factory(self, unit=old_unit).id, | ||
"expected_unit": new_unit, | ||
} | ||
for old_unit, new_unit in self.expected_mappings.items() | ||
] | ||
|
||
def test_change_legacy_unit_codes(self): | ||
|
||
GoodOnApplication = self.new_state.apps.get_model("applications", "GoodOnApplication") | ||
|
||
assert len(self.test_records) == len(self.expected_mappings) | ||
|
||
for test_record in self.test_records: | ||
good_on_application = GoodOnApplication.objects.get(id=test_record["id"]) | ||
|
||
assert good_on_application.unit == test_record["expected_unit"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import pytest | ||
|
||
from django.test import RequestFactory | ||
from parameterized import parameterized | ||
from urllib.parse import urlencode | ||
|
||
from api.applications.models import BaseApplication | ||
from api.applications.views.applications import ApplicationList | ||
from api.applications.views.filters import ApplicationSiteFilter, ApplicationStateFilter | ||
from api.applications.tests.factories import ( | ||
DraftStandardApplicationFactory, | ||
SiteOnApplicationFactory, | ||
StandardApplicationFactory, | ||
) | ||
from api.core.authentication import ORGANISATION_ID | ||
from api.core.constants import ExporterPermissions, Roles | ||
from api.core.exceptions import NotFoundError | ||
from api.organisations.models import Site | ||
from api.organisations.tests.factories import OrganisationFactory, SiteFactory | ||
from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status | ||
from api.users.models import Permission, Role, UserOrganisationRelationship | ||
from api.users.tests.factories import ExporterUserFactory, UserOrganisationRelationshipFactory | ||
from test_helpers.clients import DataTestClient | ||
|
||
|
||
class ApplicationFiltersTests(DataTestClient): | ||
|
||
def setUp(self): | ||
super().setUp() | ||
|
||
self.view = ApplicationList.as_view() | ||
self.queryset = BaseApplication.objects.all() | ||
|
||
def get_request(self, url, params): | ||
factory = RequestFactory() | ||
|
||
url = f"{url}?{urlencode(params, doseq=True)}" | ||
request = factory.get(url) | ||
request.META[ORGANISATION_ID] = self.organisation.id | ||
request.user = self.exporter_user.baseuser_ptr | ||
request.user.exporteruser = self.exporter_user | ||
|
||
return request | ||
|
||
@parameterized.expand( | ||
[ | ||
[4, 2, [], 4], | ||
[4, 2, [ExporterPermissions.ADMINISTER_SITES.name], 6], | ||
] | ||
) | ||
def test_exporter_user_only_access_assigned_sites(self, site1_count, site2_count, permissions, expected): | ||
filter = ApplicationSiteFilter() | ||
request = self.get_request("/", {}) | ||
|
||
# assign user to specific organisation and site | ||
user_org = UserOrganisationRelationship.objects.get( | ||
user=self.exporter_user, | ||
organisation=self.organisation, | ||
role=Role.objects.get(id=Roles.EXPORTER_EXPORTER_ROLE_ID), | ||
) | ||
site = Site.objects.get(organisation=self.organisation) | ||
site.users.add(user_org) | ||
|
||
# set permissions | ||
user_org.role.permissions.add(*list(Permission.objects.filter(id__in=permissions))) | ||
|
||
for _ in range(site1_count): | ||
SiteOnApplicationFactory( | ||
site=site, | ||
application=StandardApplicationFactory(organisation=self.organisation), | ||
) | ||
|
||
# Create additional sites | ||
another_user_org = UserOrganisationRelationshipFactory( | ||
user=ExporterUserFactory(), organisation=self.organisation | ||
) | ||
another_site = SiteFactory(organisation=self.organisation) | ||
another_site.users.add(another_user_org) | ||
|
||
for i in range(site2_count): | ||
SiteOnApplicationFactory( | ||
site=another_site, | ||
application=StandardApplicationFactory(organisation=another_user_org.organisation), | ||
) | ||
|
||
queryset = filter.filter_queryset(request, self.queryset, self.view) | ||
self.assertEqual(queryset.count(), expected) | ||
|
||
def test_exporter_user_unauthorized_site_raises_error(self): | ||
filter = ApplicationSiteFilter() | ||
|
||
request = self.get_request("/", {}) | ||
some_other_org = OrganisationFactory() | ||
request.META[ORGANISATION_ID] = some_other_org.id | ||
|
||
StandardApplicationFactory(organisation=self.organisation) | ||
|
||
with pytest.raises(NotFoundError): | ||
filter.filter_queryset(request, self.queryset, self.view) | ||
|
||
@parameterized.expand( | ||
[ | ||
[ | ||
{"num_drafts": 10}, | ||
{"status": "submitted", "count": 2}, | ||
[ | ||
{"selected_filter": "draft_applications", "expected": 8}, | ||
{"selected_filter": "submitted_applications", "expected": 2}, | ||
{"selected_filter": "archived_applications", "expected": 0}, | ||
{"selected_filter": "unknown_filter", "expected": 2}, | ||
], | ||
], | ||
[ | ||
{"num_drafts": 10}, | ||
{"status": "submitted", "count": 4}, | ||
[ | ||
{"selected_filter": "draft_tab", "expected": 6}, | ||
{"selected_filter": "submitted_applications", "expected": 4}, | ||
], | ||
], | ||
[ | ||
{"num_drafts": 10}, | ||
{"status": "finalised", "count": 5}, | ||
[ | ||
{"selected_filter": "finalised_applications", "expected": 5}, | ||
{"selected_filter": "draft_applications", "expected": 5}, | ||
], | ||
], | ||
[ | ||
{"num_drafts": 10}, | ||
{"status": "superseded_by_exporter_edit", "count": 3}, | ||
[ | ||
{"selected_filter": "archived_applications", "expected": 3}, | ||
{"selected_filter": "draft_applications", "expected": 7}, | ||
{"selected_filter": "finalised_applications", "expected": 0}, | ||
], | ||
], | ||
] | ||
) | ||
def test_exporter_user_see_applications_with_specified_status(self, initial, target_state, filters): | ||
filter = ApplicationStateFilter() | ||
|
||
drafts = [ | ||
DraftStandardApplicationFactory( | ||
organisation=self.organisation, | ||
) | ||
for _ in range(initial["num_drafts"]) | ||
] | ||
|
||
for draft in drafts[: target_state["count"]]: | ||
draft.status = get_case_status_by_status(target_state["status"]) | ||
draft.save() | ||
|
||
for filter_item in filters: | ||
expected_count = filter_item.pop("expected") | ||
request = self.get_request("/", filter_item) | ||
|
||
result_queryset = filter.filter_queryset(request, self.queryset, self.view) | ||
self.assertEqual(result_queryset.count(), expected_count) |
Oops, something went wrong.