clinicedc 2.0.6__py3-none-any.whl → 2.0.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.

Potentially problematic release.


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

Files changed (495) hide show
  1. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
  3. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
  4. edc_action_item/action.py +1 -1
  5. edc_action_item/action_item_notification.py +2 -2
  6. edc_action_item/auths.py +37 -32
  7. edc_action_item/create_action_item.py +1 -1
  8. edc_action_item/decorators.py +1 -1
  9. edc_action_item/migrations/0001_initial.py +21 -22
  10. edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
  11. edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
  12. edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
  13. edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
  14. edc_action_item/migrations/0030_edcpermissions.py +3 -2
  15. edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
  16. edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
  17. edc_action_item/models/action_item.py +9 -4
  18. edc_action_item/models/action_model_mixin.py +5 -6
  19. edc_action_item/models/reference.py +2 -2
  20. edc_action_item/models/signals.py +22 -23
  21. edc_action_item/post_migrate_signals.py +1 -1
  22. edc_action_item/send_email.py +0 -85
  23. edc_action_item/site_action_items.py +5 -9
  24. edc_action_item/utils.py +3 -3
  25. edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
  26. edc_adherence/model_mixins.py +1 -1
  27. edc_adverse_event/auths.py +55 -51
  28. edc_adverse_event/migrations/0001_initial.py +5 -4
  29. edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
  30. edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
  31. edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
  32. edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
  33. edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
  34. edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
  35. edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
  36. edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
  37. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
  38. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
  39. edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
  40. edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
  41. edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
  42. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
  43. edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
  44. edc_adverse_event/models/signals.py +7 -7
  45. edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
  46. edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
  47. edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
  48. edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
  49. edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
  50. edc_appointment/admin/appointment_admin.py +2 -2
  51. edc_appointment/admin/list_filters.py +2 -2
  52. edc_appointment/auths.py +14 -10
  53. edc_appointment/creators/appointment_creator.py +1 -1
  54. edc_appointment/creators/appointments_creator.py +1 -1
  55. edc_appointment/form_validators/appointment_form_validator.py +108 -82
  56. edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
  57. edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
  58. edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
  59. edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
  60. edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
  61. edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
  62. edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
  63. edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
  64. edc_appointment/models/appointment.py +1 -1
  65. edc_appointment/models/signals.py +44 -35
  66. edc_appointment/utils.py +19 -24
  67. edc_appointment/view_utils/appointment_button.py +2 -2
  68. edc_auth/admin/user_admin.py +1 -1
  69. edc_auth/auth_objects/__init__.py +2 -20
  70. edc_auth/auth_objects/default_groups.py +13 -11
  71. edc_auth/auth_objects/default_roles.py +26 -24
  72. edc_auth/auth_updater/auth_updater.py +13 -2
  73. edc_auth/auth_updater/group_updater.py +12 -10
  74. edc_auth/auth_updater/role_updater.py +2 -2
  75. edc_auth/constants.py +10 -0
  76. edc_auth/import_users.py +3 -3
  77. edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
  78. edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
  79. edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
  80. edc_auth/migrations/0025_permissions.py +3 -2
  81. edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
  82. edc_auth/models/user_profile.py +14 -11
  83. edc_auth/post_migrate_signals.py +1 -1
  84. edc_auth/site_auths.py +80 -67
  85. edc_consent/actions.py +4 -5
  86. edc_consent/auths.py +18 -12
  87. edc_consent/migrations/0001_initial.py +3 -2
  88. edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  89. edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
  90. edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
  91. edc_consent/utils.py +1 -1
  92. edc_constants/constants.py +1 -0
  93. edc_crf/auths.py +5 -0
  94. edc_crf/migrations/0001_initial.py +3 -2
  95. edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
  96. edc_dashboard/auths.py +10 -6
  97. edc_dashboard/migrations/0001_initial.py +3 -2
  98. edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  99. edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
  100. edc_dashboard/url_config.py +92 -83
  101. edc_dashboard/url_names.py +4 -4
  102. edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
  103. edc_data_manager/action_items.py +4 -6
  104. edc_data_manager/admin/actions.py +5 -5
  105. edc_data_manager/admin/data_query_admin.py +12 -11
  106. edc_data_manager/auths.py +37 -34
  107. edc_data_manager/handlers/handlers.py +6 -7
  108. edc_data_manager/migrations/0001_initial.py +19 -19
  109. edc_data_manager/migrations/0025_edcpermissions.py +3 -2
  110. edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
  111. edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
  112. edc_data_manager/models/data_query.py +5 -5
  113. edc_data_manager/models/model_mixins.py +8 -8
  114. edc_data_manager/rule/query_rule_wrapper.py +7 -7
  115. edc_data_manager/rule/rule_runner.py +4 -3
  116. edc_document_status/model_mixins.py +1 -1
  117. edc_egfr/egfr.py +11 -7
  118. edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
  119. edc_export/admin/data_request_admin.py +2 -2
  120. edc_export/archive_exporter.py +7 -5
  121. edc_export/auths.py +32 -28
  122. edc_export/files_archiver.py +3 -2
  123. edc_export/migrations/0001_initial.py +26 -26
  124. edc_export/migrations/0004_auto_20190305_0123.py +25 -72
  125. edc_export/migrations/0013_edcpermissions.py +3 -2
  126. edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
  127. edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
  128. edc_export/model_exporter/file_history_updater.py +10 -10
  129. edc_export/model_exporter/model_exporter.py +17 -15
  130. edc_export/model_exporter/object_history_helpers.py +2 -2
  131. edc_export/models/data_request_history.py +4 -4
  132. edc_export/utils.py +10 -15
  133. edc_facility/auths.py +8 -3
  134. edc_facility/facility.py +16 -22
  135. edc_facility/import_holidays.py +13 -13
  136. edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
  137. edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
  138. edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
  139. edc_facility/model_mixins.py +5 -5
  140. edc_form_label/custom_label_condition.py +11 -8
  141. edc_form_label/form_label.py +1 -1
  142. edc_form_runners/auths.py +11 -6
  143. edc_form_runners/form_runner.py +3 -5
  144. edc_form_runners/migrations/0001_initial.py +3 -2
  145. edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
  146. edc_form_validators/applicable_field_validator.py +7 -6
  147. edc_form_validators/base_form_validator.py +8 -9
  148. edc_form_validators/other_specify_field_validator.py +2 -8
  149. edc_form_validators/required_field_validator.py +19 -16
  150. edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
  151. edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
  152. edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
  153. edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
  154. edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
  155. edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
  156. edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
  157. edc_identifier/model_mixins.py +1 -1
  158. edc_identifier/models.py +9 -9
  159. edc_identifier/research_identifier.py +11 -10
  160. edc_identifier/simple_identifier.py +9 -5
  161. edc_identifier/subject_identifier.py +3 -2
  162. edc_lab/auths.py +26 -23
  163. edc_lab/lab/aliquot_creator.py +5 -8
  164. edc_lab/lab/primary_aliquot.py +14 -5
  165. edc_lab/migrations/0001_initial.py +29 -29
  166. edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
  167. edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
  168. edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
  169. edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
  170. edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
  171. edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
  172. edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
  173. edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
  174. edc_lab/model_mixins/panel_model_mixin.py +18 -7
  175. edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
  176. edc_lab/model_mixins/requisition/requisition_model_mixin.py +13 -16
  177. edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
  178. edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
  179. edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
  180. edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
  181. edc_lab/models/aliquot.py +2 -2
  182. edc_lab/models/box.py +1 -1
  183. edc_lab/models/box_item.py +6 -7
  184. edc_lab/models/manifest/manifest.py +3 -3
  185. edc_lab/models/manifest/manifest_item.py +7 -7
  186. edc_lab/models/manifest/shipper.py +3 -4
  187. edc_lab/models/order.py +6 -4
  188. edc_lab/models/panel.py +4 -4
  189. edc_lab/models/result.py +2 -2
  190. edc_lab/models/result_item.py +2 -2
  191. edc_lab_dashboard/auths.py +16 -11
  192. edc_lab_dashboard/migrations/0001_initial.py +3 -2
  193. edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  194. edc_lab_dashboard/views/action_views/receive_view.py +2 -2
  195. edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
  196. edc_lab_results/calculate_missing.py +8 -8
  197. edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
  198. edc_lab_results/get_summary.py +26 -25
  199. edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -7
  200. edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
  201. edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
  202. edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
  203. edc_label/auths.py +6 -1
  204. edc_label/label_template.py +8 -8
  205. edc_label/migrations/0001_initial.py +3 -2
  206. edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
  207. edc_list_data/list_model_maker.py +2 -2
  208. edc_list_data/load_list_data.py +11 -14
  209. edc_list_data/load_model_data.py +3 -3
  210. edc_list_data/model_mixins.py +12 -4
  211. edc_list_data/post_migrate_signals.py +1 -1
  212. edc_list_data/preload_data.py +4 -4
  213. edc_list_data/row.py +1 -1
  214. edc_list_data/site_list_data.py +6 -5
  215. edc_listboard/migrations/0001_initial.py +3 -2
  216. edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
  217. edc_locator/auths.py +18 -13
  218. edc_locator/migrations/0001_initial.py +7 -7
  219. edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
  220. edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
  221. edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
  222. edc_locator/model_mixins/locator_model_mixin.py +2 -2
  223. edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
  224. edc_locator/modeladmin_mixins.py +5 -4
  225. edc_ltfu/model_mixins.py +7 -5
  226. edc_metadata/auths.py +11 -7
  227. edc_metadata/metadata/metadata.py +1 -1
  228. edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
  229. edc_metadata/metadata_rules/decorators.py +1 -1
  230. edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
  231. edc_metadata/metadata_rules/rule.py +2 -3
  232. edc_metadata/metadata_rules/rule_evaluator.py +1 -1
  233. edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
  234. edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
  235. edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
  236. edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
  237. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
  238. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
  239. edc_metadata/models/crf_metadata.py +5 -5
  240. edc_metadata/models/crf_metadata_model_mixin.py +4 -5
  241. edc_metadata/models/requisition_metadata.py +6 -6
  242. edc_metadata/models/signals.py +10 -11
  243. edc_metadata/views/refresh_metadata_actions_view.py +3 -3
  244. edc_model/models/address_mixin.py +6 -6
  245. edc_model/models/fields/initials_field.py +2 -1
  246. edc_model/models/historical_records.py +2 -9
  247. edc_model/models/url_model_mixin.py +2 -2
  248. edc_model/validators/date.py +7 -8
  249. edc_model_admin/list_filters/future_date_list_filter.py +3 -3
  250. edc_model_admin/list_filters/past_date_list_filter.py +3 -3
  251. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
  252. edc_model_fields/fields/other_charfield.py +2 -2
  253. edc_navbar/auths.py +18 -13
  254. edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
  255. edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
  256. edc_notification/auths.py +9 -4
  257. edc_notification/migrations/0001_initial.py +3 -3
  258. edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
  259. edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
  260. edc_notification/models/notification.py +1 -1
  261. edc_notification/notification/graded_event_notification.py +2 -2
  262. edc_notification/notification/model_notification.py +3 -30
  263. edc_notification/notification/new_model_notification.py +1 -1
  264. edc_notification/notification/notification.py +12 -12
  265. edc_notification/notification/updated_model_notification.py +2 -2
  266. edc_offstudy/auths.py +12 -7
  267. edc_offstudy/migrations/0001_initial.py +4 -4
  268. edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
  269. edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
  270. edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
  271. edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
  272. edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
  273. edc_pdutils/df_exporters/csv_exporter.py +33 -37
  274. edc_pdutils/df_exporters/csv_model_exporter.py +7 -3
  275. edc_pdutils/migrations/0001_initial.py +8 -8
  276. edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
  277. edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
  278. edc_pharmacy/auths.py +19 -15
  279. edc_pharmacy/migrations/0001_initial.py +64 -63
  280. edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
  281. edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
  282. edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
  283. edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
  284. edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
  285. edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
  286. edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
  287. edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
  288. edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
  289. edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
  290. edc_pharmacy/migrations/0068_stockout.py +2 -3
  291. edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
  292. edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
  293. edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
  294. edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
  295. edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
  296. edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
  297. edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
  298. edc_pharmacy/models/medication/formulation.py +5 -7
  299. edc_pharmacy/models/medication/medication.py +3 -3
  300. edc_pharmacy/models/model_mixins.py +10 -11
  301. edc_pharmacy/models/prescription/rx.py +13 -12
  302. edc_pharmacy/models/prescription/rx_refill.py +0 -1
  303. edc_pharmacy/models/stock/allocation.py +3 -3
  304. edc_pharmacy/models/stock/confirmation.py +3 -3
  305. edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
  306. edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
  307. edc_pharmacy/models/stock/dispense.py +5 -6
  308. edc_pharmacy/models/stock/dispense_item.py +2 -2
  309. edc_pharmacy/models/stock/location.py +3 -4
  310. edc_pharmacy/models/stock/lot.py +6 -7
  311. edc_pharmacy/models/stock/order.py +1 -1
  312. edc_pharmacy/models/stock/receive.py +3 -3
  313. edc_pharmacy/models/stock/receive_item.py +4 -4
  314. edc_pharmacy/models/stock/repack_request.py +2 -2
  315. edc_pharmacy/models/stock/stock.py +12 -18
  316. edc_pharmacy/models/stock/stock_adjustment.py +4 -4
  317. edc_pharmacy/models/stock/stock_request.py +2 -2
  318. edc_pharmacy/models/stock/stock_request_item.py +2 -2
  319. edc_pharmacy/models/stock/stock_transfer.py +3 -3
  320. edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
  321. edc_pharmacy/models/stock/storage_bin.py +3 -4
  322. edc_pharmacy/models/stock/storage_bin_item.py +2 -2
  323. edc_pharmacy/models/stock/supplier.py +3 -4
  324. edc_pharmacy/models/storage/box.py +2 -2
  325. edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
  326. edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
  327. edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
  328. edc_pharmacy/models/storage/room.py +2 -2
  329. edc_pharmacy/models/storage/shelf.py +2 -2
  330. edc_pharmacy/models/storage/utils.py +1 -1
  331. edc_pharmacy/prescribe/create_prescription.py +3 -3
  332. edc_pharmacy/utils/allocate_stock.py +2 -3
  333. edc_pharmacy/utils/confirm_stock.py +3 -4
  334. edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
  335. edc_pharmacy/utils/dispense.py +3 -4
  336. edc_pharmacy/utils/process_repack_request.py +4 -5
  337. edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
  338. edc_pharmacy/utils/transfer_stock.py +2 -3
  339. edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
  340. edc_pharmacy/views/allocate_to_subject_view.py +2 -2
  341. edc_pharmacy/views/confirmation_at_site_view.py +6 -9
  342. edc_pharmacy/views/dispense_view.py +2 -2
  343. edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
  344. edc_pharmacy/views/print_labels_view.py +2 -2
  345. edc_prn/admin_site.py +5 -0
  346. edc_prn/prn.py +10 -11
  347. edc_prn/urls.py +11 -0
  348. edc_protocol/research_protocol_config.py +2 -3
  349. edc_protocol_incident/action_items.py +4 -4
  350. edc_protocol_incident/auths.py +27 -20
  351. edc_protocol_incident/migrations/0001_initial.py +7 -7
  352. edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
  353. edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
  354. edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
  355. edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
  356. edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
  357. edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
  358. edc_pylabels/actions.py +3 -5
  359. edc_pylabels/auths.py +6 -1
  360. edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
  361. edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
  362. edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
  363. edc_qareports/auths.py +11 -7
  364. edc_qareports/migrations/0001_initial.py +4 -5
  365. edc_qareports/migrations/0005_edcpermissions.py +3 -3
  366. edc_qareports/migrations/0006_qareportlog.py +2 -3
  367. edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
  368. edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
  369. edc_qareports/model_mixins/note_model_mixin.py +7 -4
  370. edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
  371. edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
  372. edc_qareports/models/note.py +4 -4
  373. edc_qareports/models/qa_reports_log.py +2 -3
  374. edc_randomization/admin.py +30 -24
  375. edc_randomization/auths.py +12 -7
  376. edc_randomization/decorators.py +1 -1
  377. edc_randomization/migrations/0001_initial.py +3 -2
  378. edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
  379. edc_randomization/migrations/0009_edcpermissions.py +3 -2
  380. edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
  381. edc_randomization/model_mixins.py +9 -9
  382. edc_randomization/randomizer.py +22 -20
  383. edc_randomization/utils.py +19 -18
  384. edc_refusal/auths.py +7 -2
  385. edc_refusal/migrations/0001_initial.py +4 -4
  386. edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
  387. edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
  388. edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
  389. edc_refusal/model_mixins.py +4 -4
  390. edc_registration/auths.py +28 -23
  391. edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
  392. edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
  393. edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
  394. edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
  395. edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
  396. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +15 -7
  397. edc_registration/models/registered_subject.py +28 -27
  398. edc_reportable/age_evaluator.py +4 -2
  399. edc_reportable/formula.py +5 -5
  400. edc_reportable/migrations/0001_initial.py +7 -7
  401. edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
  402. edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
  403. edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
  404. edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
  405. edc_reportable/models/normal_data.py +4 -5
  406. edc_reportable/models/reference_model_mixins.py +10 -11
  407. edc_reportable/models/reference_range_collection.py +12 -13
  408. edc_reportable/post_migrate_signals.py +1 -1
  409. edc_reportable/utils/convert_units.py +11 -45
  410. edc_reportable/utils/get_normal_data_or_raise.py +2 -2
  411. edc_reportable/utils/get_reference_range_collection.py +2 -3
  412. edc_reportable/utils/load_data.py +4 -4
  413. edc_reportable/utils/update_grading_data.py +5 -5
  414. edc_review_dashboard/auths.py +23 -18
  415. edc_review_dashboard/migrations/0001_initial.py +3 -2
  416. edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  417. edc_screening/age_evaluator.py +6 -6
  418. edc_screening/auths.py +35 -30
  419. edc_screening/eligibility.py +1 -1
  420. edc_screening/gender_evaluator.py +1 -1
  421. edc_screening/migrations/0001_initial.py +3 -2
  422. edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  423. edc_screening/model_mixins/eligibility_model_mixin.py +3 -6
  424. edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
  425. edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
  426. edc_screening/screening_eligibility.py +2 -4
  427. edc_screening/utils.py +9 -9
  428. edc_search/generate_slug.py +26 -0
  429. edc_search/model_mixins.py +10 -22
  430. edc_sites/auths.py +8 -3
  431. edc_sites/migrations/0007_edcpermissions.py +3 -2
  432. edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
  433. edc_sites/model_mixins/site_model_mixin.py +2 -2
  434. edc_sites/site.py +5 -5
  435. edc_sites/system_checks.py +1 -1
  436. edc_subject_dashboard/auths.py +27 -22
  437. edc_subject_dashboard/migrations/0001_initial.py +3 -2
  438. edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  439. edc_subject_dashboard/requisition_report.py +6 -4
  440. edc_subject_dashboard/requisition_verifier.py +6 -6
  441. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
  442. edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
  443. edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
  444. edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
  445. edc_timepoint/apps.py +0 -21
  446. edc_timepoint/model_mixins.py +22 -20
  447. edc_transfer/model_mixins.py +4 -4
  448. edc_transfer/modeladmin_mixins.py +1 -1
  449. edc_unblinding/auths.py +9 -4
  450. edc_unblinding/migrations/0001_initial.py +13 -13
  451. edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
  452. edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
  453. edc_unblinding/models/unblinding_request.py +2 -2
  454. edc_unblinding/models/unblinding_review.py +3 -3
  455. edc_utils/__init__.py +3 -1
  456. edc_utils/age.py +10 -16
  457. edc_utils/show_urls.py +29 -2
  458. edc_visit_schedule/auths.py +6 -1
  459. edc_visit_schedule/migrations/0001_initial.py +3 -3
  460. edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
  461. edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
  462. edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
  463. edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
  464. edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
  465. edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
  466. edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
  467. edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
  468. edc_visit_schedule/models/subject_schedule_history.py +6 -6
  469. edc_visit_schedule/schedule/visit_collection.py +1 -1
  470. edc_visit_schedule/site_visit_schedules.py +2 -2
  471. edc_visit_schedule/subject_schedule.py +5 -4
  472. edc_visit_schedule/view_mixins.py +2 -3
  473. edc_visit_schedule/visit/visit.py +3 -2
  474. edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
  475. edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
  476. edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
  477. edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
  478. edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
  479. edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
  480. edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
  481. edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
  482. edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
  483. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
  484. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
  485. edc_visit_tracking/models/signals.py +3 -3
  486. edc_visit_tracking/models/subject_visit.py +1 -1
  487. edc_vitals/calculators/bmi.py +7 -5
  488. edc_vitals/utils.py +1 -1
  489. edc_form_label/models.py +0 -0
  490. edc_search/constants.py +0 -1
  491. edc_search/models.py +0 -0
  492. edc_search/search_slug.py +0 -50
  493. edc_search/updater.py +0 -30
  494. edc_search/wsgi.py +0 -7
  495. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,188 @@
