Skip to content

Commit 445dd41

Browse files
authored
Merge pull request #4592 from unicef/ordering-models
ordering models
2 parents e4f483c + 180f68b commit 445dd41

File tree

23 files changed

+285
-267
lines changed

23 files changed

+285
-267
lines changed

src/hct_mis_api/api/models.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@ def choices(cls) -> Tuple[Tuple[Any, Any], ...]:
3030
class APIToken(models.Model):
3131
user = models.ForeignKey(User, on_delete=models.CASCADE)
3232
key = models.CharField(_("Key"), max_length=40, unique=True, blank=True)
33-
allowed_ips = models.CharField(_("IPs"), max_length=200, blank=True, null=True)
34-
valid_from = models.DateField(default=timezone.now)
35-
valid_to = models.DateField(blank=True, null=True)
36-
37-
valid_for = models.ManyToManyField(BusinessArea)
3833
grants = ChoiceArrayField(
3934
models.CharField(choices=Grant.choices(), max_length=255),
4035
)
36+
valid_from = models.DateField(default=timezone.now)
37+
valid_to = models.DateField(blank=True, null=True)
38+
valid_for = models.ManyToManyField(BusinessArea)
39+
allowed_ips = models.CharField(_("IPs"), max_length=200, blank=True, null=True)
4140

4241
def __str__(self) -> str:
4342
return f"Token #{self.pk}"

src/hct_mis_api/apps/account/admin/user_role.py

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class UserRoleInline(admin.TabularInline):
2424
model = account_models.UserRole
2525
extra = 0
2626
formset = UserRoleInlineFormSet
27+
raw_id_fields = ("business_area", "role")
2728

2829

2930
@admin.register(account_models.UserRole)

src/hct_mis_api/apps/account/models.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,9 @@ def formfield(self, form_class: Optional[Any] = ..., choices_form_class: Optiona
322322

323323

324324
class UserRole(NaturalKeyModel, TimeStampedUUIDModel):
325-
business_area = models.ForeignKey("core.BusinessArea", related_name="user_roles", on_delete=models.CASCADE)
326325
user = models.ForeignKey("account.User", related_name="user_roles", on_delete=models.CASCADE)
327326
role = models.ForeignKey("account.Role", related_name="user_roles", on_delete=models.CASCADE)
327+
business_area = models.ForeignKey("core.BusinessArea", related_name="user_roles", on_delete=models.CASCADE)
328328
expiry_date = models.DateField(
329329
blank=True, null=True, help_text="After expiry date this User Role will be inactive."
330330
)
@@ -337,9 +337,9 @@ def __str__(self) -> str:
337337

338338

339339
class UserGroup(NaturalKeyModel, models.Model):
340-
business_area = models.ForeignKey("core.BusinessArea", related_name="user_groups", on_delete=models.CASCADE)
341340
user = models.ForeignKey("account.User", related_name="user_groups", on_delete=models.CASCADE)
342341
group = models.ForeignKey(Group, related_name="user_groups", on_delete=models.CASCADE)
342+
business_area = models.ForeignKey("core.BusinessArea", related_name="user_groups", on_delete=models.CASCADE)
343343

344344
class Meta:
345345
unique_together = ("business_area", "user", "group")

src/hct_mis_api/apps/accountability/admin.py

+12
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@ class MessageAdmin(AdminAdvancedFiltersMixin, HOPEModelAdminBase, IsOriginalAdmi
5656
"title",
5757
"body",
5858
"business_area",
59+
"program",
60+
"payment_plan",
5961
"registration_data_import",
6062
"sampling_type",
6163
"sample_size",
64+
"created_by",
65+
"copied_from",
66+
"is_original",
6267
)
6368
list_display = (
6469
"unicef_id",
@@ -92,6 +97,13 @@ class SurveyAdmin(HOPEModelAdminBase):
9297
"sample_file",
9398
"sample_size",
9499
)
100+
readonly_fields = (
101+
"category",
102+
"created_by",
103+
"payment_plan",
104+
"program",
105+
"business_area",
106+
)
95107
list_filter = ("category", ("flow_id", AutoCompleteFilter))
96108
search_fields = ("unicef_id", "title")
97109
raw_id_fields = ("created_by", "payment_plan", "program", "business_area")

src/hct_mis_api/apps/accountability/models.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ class Feedback(TimeStampedUUIDModel, AdminUrlMixin, UnicefIdentifiedModel):
118118
(NEGATIVE_FEEDBACK, _("Negative feedback")),
119119
)
120120

