11from django .conf import settings
22from django .contrib .postgres .fields import ArrayField
3- from django .db import models
3+ from django .db import models , transaction
44from django .utils .translation import gettext_lazy as _
55
66from api .models import Admin2 , Country , DisasterType , District
@@ -206,9 +206,14 @@ class EAPBaseModel(models.Model):
206206 related_name = "%(class)s_modified_by" ,
207207 )
208208
209+ # TYPING
210+ id : int
211+ created_by_id : int
212+ modified_by_id : int
213+
209214 class Meta :
210215 abstract = True
211- ordering = ["-created_at " ]
216+ ordering = ["-id " ]
212217
213218
214219class EAPFile (EAPBaseModel ):
@@ -224,6 +229,7 @@ class EAPFile(EAPBaseModel):
224229 class Meta :
225230 verbose_name = _ ("eap file" )
226231 verbose_name_plural = _ ("eap files" )
232+ ordering = ["-id" ]
227233
228234
229235class OperationActivity (models .Model ):
@@ -377,7 +383,7 @@ class EAPStatus(models.IntegerChoices):
377383 """Initial status when an EAP is being created."""
378384
379385 UNDER_REVIEW = 20 , _ ("Under Review" )
380- """ EAP has been submitted by NS. It is under review by IFRC and/or technical partners."""
386+ """EAP has been submitted by NS. It is under review by IFRC and/or technical partners."""
381387
382388 NS_ADDRESSING_COMMENTS = 30 , _ ("NS Addressing Comments" )
383389 """NS is addressing comments provided during the review process.
@@ -471,6 +477,14 @@ class EAPRegistration(EAPBaseModel):
471477 help_text = _ ("Upload the validated budget file once the EAP is technically validated." ),
472478 )
473479
480+ # Review checklist
481+ review_checklist_file = SecureFileField (
482+ verbose_name = _ ("Review Checklist File" ),
483+ upload_to = "eap/files/" ,
484+ null = True ,
485+ blank = True ,
486+ )
487+
474488 # Contacts
475489 # National Society
476490 national_society_contact_name = models .CharField (
@@ -537,6 +551,7 @@ class EAPRegistration(EAPBaseModel):
537551 class Meta :
538552 verbose_name = _ ("Development Registration EAP" )
539553 verbose_name_plural = _ ("Development Registration EAPs" )
554+ ordering = ["-id" ]
540555
541556 def __str__ (self ):
542557 # NOTE: Use select_related in admin get_queryset for national_society field to avoid extra queries
@@ -546,7 +561,9 @@ def __str__(self):
546561 def has_eap_application (self ) -> bool :
547562 """Check if the EAP Registration has an associated EAP application."""
548563 # TODO(susilnem): Add FULL EAP check, when model is created.
549- return hasattr (self , "simplified_eap" )
564+ if hasattr (self , "simplified_eap" ) and self .simplified_eap .exists ():
565+ return True
566+ return False
550567
551568 @property
552569 def get_status_enum (self ) -> EAPStatus :
@@ -574,7 +591,7 @@ def update_eap_type(self, eap_type: EAPType, commit: bool = True):
574591class SimplifiedEAP (EAPBaseModel ):
575592 """Model representing a Simplified EAP."""
576593
577- eap_registration = models .OneToOneField [EAPRegistration , EAPRegistration ](
594+ eap_registration = models .ForeignKey [EAPRegistration , EAPRegistration ](
578595 EAPRegistration ,
579596 on_delete = models .CASCADE ,
580597 verbose_name = _ ("EAP Development Registration" ),
@@ -865,13 +882,70 @@ class SimplifiedEAP(EAPBaseModel):
865882 blank = True ,
866883 )
867884
885+ # Review Checklist
886+ updated_checklist_file = SecureFileField (
887+ verbose_name = _ ("Updated Checklist File" ),
888+ upload_to = "eap/files/" ,
889+ null = True ,
890+ blank = True ,
891+ )
892+
893+ # NOTE: Snapshot fields
894+ version = models .IntegerField (
895+ verbose_name = _ ("Version" ),
896+ help_text = _ ("Version identifier for the Simplified EAP." ),
897+ default = 1 ,
898+ )
899+ is_locked = models .BooleanField (
900+ verbose_name = _ ("Is Locked?" ),
901+ help_text = _ ("Indicates whether the Simplified EAP is locked for editing." ),
902+ default = False ,
903+ )
904+ parent = models .ForeignKey (
905+ "self" ,
906+ on_delete = models .SET_NULL ,
907+ verbose_name = _ ("Parent Simplified EAP" ),
908+ help_text = _ ("Reference to the parent Simplified EAP if this is a snapshot." ),
909+ null = True ,
910+ blank = True ,
911+ related_name = "snapshots" ,
912+ )
913+
868914 # TYPING
869915 eap_registration_id : int
916+ parent_id : int
870917 id = int
871918
872919 class Meta :
873920 verbose_name = _ ("Simplified EAP" )
874921 verbose_name_plural = _ ("Simplified EAPs" )
922+ ordering = ["-id" ]
875923
876924 def __str__ (self ):
877- return f"Simplified EAP for { self .eap_registration } "
925+ return f"Simplified EAP for { self .eap_registration } - version:{ self .version } "
926+
927+ def generate_snapshot (self ):
928+ """
929+ Generate a snapshot of the given Simplified EAP.
930+ """
931+
932+ from eap .utils import copy_model_instance
933+
934+ with transaction .atomic ():
935+ copy_model_instance (
936+ self ,
937+ overrides = {
938+ "parent_id" : self .id ,
939+ "version" : self .version + 1 ,
940+ "created_by_id" : self .created_by_id ,
941+ "modified_by_id" : self .modified_by_id ,
942+ "updated_checklist_file" : None ,
943+ },
944+ exclude_clone_m2m_fields = [
945+ "admin2" ,
946+ ],
947+ )
948+
949+ # Setting Parent as locked
950+ self .is_locked = True
951+ self .save (update_fields = ["is_locked" ])
0 commit comments