clinicedc 2.0.28__py3-none-any.whl → 2.0.29__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.

Potentially problematic release.


This version of clinicedc might be problematic. Click here for more details.

Files changed (95) hide show
  1. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/RECORD +95 -95
  3. edc_auth/admin/fieldsets.py +11 -15
  4. edc_auth/admin/group_admin.py +2 -5
  5. edc_auth/admin/list_filters.py +8 -7
  6. edc_auth/admin/role_admin.py +7 -10
  7. edc_auth/admin/user_admin.py +2 -2
  8. edc_auth/admin/user_profile_admin.py +3 -7
  9. edc_auth/apps.py +2 -2
  10. edc_auth/auth_updater/group_updater.py +4 -4
  11. edc_auth/auth_updater/role_updater.py +1 -3
  12. edc_auth/backends.py +1 -1
  13. edc_auth/export_users.py +6 -5
  14. edc_auth/fix_export_permissions.py +8 -8
  15. edc_auth/forms.py +21 -24
  16. edc_auth/get_app_codenames.py +2 -2
  17. edc_auth/import_users.py +25 -24
  18. edc_auth/management/commands/export_users.py +1 -1
  19. edc_auth/management/commands/fix_export_permissions.py +1 -1
  20. edc_auth/management/commands/import_users.py +1 -1
  21. edc_auth/management/commands/reset_password.py +2 -2
  22. edc_auth/models/signals.py +1 -1
  23. edc_auth/models/user_profile.py +4 -5
  24. edc_auth/password_setter.py +4 -4
  25. edc_auth/post_migrate_signals.py +2 -2
  26. edc_auth/send_new_credentials_to_user.py +1 -1
  27. edc_auth/system_checks.py +7 -6
  28. edc_auth/utils.py +9 -11
  29. edc_consent/consent_definition.py +4 -1
  30. edc_model_admin/mixins/model_admin_form_instructions_mixin.py +9 -3
  31. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +7 -7
  32. edc_pharmacy/admin_mixin.py +1 -1
  33. edc_pharmacy/approve_prescription.py +10 -8
  34. edc_pharmacy/auth_objects.py +1 -1
  35. edc_pharmacy/exceptions.py +7 -7
  36. edc_pharmacy/settings.py +1 -1
  37. edc_pharmacy/views/add_to_storage_bin_view.py +22 -24
  38. edc_pharmacy/views/allocate_to_subject_view.py +10 -18
  39. edc_pharmacy/views/celery_task_status_view.py +1 -2
  40. edc_pharmacy/views/confirm_stock_from_instance_view.py +1 -1
  41. edc_pharmacy/views/confirm_stock_from_queryset_view.py +5 -8
  42. edc_pharmacy/views/dispense_view.py +1 -1
  43. edc_pharmacy/views/move_to_storage_bin_view.py +7 -3
  44. edc_pharmacy/views/prepare_and_review_stock_request_view.py +62 -70
  45. edc_pharmacy/views/print_labels_view.py +1 -1
  46. edc_pharmacy/views/transfer_stock_view.py +1 -1
  47. edc_prn/modelform_mixins.py +8 -9
  48. edc_prn/models.py +3 -1
  49. edc_prn/site_prn_forms.py +2 -2
  50. edc_prn/templatetags/edc_prn_extras.py +1 -1
  51. edc_protocol/middleware.py +1 -1
  52. edc_protocol/research_protocol_config.py +7 -5
  53. edc_protocol_incident/admin/protocol_deviation_violation_admin.py +1 -1
  54. edc_protocol_incident/form_validators/mixins.py +9 -6
  55. edc_protocol_incident/modeladmin_mixins.py +1 -1
  56. edc_pylabels/admin/label_configuration_admin.py +1 -1
  57. edc_pylabels/admin/label_specification_admin.py +1 -1
  58. edc_pylabels/auth_objects.py +1 -1
  59. edc_pylabels/site_label_configs.py +2 -2
  60. edc_qareports/admin/qa_report_log_admin.py +5 -5
  61. edc_qareports/admin/qa_report_log_summary_admin.py +1 -1
  62. edc_qareports/forms/note_form.py +2 -3
  63. edc_qareports/modeladmin_mixins/list_filters.py +23 -19
  64. edc_qareports/modeladmin_mixins/note_modeladmin_mixin.py +7 -7
  65. edc_qareports/modeladmin_mixins/on_study_missing_values_modeladmin_mixin.py +8 -8
  66. edc_qareports/modeladmin_mixins/qa_report_modeladmin_mixin.py +3 -7
  67. edc_qareports/sql_generator/crf_case.py +1 -1
  68. edc_qareports/sql_generator/crf_subquery.py +1 -1
  69. edc_qareports/sql_generator/requisition_subquery.py +1 -1
  70. edc_qareports/sql_generator/sql_view_generator.py +1 -1
  71. edc_qareports/sql_generator/subquery_from_dict.py +39 -39
  72. edc_qareports/utils.py +12 -13
  73. edc_randomization/model_mixins.py +1 -1
  74. edc_randomization/system_checks.py +1 -1
  75. edc_refusal/admin.py +4 -2
  76. edc_registration/modeladmin_mixins.py +18 -20
  77. edc_registration/modelform_mixins.py +2 -2
  78. edc_registration/models/signals.py +1 -1
  79. edc_registration/utils.py +1 -1
  80. edc_reportable/age_evaluator.py +4 -4
  81. edc_reportable/data/grading_data/daids_july_2017.py +3 -3
  82. edc_reportable/evaluator.py +15 -15
  83. edc_reportable/exceptions.py +4 -4
  84. edc_reportable/forms/reportables_form_validator_mixin.py +6 -2
  85. edc_reportable/management/commands/export_reportables.py +1 -1
  86. edc_reportable/models/grading_exception.py +1 -6
  87. edc_reportable/models/normal_data.py +3 -3
  88. edc_reportable/models/reference_range_collection.py +1 -6
  89. edc_reportable/utils/get_grade_for_value.py +15 -15
  90. edc_reportable/utils/get_normal_data_or_raise.py +14 -14
  91. edc_reportable/utils/in_normal_bounds_or_raise.py +6 -6
  92. edc_reportable/utils/load_data.py +1 -1
  93. edc_reportable/utils/update_grading_exceptions.py +5 -5
  94. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/WHEEL +0 -0
  95. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/licenses/LICENSE +0 -0
