Skip to content

Commit

Permalink
Merge branch 'master' into LTD-1239-departments-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Manos authored Sep 30, 2021
2 parents 29ce03d + 61403a2 commit a56049f
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 0 deletions.
32 changes: 32 additions & 0 deletions api/applications/serializers/standard_application.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.db.models import Q
from rest_framework import serializers
from rest_framework.fields import CharField

Expand All @@ -17,10 +18,13 @@
from api.applications.serializers.good import GoodOnApplicationViewSerializer
from api.licences.serializers.view_licence import CaseLicenceViewSerializer
from api.applications.serializers.serializer_helper import validate_field
from api.audit_trail.enums import AuditType
from api.audit_trail.models import Audit
from api.cases.enums import CaseTypeEnum
from api.core.serializers import KeyValueChoiceField
from api.licences.models import Licence
from lite_content.lite_api import strings
from api.staticdata.statuses.enums import CaseStatusEnum
from api.staticdata.trade_control.enums import TradeControlProductCategory, TradeControlActivity


Expand All @@ -34,6 +38,7 @@ class StandardApplicationViewSerializer(PartiesSerializerMixin, GenericApplicati
trade_control_activity = serializers.SerializerMethodField()
trade_control_product_categories = serializers.SerializerMethodField()
sanction_matches = serializers.SerializerMethodField()
is_amended = serializers.SerializerMethodField()

class Meta:
model = StandardApplication
Expand Down Expand Up @@ -69,6 +74,7 @@ class Meta:
"trade_control_activity",
"trade_control_product_categories",
"sanction_matches",
"is_amended",
)
)

Expand Down Expand Up @@ -99,6 +105,32 @@ def get_denial_matches(self, instance):
denial_matches = DenialMatchOnApplication.objects.filter(application=instance, denial__is_revoked=False)
return DenialMatchOnApplicationViewSerializer(denial_matches, many=True).data

def get_is_amended(self, instance):
"""Determines whether an application is major/minor edited using Audit logs
and returns True if either of the amends are done, False otherwise"""
audit_qs = Audit.objects.filter(target_object_id=instance.id)
is_reference_name_updated = audit_qs.filter(verb=AuditType.UPDATED_APPLICATION_NAME).exists()
is_product_removed = audit_qs.filter(verb=AuditType.REMOVE_GOOD_FROM_APPLICATION).exists()
app_letter_ref_updated = audit_qs.filter(
Q(
verb__in=[
AuditType.ADDED_APPLICATION_LETTER_REFERENCE,
AuditType.UPDATE_APPLICATION_LETTER_REFERENCE,
AuditType.REMOVED_APPLICATION_LETTER_REFERENCE,
]
)
)
# in case of doing major edits then the status is set as "Applicant editing"
# Here we are detecting the transition from "Submitted" -> "Applicant editing"
for item in audit_qs.filter(verb=AuditType.UPDATED_STATUS):
status = item.payload["status"]
if status["old"] == CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED) and status[
"new"
] == CaseStatusEnum.get_text(CaseStatusEnum.APPLICANT_EDITING):
return True

return any([is_reference_name_updated, app_letter_ref_updated, is_product_removed])