1
+ # Generated by Django 5.2.6 on 2025-09-17 16:53
2
+
3
+ import edc_model_fields.fields.other_charfield
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("edc_offstudy", "0022_alter_historicalsubjectoffstudy_revision_and_more"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name="historicalsubjectoffstudy",
16
+ name="action_identifier",
17
+ field=models.CharField(
18
+ blank=True, db_index=True, default="", max_length=50
19
+ ),
20
+ ),
21
+ migrations.AlterField(
22
+ model_name="historicalsubjectoffstudy",
23
+ name="action_item_reason",
24
+ field=models.TextField(default="", editable=False),
25
+ ),
26
+ migrations.AlterField(
27
+ model_name="historicalsubjectoffstudy",
28
+ name="comment",
29
+ field=models.TextField(
30
+ blank=True,
31
+ default="",
32
+ max_length=500,
33
+ verbose_name="Please provide further details if possible",
34
+ ),
35
+ ),
36
+ migrations.AlterField(
37
+ model_name="historicalsubjectoffstudy",
38
+ name="device_created",
39
+ field=models.CharField(
40
+ blank=True, default="", max_length=10, verbose_name="Device created"
41
+ ),
42
+ ),
43
+ migrations.AlterField(
44
+ model_name="historicalsubjectoffstudy",
45
+ name="device_modified",
46
+ field=models.CharField(
47
+ blank=True, default="", max_length=10, verbose_name="Device modified"
48
+ ),
49
+ ),
50
+ migrations.AlterField(
51
+ model_name="historicalsubjectoffstudy",
52
+ name="locale_created",
53
+ field=models.CharField(
54
+ blank=True,
55
+ default="",
56
+ help_text="Auto-updated by Modeladmin",
57
+ max_length=10,
58
+ verbose_name="Locale created",
59
+ ),
60
+ ),
61
+ migrations.AlterField(
62
+ model_name="historicalsubjectoffstudy",
63
+ name="locale_modified",
64
+ field=models.CharField(
65
+ blank=True,
66
+ default="",
67
+ help_text="Auto-updated by Modeladmin",
68
+ max_length=10,
69
+ verbose_name="Locale modified",
70
+ ),
71
+ ),
72
+ migrations.AlterField(
73
+ model_name="historicalsubjectoffstudy",
74
+ name="other_offstudy_reason",
75
+ field=edc_model_fields.fields.other_charfield.OtherCharField(
76
+ blank=True,
77
+ default="",
78
+ max_length=35,
79
+ verbose_name="If other, please specify ...",
80
+ ),
81
+ ),
82
+ migrations.AlterField(
83
+ model_name="historicalsubjectoffstudy",
84
+ name="parent_action_identifier",
85
+ field=models.CharField(
86
+ blank=True,
87
+ default="",
88
+ help_text="action identifier that links to parent reference model instance.",
89
+ max_length=30,
90
+ ),
91
+ ),
92
+ migrations.AlterField(
93
+ model_name="historicalsubjectoffstudy",
94
+ name="related_action_identifier",
95
+ field=models.CharField(
96
+ blank=True,
97
+ default="",
98
+ help_text="action identifier that links to related reference model instance.",
99
+ max_length=30,
100
+ ),
101
+ ),
102
+ migrations.AlterField(
103
+ model_name="subjectoffstudy",
104
+ name="action_identifier",
105
+ field=models.CharField(blank=True, default="", max_length=50, unique=True),
106
+ ),
107
+ migrations.AlterField(
108
+ model_name="subjectoffstudy",
109
+ name="action_item_reason",
110
+ field=models.TextField(default="", editable=False),
111
+ ),
112
+ migrations.AlterField(
113
+ model_name="subjectoffstudy",
114
+ name="comment",
115
+ field=models.TextField(
116
+ blank=True,
117
+ default="",
118
+ max_length=500,
119
+ verbose_name="Please provide further details if possible",
120
+ ),
121
+ ),
122
+ migrations.AlterField(
123
+ model_name="subjectoffstudy",
124
+ name="device_created",
125
+ field=models.CharField(
126
+ blank=True, default="", max_length=10, verbose_name="Device created"
127
+ ),
128
+ ),
129
+ migrations.AlterField(
130
+ model_name="subjectoffstudy",
131
+ name="device_modified",
132
+ field=models.CharField(
133
+ blank=True, default="", max_length=10, verbose_name="Device modified"
134
+ ),
135
+ ),
136
+ migrations.AlterField(
137
+ model_name="subjectoffstudy",
138
+ name="locale_created",
139
+ field=models.CharField(
140
+ blank=True,
141
+ default="",
142
+ help_text="Auto-updated by Modeladmin",
143
+ max_length=10,
144
+ verbose_name="Locale created",
145
+ ),
146
+ ),
147
+ migrations.AlterField(
148
+ model_name="subjectoffstudy",
149
+ name="locale_modified",
150
+ field=models.CharField(
151
+ blank=True,
152
+ default="",
153
+ help_text="Auto-updated by Modeladmin",
154
+ max_length=10,
155
+ verbose_name="Locale modified",
156
+ ),
157
+ ),
158
+ migrations.AlterField(
159
+ model_name="subjectoffstudy",
160
+ name="other_offstudy_reason",
161
+ field=edc_model_fields.fields.other_charfield.OtherCharField(
162
+ blank=True,
163
+ default="",
164
+ max_length=35,
165
+ verbose_name="If other, please specify ...",
166
+ ),
167
+ ),
168
+ migrations.AlterField(
169
+ model_name="subjectoffstudy",
170
+ name="parent_action_identifier",
171
+ field=models.CharField(
172
+ blank=True,
173
+ default="",
174
+ help_text="action identifier that links to parent reference model instance.",
175
+ max_length=30,
176
+ ),
177
+ ),
178
+ migrations.AlterField(
179
+ model_name="subjectoffstudy",
180
+ name="related_action_identifier",
181
+ field=models.CharField(
182
+ blank=True,
183
+ default="",
184
+ help_text="action identifier that links to related reference model instance.",
185
+ max_length=30,
186
+ ),
187
+ ),
188
+ ]
@@ -0,0 +1,43 @@
1
+ # Generated by Django 5.2.6 on 2025-09-18 00:24
2
+
3
+ import django.utils.timezone
4
+ import edc_model.validators.date
5
+ import edc_protocol.validators
6
+ from django.db import migrations, models
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ (
13
+ "edc_offstudy",
14
+ "0023_alter_historicalsubjectoffstudy_action_identifier_and_more",
15
+ ),
16
+ ]
17
+
18
+ operations = [
19
+ migrations.AlterField(
20
+ model_name="historicalsubjectoffstudy",
21
+ name="offstudy_datetime",
22
+ field=models.DateTimeField(
23
+ default=django.utils.timezone.now,
24
+ validators=[
25
+ edc_protocol.validators.datetime_not_before_study_start,
26
+ edc_model.validators.date.datetime_not_future,
27
+ ],
28
+ verbose_name="Off-study date and time",
29
+ ),
30
+ ),
31
+ migrations.AlterField(
32
+ model_name="subjectoffstudy",
33
+ name="offstudy_datetime",
34
+ field=models.DateTimeField(
35
+ default=django.utils.timezone.now,
36
+ validators=[
37
+ edc_protocol.validators.datetime_not_before_study_start,
38
+ edc_model.validators.date.datetime_not_future,
39
+ ],
40
+ verbose_name="Off-study date and time",
41
+ ),
42
+ ),
43
+ ]
@@ -3,12 +3,13 @@ from zoneinfo import ZoneInfo
3
3
  from django.conf import settings
