Skip to content

Commit

Permalink
Merge pull request #782 from uktrade/revert-769-LTD-855-expiry-valida…
Browse files Browse the repository at this point in the history
…tion

Revert "Add additional certificate expiry validation"
  • Loading branch information
saruniitr authored Jul 1, 2021
2 parents 3ebd2ef + 92e7965 commit eb8c5ab
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 446 deletions.
8 changes: 4 additions & 4 deletions api/applications/serializers/good.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from api.goods.enums import GoodControlled, ItemType
from api.goods.helpers import update_firearms_certificate_data
from api.goods.models import Good
from api.goods.serializers import GoodSerializerInternal, FirearmGoodDetailsSerializer
from api.goods.serializers import GoodSerializerInternal, FirearmDetailsSerializer
from api.licences.models import GoodOnLicence
from api.organisations.models import DocumentOnOrganisation
from api.staticdata.control_list_entries.serializers import ControlListEntrySerializer
Expand Down Expand Up @@ -68,7 +68,7 @@ class GoodOnApplicationViewSerializer(serializers.ModelSerializer):
control_list_entries = ControlListEntrySerializer(many=True)
audit_trail = serializers.SerializerMethodField()
is_good_controlled = KeyValueChoiceField(choices=GoodControlled.choices)
firearm_details = FirearmGoodDetailsSerializer()
firearm_details = FirearmDetailsSerializer()

class Meta:
model = GoodOnApplication
Expand Down Expand Up @@ -125,7 +125,7 @@ class GoodOnApplicationCreateSerializer(serializers.ModelSerializer):
max_length=100,
error_messages={"required": strings.Goods.OTHER_ITEM_TYPE, "blank": strings.Goods.OTHER_ITEM_TYPE},
)
firearm_details = FirearmGoodDetailsSerializer(required=False)
firearm_details = FirearmDetailsSerializer(required=False)