@@ -46,7 +46,9 @@ class ModelAdminFormInstructionsMixin:
46
46
  change_additional_instructions = ()
47
47
 
48
48
  def get_add_instructions(
49
- self, extra_context: dict | None, request: WSGIRequest | None = None
49
+ self,
50
+ extra_context: dict | None,
51
+ request: WSGIRequest | None = None, # noqa: ARG002
50
52
  ):
51
53
  extra_context = extra_context or {}
52
54
  extra_context["instructions"] = self.add_instructions or self.instructions
@@ -56,7 +58,9 @@ class ModelAdminFormInstructionsMixin:
56
58
  return extra_context
57
59
 
58
60
  def get_change_instructions(
59
- self, extra_context: dict | None, request: WSGIRequest | None = None
61
+ self,
62
+ extra_context: dict | None,
63
+ request: WSGIRequest | None = None, # noqa: ARG002
60
64
  ):
61
65
  extra_context = extra_context or {}
62
66
  extra_context["instructions"] = self.change_instructions or self.instructions
@@ -65,7 +69,9 @@ class ModelAdminFormInstructionsMixin:
65
69
  )
66
70
  return extra_context
67
71
 
68
- def add_view(self, request: WSGIRequest, form_url: str = "", extra_context: dict = None):
72
+ def add_view(
73
+ self, request: WSGIRequest, form_url: str = "", extra_context: dict | None = None
74
+ ):
69
75
  extra_context = self.get_add_instructions(extra_context, request=request)
70
76
  return super().add_view(request, form_url=form_url, extra_context=extra_context)
71
77
 
@@ -23,20 +23,20 @@ class ModelAdminProtectPiiMixin:
23
23
 
24
24
  extra_pii_attrs: tuple[str] | None = ()
25
25
 
26
- def get_extra_pii_attrs(self) -> list[str | tuple[str, str]]:
27
- return self.extra_pii_attrs or []
26
+ def get_extra_pii_attrs(self) -> tuple[str | tuple[str, str]]:
27
+ return self.extra_pii_attrs
28
28
 
29
29
  def get_encrypted_fields(self) -> tuple[str, ...]:
30
- encrypted_fields = [f.name for f in get_encrypted_fields(self.model)]
31
- encrypted_fields.extend(*self.get_extra_pii_attrs())
32
- return tuple(set(encrypted_fields))
30
+ encrypted_fields = tuple([f.name for f in get_encrypted_fields(self.model)])
31
+ return tuple({*encrypted_fields, *self.get_extra_pii_attrs()})
33
32
 
34
33
  def get_list_display(self, request) -> tuple[str]:
35
34
  list_display = super().get_list_display(request)
36
35
  if not request.user.groups.filter(name__in=[PII, PII_VIEW]).exists():
37
36
  # TODO: search replace from list_display if extra_pii_attr has tuple
38
- list_display = [f for f in list_display if f not in self.get_encrypted_fields()]
39
- list_display = tuple(list_display)
37
+ list_display = tuple(
38
+ *{f for f in list_display if f not in self.get_encrypted_fields()}
39
+ )
40
40
  return list_display
41
41
 
42
42
  def get_list_display_links(self, request, list_display) -> list[str] | None:
@@ -7,7 +7,7 @@ class PrintButtonAdminMixin:
7
7
  print_server_error = None
8
8
 
9
9
  def __init__(self, args, *kwargs):
10
- super(PrintButtonAdminMixin, self).__init__(*args, **kwargs)
10
+ super().__init__(*args, **kwargs)
11
11
  app_config = django_apps.get_app_config("edc_label")
12
12
  self._print_server = None
13
13
  self._printers = {}
@@ -8,12 +8,14 @@ class ApprovePrescription:
8
8
  def __init__(self, rx_model_obj=None):
9
9
  dispense_appointment = rx_model_obj.dispense_appointment
10
10
  previous_appointment = dispense_appointment.previous()
11
- if previous_appointment:
12
- if rx_model_obj.__class__.objects.filter(
11
+ if (
12
+ previous_appointment
13
+ and rx_model_obj.__class__.objects.filter(
13
14
  is_approved=False, dispense_appointment=previous_appointment
14
- ).exists():
15
- raise PrescriptionApprovalValidatorError(
16
- f"Future prescriptions cannot be approved. Approve "
17
- f"prescriptions for dispensing date "
18
- f"{previous_appointment.appt_datetime}"
19
- )
15
+ ).exists()
16
+ ):
17
+ raise PrescriptionApprovalValidatorError(
18
+ f"Future prescriptions cannot be approved. Approve "
19
+ f"prescriptions for dispensing date "
20
+ f"{previous_appointment.appt_datetime}"
21
+ )
@@ -20,7 +20,7 @@ PHARMACY_SUPER_ROLE = "PHARMACY_SUPER_ROLE"
20
20
  navbar_codenames = ["edc_pharmacy.nav_pharmacy_section"]
21
21
  navbar_tuples = []
22
22
  for codename in navbar_codenames:
23
- navbar_tuples.append((codename, f"Can access {codename.split('.')[1]}"))
23
+ navbar_tuples.append((codename, f"Can access {codename.split('.')[1]}")) # noqa: PERF401
24
24
 
25
25
 
26
26
  # central pharmacist
@@ -1,4 +1,4 @@
1
- class ActivePrescriptionRefillOverlap(Exception):
1
+ class ActivePrescriptionRefillOverlap(Exception): # noqa: N818
2
2
  pass
3
3
 
4
4
 
@@ -6,7 +6,7 @@ class RefillError(Exception):
6
6
  pass
7
7
 
8
8
 
9
- class ActiveRefillAlreadyExists(Exception):
9
+ class ActiveRefillAlreadyExists(Exception): # noqa: N818
10
10
  pass
11
11
 
12
12
 
@@ -34,7 +34,7 @@ class PackagingLotNumberMismatchError(Exception):
34
34
  pass
35
35
 
36
36
 
37
- class PrescriptionAlreadyExists(Exception):
37
+ class PrescriptionAlreadyExists(Exception): # noqa: N818
38
38
  pass
39
39
 
40
40
 
@@ -42,15 +42,15 @@ class PrescriptionError(Exception):
42
42
  pass
43
43
 
44
44
 
45
- class PrescriptionExpired(Exception):
45
+ class PrescriptionExpired(Exception): # noqa: N818
46
46
  pass
47
47
 