121-
business_area = models.ForeignKey("core.BusinessArea", on_delete=models.CASCADE)
122121
issue_type = models.CharField(verbose_name=_("Issue type"), choices=ISSUE_TYPE_CHOICES, max_length=20)
123122
household_lookup = models.ForeignKey(
124123
"household.Household",
@@ -136,13 +135,13 @@ class Feedback(TimeStampedUUIDModel, AdminUrlMixin, UnicefIdentifiedModel):
136135
on_delete=models.SET_NULL,
137136
verbose_name=_("Individual lookup"),
138137
)
139-
description = models.TextField()
140-
comments = models.TextField(blank=True, null=True)
141-
admin2 = models.ForeignKey("geo.Area", null=True, blank=True, on_delete=models.SET_NULL)
138+
business_area = models.ForeignKey("core.BusinessArea", on_delete=models.CASCADE)
139+
program = models.ForeignKey("program.Program", null=True, blank=True, on_delete=models.CASCADE)
142140
area = models.CharField(max_length=250, blank=True)
141+
admin2 = models.ForeignKey("geo.Area", null=True, blank=True, on_delete=models.SET_NULL)
142+
description = models.TextField()
143143
language = models.TextField(blank=True)
144-
consent = models.BooleanField(default=True)
145-
program = models.ForeignKey("program.Program", null=True, blank=True, on_delete=models.CASCADE)
144+
comments = models.TextField(blank=True, null=True)
146145
created_by = models.ForeignKey(
147146
settings.AUTH_USER_MODEL,
148147
on_delete=models.SET_NULL,
@@ -159,6 +158,7 @@ class Feedback(TimeStampedUUIDModel, AdminUrlMixin, UnicefIdentifiedModel):
159158
blank=True,
160159
verbose_name=_("Linked grievance"),
161160
)
161+
consent = models.BooleanField(default=True)
162162
is_original = models.BooleanField(db_index=True, default=False)
163163
copied_from = models.ForeignKey(
164164
"self",
@@ -267,15 +267,15 @@ class Survey(UnicefIdentifiedModel, AdminUrlMixin, TimeStampedUUIDModel):
267267
on_delete=models.SET_NULL,
268268
)
269269
business_area = models.ForeignKey("core.BusinessArea", on_delete=models.CASCADE)
270+
flow_id = models.CharField(max_length=255, blank=True, null=True)
271+
272+
sampling_type = models.CharField(max_length=50, choices=SAMPLING_CHOICES, default=SAMPLING_FULL_LIST)
273+
sample_size = models.PositiveIntegerField(default=0)
270274
sample_file = models.FileField(upload_to="", blank=True, null=True)
271275
sample_file_generated_at = models.DateTimeField(blank=True, null=True)
272276

273-
sampling_type = models.CharField(max_length=50, choices=SAMPLING_CHOICES, default=SAMPLING_FULL_LIST)
274277
full_list_arguments = models.JSONField(default=dict)
275278
random_sampling_arguments = models.JSONField(default=dict)
276-
sample_size = models.PositiveIntegerField(default=0)
277-
278-
flow_id = models.CharField(max_length=255, blank=True, null=True)
279279
successful_rapid_pro_calls = ArrayField(models.JSONField(), default=list)
280280

281281
class Meta:

src/hct_mis_api/apps/core/admin.py

+1
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ class XLSXKoboTemplateAdmin(SoftDeletableAdminMixin, HOPEModelAdminBase):
562562
"file",
563563
"import_status",
564564
"error_description",
565+
"first_connection_failed_time",
565566
)
566567

567568
def import_status(self, obj: Any) -> str:

src/hct_mis_api/apps/core/models.py