class Meta:
model = GoodOnApplication
Expand Down Expand Up @@ -190,7 +190,7 @@ def create(self, validated_data):
if validated_data.get("firearm_details"):
firearm_data.update(validated_data["firearm_details"])
firearm_data = update_firearms_certificate_data(validated_data["good"].organisation_id, firearm_data)
serializer = FirearmGoodDetailsSerializer(data=firearm_data)
serializer = FirearmDetailsSerializer(data=firearm_data)
serializer.is_valid(raise_exception=True)
validated_data["firearm_details"] = serializer.save()
return super().create(validated_data)
Expand Down
4 changes: 2 additions & 2 deletions api/applications/tests/test_standard_application_submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from api.core.constants import AutoGeneratedDocuments
from api.flags.enums import SystemFlags
from api.goods.enums import GoodStatus, ItemCategory
from api.goods.tests.factories import FirearmGoodDetailsFactory, GoodFactory
from api.goods.tests.factories import FirearmFactory, GoodFactory
from lite_content.lite_api import strings
from api.parties.enums import PartyType
from api.parties.models import PartyDocument
Expand Down Expand Up @@ -411,7 +411,7 @@ def test_standard_application_declaration_submit_tcs_false_failure(self):
def test_submit_standard_application_adds_system_case_flags_success(self, upload_bytes_file_func, html_to_pdf_func):
upload_bytes_file_func.return_value = None
html_to_pdf_func.return_value = None
firearm_details = FirearmGoodDetailsFactory()
firearm_details = FirearmFactory()
firearm_good = GoodFactory(
description="a good",
organisation=self.organisation,
Expand Down
9 changes: 1 addition & 8 deletions api/goods/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from django.utils import timezone
from dateutil.relativedelta import relativedelta

from rest_framework import serializers
from rest_framework.exceptions import ValidationError

Expand Down Expand Up @@ -140,7 +138,7 @@ def validate_firearms_act_certificate_expiry_date(validated_data):
if covered_by_firearms_act == "No" or covered_by_firearms_act == "Unsure":
return

certificate_missing = validated_data.get("section_certificate_missing", False)
certificate_missing = validated_data.get("section_certificate_missing", False) == True
if certificate_missing:
if validated_data.get("section_certificate_missing_reason", "") == "":
errors["section_certificate_missing_reason"] = "Enter a reason why you do not have a section 1 certificate"
Expand All @@ -159,11 +157,6 @@ def validate_firearms_act_certificate_expiry_date(validated_data):
if date_of_expiry and date_of_expiry < timezone.now().date():
errors["section_certificate_date_of_expiry"] = strings.Goods.FIREARM_GOOD_INVALID_EXPIRY_DATE

difference_in_years = relativedelta(date_of_expiry, timezone.now().date()).years

if difference_in_years >= 5:
errors["section_certificate_date_of_expiry"] = "Expiry date is too far in the future"

if errors:
raise serializers.ValidationError(errors)

Expand Down
44 changes: 18 additions & 26 deletions api/goods/libraries/save_good.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,26 @@
from api.core.helpers import str_to_bool


def flatten_errors(errors, data):
pv_grading_errors = errors.pop("pv_grading_details", {})
firearm_errors = errors.pop("firearm_details", {})
# The errors need to be flattened otherwise they will be contained within
# nested 'pv_grading_details', 'firearm_details' and 'document_on_organisation' dictionaries
document_on_organisation_errors = firearm_errors.pop("document_on_organisation", {})

flattened_errors = {
**errors,
**firearm_errors,
**pv_grading_errors,
**document_on_organisation_errors,
}
if data.get("firearm_details"):
if (
data["firearm_details"].get("rfd_status") is True
and "is_covered_by_firearm_act_section_one_two_or_five" in flattened_errors
):
flattened_errors["is_covered_by_firearm_act_section_one_two_or_five"] = [
"Select yes if the product is covered by section 5 of the Firearms Act 1968"
]

return flattened_errors


def create_or_update_good(serializer, data, is_created):
if not serializer.is_valid():
flattened_errors = flatten_errors(serializer.errors, data)
errors = serializer.errors
pv_grading_errors = errors.pop("pv_grading_details", None)
firearm_errors = errors.pop("firearm_details", None)
# The errors need to be flattened otherwise they will be contained within a 'pv_grading_details' dict
if firearm_errors:
flattened_errors = (
{**errors, **firearm_errors, **pv_grading_errors} if pv_grading_errors else {**errors, **firearm_errors}
)
if (
data["firearm_details"].get("rfd_status") is True
and "is_covered_by_firearm_act_section_one_two_or_five" in flattened_errors
):
flattened_errors["is_covered_by_firearm_act_section_one_two_or_five"] = [
"Select yes if the product is covered by section 5 of the Firearms Act 1968"
]

else:
flattened_errors = {**errors, **pv_grading_errors} if pv_grading_errors else errors
return JsonResponse(data={"errors": flattened_errors}, status=status.HTTP_400_BAD_REQUEST)

if str_to_bool(data.get("validate_only")):
Expand Down
63 changes: 15 additions & 48 deletions api/goods/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from api.gov_users.serializers import GovUserSimpleSerializer
from lite_content.lite_api import strings
from api.organisations.models import Organisation
from api.organisations.serializers import DocumentOnOrganisationSerializer
from api.queries.goods_query.models import GoodsQuery
from api.staticdata.control_list_entries.serializers import ControlListEntrySerializer
from api.staticdata.missing_document_reasons.enums import GoodMissingDocumentReasons
Expand Down Expand Up @@ -91,7 +90,7 @@ def to_internal_value(self, data):
raise error


class FirearmGoodDetailsSerializer(serializers.ModelSerializer):
class FirearmDetailsSerializer(serializers.ModelSerializer):
type = KeyValueChoiceField(
choices=FirearmGoodType.choices,
allow_null=False,
Expand Down Expand Up @@ -138,10 +137,6 @@ class FirearmGoodDetailsSerializer(serializers.ModelSerializer):
)
serial_numbers = serializers.ListField(child=serializers.CharField(allow_blank=True), required=False)

is_registered_firearm_dealer = serializers.BooleanField(allow_null=True, required=False)

document_on_organisation = DocumentOnOrganisationSerializer(allow_null=True, required=False)

class Meta:
model = FirearmGoodDetails
fields = (
Expand All @@ -168,27 +163,10 @@ class Meta:
"deactivation_standard_other",
"number_of_items",
"serial_numbers",
# non model fields below included for validation only
"is_registered_firearm_dealer",
"document_on_organisation",
)

def create(self, validated_data):
# These fields not in the model so remove before create
if "is_registered_firearm_dealer" in validated_data:
validated_data.pop("is_registered_firearm_dealer")

if validated_data.get("document_on_organisation"):
validated_data["document_on_organisation"] = DocumentOnOrganisationSerializer.create(
DocumentOnOrganisationSerializer(context=self.context),
validated_data=validated_data["document_on_organisation"],
)
validated_data.pop("document_on_organisation")

return super().create(validated_data)

def validate(self, data):
validated_data = super().validate(data)
validated_data = super(FirearmDetailsSerializer, self).validate(data)

# Year of manufacture should be in the past and a valid year
year_of_manufacture = validated_data.get("year_of_manufacture")
Expand All @@ -209,7 +187,7 @@ def validate(self, data):
raise serializers.ValidationError({"is_replica": "Select yes if the product is a replica firearm"})

if validated_data.get("is_replica") is True:
if "replica_description" not in validated_data or validated_data.get("replica_description") == "":
if "replica_description" not in validated_data or validated_data.get("replica_description") is "":
raise serializers.ValidationError({"replica_description": "Enter description"})
if validated_data.get("is_replica") is not None and "firearms" != validated_data.get("type"):
raise serializers.ValidationError({"is_replica": "Invalid firearm product type"})
Expand All @@ -229,14 +207,6 @@ def validate(self, data):
{"is_sporting_shotgun": [get_sporting_shortgun_errormsg(validated_data.get("type"))]}
)

