Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UAT release #2366

Merged
merged 13 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/cases/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ def search( # noqa
"queues",
"queues__team",
"baseapplication__licences",
"flags",
Prefetch(
"baseapplication__parties",
to_attr="end_user_parties",
Expand Down
3 changes: 3 additions & 0 deletions api/cases/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from api.compliance.serializers.ComplianceVisitCaseSerializers import ComplianceVisitSerializer
from api.core.serializers import KeyValueChoiceField, PrimaryKeyRelatedSerializerField
from api.documents.libraries.process_document import process_document
from api.flags.serializers import CaseListFlagSerializer
from api.flags.models import Flag
from api.gov_users.serializers import GovUserSimpleSerializer
from api.organisations.models import Organisation
from api.organisations.serializers import TinyOrganisationViewSerializer
Expand Down Expand Up @@ -122,6 +124,7 @@ class CaseListSerializer(serializers.Serializer):
intended_end_use = serializers.SerializerMethodField()
end_users = serializers.SerializerMethodField()
sub_status = CaseSubStatusSerializer()
flags = PrimaryKeyRelatedSerializerField(many=True, queryset=Flag.objects.all(), serializer=CaseListFlagSerializer)

def __init__(self, *args, **kwargs):
self.team = kwargs.pop("team", None)
Expand Down
21 changes: 1 addition & 20 deletions api/cases/views/search/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from api.applications.serializers.advice import AdviceSearchViewSerializer
from api.cases.models import Case, EcjuQuery, Advice
from api.common.dates import working_days_in_range, number_of_days_since
from api.flags.models import Flag
from api.flags.serializers import CaseListFlagSerializer
from api.organisations.models import Organisation
from api.staticdata.statuses.enums import CaseStatusEnum
Expand Down Expand Up @@ -50,27 +51,7 @@ def get_advice_types_list():
return AdviceType.to_representation()


def populate_other_flags(cases: List[Dict]):
from api.flags.models import Flag

case_ids = [case["id"] for case in cases]

union_flags = set(
[
*Flag.objects.filter(cases__id__in=case_ids).annotate(case_id=F("cases__id")),
*Flag.objects.filter(organisations__cases__id__in=case_ids).annotate(case_id=F("organisations__cases__id")),
]
)

for case in cases:
case_id = str(case["id"])
flags = [flag for flag in union_flags if str(flag.case_id) == case_id]
case["flags"] = CaseListFlagSerializer(flags, many=True).data


def populate_goods_flags(cases: List[Dict]):
from api.flags.models import Flag

case_ids = [case["id"] for case in cases]
qs1 = Flag.objects.filter(goods__goods_on_application__application_id__in=case_ids).annotate(
case_id=F("goods__goods_on_application__application_id"),
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ def setUp(self):
super().setUp()

self.other_team = self.create_team("other team")
self.other_team_gov_user = self.create_gov_user("new_user@digital.trade.gov.uk", self.other_team)
self.other_team_gov_user = self.create_gov_user("new_user@digital.trade.gov.uk", self.other_team) # /PS-IGNORE
self.queue = self.create_queue("my new queue", self.team)
self.case = self.create_standard_application_case(self.organisation)
self.case.queues.set([self.queue])
Expand Down Expand Up @@ -1011,7 +1011,7 @@ def test_api_success(self):
self._create_data()
self.advice = FinalAdviceFactory(user=self.gov_user, case=self.case, type=AdviceType.APPROVE, good=self.good)
self.gov_user2 = self.create_gov_user(
team=self.create_team(name="other_team"), email="new_user2@digital.trade.gov.uk"
team=self.create_team(name="other_team"), email="new_user2@digital.trade.gov.uk" # /PS-IGNORE
)
self.group_advice = FinalAdviceFactory(
user=self.gov_user2, case=self.case, type=AdviceType.REFUSE, good=self.good
Expand Down Expand Up @@ -1148,12 +1148,33 @@ def test_api_success(self):
],
)

# Reflect rest framework's way of rendering datetime objects... https://github.com/encode/django-rest-framework/blob/c9e7b68a4c1db1ac60e962053380acda549609f3/rest_framework/utils/encoders.py#L29
# Reflect rest framework's way of rendering datetime objects... https://github.com/encode/django-rest-framework/blob/c9e7b68a4c1db1ac60e962053380acda549609f3/rest_framework/utils/encoders.py#L29 /PS-IGNORE
expected_submitted_at = self.case.submitted_at.isoformat()
if expected_submitted_at.endswith("+00:00"):
expected_submitted_at = expected_submitted_at[:-6] + "Z"
self.assertEqual(case_api_result["submitted_at"], expected_submitted_at)

def test_api_multiple_cases_flags_correct(self):
# Create two cases..
self._create_data()
self._create_data()
# Add a case flag to each case..
flag_alias = "REFER_TO_FCDO_MEUC_CONCERNS"
flag = Flag.objects.get(alias=flag_alias)
all_cases = Case.objects.all()
for case in all_cases:
case.flags.add(flag)

# Perform the search
response = self.client.get(self.url, **self.gov_headers)
response_data = response.json()["results"]

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response_data["cases"]), 2)
for search_result in response_data["cases"]:
self.assertEqual(len(search_result["flags"]), 1)
self.assertEqual(search_result["flags"][0]["alias"], flag_alias)