+33-31
Original file line numberDiff line numberDiff line change
@@ -70,36 +70,43 @@ class BusinessArea(NaturalKeyModel, TimeStampedUUIDModel):
7070
code_to_cash_assist_mapping = {"575RE00000": "SLVK"}
7171
cash_assist_to_code_mapping = {v: k for k, v in code_to_cash_assist_mapping.items()}
7272
code = models.CharField(max_length=10, unique=True)
73-
name = models.CharField(max_length=255)
74-
long_name = models.CharField(max_length=255)
75-
region_code = models.CharField(max_length=8)
76-
region_name = models.CharField(max_length=8)
77-
kobo_username = models.CharField(max_length=255, null=True, blank=True)
78-
kobo_token = models.CharField(max_length=255, null=True, blank=True)
79-
kobo_url = models.URLField(max_length=255, null=True, blank=True)
80-
rapid_pro_host = models.URLField(null=True, blank=True)
81-
rapid_pro_payment_verification_token = models.CharField(max_length=40, null=True, blank=True)
82-
rapid_pro_messages_token = models.CharField(max_length=40, null=True, blank=True)
83-
rapid_pro_survey_token = models.CharField(max_length=40, null=True, blank=True)
8473
slug = models.CharField(
8574
max_length=250,
8675
unique=True,
8776
db_index=True,
8877
)
89-
custom_fields = JSONField(default=dict, blank=True)
90-
91-
has_data_sharing_agreement = models.BooleanField(default=False)
78+
name = models.CharField(max_length=255)
79+
long_name = models.CharField(max_length=255)
9280
parent = models.ForeignKey(
9381
"self",
9482
related_name="children",
9583
on_delete=models.SET_NULL,
9684
null=True,
9785
blank=True,
9886
)
87+
partners = models.ManyToManyField(
88+
to="account.Partner", through=BusinessAreaPartnerThrough, related_name="business_areas"
89+
)
90+
countries = models.ManyToManyField("geo.Country", related_name="business_areas")
91+
9992
is_split = models.BooleanField(default=False)
93+
region_code = models.CharField(max_length=8)
94+
region_name = models.CharField(max_length=8)
95+
has_data_sharing_agreement = models.BooleanField(default=False)
96+
is_accountability_applicable = models.BooleanField(default=False)
97+
active = models.BooleanField(default=False)
98+
enable_email_notification = models.BooleanField(default=True, verbose_name="Automatic Email notifications enabled")
99+
100+
kobo_username = models.CharField(max_length=255, null=True, blank=True)
101+
kobo_token = models.CharField(max_length=255, null=True, blank=True)
102+
kobo_url = models.URLField(max_length=255, null=True, blank=True)
103+
104+
rapid_pro_host = models.URLField(null=True, blank=True)
105+
rapid_pro_payment_verification_token = models.CharField(max_length=40, null=True, blank=True)
106+
rapid_pro_messages_token = models.CharField(max_length=40, null=True, blank=True)
107+
rapid_pro_survey_token = models.CharField(max_length=40, null=True, blank=True)
100108

101109
postpone_deduplication = models.BooleanField(default=False)
102-
countries = models.ManyToManyField("geo.Country", related_name="business_areas")
103110
deduplication_duplicate_score = models.FloatField(
104111
default=6.0,
105112
validators=[MinValueValidator(0.0)],
@@ -134,13 +141,8 @@ class BusinessArea(NaturalKeyModel, TimeStampedUUIDModel):
134141
help_text="Threshold for Face Image Deduplication",
135142
validators=[MinValueValidator(0.0), MaxValueValidator(100.0)],
136143
)
137-
is_accountability_applicable = models.BooleanField(default=False)
138-
active = models.BooleanField(default=False)
139-
enable_email_notification = models.BooleanField(default=True, verbose_name="Automatic Email notifications enabled")
140144

141-
partners = models.ManyToManyField(
142-
to="account.Partner", through=BusinessAreaPartnerThrough, related_name="business_areas"
143-
)
145+
custom_fields = JSONField(default=dict, blank=True)
144146

145147
def save(self, *args: Any, **kwargs: Any) -> None:
146148
unique_slugify(self, self.name, slug_field_name="slug")
@@ -226,9 +228,12 @@ class FlexibleAttribute(SoftDeletableModel, NaturalKeyModel, TimeStampedUUIDMode
226228
(ASSOCIATED_WITH_INDIVIDUAL, _("Individual")),
227229
)
228230

