Skip to content

Commit

Permalink
Merge pull request #2122 from uktrade/uat
Browse files Browse the repository at this point in the history
prod release
  • Loading branch information
saruniitr authored Aug 7, 2024
2 parents 144fa93 + 757aee8 commit 85caed6
Show file tree
Hide file tree
Showing 19 changed files with 921 additions and 38 deletions.
37 changes: 37 additions & 0 deletions api/applications/migrations/0082_alter_goodonapplication_unit.py
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,
),
),
]
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)]
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"]
67 changes: 67 additions & 0 deletions api/applications/tests/test_create_application.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from parameterized import parameterized
from rest_framework import status
from rest_framework.reverse import reverse
from urllib.parse import urlencode

from api.applications.enums import ApplicationExportType, ApplicationExportLicenceOfficialType
from api.applications.models import StandardApplication, BaseApplication
from api.applications.tests.factories import DraftStandardApplicationFactory
from api.cases.enums import CaseTypeEnum, CaseTypeReferenceEnum
from lite_content.lite_api import strings
from api.staticdata.trade_control.enums import TradeControlActivity, TradeControlProductCategory
from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status
from test_helpers.clients import DataTestClient


Expand Down Expand Up @@ -143,3 +146,67 @@ def test_trade_control_application_failure(self, case_type, missing_field, expec
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
errors = response.json()["errors"]
self.assertEqual(errors[missing_field], [expected_error])


class ApplicationsListTests(DataTestClient):
url = reverse("applications:applications")

@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},
],
],
[
{"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_retrieve_applications_tests(self, initial, target_state, filters):
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 in filters:
expected_count = filter.pop("expected")

url = f"{self.url}?{urlencode(filter, doseq=True)}"
response = self.client.get(url, **self.exporter_headers)
self.assertEqual(response.status_code, status.HTTP_200_OK)

response = response.json()
self.assertEqual(len(response["results"]), expected_count)
159 changes: 159 additions & 0 deletions api/applications/tests/test_filters.py
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)
Loading

0 comments on commit 85caed6

Please sign in to comment.