4
4
  from django.core.exceptions import ValidationError
5
5
  from django.db import models
6
+ from django.utils import timezone
6
7
 
7
8
  from edc_identifier.model_mixins import UniqueSubjectIdentifierFieldMixin
8
9
  from edc_model.validators import datetime_not_future
9
10
  from edc_model_fields.fields import OtherCharField
10
11
  from edc_protocol.validators import datetime_not_before_study_start
11
- from edc_utils import convert_php_dateformat, get_utcnow
12
+ from edc_utils import convert_php_dateformat
12
13
  from edc_visit_schedule.utils import (
13
14
  off_all_schedules_or_raise,
14
15
  offstudy_datetime_after_all_offschedule_datetimes,
@@ -39,7 +40,7 @@ class OffstudyModelMixin(UniqueSubjectIdentifierFieldMixin, models.Model):
39
40
  offstudy_datetime = models.DateTimeField(
40
41
  verbose_name="Off-study date and time",
41
42
  validators=[datetime_not_before_study_start, datetime_not_future],
42
- default=get_utcnow,
43
+ default=timezone.now,
43
44
  )
44
45
 
45
46
  report_datetime = models.DateTimeField(null=True, editable=False)
@@ -1,13 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
3
+ import contextlib
4
4
  import sys
5
+ from pathlib import Path
5
6
 
6
7
  import pandas as pd
7
8
  from django.apps import apps as django_apps
8
9
  from django.conf import settings
9
10
  from django.core.management.color import color_style
10
11
  from django.db.models import QuerySet
12
+ from django.utils import timezone
11
13
 
12
14
  from edc_export.exceptions import (
13
15
  ExporterExportFolder,
@@ -15,7 +17,6 @@ from edc_export.exceptions import (
15
17
  ExporterInvalidExportFormat,
16
18
  )
17
19
  from edc_export.utils import get_base_dir
18
- from edc_utils import get_utcnow
19
20
 
20
21
  from ..site_values_mappings import site_values_mappings
21
22
  from ..utils import get_export_folder, get_model_from_table_name
@@ -24,9 +25,7 @@ style = color_style()
24
25
 
25
26
 
26
27
  class Exported:
27
- def __init__(
28
- self, path: str = None, model_name: str = None, record_count: int | None = None
29
- ):
28
+ def __init__(self, path: Path, model_name: str, record_count: int):
30
29
  self.path = path
31
30
  self.model_name = model_name
32
31
  self.record_count = record_count
@@ -53,7 +52,7 @@ class CsvExporter:
53
52
  data_label: str | None = None,
54
53
  app_label: str | None = None,
55
54
  sort_by: list | tuple | str | None = None,
56
- export_folder: str = None,
55
+ export_folder: Path | None = None,
57
56
  delimiter: str | None = None,
58
57
  date_format: str | None = None,
59
58
  index: bool | None = None,
@@ -75,13 +74,11 @@ class CsvExporter:
75
74
  self.verbose = verbose
76
75
  if not self.export_folder:
77
76
  raise ExporterExportFolder("Invalid export folder. Got None")
78
- if not os.path.exists(self.export_folder):
77
+ if not self.export_folder.exists():
79
78
  raise ExporterExportFolder(f"Invalid export folder. Got {self.export_folder}")
80
79
  if self.model_name:
81
- try:
80
+ with contextlib.suppress(LookupError, AttributeError):
82
81
  self.model_cls = django_apps.get_model(self.model_name)
83
- except (LookupError, AttributeError):
84
- pass
85
82
  elif self.table_name:
86
83
  self.model_cls = get_model_from_table_name(table_name)
87
84
  if self.model_cls:
@@ -89,7 +86,7 @@ class CsvExporter:
89
86
  self.data_label = data_label or model_name or table_name
90
87
 
91
88
  def to_format(
92
- self, export_format, dataframe=None, export_folder=None, **kwargs
89
+ self, export_format: str, dataframe: pd.DataFrame, export_folder: Path, **kwargs
93
90
  ) -> Exported:
94
91
  """Returns the full path of the written CSV file if the
95
92
  dataframe is exported otherwise None.
@@ -109,18 +106,18 @@ class CsvExporter:
109
106
  if not dataframe.empty:
110
107
  path = self.get_path()
111
108
  if self.sort_by:
112
- dataframe.sort_values(by=self.sort_by, inplace=True)
109
+ dataframe = dataframe.sort_values(by=self.sort_by)
113
110
  if self.verbose:
114
111
  sys.stdout.write(f"( ) {self.model_name} ... \r")
115
112
  if export_format == "csv":
116
- path = ".".join([path, "csv"])
113
+ path = path.with_suffix(".csv")
117
114
  dataframe.to_csv(path_or_buf=path, **self.csv_options)
118
115
  elif export_format == "stata":
119
- path = ".".join([path, "dta"])
116
+ path = path.with_suffix(".dta")
120
117
  dta_version: str | None = kwargs.pop("dta_version", None)
121
118
  dta_version = int(dta_version) if dta_version else None
122
119
  dataframe.to_stata(
123
- path=path, **self.stata_options, version=dta_version, **kwargs
120
+ path=str(path), **self.stata_options, version=dta_version, **kwargs
124
121
  )
125
122
  else:
126
123
  raise ExporterInvalidExportFormat(
@@ -135,7 +132,7 @@ class CsvExporter:
135
132
  sys.stdout.write(f"(?) {self.model_name} empty \n")
136
133
  return Exported(path, self.model_name, record_count)
137
134
 
138
- def to_csv(self, dataframe: pd.DataFrame = None, export_folder: str = None) -> Exported:
135
+ def to_csv(self, dataframe: pd.DataFrame, export_folder: Path) -> Exported:
139
136
  """Returns the full path of the written CSV file if the
140
137
  dataframe is exported otherwise None.
141
138
 
@@ -149,9 +146,9 @@ class CsvExporter:
149
146
 
150
147
  def to_stata(
151
148
  self,
152
- dataframe: pd.DataFrame = None,
153
- export_folder: str = None,
154
- dta_version: str = None,
149
+ dataframe: pd.DataFrame,
150
+ export_folder: Path,
151
+ dta_version: str | None = None,
155
152
  ) -> Exported:
156
153
  """Returns the full path of the written STATA file if the
157
154
  dataframe is exported otherwise None.
@@ -184,16 +181,16 @@ class CsvExporter:
184
181
  """Returns default options for dataframe.to_stata()."""
185
182
  return dict(data_label=f"{self.data_label}.dta")
186
183
 
187
- def get_path(self) -> str:
184
+ def get_path(self) -> Path:
188
185
  """Returns a full path with filename."""
189
186
  root_dir = self.export_folder
190
- if not os.path.exists(root_dir):
187
+ if not root_dir.exists():
191
188
  raise ExporterExportFolder(f"Base folder does not exist. Got {root_dir}.")
192
- base_dir: str = get_base_dir()
193
- if not os.path.exists(os.path.join(root_dir, base_dir)):
194
- os.makedirs(os.path.join(root_dir, base_dir))
195
- path = os.path.join(root_dir, base_dir, self.filename)
196
- if os.path.exists(path) and not self.file_exists_ok:
189
+ base_dir = get_base_dir()
190
+ if not (root_dir / base_dir).exists():
191
+ (root_dir / base_dir).mkdir(parents=True, exist_ok=False)
192
+ path = root_dir / base_dir / self.filename
193
+ if path.exists() and not self.file_exists_ok:
197
194
  raise ExporterFileExists(
198
195
  f"File '{path}' exists! Not exporting {self.model_name}.\n"
199
196
  )
@@ -212,7 +209,7 @@ class CsvExporter:
212
209
  if not timestamp_format:
213
210
  suffix = ""
214
211
  else:
215
- suffix = f"_{get_utcnow().strftime(timestamp_format)}"
212
+ suffix = f"_{timezone.now().strftime(timestamp_format)}"
216
213
  prefix = (self.model_name or self.data_label).replace("-", "_").replace(".", "_")
217
214
  filename = f"{prefix}{suffix}"
218
215
  return filename
@@ -229,15 +226,14 @@ class CsvExporter:
229
226
  choices = {}
230
227
  if self.model_cls:
231
228
  for field_cls in self.model_cls._meta.get_fields():
232
- if field_cls.get_internal_type() == "CharField":
233
- if field_cls.choices:
234
- responses = []
235
- for tpl in field_cls.choices:
236
- if mapped_choice := site_values_mappings.get_by_choices(tpl):
237
- responses.append([mapped_choice[0], mapped_choice[1]])
238
- else:
239
- responses.append([tpl[0], tpl[1]])
240
- choices.update({field_cls.name: responses})
229
+ if field_cls.get_internal_type() == "CharField" and field_cls.choices:
230
+ responses = []
231
+ for tpl in field_cls.choices:
232
+ if mapped_choice := site_values_mappings.get_by_choices(tpl):
233
+ responses.append([mapped_choice[0], mapped_choice[1]])
234
+ else:
235
+ responses.append([tpl[0], tpl[1]])
236
+ choices.update({field_cls.name: responses})
241
237
  for fname, responses in choices.items():
242
238
  labels = []
243
239
  if fname in list(dataframe.columns):
@@ -248,7 +244,7 @@ class CsvExporter:
248
244
  commands.append(f"ren {fname} {fname}_edc")
249
245
  commands.append(f"ren {fname}_encoded {fname}")
250
246
  commands.append("")
251
- with open(f"{self.get_path()}.do", "w") as f:
247
+ with (self.get_path() / ".do").open("w") as f:
252
248
  f.writelines(f"{command}\n" for command in commands)
253
249
  return commands
254
250
 
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from pathlib import Path
3
4
  from typing import TYPE_CHECKING
4
5
 
5
6
  from django.core.management.color import color_style
@@ -24,11 +25,12 @@ class CsvModelExporter:
24
25
  queryset: QuerySet | None = None,
25
26
  decrypt: bool | None = None,
26
27
  sort_by: list | tuple | str | None = None,
27
- export_folder: str | None = None,
28
+ export_folder: Path | None = None,
28
29
  site_ids: list[int] | None = None,
29
30
  **kwargs,
30
31
  ):
31
32
  self.model = model or queryset.model._meta.label_lower
33
+ self.export_folder = export_folder
32
34
  self.df_maker = self.df_maker_cls(
33
35
  model=model,
34
36
  queryset=queryset,
@@ -45,8 +47,10 @@ class CsvModelExporter:
45
47
 
46
48
  def to_csv(self):
47
49
  dataframe = self.df_maker.dataframe
48
- return self.csv_exporter.to_csv(dataframe=dataframe)
50
+ return self.csv_exporter.to_csv(dataframe=dataframe, export_folder=self.export_folder)
49
51
 
50
52
  def to_stata(self):
51
53
  dataframe = self.df_maker.dataframe
52
- return self.csv_exporter.to_stata(dataframe=dataframe)
54
+ return self.csv_exporter.to_stata(
55
+ dataframe=dataframe, export_folder=self.export_folder
56
+ )
@@ -10,7 +10,7 @@ from django.db import migrations, models
10
10
 
11
11
  import edc_model_fields.fields.hostname_modification_field
12
12
  import edc_model_fields.fields.userfield
13
- import edc_utils
13
+ import django.utils.timezone
14
14
 
15
15
 
16
16
  class Migration(migrations.Migration):
@@ -24,11 +24,11 @@ class Migration(migrations.Migration):
24
24
  fields=[
25
25
  (
26
26
  "created",
27
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
27
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
28
28
  ),
29
29
  (
30
30
  "modified",
31
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
31
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
32
32
  ),
33
33
  (
34
34
  "user_created",
@@ -109,11 +109,11 @@ class Migration(migrations.Migration):
109
109
  fields=[
110
110
  (
111
111
  "created",
112
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
112
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
113
113
  ),
114
114
  (
115
115
  "modified",
116
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
116
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
117
117
  ),
118
118
  (
119
119
  "user_created",
@@ -179,7 +179,7 @@ class Migration(migrations.Migration):
179
179
  ("summary", models.TextField(null=True)),
180
180
  (
181
181
  "exported_datetime",
182
- models.DateTimeField(default=edc_utils.date.get_utcnow),
182
+ models.DateTimeField(default=django.utils.timezone.now),
183
183
  ),
184
184
  (
185
185
  "data_request",
@@ -196,11 +196,11 @@ class Migration(migrations.Migration):
196
196
  fields=[
197
197
  (
198
198
  "created",
199
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
199
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
200
200
  ),
201
201
  (
202
202
  "modified",
203
- models.DateTimeField(blank=True, default=edc_utils.date.get_utcnow),
203
+ models.DateTimeField(blank=True, default=django.utils.timezone.now),
204
204
  ),
205
205
  (
206
206
  "user_created",
@@ -2,12 +2,13 @@ from django.conf import settings
2
2
  from django.contrib import admin
3
3
  from django.template.loader import render_to_string
4
4
  from django.urls import reverse
5
+ from django.utils import timezone
5
6
  from django.utils.html import format_html
6
7
  from django.utils.safestring import mark_safe
7
8
  from django_audit_fields.admin import audit_fieldset_tuple
8
9
 
9
10
  from edc_appointment.models import Appointment
10
- from edc_utils import convert_php_dateformat, formatted_age, get_utcnow
11
+ from edc_utils import convert_php_dateformat, formatted_age
11
12
 
12
13
  from ...admin_site import edc_pharmacy_admin
13
14
  from ...forms import RxRefillForm
@@ -21,7 +22,7 @@ class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
21
22
 
22
23
  ordering: tuple[str, ...] = ("refill_start_datetime",)
23
24
 
24
- autocomplete_fields = ["dosage_guideline", "formulation"]
25
+ autocomplete_fields = ("dosage_guideline", "formulation")
25
26
 
26
27
  form = RxRefillForm
27
28
 
@@ -140,7 +141,7 @@ class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
140
141
  "initials": obj.rx.registered_subject.initials,
141
142
  "gender": obj.rx.registered_subject.gender,
142
143
  "age_in_years": formatted_age(
143
- born=obj.rx.registered_subject.dob, reference_dt=get_utcnow()
144
+ born=obj.rx.registered_subject.dob, reference_dt=timezone.now()
144
145
  ),
145
146
  "number_of_days": obj.number_of_days,
146
147
  "remaining": obj.remaining,
@@ -1,6 +1,7 @@
1
1
  from django.contrib import admin
2
2
  from django.db.models import QuerySet
3
3
  from django.urls import reverse
4
+ from django.utils import timezone
4
5
  from django.utils.html import format_html
5
6
  from rangefilter.filters import DateRangeFilterBuilder, NumericRangeFilterBuilder
6
7
 
@@ -8,7 +9,6 @@ from edc_model_admin.dashboard import ModelAdminDashboardMixin
8
9
  from edc_model_admin.mixins import TemplatesModelAdminMixin
9
10
  from edc_qareports.modeladmin_mixins import QaReportModelAdminMixin
10
11
  from edc_sites.admin import SiteModelAdminMixin
11
- from edc_utils import get_utcnow
12
12
 
13
13
  from ...admin_site import edc_pharmacy_admin
14
14
  from ...analytics.dataframes.no_stock_for_subjects_df import stock_for_subjects_df
@@ -21,7 +21,8 @@ def wrap_html(s, url):
21
21
 
22
22
 
23
23
  def update_report(modeladmin, request):
24
- now = get_utcnow()
24
+ now = timezone.now()
25
+ created = 0
25
26
  modeladmin.model.objects.all().delete()
26
27
 
27
28
  df = stock_for_subjects_df()
@@ -50,9 +51,8 @@ def update_report(modeladmin, request):
50
51
  )
51
52
  for _, row in df.iterrows()
52
53
  ]
53
- created = len(modeladmin.model.objects.bulk_create(data))
54
- # messages.success(request, "{} records were successfully created.".format(created))
55
- return created
54
+ return len(modeladmin.model.objects.bulk_create(data))
55
+ return created
56
56
 
57
57
 
58
58
  @admin.register(StockAvailability, site=edc_pharmacy_admin)
@@ -63,7 +63,6 @@ class StockAvailabilityModelAdmin(
63
63
  TemplatesModelAdminMixin,
64
64
  admin.ModelAdmin,
65
65
  ):
66
-
67
66
  queryset_filter: dict | None = None
68
67
  qa_report_list_display_insert_pos = 3
69
68
  include_note_column = False
edc_pharmacy/auths.py CHANGED
@@ -18,21 +18,25 @@ from .auth_objects import (
18
18
  prescriber_codenames,
19
19
  )
20
20
 
21
- site_auths.add_post_update_func(
22
- "edc_pharmacy", remove_default_model_permissions_from_edc_permissions
23
- )
24
- site_auths.add_custom_permissions_tuples(
25
- model="edc_pharmacy.edcpermissions", codename_tuples=navbar_tuples
26
- )
27
21
 
28
- site_auths.add_group(*pharmacy_codenames, name=PHARMACY_VIEW, view_only=True)
29
- site_auths.add_group(*prescriber_codenames, name=PHARMACY_PRESCRIBER, no_delete=True)
30
- site_auths.add_group(*pharmacy_site_codenames, name=PHARMACY_SITE, no_delete=False)
31
- site_auths.add_group(*pharmacy_codenames, name=PHARMACY, no_delete=False)
22
+ def update_site_auths() -> None:
23
+ site_auths.add_post_update_func(
24
+ "edc_pharmacy", remove_default_model_permissions_from_edc_permissions
25
+ )
26
+ site_auths.add_custom_permissions_tuples(
27
+ model="edc_pharmacy.edcpermissions", codename_tuples=navbar_tuples
28
+ )
29
+
30
+ site_auths.add_group(*pharmacy_codenames, name=PHARMACY_VIEW, view_only=True)
31
+ site_auths.add_group(*prescriber_codenames, name=PHARMACY_PRESCRIBER, no_delete=True)
32
+ site_auths.add_group(*pharmacy_site_codenames, name=PHARMACY_SITE, no_delete=False)
33
+ site_auths.add_group(*pharmacy_codenames, name=PHARMACY, no_delete=False)
34
+
35
+ site_auths.add_role(PHARMACY_VIEW, name=PHARMACY_AUDITOR_ROLE)
36
+ site_auths.add_role(PHARMACY_PRESCRIBER, name=PHARMACY_PRESCRIBER_ROLE)
37
+ site_auths.add_role(PHARMACY_SITE, PYLABELS, name=SITE_PHARMACIST_ROLE)
38
+ site_auths.add_role(PHARMACY, PYLABELS, name=PHARMACIST_ROLE)
39
+ site_auths.add_role(PHARMACY, name=PHARMACY_SUPER_ROLE)
32
40
 
33
41
 
34
- site_auths.add_role(PHARMACY_VIEW, name=PHARMACY_AUDITOR_ROLE)
35
- site_auths.add_role(PHARMACY_PRESCRIBER, name=PHARMACY_PRESCRIBER_ROLE)
36
- site_auths.add_role(PHARMACY_SITE, PYLABELS, name=SITE_PHARMACIST_ROLE)
37
- site_auths.add_role(PHARMACY, PYLABELS, name=PHARMACIST_ROLE)
38
- site_auths.add_role(PHARMACY, name=PHARMACY_SUPER_ROLE)
42
+ update_site_auths()