229-
type = models.CharField(max_length=16, choices=TYPE_CHOICE)
230231
name = models.CharField(max_length=255)
231-
required = models.BooleanField(default=False)
232+
group = models.ForeignKey(
233+
"core.FlexibleAttributeGroup", on_delete=models.CASCADE, related_name="flex_attributes", null=True, blank=True
234+
)
235+
type = models.CharField(max_length=16, choices=TYPE_CHOICE)
236+
associated_with = models.SmallIntegerField(choices=ASSOCIATED_WITH_CHOICES)
232237
program = models.ForeignKey(
233238
"program.Program",
234239
on_delete=models.CASCADE,
@@ -243,12 +248,9 @@ class FlexibleAttribute(SoftDeletableModel, NaturalKeyModel, TimeStampedUUIDMode
243248
null=True,
244249
related_name="flex_field",
245250
)
251+
required = models.BooleanField(default=False)
246252
label = JSONField(default=dict, validators=[label_contains_english_en_validator])
247253
hint = JSONField(default=dict)
248-
group = models.ForeignKey(
249-
"core.FlexibleAttributeGroup", on_delete=models.CASCADE, related_name="flex_attributes", null=True, blank=True
250-
)
251-
associated_with = models.SmallIntegerField(choices=ASSOCIATED_WITH_CHOICES)
252254

253255
class Meta:
254256
constraints = [
@@ -347,8 +349,8 @@ class PeriodicFieldData(models.Model):
347349
)
348350

349351
subtype = models.CharField(max_length=16, choices=TYPE_CHOICES)
350-
number_of_rounds = models.IntegerField()
351352
rounds_names = ArrayField(models.CharField(max_length=255), default=list)
353+
number_of_rounds = models.IntegerField()
352354

353355
class Meta:
354356
verbose_name = "Periodic Field Data"
@@ -540,12 +542,10 @@ class Type(models.TextChoices):
540542
STANDARD = "STANDARD", "Standard"
541543
SOCIAL = "SOCIAL", "Social Workers"
542544

543-
label = models.CharField(max_length=32, blank=True)
544545
code = models.CharField(max_length=32)
546+
label = models.CharField(max_length=32, blank=True)
545547
type = models.CharField(choices=Type.choices, null=True, blank=True, max_length=32)
546548
description = models.TextField(blank=True)
547-
compatible_types = models.ManyToManyField("self", blank=True, symmetrical=False)
548-
limit_to = models.ManyToManyField(to="BusinessArea", related_name="data_collecting_types", blank=True)
549549
active = models.BooleanField(default=True)
550550
deprecated = models.BooleanField(
551551
default=False, help_text="Cannot be used in new programs, totally hidden in UI, only admin have access"
@@ -554,6 +554,8 @@ class Type(models.TextChoices):
554554
household_filters_available = models.BooleanField(default=True)
555555
recalculate_composition = models.BooleanField(default=False)
556556
weight = models.PositiveSmallIntegerField(default=0)
557+
compatible_types = models.ManyToManyField("self", blank=True, symmetrical=False)
558+
limit_to = models.ManyToManyField(to="BusinessArea", related_name="data_collecting_types", blank=True)
557559

558560
def __str__(self) -> str:
559561
return self.label

src/hct_mis_api/apps/grievance/admin.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class TicketNoteAdmin(LinkedObjectsMixin, HOPEModelAdminBase):
106106

107107
@admin.register(TicketComplaintDetails)
108108
class TicketComplaintDetailsAdmin(LinkedObjectsMixin, HOPEModelAdminBase):
109-
raw_id_fields = ("ticket", "household", "individual")
109+
raw_id_fields = ("ticket", "household", "individual", "payment")
110110

111111

112112
@admin.register(TicketSensitiveDetails)
@@ -136,7 +136,7 @@ class TicketDeleteIndividualDetailsAdmin(LinkedObjectsMixin, HOPEModelAdminBase)
136136

137137
@admin.register(TicketDeleteHouseholdDetails)
138138
class TicketDeleteHouseholdDetailsAdmin(LinkedObjectsMixin, HOPEModelAdminBase):
139-
raw_id_fields = ("ticket", "household")
139+
raw_id_fields = ("ticket", "household", "reason_household")
140140

141141

142142
@admin.register(TicketNeedsAdjudicationDetails)
@@ -154,7 +154,7 @@ class TicketNeedsAdjudicationDetailsAdmin(LinkedObjectsMixin, HOPEModelAdminBase
154154

155155
@admin.register(TicketPaymentVerificationDetails)
156156
class TicketPaymentVerificationDetailsAdmin(LinkedObjectsMixin, HOPEModelAdminBase):
157-
raw_id_fields = ("ticket",)
157+
raw_id_fields = ("ticket", "payment_verifications")
158158
filter_horizontal = ["payment_verifications"]
159159

160160

0 commit comments

Comments
 (0)