meta-edc 1.1.6__py3-none-any.whl → 1.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meta-edc
3
- Version: 1.1.6
3
+ Version: 1.1.8
4
4
  Summary: META Trial EDC (http://www.isrctn.com/ISRCTN76157257)
5
5
  Home-page: https://github.com/meta-trial/meta-edc
6
6
  Author: Erik van Widenfelt
@@ -694,7 +694,7 @@ Requires-Python: >=3.12
694
694
  Description-Content-Type: text/x-rst
695
695
  License-File: LICENSE
696
696
  License-File: AUTHORS.rst
697
- Requires-Dist: edc==1.1.5
697
+ Requires-Dist: edc==1.1.7
698
698
  Requires-Dist: beautifulsoup4
699
699
  Requires-Dist: celery[redis]
700
700
  Requires-Dist: django-pylabels
@@ -290,8 +290,8 @@ meta_edc/tests/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
290
290
  meta_edc/tests/tests/test_endpoints.py,sha256=5FdIHTd1xhUIgQLBzMV-Ml3VoFrlBrLLUbNarme5raw,23541
291
291
  meta_edc/views/__init__.py,sha256=TBXTih4Mpsg5Oh2jbyXqL9kH7bu3vWNRgVe93hvLCl8,32
292
292
  meta_edc/views/home_view.py,sha256=BXydy77TcdcM0-R3S_uHI4DtfnLMIzPJMyqjFJZFSsA,916
293
- meta_edc-1.1.6.dist-info/licenses/AUTHORS.rst,sha256=wL4KUOd7FAFThhkLAJxSLQ2BPzd3ikG9q0UVZr3BbLg,244
294
- meta_edc-1.1.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
293
+ meta_edc-1.1.8.dist-info/licenses/AUTHORS.rst,sha256=wL4KUOd7FAFThhkLAJxSLQ2BPzd3ikG9q0UVZr3BbLg,244
294
+ meta_edc-1.1.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
295
295
  meta_export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
296
296
  meta_export/admin_site.py,sha256=CiKAf0gDFvBKVc-1VM6KwM905ayVZuiY1tgaTeUeCi0,167
297
297
  meta_export/apps.py,sha256=3_5LB1MLtzfKekI2vT9Cm6puAx6t6AjtIfTTVdItdKg,226
@@ -816,7 +816,7 @@ meta_subject/admin/eq5d3l_admin.py,sha256=NB_DwtEA4PNnoxXqXdfnMYqUDVjwOaRtNOsIbz
816
816
  meta_subject/admin/fields.py,sha256=-be67ToKIOHOmytxR9qsEAucbDEFWyFySmG_VoIrRn4,277
817
817
  meta_subject/admin/fieldsets.py,sha256=nds9nLPscsaETET-bxX94AsBGZ6npQk_4POz8oex6jc,1523
818
818
  meta_subject/admin/followup_examination_admin.py,sha256=_w8Mds3K0JajsMa7stKRKdJM-QidPu_k-ZKWX1805TA,5154
819
- meta_subject/admin/followup_vitals_admin.py,sha256=dvpU5tR-_5YeB5_HHrP8-DwQ7Z6j9tgCsyP5Bn3yM3M,1585
819
+ meta_subject/admin/followup_vitals_admin.py,sha256=epzZAT9Rr1bEjAvThqb7h01bns5-5tYwPufcru8KvqU,2292
820
820
  meta_subject/admin/glucose_admin.py,sha256=IBKJp-tgeIZUObmanL8UPtZWQHsUiOl3raBqesh0MJU,2981
821
821
  meta_subject/admin/glucose_fbg_admin.py,sha256=GsXp5vIzgEt355qyXYr5QhWkGZdOzXzX-ZPOWAHmGlU,2492
822
822
  meta_subject/admin/hepatitis_test_admin.py,sha256=xIsUIS6Fh5U03soz_RSzqoQSyAG-zE5IEC_LrFDp_mk,1404
@@ -867,7 +867,7 @@ meta_subject/forms/delivery_form.py,sha256=L4WZqWbo9gz_BzxSdckh3e0v6DojOSoygD2xE
867
867
  meta_subject/forms/egfr_drop_notification_form.py,sha256=qQ5Q1aeGqzohD5FjBto1ThMP8iS-aNrA7I_OMrtVZFA,507
868
868
  meta_subject/forms/eq53d3l_form.py,sha256=EE67-CAIRNKZCKpmQolC8wgL5MMIjXlkn5SXe3XdhN0,508
869
869
  meta_subject/forms/followup_examination_form.py,sha256=PATGiGn1AXmK1koXy1QjMvgn43KuZn7yyZIrA_8sPXk,502
870
- meta_subject/forms/followup_vitals_form.py,sha256=uSwVTw7pE-RxvxLKx-UWUH4fLhY4_gAgmY5CdG55lRU,354
870
+ meta_subject/forms/followup_vitals_form.py,sha256=o3e7DMFNUx8hxClRApmwm-FY3BflSBUVPbukGhYJ9iU,1397
871
871
  meta_subject/forms/glucose_fbg_form.py,sha256=H1cEIkGUBe49nnhDd7x62Tr-3nrZg5Hn62GAMvIJZkU,2372
872
872
  meta_subject/forms/glucose_form.py,sha256=3PjxVaUEjswCq-m-LGz4Gj6dX1EDVdFs6UQH99ekMBs,442
873
873
  meta_subject/forms/hepatitis_test_form.py,sha256=d4ZZuB0cGiuTHrbhkLnkyMmnOKs76op-J4CFATDJML4,794
@@ -883,7 +883,7 @@ meta_subject/forms/physical_exam_form.py,sha256=QgH1zAmYgp8Hi1tU-e68HaRRkZxf-6xG
883
883
  meta_subject/forms/pregnancy_update_form.py,sha256=BTiWPoQ-HYbZhW0Go2DSqYU_e51pmJ_UIxEdSNlzTwE,559
884
884
  meta_subject/forms/sf12_form.py,sha256=VDV4hyU9UckPX70isylfHWggcWZwiQfCWrpk9kGvxis,397
885
885
  meta_subject/forms/slider_widget.py,sha256=KOIyTfpl8yrcR9GZH4zrba8JUsVVEJME3AvrYiPHYJc,821
886
- meta_subject/forms/study_medication_form.py,sha256=KI-aFBQGZywwUUOlswTOiOrhR4jhOXfjTq7_SzZ3Y30,3104
886
+ meta_subject/forms/study_medication_form.py,sha256=UQoin_iqi3iCM5D2dij2S94VnUbpJf2gA5TszNM_y8o,3170
887
887
  meta_subject/forms/subject_requisition_form.py,sha256=BWWk1njDTxenHAX1a-VHPgz9zAGTJxMNHtVsobO7Vqo,953
888
888
  meta_subject/forms/subject_visit_form.py,sha256=Zxyjb5-7wUmcLHD-M76ofuM8Vr92yzjvXqQ7GsB3U6o,1374
889
889
  meta_subject/forms/subject_visit_missed_form.py,sha256=Qrvo2A8836CspOKll_iN3a6U6ttzz1TFNbEbJRrg62g,2275
@@ -1134,13 +1134,15 @@ meta_subject/migrations/0221_auto_20250402_1913.py,sha256=4quuKgAvnd-_yRhyC211x6
1134
1134
  meta_subject/migrations/0222_alter_historicalstudymedication_stock_codes_and_more.py,sha256=hxGQ5E2_DG8RmBeg7rRxtODsigUOZANop8GJYHPNVqg,1544
1135
1135
  meta_subject/migrations/0223_bloodresultsfbc_errors_bloodresultsgludummy_errors_and_more.py,sha256=twzCzmB230Fd2Os2WOkLHyodfWGgHPBYBkDas7lhG7A,2714
1136
1136
  meta_subject/migrations/0224_bloodresultsfbc_abnormal_summary_and_more.py,sha256=U_-nNqH6AHwGDoCEqogGZ9GMdPK92s_hCrJWVeUMyrY,5471
1137
+ meta_subject/migrations/0225_followupvitals_waist_circumference_and_more.py,sha256=50t7cUy6s5phxdpRBV7zSnkb4igqZkjU3Bjl2lFEPEY,1451
1138
+ meta_subject/migrations/0226_followupvitals_waist_circumference_comment_and_more.py,sha256=E8EsKrrGBubuGkALTAOErXZ8nozfEcF4N1Ikpx586x4,3751
1137
1139
  meta_subject/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1138
1140
  meta_subject/model_mixins/__init__.py,sha256=6DdDDOwDdagrz6Q7X9lxuAVszsFWFhwPqLz4JOD85Wo,286
1139
1141
  meta_subject/model_mixins/arv_history_model_mixin.py,sha256=6ILacF2koyYmwZIFHmmQO1uIT1eWzrahXxhAlxpQiX0,2898
1140
1142
  meta_subject/model_mixins/crf_model_mixin.py,sha256=UK1ycbYwaZ8LSNTJm74QJ5c-01HDXOApDy5k9LM4RKM,248
1141
1143
  meta_subject/model_mixins/crf_with_action_model_mixin.py,sha256=q1Q16YyPjQlpDtCPOXRkO5C7Vr7JO_QL8xWC48Uz33M,298
1142
1144
  meta_subject/model_mixins/search_slug_model_mixin.py,sha256=r5KmTykU0qV4JymMMKP2IBwAP8Z5hDnVJix-rO2PvME,296
1143
- meta_subject/model_mixins/vitals_fields_model_mixin.py,sha256=JYh0w1eEFLR_BCvzHb2ldwNIkyINbfvef-SL4_wA-NY,1160
1145
+ meta_subject/model_mixins/vitals_fields_model_mixin.py,sha256=PUprWNOqZ4w3LW73RWhU_1d6AX9fGti9UvZytdXrZE0,2204
1144
1146
  meta_subject/models/__init__.py,sha256=c8EYwYsi7e3dAqhsw_KeF6MRyBQStC_rSpthVpO_a98,1835
1145
1147
  meta_subject/models/birth_outcomes.py,sha256=zikxatYZvL1qvnJ6JtVZ5aw8LCKLwQNXi6cP5F-5Jj0,3124
1146
1148
  meta_subject/models/complications.py,sha256=lkUoM3wJ9GuCFkuBUVxbCRSWfl3UtiVNSoMmkPKQdzg,1849
@@ -1241,7 +1243,7 @@ tests/etc/user-rsa-restricted-private.pem,sha256=CUcHW9bznWdmmASN00hCzvxFPAFl4N2
1241
1243
  tests/etc/user-rsa-restricted-public.pem,sha256=mt84djoL-uHw6Wc5SJh0zml6VzXulnf8eQSFg7-fheg,450
1242
1244
  tests/etc/user-salt-local.key,sha256=x5anBw9fvbHurczouT3CjrkWb_xs7Ypm1htIJsgiuiw,256
1243
1245
  tests/etc/user-salt-restricted.key,sha256=pxmpcfBRNB-4C6wTvHXz-9fOfJgKIFOjaAF8ZFfa4q4,256
1244
- meta_edc-1.1.6.dist-info/METADATA,sha256=Qbt-04xTpfHc9wiuVYaDjKqLoA7hadK1grKijn4sQn4,43587
1245
- meta_edc-1.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1246
- meta_edc-1.1.6.dist-info/top_level.txt,sha256=RkzjNXwRq2kg_uZ_1bDwPUntijSXoY2YBqtByDwvvrc,244
1247
- meta_edc-1.1.6.dist-info/RECORD,,
1246
+ meta_edc-1.1.8.dist-info/METADATA,sha256=xJbuDwwUyCvWLHpA1Lm48D7ChFS9LLaB8EpMbL2M1ZQ,43587
1247
+ meta_edc-1.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1248
+ meta_edc-1.1.8.dist-info/top_level.txt,sha256=RkzjNXwRq2kg_uZ_1bDwPUntijSXoY2YBqtByDwvvrc,244
1249
+ meta_edc-1.1.8.dist-info/RECORD,,
@@ -16,27 +16,52 @@ class FollowupVitalsAdmin(CrfModelAdminMixin, FormLabelModelAdminMixin, SimpleHi
16
16
  form = FollowupVitalsForm
17
17
 
18
18
  additional_instructions = [
19
- "If participant is pregnant, complete the action linked CRF `Pregnancy notification`."
19
+ "If participant is pregnant, complete the action "
20
+ "linked CRF `Pregnancy notification`."
20
21
  ]
21
22
 
22
23
  fieldsets = (
23
24
  (None, {"fields": ("subject_visit", "report_datetime")}),
24
25
  (
25
- "Vitals",
26
+ "Weight",
27
+ {
28
+ "fields": ("weight",),
29
+ },
30
+ ),
31
+ (
32
+ "Waist circumference",
33
+ {
34
+ "description": (
35
+ "REQUIRED at 36 and 48 months. If not measured "
36
+ "at 36 and 48 months, provide the reason."
37
+ ),
38
+ "fields": (
39
+ "waist_circumference_measured",
40
+ "waist_circumference",
41
+ "waist_circumference_comment",
42
+ ),
43
+ },
44
+ ),
45
+ (
46
+ "BP and heart rate",
26
47
  {
27
48
  "description": (
28
49
  "To be completed by the research nurse. <BR>"
29
50
  "Refer to SOP for blood pressure measurement procedure."
30
51
  ),
31
52
  "fields": (
32
- "weight",
33
53
  *get_blood_pressure_fields(),
34
54
  "heart_rate",
35
55
  *get_respiratory_o2_fields(),
36
- "temperature",
37
56
  ),
38
57
  },
39
58
  ),
59
+ (
60
+ "Temperature",
61
+ {
62
+ "fields": ("temperature",),
63
+ },
64
+ ),
40
65
  crf_status_fieldset,
41
66
  audit_fieldset_tuple,
42
67
  )
@@ -44,5 +69,6 @@ class FollowupVitalsAdmin(CrfModelAdminMixin, FormLabelModelAdminMixin, SimpleHi
44
69
  filter_horizontal = ()
45
70
 
46
71
  radio_fields = {
72
+ "waist_circumference_measured": admin.VERTICAL,
47
73
  "severe_htn": admin.VERTICAL,
48
74
  }
@@ -1,12 +1,43 @@
1
1
  from django import forms
2
+ from edc_constants.constants import NO, YES
2
3
  from edc_crf.crf_form_validator import CrfFormValidator
3
4
  from edc_crf.modelform_mixins import CrfModelFormMixin
5
+ from edc_visit_schedule.constants import MONTH36, MONTH48
4
6
 
5
7
  from ..models import FollowupVitals
6
8
 
7
9
 
10
+ class FollowupVitalsFormValidator(CrfFormValidator):
11
+ def clean(self):
12
+
13
+ self.required_if(
14
+ YES, field="waist_circumference_measured", field_required="waist_circumference"
15
+ )
16
+
17
+ visit_code = (
18
+ f"{self.related_visit.visit_code}.{self.related_visit.visit_code_sequence}"
19
+ )
20
+ require_waist_circumference_comment = (
21
+ True
22
+ if (
23
+ visit_code in [f"{MONTH36}.0", f"{MONTH48}.0"]
24
+ or self.cleaned_data.get("waist_circumference_measured") == YES
25
+ )
26
+ else False
27
+ )
28
+
29
+ if (
30
+ self.cleaned_data.get("waist_circumference_measured")
31
+ and self.cleaned_data.get("waist_circumference_measured") == NO
32
+ ):
33
+ self.required_if_true(
34
+ require_waist_circumference_comment,
35
+ field_required="waist_circumference_comment",
36
+ )
37
+
38
+
8
39
  class FollowupVitalsForm(CrfModelFormMixin, forms.ModelForm):
9
- form_validator_cls = CrfFormValidator
40
+ form_validator_cls = FollowupVitalsFormValidator
10
41
 
11
42
  class Meta:
12
43
  model = FollowupVitals
@@ -1,6 +1,7 @@
1
1
  import re
2
2
 
3
3
  from django import forms
4
+ from django.core.exceptions import ObjectDoesNotExist
4
5
  from edc_crf.modelform_mixins import CrfModelFormMixin
5
6
  from edc_form_validators import INVALID_ERROR
6
7
  from edc_pharmacy.form_validators import (
@@ -53,12 +54,12 @@ class StudyMedicationFormValidator(BaseStudyMedicationFormValidator):
53
54
  try:
54
55
  Stock.objects.get(
55
56
  code=stock_code,
56
- dispensed=True,
57
+ dispenseitem__isnull=False,
57
58
  allocation__registered_subject__subject_identifier=(
58
59
  self.subject_identifier
59
60
  ),
60
61
  )
61
- except Stock.DoesNotExist:
62
+ except ObjectDoesNotExist:
62
63
  raise forms.ValidationError(
63
64
  {
64
65
  "stock_codes": (
@@ -0,0 +1,46 @@
1
+ # Generated by Django 5.2.3 on 2025-07-10 12:05
2
+
3
+ import django.core.validators
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("meta_subject", "0224_bloodresultsfbc_abnormal_summary_and_more"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name="followupvitals",
16
+ name="waist_circumference",
17
+ field=models.DecimalField(
18
+ blank=True,
19
+ decimal_places=1,
20
+ help_text="in centimeters",
21
+ max_digits=5,
22
+ null=True,
23
+ validators=[
24
+ django.core.validators.MinValueValidator(50.0),
25
+ django.core.validators.MaxValueValidator(175.0),
26
+ ],
27
+ verbose_name="Waist circumference",
28
+ ),
29
+ ),
30
+ migrations.AddField(
31
+ model_name="historicalfollowupvitals",
32
+ name="waist_circumference",
33
+ field=models.DecimalField(
34
+ blank=True,
35
+ decimal_places=1,
36
+ help_text="in centimeters",
37
+ max_digits=5,
38
+ null=True,
39
+ validators=[
40
+ django.core.validators.MinValueValidator(50.0),
41
+ django.core.validators.MaxValueValidator(175.0),
42
+ ],
43
+ verbose_name="Waist circumference",
44
+ ),
45
+ ),
46
+ ]
@@ -0,0 +1,97 @@
1
+ # Generated by Django 5.2.3 on 2025-07-10 14:28
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("meta_subject", "0225_followupvitals_waist_circumference_and_more"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="followupvitals",
15
+ name="waist_circumference_comment",
16
+ field=models.TextField(
17
+ blank=True,
18
+ help_text="A comment is only required at 36 and 48 months",
19
+ null=True,
20
+ verbose_name="If waist circumference not measured, please explain ...",
21
+ ),
22
+ ),
23
+ migrations.AddField(
24
+ model_name="followupvitals",
25
+ name="waist_circumference_measured",
26
+ field=models.CharField(
27
+ choices=[("Yes", "Yes"), ("No", "No")],
28
+ default="No",
29
+ help_text="Waist circumference is required at 36 and 48 months",
30
+ max_length=15,
31
+ verbose_name="Was the patient's waist circumference measured today?",
32
+ ),
33
+ ),
34
+ migrations.AddField(
35
+ model_name="historicalfollowupvitals",
36
+ name="waist_circumference_comment",
37
+ field=models.TextField(
38
+ blank=True,
39
+ help_text="A comment is only required at 36 and 48 months",
40
+ null=True,
41
+ verbose_name="If waist circumference not measured, please explain ...",
42
+ ),
43
+ ),
44
+ migrations.AddField(
45
+ model_name="historicalfollowupvitals",
46
+ name="waist_circumference_measured",
47
+ field=models.CharField(
48
+ choices=[("Yes", "Yes"), ("No", "No")],
49
+ default="No",
50
+ help_text="Waist circumference is required at 36 and 48 months",
51
+ max_length=15,
52
+ verbose_name="Was the patient's waist circumference measured today?",
53
+ ),
54
+ ),
55
+ migrations.AddField(
56
+ model_name="historicalphysicalexam",
57
+ name="waist_circumference_comment",
58
+ field=models.TextField(
59
+ blank=True,
60
+ help_text="A comment is only required at 36 and 48 months",
61
+ null=True,
62
+ verbose_name="If waist circumference not measured, please explain ...",
63
+ ),
64
+ ),
65
+ migrations.AddField(
66
+ model_name="historicalphysicalexam",
67
+ name="waist_circumference_measured",
68
+ field=models.CharField(
69
+ choices=[("Yes", "Yes"), ("No", "No")],
70
+ default="No",
71
+ help_text="Waist circumference is required at 36 and 48 months",
72
+ max_length=15,
73
+ verbose_name="Was the patient's waist circumference measured today?",
74
+ ),
75
+ ),
76
+ migrations.AddField(
77
+ model_name="physicalexam",
78
+ name="waist_circumference_comment",
79
+ field=models.TextField(
80
+ blank=True,
81
+ help_text="A comment is only required at 36 and 48 months",
82
+ null=True,
83
+ verbose_name="If waist circumference not measured, please explain ...",
84
+ ),
85
+ ),
86
+ migrations.AddField(
87
+ model_name="physicalexam",
88
+ name="waist_circumference_measured",
89
+ field=models.CharField(
90
+ choices=[("Yes", "Yes"), ("No", "No")],
91
+ default="No",
92
+ help_text="Waist circumference is required at 36 and 48 months",
93
+ max_length=15,
94
+ verbose_name="Was the patient's waist circumference measured today?",
95
+ ),
96
+ ),
97
+ ]
@@ -1,11 +1,44 @@
1
1
  from django.core.validators import MaxValueValidator, MinValueValidator
2
2
  from django.db import models
3
+ from edc_constants.choices import YES_NO
4
+ from edc_constants.constants import NO
3
5
  from edc_vitals.models import WeightField
4
6
 
5
7
 
6
8
  class VitalsFieldsModelMixin(models.Model):
7
9
  weight = WeightField(null=True)
8
10
 
11
+ waist_circumference_measured = models.CharField(
12
+ verbose_name="Was the patient's waist circumference measured today?",
13
+ max_length=15,
14
+ choices=YES_NO,
15
+ help_text=(
16
+ "Waist circumference may be provided at anytime "
17
+ "but is required at 36 and 48 months"
18
+ ),
19
+ default=NO,
20
+ )
21
+
22
+ waist_circumference = models.DecimalField(
23
+ verbose_name="Waist circumference",
24
+ max_digits=5,
25
+ decimal_places=1,
26
+ validators=[MinValueValidator(50.0), MaxValueValidator(175.0)],
27
+ help_text="in centimeters",
28
+ null=True,
29
+ blank=True,
30
+ )
31
+
32
+ waist_circumference_comment = models.TextField(
33
+ verbose_name="If waist circumference not measured, please explain ...",
34
+ help_text=(
35
+ "A reason not measured may be provided at anytime "
36
+ "but is required at 36 and 48 months"
37
+ ),
38
+ null=True,
39
+ blank=True,
40
+ )
41
+
9
42
  # 10
10
43
  heart_rate = models.IntegerField(
11
44
  verbose_name="Heart rate:",