if (
"is_registered_firearm_dealer" in validated_data
and validated_data.get("is_registered_firearm_dealer") is None
):
raise serializers.ValidationError(
{"is_registered_firearm_dealer": ["Select yes if you are a registered firearms dealer"]}
)

if validated_data.get("has_proof_mark") is False and validated_data.get("no_proof_mark_details") == "":
raise serializers.ValidationError({"no_proof_mark_details": ["This field is required"]})
if validated_data.get("is_deactivated"):
Expand Down Expand Up @@ -392,7 +362,7 @@ class GoodCreateSerializer(serializers.ModelSerializer):
software_or_technology_details = serializers.CharField(
allow_null=True, required=False, allow_blank=True, max_length=2000
)
firearm_details = FirearmGoodDetailsSerializer(allow_null=True, required=False)
firearm_details = FirearmDetailsSerializer(allow_null=True, required=False)

class Meta:
model = Good
Expand Down Expand Up @@ -452,13 +422,6 @@ def __init__(self, *args, **kwargs):
if "section_certificate_date_of_expiry" in firearm_details:
firearm_details.pop("section_certificate_date_of_expiry")

# If user has answered No to registered firearms dealer question, don't validate RFD document upload
if (
not str_to_bool(firearm_details.get("is_registered_firearm_dealer"))
and "document_on_organisation" in firearm_details
):
firearm_details.pop("document_on_organisation")

if "has_identification_markings" in firearm_details:
# Keep only the details relevant for the yes/no answer
if str_to_bool(firearm_details.get("has_identification_markings")):
Expand Down Expand Up @@ -517,8 +480,8 @@ def create(self, validated_data):
)

if validated_data.get("firearm_details"):
validated_data["firearm_details"] = FirearmGoodDetailsSerializer.create(
FirearmGoodDetailsSerializer(context=self.context), validated_data=validated_data["firearm_details"]
validated_data["firearm_details"] = GoodCreateSerializer._create_firearm_details(
validated_data["firearm_details"]
)

return super(GoodCreateSerializer, self).create(validated_data)
Expand Down Expand Up @@ -630,10 +593,14 @@ def _delete_pv_grading_details(instance):
instance.delete()
return None

@staticmethod
def _create_firearm_details(firearm_details):
return FirearmDetailsSerializer.create(FirearmDetailsSerializer(), validated_data=firearm_details)

@staticmethod
def _update_firearm_details(firearm_details, instance):
return FirearmGoodDetailsSerializer.update(
FirearmGoodDetailsSerializer(), validated_data=firearm_details, instance=instance,
return FirearmDetailsSerializer.update(
FirearmDetailsSerializer(), validated_data=firearm_details, instance=instance,
)


Expand Down Expand Up @@ -750,7 +717,7 @@ class GoodSerializerInternal(serializers.Serializer):
is_document_available = serializers.BooleanField()
is_document_sensitive = serializers.BooleanField()
software_or_technology_details = serializers.CharField()
firearm_details = FirearmGoodDetailsSerializer(allow_null=True, required=False)
firearm_details = FirearmDetailsSerializer(allow_null=True, required=False)
is_precedent = serializers.BooleanField(required=False, default=False)

def get_documents(self, instance):
Expand All @@ -759,7 +726,7 @@ def get_documents(self, instance):


class TinyGoodDetailsSerializer(serializers.ModelSerializer):
firearm_details = FirearmGoodDetailsSerializer(read_only=True)
firearm_details = FirearmDetailsSerializer(read_only=True)

class Meta:
model = Good
Expand Down Expand Up @@ -794,7 +761,7 @@ class GoodSerializerExporter(serializers.Serializer):
information_security_details = serializers.CharField()
pv_grading_details = PvGradingDetailsSerializer(allow_null=True, required=False)
software_or_technology_details = serializers.CharField()
firearm_details = FirearmGoodDetailsSerializer(allow_null=True, required=False)
firearm_details = FirearmDetailsSerializer(allow_null=True, required=False)


class GoodSerializerExporterFullDetail(GoodSerializerExporter):
Expand Down
2 changes: 1 addition & 1 deletion api/goods/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def flags(self, create, extracted, **kwargs):
self.flags.set(extracted)


class FirearmGoodDetailsFactory(factory.django.DjangoModelFactory):
class FirearmFactory(factory.django.DjangoModelFactory):
type = FirearmGoodType.AMMUNITION
year_of_manufacture = 2019
calibre = "5.56x45mm"
Expand Down
Loading

0 comments on commit eb8c5ab

Please sign in to comment.