django-forms-workflows 0.74.2__tar.gz → 0.74.4__tar.gz

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.
Files changed (219) hide show
  1. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/CHANGELOG.md +35 -0
  2. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/PKG-INFO +1 -1
  3. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/diff_views.py +34 -1
  4. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/sync_api.py +33 -36
  5. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/tasks.py +32 -1
  6. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/pyproject.toml +1 -1
  7. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/LICENSE +0 -0
  8. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/README.md +0 -0
  9. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/__init__.py +0 -0
  10. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/admin.py +0 -0
  11. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/api_urls.py +0 -0
  12. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/api_views.py +0 -0
  13. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/apps.py +0 -0
  14. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/callback_registry.py +0 -0
  15. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/conditions.py +0 -0
  16. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/context_processors.py +0 -0
  17. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/data_sources/__init__.py +0 -0
  18. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/data_sources/base.py +0 -0
  19. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/data_sources/database_source.py +0 -0
  20. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/data_sources/ldap_source.py +0 -0
  21. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/data_sources/user_source.py +0 -0
  22. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/email_backends/__init__.py +0 -0
  23. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/email_backends/gmail_api.py +0 -0
  24. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/form_builder_urls.py +0 -0
  25. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/form_builder_views.py +0 -0
  26. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/forms.py +0 -0
  27. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/__init__.py +0 -0
  28. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/api_handler.py +0 -0
  29. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/base.py +0 -0
  30. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/database_handler.py +0 -0
  31. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/email_handler.py +0 -0
  32. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/executor.py +0 -0
  33. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/file_handler.py +0 -0
  34. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/handlers/ldap_handler.py +0 -0
  35. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/history.py +0 -0
  36. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/ldap_backend.py +0 -0
  37. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/create_default_templates.py +0 -0
  38. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/pull_forms.py +0 -0
  39. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/push_forms.py +0 -0
  40. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/seed_farm_demo.py +0 -0
  41. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/seed_pcn_form.py +0 -0
  42. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/seed_prefill_sources.py +0 -0
  43. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/sync_ldap_profiles.py +0 -0
  44. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/sync_ldap_users.py +0 -0
  45. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/management/commands/test_db_connection.py +0 -0
  46. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0001_initial.py +0 -0
  47. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0002_prefillsource_alter_formfield_prefill_source_and_more.py +0 -0
  48. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0003_postsubmissionaction.py +0 -0
  49. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0004_formtemplate.py +0 -0
  50. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0005_advanced_conditional_logic.py +0 -0
  51. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0006_workflowdefinition_visual_workflow_data_and_more.py +0 -0
  52. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0007_add_userprofile_ldap_enhancements.py +0 -0
  53. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0008_add_file_workflow_models.py +0 -0
  54. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0009_add_formfield_readonly.py +0 -0
  55. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0010_add_prefillsource_template_fields.py +0 -0
  56. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0011_postsubmissionaction_email_body_template_and_more.py +0 -0
  57. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0012_add_approval_step_fields.py +0 -0
  58. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0013_add_database_query_key.py +0 -0
  59. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0014_add_form_category.py +0 -0
  60. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0015_add_workflowstage_staged_approvals.py +0 -0
  61. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0016_add_pdf_generation.py +0 -0
  62. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0017_add_notification_batching.py +0 -0
  63. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0018_add_form_category_parent.py +0 -0
  64. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0019_add_ldap_group_profile.py +0 -0
  65. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0020_add_bulk_export_field.py +0 -0
  66. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0021_alter_pendingnotification_scheduled_for_and_more.py +0 -0
  67. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0022_add_bulk_pdf_export.py +0 -0
  68. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0023_add_performance_indexes.py +0 -0
  69. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0024_add_allow_resubmit.py +0 -0
  70. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0025_workflowstage_approve_label.py +0 -0
  71. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0026_alter_formfield_width.py +0 -0
  72. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0027_formsubmission_form_data_gin.py +0 -0
  73. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0028_workflowstagegroupconfig.py +0 -0
  74. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0029_formfield_workflow_stage_fk_drop_groupconfig.py +0 -0
  75. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0030_formfield_phone_type.py +0 -0
  76. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0031_sub_workflows.py +0 -0
  77. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0032_approved_pending_detached_sub_workflow.py +0 -0
  78. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0033_add_reject_parent_to_subworkflowdefinition.py +0 -0
  79. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0034_add_notificationlog.py +0 -0
  80. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0035_migrate_prefill_source_strings.py +0 -0
  81. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0036_add_workflowstage_auto_created.py +0 -0
  82. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0037_migrate_flat_workflows_to_staged.py +0 -0
  83. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0038_remove_legacy_prefill_source_and_approval_step.py +0 -0
  84. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0039_update_help_text.py +0 -0
  85. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0040_migrate_deprecated_features.py +0 -0
  86. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0041_remove_deprecated_fields.py +0 -0
  87. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0042_add_sub_workflow_section_label.py +0 -0
  88. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0043_fix_form_data_decimal_encoding.py +0 -0
  89. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0044_remove_subworkflowinstance_label.py +0 -0
  90. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0045_stageapprovalgroup_workflow_name_label.py +0 -0
  91. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0046_workflow_definition_one_to_many.py +0 -0
  92. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0047_add_hide_approval_history.py +0 -0
  93. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0048_workflowdefinition_trigger_conditions_and_more.py +0 -0
  94. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0049_formfield_multifile_type.py +0 -0
  95. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0050_workflowdefinition_collapse_parallel_stages.py +0 -0
  96. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0051_formdefinition_is_listed.py +0 -0
  97. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0052_dynamic_assignee_and_form_field_notifications.py +0 -0
  98. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0053_stageformfieldnotification_static_emails.py +0 -0
  99. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0054_rename_approved_pending_to_pending_approval.py +0 -0
  100. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0055_add_send_back.py +0 -0
  101. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0056_calculated_formula_spreadsheet.py +0 -0
  102. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0057_add_currency_field_type.py +0 -0
  103. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0058_rename_assignee_email_field_add_lookup_type.py +0 -0
  104. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0059_add_multiselect_list_field_type.py +0 -0
  105. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0060_alter_workflowstage_assignee_lookup_type_helptext.py +0 -0
  106. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0061_add_country_us_state_field_types.py +0 -0
  107. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0062_add_batch_import_to_formdefinition.py +0 -0
  108. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0063_formdefinition_api_enabled_apitoken.py +0 -0
  109. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0064_add_reviewer_groups.py +0 -0
  110. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0065_workflownotification.py +0 -0
  111. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0066_add_notify_submitter_to_workflownotification.py +0 -0
  112. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0067_migrate_legacy_notify_flags.py +0 -0
  113. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0068_drop_legacy_notify_fields.py +0 -0
  114. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0069_add_signature_field_type.py +0 -0
  115. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0070_workflowstage_allow_edit_form_data.py +0 -0
  116. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0071_alter_pendingnotification_notification_type.py +0 -0
  117. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0072_add_change_history.py +0 -0
  118. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0073_add_stage_notify_assignee_on_final_decision.py +0 -0
  119. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0074_add_notification_rule.py +0 -0
  120. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0075_migrate_to_notification_rules.py +0 -0
  121. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0076_update_notification_event_choices.py +0 -0
  122. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0077_drop_legacy_notification_models.py +0 -0
  123. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0078_allow_anonymous_submissions.py +0 -0
  124. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0079_webhookendpoint_webhookdeliverylog.py +0 -0
  125. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0080_add_rating_matrix_address_slider_fields_and_form_controls.py +0 -0
  126. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0081_add_success_page_fields.py +0 -0
  127. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0082_add_document_template_model.py +0 -0
  128. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0083_workflowdefinition_start_trigger.py +0 -0
  129. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0084_add_shared_option_list.py +0 -0
  130. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0085_add_payment_system.py +0 -0
  131. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0086_add_embed_enabled.py +0 -0
  132. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0087_notificationrule_use_triggering_stage.py +0 -0
  133. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0088_notificationrule_body_template_and_events.py +0 -0
  134. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0089_workflowstage_hide_comment_field.py +0 -0
  135. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0090_alter_stageapprovalgroup_options_and_more.py +0 -0
  136. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0091_add_uuid_fields.py +0 -0
  137. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0092_add_user_notification_preference.py +0 -0
  138. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0093_normalize_conditional_operators.py +0 -0
  139. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0094_formfield_show_help_text_in_detail.py +0 -0
  140. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/0095_notificationrule_cc_fields.py +0 -0
  141. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/migrations/__init__.py +0 -0
  142. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/models.py +0 -0
  143. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/payments/__init__.py +0 -0
  144. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/payments/base.py +0 -0
  145. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/payments/registry.py +0 -0
  146. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/payments/stripe_provider.py +0 -0
  147. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/payments/views.py +0 -0
  148. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/reporting_views.py +0 -0
  149. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/signals.py +0 -0
  150. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/sso_backends.py +0 -0
  151. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/sso_urls.py +0 -0
  152. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/sso_views.py +0 -0
  153. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/api/swagger-ui-bundle.js +0 -0
  154. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/api/swagger-ui.css +0 -0
  155. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/css/forms.css +0 -0
  156. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/dfw-embed.js +0 -0
  157. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/form-builder.js +0 -0
  158. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/form-enhancements.js +0 -0
  159. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/payment-stripe.js +0 -0
  160. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/signature-pad.js +0 -0
  161. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/static/django_forms_workflows/js/workflow-builder.js +0 -0
  162. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/sync_views.py +0 -0
  163. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/_sync_diff.html +0 -0
  164. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/diff_forms.html +0 -0
  165. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/form_builder.html +0 -0
  166. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/formdef_change_form.html +0 -0
  167. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/formdefinition/change_list.html +0 -0
  168. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/sync_import.html +0 -0
  169. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/sync_pull.html +0 -0
  170. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/sync_push.html +0 -0
  171. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/admin/django_forms_workflows/workflow_builder.html +0 -0
  172. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/_category_node.html +0 -0
  173. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/_field_value.html +0 -0
  174. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/_form_data_rows.html +0 -0
  175. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/analytics_dashboard.html +0 -0
  176. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/api/docs.html +0 -0
  177. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/approval_inbox.html +0 -0
  178. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/approve.html +0 -0
  179. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/base.html +0 -0
  180. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/batch_import_result.html +0 -0
  181. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/completed_approvals.html +0 -0
  182. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/discard_draft_confirm.html +0 -0
  183. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/embed_base.html +0 -0
  184. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/embed_success.html +0 -0
  185. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/form_categories.html +0 -0
  186. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/form_embed.html +0 -0
  187. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/form_list.html +0 -0
  188. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/form_submit.html +0 -0
  189. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/my_submissions.html +0 -0
  190. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/notification_preferences.html +0 -0
  191. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/payment_collect.html +0 -0
  192. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/payment_error.html +0 -0
  193. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/public_submission_confirmation.html +0 -0
  194. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/rate_limited.html +0 -0
  195. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/reassign_task.html +0 -0
  196. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/resubmit_confirm.html +0 -0
  197. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/sso/login.html +0 -0
  198. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/sub_workflow_detail.html +0 -0
  199. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/submission_bulk_pdf.html +0 -0
  200. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/submission_detail.html +0 -0
  201. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/submission_pdf.html +0 -0
  202. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/submission_success.html +0 -0
  203. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/django_forms_workflows/withdraw_confirm.html +0 -0
  204. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/approval_notification.html +0 -0
  205. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/approval_reminder.html +0 -0
  206. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/approval_request.html +0 -0
  207. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/email_styles.html +0 -0
  208. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/escalation_notification.html +0 -0
  209. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/notification_digest.html +0 -0
  210. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/rejection_notification.html +0 -0
  211. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/emails/submission_notification.html +0 -0
  212. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templates/registration/login.html +0 -0
  213. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templatetags/__init__.py +0 -0
  214. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/templatetags/forms_workflows_tags.py +0 -0
  215. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/urls.py +0 -0
  216. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/utils.py +0 -0
  217. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/views.py +0 -0
  218. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/workflow_builder_views.py +0 -0
  219. {django_forms_workflows-0.74.2 → django_forms_workflows-0.74.4}/django_forms_workflows/workflow_engine.py +0 -0
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.74.4] - 2026-04-29
11
+
12
+ ### Fixed
13
+ - **`send_notification_rules` is now idempotent on retry.** When a Celery
14
+ worker dies mid-execution and the broker requeues the task (e.g. with
15
+ `task_acks_late=True` + `task_reject_on_worker_lost=True`), the second
16
+ run skips recipients already present in `NotificationLog` with
17
+ `status=sent`. Failed sends are still retried. Previously a worker
18
+ crash mid-send could either lose the notification entirely (with
19
+ default acks-early) or, if acks-late was enabled, double-send to the
20
+ recipients delivered before the crash. Investigation context: a
21
+ production submission silently produced zero notification emails
22
+ while an identical submission a minute later succeeded — most likely
23
+ a prefork worker process death between ack and the send call.
24
+
25
+ ## [0.74.3] - 2026-04-29
26
+
27
+ ### Fixed
28
+ - **Notification-rule sync exports are now deterministic across
29
+ environments.** Two non-determinism sources let DB row order leak
30
+ into the export payload, producing false-positive
31
+ `Workflow notification rules: 6 → 6` diffs even when the underlying
32
+ rules were identical: rule list order relied on Meta ordering that
33
+ doesn't disambiguate workflow-level rules sharing an event, and
34
+ `notify_groups` M2M ordering relies on through-row id (varies per
35
+ instance). Both lists are now sorted by content, so push/pull and
36
+ the diff viewer give stable results.
37
+
38
+ ### Changed
39
+ - **Diff viewer reports which notification rule changed when counts
40
+ match.** When stage- or workflow-level notification rule lists
41
+ differ in content but not in length, the diff now names the rule
42
+ (by event) and the specific keys that changed instead of showing
43
+ an opaque `6 → 6` message.
44
+
10
45
  ## [0.74.2] - 2026-04-29