class StandardApplicationCreateSerializer(GenericApplicationCreateSerializer):
export_type = KeyValueChoiceField(
Expand Down
4 changes: 4 additions & 0 deletions api/applications/tests/test_application_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from parameterized import parameterized
from rest_framework import status

from api.audit_trail.models import AuditType, Audit
from api.cases.models import CaseAssignment
from gov_notify.enums import TemplateType
from api.licences.enums import LicenceStatus
Expand Down Expand Up @@ -57,6 +58,9 @@ def test_exporter_set_application_status_applicant_editing_when_in_editable_stat

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(self.standard_application.status, get_case_status_by_status(CaseStatusEnum.APPLICANT_EDITING))
audit_event = Audit.objects.first()
self.assertEqual(audit_event.verb, AuditType.UPDATED_STATUS)
self.assertEqual(audit_event.payload, {"status": {"new": "Applicant editing", "old": "Submitted"}})

def test_exporter_set_application_status_withdrawn_when_application_not_terminal_success(self):
self.submit_application(self.standard_application)
Expand Down
1 change: 1 addition & 0 deletions api/applications/tests/test_edit_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def test_edit_application_name_in_editable_status_success(self, editable_status)
self.assertEqual(application.name, self.data["name"])
self.assertNotEqual(application.updated_at, updated_at)
self.assertEqual(audit_qs.count(), 2)
self.assertEqual(audit_object.verb, AuditType.UPDATED_APPLICATION_NAME)
self.assertEqual(audit_object.payload, {"new_name": self.data["name"], "old_name": old_name})

@parameterized.expand(get_case_statuses(read_only=True))
Expand Down
3 changes: 3 additions & 0 deletions api/applications/tests/test_removing_goods.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from api.applications.libraries.case_status_helpers import get_case_statuses
from api.applications.models import GoodOnApplication
from api.audit_trail.models import Audit, AuditType
from api.flags.enums import SystemFlags
from api.goods.enums import GoodStatus
from api.goods.models import Good, FirearmGoodDetails
Expand Down Expand Up @@ -88,6 +89,8 @@ def test_remove_a_good_from_application_success_when_good_is_on_multiple_applica
self.assertEqual(
Good.objects.get(pk=good_on_application2.good.pk).status, GoodStatus.SUBMITTED,
)
audit_event = Audit.objects.first()
self.assertEqual(audit_event.verb, AuditType.REMOVE_GOOD_FROM_APPLICATION)

def test_remove_a_good_that_does_not_exist_from_draft(self):
"""
Expand Down
1 change: 1 addition & 0 deletions api/data_workspace/tests/test_application_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def test_dw_standard_application_views(self):
"destinations",
"denial_matches",
"licence",
"is_amended",
)
for key in expected_keys:
self.assertTrue(key in actual_keys)
Expand Down
Empty file.
Empty file.
57 changes: 57 additions & 0 deletions api/teams/management/commands/edit_teams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import csv
import logging

from django.core.management.base import BaseCommand
from django.db import transaction

from api.teams.models import Team

log = logging.getLogger(__name__)


class Command(BaseCommand):
"""Update team records from a CSV file.
The first line in the file is a header that consists of the field names on the Team model
to update. A subset of field names can be specified, but the first column must always be `id`.
For example, to update just the team name and is_ogd attribute for two teams, the file would contain:
id,name,is_ogd
57c341d6-7a28-473f-a6c8-5952742b6b03,team1_new_name,true
94996aa5-f494-4116-9e74-d757d39c5ee8,team2_new_name,false
"""

help = "Updates teams from a CSV input file"

def add_arguments(self, parser):
parser.add_argument("input_csv", type=str, help="Path to the input CSV file")
parser.add_argument(
"--dry", action="store_true", help="Print out what action will happen without applying any changes"
)

def handle(self, *args, **options):
dry_run = options["dry"]
if dry_run:
log.info("Dry run only, no changes will be applied")

with open(options["input_csv"]) as w:
reader = csv.DictReader(w)
to_update = [{k: v.strip() for k, v in record.items()} for record in reader]

with transaction.atomic():
for record in to_update:
team = Team.objects.filter(id=record.pop("id")) # id must always exist
log.info(f"Updating '{team[0].name}' with {record}")

if not dry_run:
converters = {
"name": str,
"department": lambda x: str(x) if x else None,
"part_of_ecju": lambda x: x.lower() == "true",
"is_ogd": lambda x: x.lower() == "true",
}

team.update(
**{attr_name: converters[attr_name](attr_val) for attr_name, attr_val in record.items()}
)

0 comments on commit a56049f

Please sign in to comment.