def test_api_no_advice(self):
self._create_data()
response = self.client.get(self.url, **self.gov_headers)
Expand Down
1 change: 0 additions & 1 deletion api/cases/views/search/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def get(self, request, *args, **kwargs):
# Populate certain fields outside of the serializer for performance improvements
service.populate_goods_flags(cases)
service.populate_destinations_flags(cases)
service.populate_other_flags(cases)
service.populate_organisation(cases)
service.populate_is_recently_updated(cases)
service.populate_activity_updates(case_map)
Expand Down
2 changes: 1 addition & 1 deletion api/conf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@
{
"un_sanctions_file": "https://scsanctions.un.org/resources/xml/en/consolidated.xml",
"office_financial_sanctions_file": "https://ofsistorage.blob.core.windows.net/publishlive/2022format/ConList.xml",
"uk_sanctions_file": "https://assets.publishing.service.gov.uk/media/65ca02639c5b7f0012951caf/UK_Sanctions_List.xml", # /PS-IGNORE
"uk_sanctions_file": "https://assets.publishing.service.gov.uk/media/6776a7d49d03f12136308d1c/UK_Sanctions_List.xml", # /PS-IGNORE
},
)
LITE_INTERNAL_NOTIFICATION_EMAILS = env.json("LITE_INTERNAL_NOTIFICATION_EMAILS", {})
Expand Down
6 changes: 5 additions & 1 deletion api/organisations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,11 @@ class OrganisationRegistrationNumberSerializer(serializers.Serializer):
def validate_registration_number(self, value):
# Check for uniqueness only when creating a new Organisation
if not self.instance:
if Organisation.objects.filter(registration_number=value).exists():
if (
Organisation.objects.filter(registration_number=value)
.exclude(status__in=[OrganisationStatus.REJECTED, OrganisationStatus.DRAFT])
.exists()
):
raise serializers.ValidationError("This registration number is already in use.")

return value
12 changes: 10 additions & 2 deletions api/organisations/tests/test_organisations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest

from unittest import mock
from django.conf import settings
from faker import Faker
from parameterized import parameterized

Expand All @@ -14,7 +13,6 @@
from api.core.authentication import EXPORTER_USER_TOKEN_HEADER
from api.core.constants import Roles, GovPermissions
from lite_content.lite_api.strings import Organisations
from api.organisations.constants import UK_VAT_VALIDATION_REGEX, UK_EORI_VALIDATION_REGEX
from api.organisations.enums import OrganisationType, OrganisationStatus
from api.organisations.tests.factories import OrganisationFactory
from api.organisations.models import Organisation
Expand Down Expand Up @@ -974,3 +972,13 @@ def test_validate_registration_number_fail(self):
self.assertEqual(
response.json(), {"errors": {"registration_number": ["This registration number is already in use."]}}
)

@parameterized.expand([OrganisationStatus.REJECTED, OrganisationStatus.DRAFT])
def test_validate_registration_number_success_for_rejected_or_draft_org(self, org_status):
self.organisation.refresh_from_db()
self.organisation.status = org_status
self.organisation.save()
data = {"registration_number": self.organisation.registration_number}
response = self.client.post(self.url, data, **self.exporter_headers)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json(), data)
Loading