11
46
 
12
47
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-forms-workflows
3
- Version: 0.74.2
3
+ Version: 0.74.4
4
4
  Summary: Enterprise-grade, database-driven form builder with approval workflows and external data integration
5
5
  License: LGPL-3.0-only
6
6
  License-File: LICENSE
@@ -103,6 +103,20 @@ def _build_summary(forms_data):
103
103
  diffs.append(
104
104
  f"Stage '{key[1]}' notifications: {len(b_notifs)} → {len(o_notifs)}"
105
105
  )
106
+ elif b_notifs != o_notifs:
107
+ for idx, (bn, on) in enumerate(
108
+ zip(b_notifs, o_notifs, strict=False)
109
+ ):
110
+ if bn == on:
111
+ continue
112
+ changed_keys = sorted(
113
+ k for k in set(bn) | set(on) if bn.get(k) != on.get(k)
114
+ )
115
+ label = bn.get("event") or on.get("event") or f"#{idx}"
116
+ diffs.append(
117
+ f"Stage '{key[1]}' notification '{label}' changed: "
118
+ f"{', '.join(changed_keys)}"
119
+ )
106
120
  # Approval groups: support both old string lists and new dict lists
107
121
  b_groups = {
108
122
  g["name"] if isinstance(g, dict) else g
@@ -147,10 +161,29 @@ def _build_summary(forms_data):
147
161
  # Workflow-level notification rules (stage=null)
148
162
  b_wf_notifs = b_wf.get("notification_rules", [])
149
163
  o_wf_notifs = o_wf.get("notification_rules", [])
150
- if b_wf_notifs != o_wf_notifs:
164
+ if len(b_wf_notifs) != len(o_wf_notifs):
151
165
  diffs.append(
152
166
  f"Workflow notification rules: {len(b_wf_notifs)} → {len(o_wf_notifs)}"
153
167
  )
168
+ elif b_wf_notifs != o_wf_notifs:
169
+ # Same count but content differs — surface what changed.
170
+ changed = []
171
+ for idx, (br, or_) in enumerate(
172
+ zip(b_wf_notifs, o_wf_notifs, strict=False)
173
+ ):
174
+ if br == or_:
175
+ continue
176
+ changed_keys = sorted(
177
+ k for k in set(br) | set(or_) if br.get(k) != or_.get(k)
178
+ )
179
+ label = br.get("event") or or_.get("event") or f"#{idx}"
180
+ diffs.append(
181
+ f"Workflow notification rule '{label}' changed: "
182
+ f"{', '.join(changed_keys)}"
183
+ )
184
+ changed.append(label)
185
+ if not changed:
186
+ diffs.append("Workflow notification rules: order changed")
154
187
 
155
188
  # Form metadata
156
189
  meta_keys = [
@@ -22,6 +22,7 @@ Management commands (bundled)::
22
22
  python manage.py push_forms --dest-url=https://prod.example.com --token=SECRET --slugs=time-off,onboarding
23
23
  """
24
24
 
25
+ import json
25
26
  import logging
26
27
  from decimal import Decimal
27
28
 
@@ -241,6 +242,34 @@ def _serialize_field(field, wf_pk_to_index=None):
241
242
  }
242
243
 
243
244
 
245
+ def _serialize_notification_rule(r):
246
+ # Sort notify_groups so order is deterministic across environments
247
+ # (M2M default ordering relies on row id, which differs per-instance).
248
+ return {
249
+ "event": r.event,
250
+ "use_triggering_stage": r.use_triggering_stage,
251
+ "notify_submitter": r.notify_submitter,
252
+ "email_field": r.email_field,
253
+ "static_emails": r.static_emails,
254
+ "cc_email_field": r.cc_email_field,
255
+ "cc_static_emails": r.cc_static_emails,
256
+ "notify_stage_assignees": r.notify_stage_assignees,
257
+ "notify_stage_groups": r.notify_stage_groups,
258
+ "subject_template": r.subject_template,
259
+ "body_template": r.body_template,
260
+ "conditions": r.conditions,
261
+ "notify_groups": sorted(g.name for g in r.notify_groups.all()),
262
+ }
263
+
264
+
265
+ def _sorted_rule_payloads(rules):
266
+ # Sort by serialized content so order is deterministic across environments.
267
+ # Two rules with the same event would otherwise come back from the DB in
268
+ # indeterminate order, producing false-positive diffs on push/pull.
269
+ serialized = [_serialize_notification_rule(r) for r in rules]
270
+ return sorted(serialized, key=lambda d: json.dumps(d, sort_keys=True, default=str))
271
+
272
+
244
273
  def _serialize_workflow_stage(stage):
245
274
  # Serialize approval groups with their sequence position so that
246
275
  # "sequence" stages are restored in the correct order on import.
@@ -265,24 +294,7 @@ def _serialize_workflow_stage(stage):
265
294
  "allow_reassign": stage.allow_reassign,
266
295
  "allow_send_back": stage.allow_send_back,
267
296
  "allow_edit_form_data": stage.allow_edit_form_data,
268
- "notification_rules": [
269
- {
270
- "event": r.event,
271
- "use_triggering_stage": r.use_triggering_stage,
272
- "notify_submitter": r.notify_submitter,
273
- "email_field": r.email_field,
274
- "static_emails": r.static_emails,
275
- "cc_email_field": r.cc_email_field,
276
- "cc_static_emails": r.cc_static_emails,
277
- "notify_stage_assignees": r.notify_stage_assignees,
278
- "notify_stage_groups": r.notify_stage_groups,
279
- "subject_template": r.subject_template,
280
- "body_template": r.body_template,
281
- "conditions": r.conditions,
282
- "notify_groups": [g.name for g in r.notify_groups.all()],
283
- }
284
- for r in stage.notification_rules.all()
285
- ],
297
+ "notification_rules": _sorted_rule_payloads(stage.notification_rules.all()),
286
298
  }
287
299
 
288
300
 
@@ -355,24 +367,9 @@ def _serialize_workflow(wf):
355
367
  # Visual editor data
356
368
  "visual_workflow_data": wf.visual_workflow_data,
357
369
  # Workflow-level notification rules (stage=null)
358
- "notification_rules": [
359
- {
360
- "event": r.event,
361
- "use_triggering_stage": r.use_triggering_stage,
362
- "notify_submitter": r.notify_submitter,
363
- "email_field": r.email_field,
364
- "static_emails": r.static_emails,
365
- "cc_email_field": r.cc_email_field,
366
- "cc_static_emails": r.cc_static_emails,
367
- "notify_stage_assignees": r.notify_stage_assignees,
368
- "notify_stage_groups": r.notify_stage_groups,
369
- "subject_template": r.subject_template,
370
- "body_template": r.body_template,
371
- "conditions": r.conditions,
372
- "notify_groups": [g.name for g in r.notify_groups.all()],
373
- }
374
- for r in wf.notification_rules.filter(stage__isnull=True)
375
- ],
370
+ "notification_rules": _sorted_rule_payloads(
371
+ wf.notification_rules.filter(stage__isnull=True)
372
+ ),
376
373
  "webhook_endpoints": [
377
374
  _serialize_webhook_endpoint(endpoint)
378
375
  for endpoint in wf.webhook_endpoints.all().order_by("name")
@@ -1358,6 +1358,18 @@ def send_notification_rules(
1358
1358
  event, "{form_name} (ID {submission_id})"
1359
1359
  )
1360
1360
 
1361
+ # Idempotency guard: if this task is being re-executed (e.g. acks_late
1362
+ # requeued it after a worker died mid-send), skip recipients we already
1363
+ # successfully delivered to. Only "sent" entries dedup — "failed" entries
1364
+ # should be retried.
1365
+ already_sent: set[str] = set(
1366
+ NotificationLog.objects.filter(
1367
+ submission_id=submission_id,
1368
+ notification_type=event,
1369
+ status="sent",
1370
+ ).values_list("recipient_email", flat=True)
1371
+ )
1372
+
1361
1373
  for rule in rules:
1362
1374
  # Evaluate optional conditions
1363
1375
  if rule.conditions:
@@ -1388,9 +1400,28 @@ def send_notification_rules(
1388
1400
  cc_recipients = _collect_notification_cc(rule, form_data)
1389
1401
  # Prevent duplicate delivery: don't CC anyone already in the TO list.
1390
1402
  cc_recipients = [c for c in cc_recipients if c not in recipients]
1403
+
1404
+ # Drop recipients already successfully delivered (acks_late retry guard).
1405
+ # NotificationLog stores TO entries as the bare email and CC entries as
1406
+ # ``cc:{recipient}`` — match each list against its own log key format.
1407
+ if already_sent:
1408
+ before_to, before_cc = len(recipients), len(cc_recipients)
1409
+ recipients = [r for r in recipients if r not in already_sent]
1410
+ cc_recipients = [c for c in cc_recipients if f"cc:{c}" not in already_sent]
1411
+ skipped = (before_to - len(recipients)) + (before_cc - len(cc_recipients))
1412
+ if skipped:
1413
+ logger.info(
1414
+ "NotificationRule %s: skipped %d already-sent recipient(s) "
1415
+ "for submission %s (idempotency)",
1416
+ rule.id,
1417
+ skipped,
1418
+ submission.id,
1419
+ )
1420
+
1391
1421
  if not recipients:
1392
1422
  logger.info(
1393
- "NotificationRule %s: no recipients resolved for submission %s; skipping.",
1423
+ "NotificationRule %s: no recipients to send to for submission %s; "
1424
+ "skipping (resolved zero, or all already delivered).",
1394
1425
  rule.id,
1395
1426
  submission.id,
1396
1427
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-forms-workflows"
3
- version = "0.74.2"
3
+ version = "0.74.4"
4
4
  description = "Enterprise-grade, database-driven form builder with approval workflows and external data integration"
5
5
  license = "LGPL-3.0-only"
6
6
  readme = "README.md"