48
48
 
49
- class RefillAlreadyExists(Exception):
49
+ class RefillAlreadyExists(Exception): # noqa: N818
50
50
  pass
51
51
 
52
52
 
53
- class PrescriptionNotStarted(Exception):
53
+ class PrescriptionNotStarted(Exception): # noqa: N818
54
54
  pass
55
55
 
56
56
 
@@ -74,7 +74,7 @@ class InsufficientStockError(Exception):
74
74
  pass
75
75
 
76
76
 
77
- class InvalidContainer(Exception):
77
+ class InvalidContainer(Exception): # noqa: N818
78
78
  pass
79
79
 
80
80
 
edc_pharmacy/settings.py CHANGED
@@ -15,7 +15,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
15
15
  # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
16
16
 
17
17
  # SECURITY WARNING: keep the secret key used in production secret!
18
- SECRET_KEY = "django-insecure-+#-*m&byi1w8=#e5nr))^kollb=k1b#rvjffo#+teji^qpm14o" # nosec B105
18
+ SECRET_KEY = "django-insecure-+#-*m&byi1w8=#e5nr))^kollb=k1b#rvjffo#+teji^qpm14o" # nosec B105 # noqa: S105
19
19
 
20
20
  # SECURITY WARNING: don't run with debug turned on in production!
21
21
  DEBUG = True
@@ -95,8 +95,7 @@ class AddToStorageBinView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, T
95
95
  def storage_bin_changelist_url(self) -> str:
96
96
  if self.storage_bin:
97
97
  url = reverse("edc_pharmacy_admin:edc_pharmacy_storagebin_changelist")
98
- url = f"{url}?q={self.storage_bin.bin_identifier}"
99
- return url
98
+ return f"{url}?q={self.storage_bin.bin_identifier}"
100
99
  return "/"
101
100
 
102
101
  def redirect_on_has_duplicates(
@@ -144,30 +143,29 @@ class AddToStorageBinView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, T
144
143
  def redirect_on_invalid_subject_for_location(
145
144
  self, stock_codes: list[str], storage_bin: StorageBin
146
145
  ) -> HttpResponseRedirect | None:
147
- if stock_codes:
148
- if (
149
- Stock.objects.filter(code__in=stock_codes)
150
- .exclude(location=storage_bin.location)
151
- .exists()
152
- ):
153
- qs = Stock.objects.filter(code__in=stock_codes).exclude(
154
- location=storage_bin.location
155
- )
156
- messages.add_message(
157
- self.request,
158
- messages.ERROR,
159
- f"Stock not from this location. See {[obj.stock.code for obj in qs]}.",
160
- )
161
- url = reverse(
162
- "edc_pharmacy:add_to_storage_bin_url",
163
- kwargs={
164
- "storage_bin": storage_bin.id,
165
- },
166
- )
167
- return HttpResponseRedirect(url)
146
+ if stock_codes and (
147
+ Stock.objects.filter(code__in=stock_codes)
148
+ .exclude(location=storage_bin.location)
149
+ .exists()
150
+ ):
151
+ qs = Stock.objects.filter(code__in=stock_codes).exclude(
152
+ location=storage_bin.location
153
+ )
154
+ messages.add_message(
155
+ self.request,
156
+ messages.ERROR,
157
+ f"Stock not from this location. See {[obj.stock.code for obj in qs]}.",
158
+ )
159
+ url = reverse(
160
+ "edc_pharmacy:add_to_storage_bin_url",
161
+ kwargs={
162
+ "storage_bin": storage_bin.id,
163
+ },
164
+ )
165
+ return HttpResponseRedirect(url)
168
166
  return None
169
167
 
170
- def post(self, request, *args, **kwargs):
168
+ def post(self, request, *args, **kwargs): # noqa: ARG002
171
169
  stock_codes = request.POST.getlist("codes") if request.POST.get("codes") else None
172
170
  storage_bin = StorageBin.objects.get(id=kwargs.get("storage_bin"))
173
171
  items_to_scan = request.POST.get("items_to_scan") or kwargs.get("items_to_scan")
@@ -96,8 +96,7 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
96
96
  def stock_request_changelist_url(self) -> str:
97
97
  if self.stock_request:
98
98
  url = reverse("edc_pharmacy_admin:edc_pharmacy_stockrequest_changelist")
99
- url = f"{url}?q={self.stock_request.request_identifier}"
100
- return url
99
+ return f"{url}?q={self.stock_request.request_identifier}"
101
100
  return "/"
102
101
 
103
102
  @staticmethod
@@ -120,14 +119,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
120
119
  messages.ERROR,
121
120
  "Nothing saved. Duplicate codes detected in list. Please try again.",
122
121
  )
123
- url = reverse(
122
+ return reverse(
124
123
  "edc_pharmacy:allocate_url",
125
124
  kwargs={
126
125
  "stock_request": stock_request.id,
127
126
  "assignment": assignment.id,
128
127
  },
129
128
  )
130
- return url
131
129
  return None
132
130
 
133
131
  def redirect_on_uncomfirmed_stock_codes(
@@ -153,14 +151,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
153
151
  f"Got {uncomfirmed_codes}. "
154
152
  ),
155
153
  )
156
- url = reverse(
154
+ return reverse(
157
155
  "edc_pharmacy:allocate_url",
158
156
  kwargs={
159
157
  "stock_request": stock_request.id,
160
158
  "assignment": assignment.id,
161
159
  },
162
160
  )
163
- return url
164
161
  return None
165
162
 
166
163
  def redirect_on_invalid_stock_codes(
@@ -183,14 +180,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
183
180
  messages.ERROR,
184
181
  f"Nothing saved. Invalid codes detected. Got {invalid_codes}. ",
185
182
  )
186
- url = reverse(
183
+ return reverse(
187
184
  "edc_pharmacy:allocate_url",
188
185
  kwargs={
189
186
  "stock_request": stock_request.id,
190
187
  "assignment": assignment.id,
191
188
  },
192
189
  )
193
- return url
194
190
  return None
195
191
 
196
192
  def redirect_on_has_multiple_container_types(
@@ -211,14 +207,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
211
207
  f"only. See Stock request {stock_request.request_identifier} "
212
208
  ),
213
209
  )
214
- url = reverse(
210
+ return reverse(
215
211
  "edc_pharmacy:allocate_url",
216
212
  kwargs={
217
213
  "stock_request": stock_request.id,
218
214
  "assignment": assignment.id,
219
215
  },
220
216
  )
221
- return url
222
217
  return None
223
218
 
224
219
  def redirect_on_stock_already_allocated(
@@ -234,20 +229,19 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
234
229
  allocated_stock_codes = []
235
230
  for stock in Stock.objects.filter(code__in=stock_codes):
236
231
  if stock.allocation:
237
- allocated_stock_codes.append(stock.code)
232
+ allocated_stock_codes.append(stock.code) # noqa: PERF401
238
233
  messages.add_message(
239
234
  self.request,
240
235
  messages.ERROR,
241
236
  f"Stock already allocated. Got {','.join(allocated_stock_codes)}.",
242
237
  )
243
- url = reverse(
238
+ return reverse(
244
239
  "edc_pharmacy:allocate_url",
245
240
  kwargs={
246
241
  "stock_request": stock_request.id,
247
242
  "assignment": getattr(assignment, "id", None),
248
243
  },
249
244
  )
250
- return url
251
245
  return None
252
246
 
253
247
  def redirect_on_all_allocated_for_assignment(
@@ -265,14 +259,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
265
259
  )
266
260
  % {"assignment": assignment.display_name.upper()},
267
261
  )
268
- url = reverse(
262
+ return reverse(
269
263
  "edc_pharmacy:allocate_url",
270
264
  kwargs={
271
265
  "stock_request": stock_request.id,
272
266
  "assignment": getattr(assignment, "id", None),
273
267
  },
274
268
  )
275
- return url
276
269
  return None
277
270
 
278
271
  def redirect_on_incorrect_stock_for_assignment(
@@ -292,14 +285,13 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
292
285
  f"Expected `{assignment.display_name}` only. Check your work."
293
286
  ),
294
287
  )
295
- url = reverse(
288
+ return reverse(
296
289
  "edc_pharmacy:allocate_url",
297
290
  kwargs={
298
291
  "stock_request": stock_request.id,
299
292
  "assignment": getattr(assignment, "id", None),
300
293
  },
301
294
  )
302
- return url
303
295
  return None
304
296
 
305
297
  def get_counts(self, stock_request: StockRequest) -> tuple[int, int]:
@@ -315,7 +307,7 @@ class AllocateToSubjectView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin,
315
307
  return remaining_count or 0, total_count
316
308
  return 0, 0
317
309
 
318
- def post(self, request, *args, **kwargs):
310
+ def post(self, request, *args, **kwargs): # noqa: ARG002
319
311
  stock_codes = request.POST.getlist("codes") if request.POST.get("codes") else None
320
312
  subject_identifiers = request.POST.get("subject_identifiers")
321
313
  assignment_id = request.POST.get("assignment")
@@ -4,8 +4,7 @@ from django.views import View
4
4
 
5
5
 
6
6
  class CeleryTaskStatusView(View):
7
-
8
- def get(self, request, *args, **kwargs):
7
+ def get(self, request, *args, **kwargs): # noqa: ARG002
9
8
  task_id = request.GET.get("task_id")
10
9
  response_data = {"task_id": task_id, "status": None}
11
10
  try:
@@ -90,7 +90,7 @@ class ConfirmStockFromInstanceView(
90
90
  def model_cls(self):
91
91
  return django_apps.get_model(f"edc_pharmacy.{self.kwargs.get('model')}")
92
92
 
93
- def post(self, request, *args, **kwargs):
93
+ def post(self, request, *args, **kwargs): # noqa: ARG002
94
94
  dct = self.get_values_dict(**kwargs)
95
95
  codes = request.POST.getlist("codes")
96
96
  confirmed, already_confirmed, invalid = confirm_stock(
@@ -29,8 +29,8 @@ class ConfirmStockFromQuerySetView(
29
29
  navbar_selected_item = "pharmacy"
30
30
  codes_per_page = 12
31
31
 
32
- def get_context_data(self, **kwargs):
33
- context = dict(
32
+ def get_context_data(self, **kwargs): # noqa: ARG002
33
+ return dict(
34
34
  CONFIRMED=CONFIRMED,
35
35
  ALREADY_CONFIRMED=ALREADY_CONFIRMED,
36
36
  INVALID=INVALID,
@@ -40,7 +40,6 @@ class ConfirmStockFromQuerySetView(
40
40
  source_changelist_url=self.source_changelist_url,
41
41
  **self.session_data,
42
42
  )
43
- return context
44
43
 
45
44
  @property
46
45
  def session_data(self):
@@ -58,10 +57,8 @@ class ConfirmStockFromQuerySetView(
58
57
  [
59
58
  x,
60
59
  ALREADY_CONFIRMED,
61
- _(
62
- "already %(transaction_word)s"
63
- % {"transaction_word": transaction_word}
64
- ),
60
+ _("already %(transaction_word)s")
61
+ % {"transaction_word": transaction_word},
65
62
  ]
66
63
  for x in session_obj.get("already_confirmed_codes") or []
67
64
  ]
@@ -117,7 +114,7 @@ class ConfirmStockFromQuerySetView(
117
114
  label_lower = self.session_data.get("source_label_lower")
118
115
  return django_apps.get_model(label_lower)
119
116
 
120
- def post(self, request, *args, **kwargs):
117
+ def post(self, request, *args, **kwargs): # noqa: ARG002
121
118
  stock_codes = request.POST.getlist("stock_codes")
122
119
  if len(stock_codes) != len(list(set(stock_codes))):
123
120
  messages.add_message(
@@ -85,7 +85,7 @@ class DispenseView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Template
85
85
  )
86
86
  return confirmation_at_site
87
87
 
88
- def post(self, request, *args, **kwargs):
88
+ def post(self, request, *args, **kwargs): # noqa: ARG002
89
89
  location_id = request.POST.get("location_id")
90
90
  location = Location.objects.get(pk=location_id)
91
91
  formulation_id = request.POST.get("formulation_id")
@@ -11,6 +11,7 @@ from ..models import Stock, StorageBin, StorageBinItem
11
11
  from .add_to_storage_bin_view import AddToStorageBinView, StorageBinError
12
12
 
13
13
  p = inflect.engine()
14
+ MAX_STORAGE_BIN_CAPACITY = 50
14
15
 
15
16
 
16
17
  def move_to_bin(
@@ -25,8 +26,11 @@ def move_to_bin(
25
26
  new_capacity = StorageBinItem.objects.filter(storage_bin=storage_bin).count() + len(
26
27
  stock_codes
27
28
  )
28
- if new_capacity > 50:
29
- raise StorageBinError(f"Storage bin {storage_bin.name} capacity may not exceeded 50")
29
+ if new_capacity > MAX_STORAGE_BIN_CAPACITY:
30
+ raise StorageBinError(
31
+ f"Storage bin {storage_bin.name} capacity "
32
+ f"may not exceeded {MAX_STORAGE_BIN_CAPACITY}."
33
+ )
30
34
  if new_capacity > storage_bin.capacity:
31
35
  storage_bin.capacity = new_capacity
32
36
  storage_bin.save()
@@ -89,7 +93,7 @@ class MoveToStorageBinView(AddToStorageBinView):
89
93
  return HttpResponseRedirect(url)
90
94
  return None
91
95
 
92
- def post(self, request, *args, **kwargs):
96
+ def post(self, request, *args, **kwargs): # noqa: ARG002
93
97
  stock_codes = request.POST.getlist("codes") if request.POST.get("codes") else None
94
98
  storage_bin = StorageBin.objects.get(id=kwargs.get("storage_bin"))
95
99
  items_to_scan = request.POST.get("items_to_scan") or kwargs.get("items_to_scan")
@@ -1,6 +1,5 @@
1
1
  from uuid import uuid4
2
2
 
3
- import pandas as pd
4
3
  from celery.states import PENDING
5
4
  from django.apps import apps as django_apps
6
5
  from django.conf import settings
@@ -9,7 +8,6 @@ from django.contrib.auth.decorators import login_required
9
8
  from django.http import HttpResponseRedirect
10
9
  from django.urls import reverse
11
10
  from django.utils.decorators import method_decorator
12
- from django.utils.html import format_html
13
11
  from django.utils.safestring import mark_safe
14
12
  from django.views.generic import TemplateView
15
13
  from django_pandas.io import read_frame
@@ -37,22 +35,24 @@ class PrepareAndReviewStockRequestView(
37
35
  df = get_next_scheduled_visit_for_subjects_df(stock_request)
38
36
 
39
37
  # get unallocated stock that appears in a stock request for this location
40
- df_unallocated_request_items = read_frame(
41
- StockRequestItem.objects.values(
42
- "stock_request__request_identifier",
43
- "registered_subject__subject_identifier",
44
- ).filter(stock_request__location=stock_request.location, allocation__isnull=True)
45
- )
46
- df_unallocated_request_items.rename(
47
- columns={
48
- "registered_subject__subject_identifier": "subject_identifier",
49
- "stock_request__request_identifier": "request_identifier",
50
- },
51
- inplace=True,
38
+ df_unallocated_request_items = (
39
+ read_frame(
40
+ StockRequestItem.objects.values(
41
+ "stock_request__request_identifier",
42
+ "registered_subject__subject_identifier",
43
+ ).filter(
44
+ stock_request__location=stock_request.location, allocation__isnull=True
45
+ )
46
+ )
47
+ .rename(
48
+ columns={
49
+ "registered_subject__subject_identifier": "subject_identifier",
50
+ "stock_request__request_identifier": "request_identifier",
51
+ },
52
+ )
53
+ .reset_index(drop=True)
52
54
  )
53
- df_unallocated_request_items.reset_index(drop=True, inplace=True)
54
- df_unallocated_request_items = pd.merge(
55
- df_unallocated_request_items,
55
+ df_unallocated_request_items = df_unallocated_request_items.merge(
56
56
  df[["subject_identifier", "next_visit_code", "next_appt_datetime"]],
57
57
  on="subject_identifier",
58
58
  how="left",
@@ -60,13 +60,14 @@ class PrepareAndReviewStockRequestView(
60
60
  df_unallocated_request_items = df_unallocated_request_items[
61
61
  df_unallocated_request_items.next_visit_code.notna()
62
62
  ]
63
- df_unallocated_request_items.sort_values(by=["subject_identifier"]).reset_index(
64
- drop=True, inplace=True
65
- )
63
+ df_unallocated_request_items = df_unallocated_request_items.sort_values(
64
+ by=["subject_identifier"]
65
+ ).reset_index()
66
66
 
67
67
  # exclude unallocated subjects from appts
68
- df = df[~df.subject_identifier.isin(df_unallocated_request_items.subject_identifier)]
69
- df.reset_index(drop=True, inplace=True)
68
+ df = df[
69
+ ~df.subject_identifier.isin(df_unallocated_request_items.subject_identifier)
70
+ ].reset_index(drop=True)
70
71
 
71
72
  kwargs.update(
72
73
  stock_request=stock_request,
@@ -128,55 +129,46 @@ class PrepareAndReviewStockRequestView(
128
129
  subjects_excluded_by_request=len(
129
130
  df_unallocated_request_items.subject_identifier.unique()
130
131
  ),
131
- nostock_table=format_html(
132
- "{}",
133
- mark_safe(
134
- df_nostock.to_html(
135
- columns=[
136
- "subject_identifier",
137
- "next_visit_code",
138
- "next_appt_datetime",
139
- ],
140
- index=True,
141
- border=0,
142
- classes="table table-striped",
143
- table_id="my_table",
144
- )
145
- ), # nosec B703 B308
132
+ nostock_table=mark_safe( # noqa: S308
133
+ df_nostock.to_html(
134
+ columns=[
135
+ "subject_identifier",
136
+ "next_visit_code",
137
+ "next_appt_datetime",
138
+ ],
139
+ index=True,
140
+ border=0,
141
+ classes="table table-striped",
142
+ table_id="my_table",
143
+ )
146
144
  ),
147
- instock_table=format_html(
148
- "{}",
149
- mark_safe(
150
- df_instock.to_html(
151
- columns=[
152
- "subject_identifier",
153
- "next_visit_code",
154
- "next_appt_datetime",
155
- "code",
156
- ],
157
- index=True,
158
- border=0,
159
- classes="table table-striped",
160
- table_id="in_stock_table",
161
- )
162
- ), # nosec B703 B308
145
+ instock_table=mark_safe( # noqa: S308
146
+ df_instock.to_html(
147
+ columns=[
148
+ "subject_identifier",
149
+ "next_visit_code",
150
+ "next_appt_datetime",
151
+ "code",
152
+ ],
153
+ index=True,
154
+ border=0,
155
+ classes="table table-striped",
156
+ table_id="in_stock_table",
157
+ )
163
158
  ),
164
- unallocated_table=format_html(
165
- "{}",
166
- mark_safe(
167
- df_unallocated_request_items.to_html(
168
- columns=[
169
- "subject_identifier",
170
- "next_visit_code",
171
- "next_appt_datetime",
172
- "request_identifier",
173
- ],
174
- index=True,
175
- border=0,
176
- classes="table table-striped",
177
- table_id="unallocated_table",
178
- )
179
- ), # nosec B703 B308
159
+ unallocated_table=mark_safe( # noqa: S308
160
+ df_unallocated_request_items.to_html(
161
+ columns=[
162
+ "subject_identifier",
163
+ "next_visit_code",
164
+ "next_appt_datetime",
165
+ "request_identifier",
166
+ ],
167
+ index=True,
168
+ border=0,
169
+ classes="table table-striped",
170
+ table_id="unallocated_table",
171
+ )
180
172
  ),
181
173
  session_uuid=session_uuid,
182
174
  )
@@ -190,7 +182,7 @@ class PrepareAndReviewStockRequestView(
190
182
  def model_cls(self):
191
183
  return django_apps.get_model("edc_pharmacy.stocktransfer")
192
184
 
193
- def post(self, request, *args, **kwargs):
185
+ def post(self, request, *args, **kwargs): # noqa: ARG002
194
186
  session_uuid = request.POST.get("session_uuid")
195
187
  stock_request = StockRequest.objects.get(pk=request.POST.get("stock_request"))
196
188
  if not request.POST.get("cancel") and session_uuid:
@@ -58,7 +58,7 @@ class PrintLabelsView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Templ
58
58
  def model_cls(self):
59
59
  return django_apps.get_model(f"edc_pharmacy.{self.kwargs.get('model')}")
60
60
 
61
- def post(self, request, *args, **kwargs):
61
+ def post(self, request, *args, **kwargs): # noqa: ARG002
62
62
  session_uuid = str(kwargs.get("session_uuid"))
63
63
  stock_pks = request.session.get(session_uuid, [])
64
64
  url = self.source_changelist_url