django-forms-workflows 0.20.0__tar.gz → 0.20.2__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 (130) hide show
  1. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/PKG-INFO +1 -1
  2. django_forms_workflows-0.20.2/django_forms_workflows/migrations/0043_fix_form_data_decimal_encoding.py +22 -0
  3. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/models.py +5 -1
  4. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/submission_detail.html +30 -93
  5. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/views.py +46 -1
  6. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/pyproject.toml +1 -1
  7. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/CHANGELOG.md +0 -0
  8. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/LICENSE +0 -0
  9. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/README.md +0 -0
  10. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/__init__.py +0 -0
  11. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/admin.py +0 -0
  12. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/apps.py +0 -0
  13. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/context_processors.py +0 -0
  14. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/data_sources/__init__.py +0 -0
  15. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/data_sources/base.py +0 -0
  16. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/data_sources/database_source.py +0 -0
  17. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/data_sources/ldap_source.py +0 -0
  18. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/data_sources/user_source.py +0 -0
  19. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/email_backends/__init__.py +0 -0
  20. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/email_backends/gmail_api.py +0 -0
  21. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/form_builder_urls.py +0 -0
  22. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/form_builder_views.py +0 -0
  23. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/forms.py +0 -0
  24. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/__init__.py +0 -0
  25. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/api_handler.py +0 -0
  26. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/base.py +0 -0
  27. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/database_handler.py +0 -0
  28. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/email_handler.py +0 -0
  29. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/executor.py +0 -0
  30. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/file_handler.py +0 -0
  31. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/handlers/ldap_handler.py +0 -0
  32. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/ldap_backend.py +0 -0
  33. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/create_default_templates.py +0 -0
  34. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/pull_forms.py +0 -0
  35. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/push_forms.py +0 -0
  36. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/seed_farm_demo.py +0 -0
  37. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/seed_pcn_form.py +0 -0
  38. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/seed_prefill_sources.py +0 -0
  39. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/sync_ldap_profiles.py +0 -0
  40. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/management/commands/test_db_connection.py +0 -0
  41. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0001_initial.py +0 -0
  42. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0002_prefillsource_alter_formfield_prefill_source_and_more.py +0 -0
  43. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0003_postsubmissionaction.py +0 -0
  44. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0004_formtemplate.py +0 -0
  45. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0005_advanced_conditional_logic.py +0 -0
  46. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0006_workflowdefinition_visual_workflow_data_and_more.py +0 -0
  47. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0007_add_userprofile_ldap_enhancements.py +0 -0
  48. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0008_add_file_workflow_models.py +0 -0
  49. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0009_add_formfield_readonly.py +0 -0
  50. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0010_add_prefillsource_template_fields.py +0 -0
  51. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0011_postsubmissionaction_email_body_template_and_more.py +0 -0
  52. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0012_add_approval_step_fields.py +0 -0
  53. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0013_add_database_query_key.py +0 -0
  54. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0014_add_form_category.py +0 -0
  55. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0015_add_workflowstage_staged_approvals.py +0 -0
  56. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0016_add_pdf_generation.py +0 -0
  57. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0017_add_notification_batching.py +0 -0
  58. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0018_add_form_category_parent.py +0 -0
  59. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0019_add_ldap_group_profile.py +0 -0
  60. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0020_add_bulk_export_field.py +0 -0
  61. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0021_alter_pendingnotification_scheduled_for_and_more.py +0 -0
  62. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0022_add_bulk_pdf_export.py +0 -0
  63. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0023_add_performance_indexes.py +0 -0
  64. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0024_add_allow_resubmit.py +0 -0
  65. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0025_workflowstage_approve_label.py +0 -0
  66. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0026_alter_formfield_width.py +0 -0
  67. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0027_formsubmission_form_data_gin.py +0 -0
  68. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0028_workflowstagegroupconfig.py +0 -0
  69. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0029_formfield_workflow_stage_fk_drop_groupconfig.py +0 -0
  70. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0030_formfield_phone_type.py +0 -0
  71. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0031_sub_workflows.py +0 -0
  72. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0032_approved_pending_detached_sub_workflow.py +0 -0
  73. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0033_add_reject_parent_to_subworkflowdefinition.py +0 -0
  74. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0034_add_notificationlog.py +0 -0
  75. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0035_migrate_prefill_source_strings.py +0 -0
  76. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0036_add_workflowstage_auto_created.py +0 -0
  77. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0037_migrate_flat_workflows_to_staged.py +0 -0
  78. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0038_remove_legacy_prefill_source_and_approval_step.py +0 -0
  79. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0039_update_help_text.py +0 -0
  80. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0040_migrate_deprecated_features.py +0 -0
  81. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0041_remove_deprecated_fields.py +0 -0
  82. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/0042_add_sub_workflow_section_label.py +0 -0
  83. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/migrations/__init__.py +0 -0
  84. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/signals.py +0 -0
  85. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/sso_backends.py +0 -0
  86. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/sso_urls.py +0 -0
  87. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/sso_views.py +0 -0
  88. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/static/django_forms_workflows/js/form-builder.js +0 -0
  89. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/static/django_forms_workflows/js/form-enhancements.js +0 -0
  90. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/static/django_forms_workflows/js/workflow-builder.js +0 -0
  91. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/sync_api.py +0 -0
  92. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/sync_views.py +0 -0
  93. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/tasks.py +0 -0
  94. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/form_builder.html +0 -0
  95. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/formdef_change_form.html +0 -0
  96. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/formdefinition/change_list.html +0 -0
  97. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/sync_import.html +0 -0
  98. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/sync_pull.html +0 -0
  99. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/sync_push.html +0 -0
  100. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/admin/django_forms_workflows/workflow_builder.html +0 -0
  101. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/_category_node.html +0 -0
  102. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/approval_inbox.html +0 -0
  103. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/approve.html +0 -0
  104. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/base.html +0 -0
  105. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/completed_approvals.html +0 -0
  106. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/form_categories.html +0 -0
  107. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/form_list.html +0 -0
  108. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/form_submit.html +0 -0
  109. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/my_submissions.html +0 -0
  110. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/resubmit_confirm.html +0 -0
  111. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/sso/login.html +0 -0
  112. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/sub_workflow_detail.html +0 -0
  113. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/submission_bulk_pdf.html +0 -0
  114. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/submission_pdf.html +0 -0
  115. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/django_forms_workflows/withdraw_confirm.html +0 -0
  116. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/approval_notification.html +0 -0
  117. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/approval_reminder.html +0 -0
  118. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/approval_request.html +0 -0
  119. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/email_styles.html +0 -0
  120. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/escalation_notification.html +0 -0
  121. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/notification_digest.html +0 -0
  122. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/rejection_notification.html +0 -0
  123. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/emails/submission_notification.html +0 -0
  124. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templates/registration/login.html +0 -0
  125. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templatetags/__init__.py +0 -0
  126. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/templatetags/forms_workflows_tags.py +0 -0
  127. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/urls.py +0 -0
  128. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/utils.py +0 -0
  129. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/workflow_builder_views.py +0 -0
  130. {django_forms_workflows-0.20.0 → django_forms_workflows-0.20.2}/django_forms_workflows/workflow_engine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-forms-workflows
3
- Version: 0.20.0
3
+ Version: 0.20.2
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
@@ -0,0 +1,22 @@
1
+ # Generated by Django 5.2.7 on 2026-03-12 20:30
2
+
3
+ import django.core.serializers.json
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("django_forms_workflows", "0042_add_sub_workflow_section_label"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name="formsubmission",
16
+ name="form_data",
17
+ field=models.JSONField(
18
+ encoder=django.core.serializers.json.DjangoJSONEncoder,
19
+ help_text="The actual form responses",
20
+ ),
21
+ ),
22
+ ]
@@ -6,6 +6,7 @@ Database-driven form definitions with approval workflows and external data integ
6
6
 
7
7
  from django.conf import settings
8
8
  from django.contrib.auth.models import Group
9
+ from django.core.serializers.json import DjangoJSONEncoder
9
10
  from django.db import models
10
11
 
11
12
 
@@ -1149,7 +1150,10 @@ class FormSubmission(models.Model):
1149
1150
  )
1150
1151
 
1151
1152
  # Submission Data
1152
- form_data = models.JSONField(help_text="The actual form responses")
1153
+ form_data = models.JSONField(
1154
+ help_text="The actual form responses",
1155
+ encoder=DjangoJSONEncoder,
1156
+ )
1153
1157
  attachments = models.JSONField(
1154
1158
  default=list, blank=True, help_text="List of uploaded file paths"
1155
1159
  )
@@ -241,67 +241,52 @@
241
241
  </div>
242
242
  {% endfor %}
243
243
 
244
- {% if sub_workflow_groups %}
245
- {# ---- Sub-workflow tasks ---- #}
246
- {% for stage in sub_workflow_groups %}
247
- {% if forloop.first %}
248
- <h5 class="mb-3 mt-4"><i class="bi bi-list-check"></i> {{ stage.section_label|default:"Additional Approvals" }}</h5>
249
- {% endif %}
250
- <div class="card mb-3
251
- {% if stage.rejected_count > 0 %}border-danger
252
- {% elif stage.approved_count == stage.total_count and stage.total_count > 0 %}border-success
253
- {% elif stage.approved_count > 0 %}border-primary
254
- {% else %}border-secondary{% endif %}">
255
- <div class="card-header d-flex justify-content-between align-items-center
256
- {% if stage.rejected_count > 0 %}bg-danger text-white
257
- {% elif stage.approved_count == stage.total_count and stage.total_count > 0 %}bg-success text-white
258
- {% elif stage.approved_count > 0 %}bg-primary text-white
259
- {% else %}bg-light text-muted{% endif %}">
260
- <span>
261
- <strong>{{ stage.name }}</strong>
262
- {% if stage.approval_logic == "all" %}
263
- <span class="badge bg-light text-dark ms-2" style="font-size:11px;">All must approve</span>
264
- {% elif stage.approval_logic == "any" %}
265
- <span class="badge bg-light text-dark ms-2" style="font-size:11px;">Any can approve</span>
266
- {% elif stage.approval_logic == "sequence" %}
267
- <span class="badge bg-light text-dark ms-2" style="font-size:11px;">Sequential</span>
268
- {% endif %}
269
- </span>
270
- <span class="badge bg-light text-dark">{{ stage.approved_count }}/{{ stage.total_count }} approved</span>
271
- </div>
244
+ {% if sub_workflow_instances_merged %}
245
+ {# ---- Merged sub-workflow table ---- #}
246
+ <h5 class="mb-3 mt-4"><i class="bi bi-list-check"></i> {{ sub_wf_section_label|default:"Additional Approvals" }}</h5>
247
+ <div class="card mb-3 border-secondary">
272
248
  <div class="card-body p-0">
273
249
  <div class="table-responsive">
274
- <table class="table table-sm mb-0">
275
- <thead>
250
+ <table class="table table-sm table-hover mb-0">
251
+ <thead class="table-light">
276
252
  <tr>
253
+ <th>#</th>
254
+ <th>Label</th>
277
255
  <th>Assigned To</th>
278
256
  <th>Status</th>
279
257
  <th>Completed By</th>
280
258
  <th>Completed At</th>
281
- <th>Comments</th>
259
+ <th></th>
282
260
  </tr>
283
261
  </thead>
284
262
  <tbody>
285
- {% for task in stage.tasks %}
263
+ {% for row in sub_workflow_instances_merged %}
286
264
  <tr>
265
+ <td>{{ row.instance.index }}</td>
266
+ <td>{{ row.instance.label }}</td>
287
267
  <td>
288
- {% if task.assigned_to %}
289
- {{ task.assigned_to.get_full_name|default:task.assigned_to.username }}
290
- {% elif task.assigned_group %}
291
- {{ task.assigned_group.name }} <span class="text-muted">(Group)</span>
268
+ {% if row.task %}
269
+ {% if row.task.assigned_to %}
270
+ {{ row.task.assigned_to.get_full_name|default:row.task.assigned_to.username }}
271
+ {% elif row.task.assigned_group %}
272
+ {{ row.task.assigned_group.name }}
273
+ {% else %}-{% endif %}
292
274
  {% else %}-{% endif %}
293
275
  </td>
294
276
  <td>
295
- {% if task.status == 'pending' %}<span class="badge bg-warning text-dark">Pending</span>
296
- {% elif task.status == 'approved' %}<span class="badge bg-success">Approved</span>
297
- {% elif task.status == 'rejected' %}<span class="badge bg-danger">Rejected</span>
298
- {% elif task.status == 'expired' %}<span class="badge bg-secondary">Expired</span>
299
- {% elif task.status == 'skipped' %}<span class="badge bg-secondary">Skipped</span>
277
+ {% if row.instance.status == 'approved' %}<span class="badge bg-success">Approved</span>
278
+ {% elif row.instance.status == 'rejected' %}<span class="badge bg-danger">Rejected</span>
279
+ {% elif row.instance.status == 'in_progress' %}<span class="badge bg-primary">In Progress</span>
280
+ {% else %}<span class="badge bg-secondary">Pending</span>
300
281
  {% endif %}
301
282
  </td>
302
- <td>{% if task.completed_by %}{{ task.completed_by.get_full_name|default:task.completed_by.username }}{% else %}-{% endif %}</td>
303
- <td>{% if task.completed_at %}{{ task.completed_at|date:"Y-m-d H:i" }}{% else %}-{% endif %}</td>
304
- <td>{{ task.comments|default:"-" }}</td>
283
+ <td>{% if row.task and row.task.completed_by %}{{ row.task.completed_by.get_full_name|default:row.task.completed_by.username }}{% else %}-{% endif %}</td>
284
+ <td>{% if row.task and row.task.completed_at %}{{ row.task.completed_at|date:"Y-m-d H:i" }}{% else %}-{% endif %}</td>
285
+ <td>
286
+ <a href="{% url 'forms_workflows:sub_workflow_detail' row.instance.id %}" class="btn btn-sm btn-outline-secondary">
287
+ <i class="bi bi-eye"></i> View
288
+ </a>
289
+ </td>
305
290
  </tr>
306
291
  {% endfor %}
307
292
  </tbody>
@@ -309,7 +294,6 @@
309
294
  </div>
310
295
  </div>
311
296
  </div>
312
- {% endfor %}
313
297
  {% endif %}
314
298
 
315
299
  {% else %}
@@ -364,54 +348,7 @@
364
348
 
365
349
  {% endif %}
366
350
 
367
- <!-- Sub-workflows -->
368
- {% with sub_wfs=submission.sub_workflows.all %}
369
- {% if sub_wfs %}
370
- <div class="card mb-4">
371
- <div class="card-header bg-light">
372
- <h5 class="mb-0"><i class="bi bi-diagram-2"></i> Payment Approvals</h5>
373
- </div>
374
- <div class="card-body p-0">
375
- <table class="table table-hover mb-0">
376
- <thead class="table-light">
377
- <tr>
378
- <th>#</th>
379
- <th>Label</th>
380
- <th>Status</th>
381
- <th>Created</th>
382
- <th></th>
383
- </tr>
384
- </thead>
385
- <tbody>
386
- {% for swf in sub_wfs %}
387
- <tr>
388
- <td>{{ swf.index }}</td>
389
- <td>{{ swf.label }}</td>
390
- <td>
391
- {% if swf.status == 'approved' %}
392
- <span class="badge bg-success">Approved</span>
393
- {% elif swf.status == 'rejected' %}
394
- <span class="badge bg-danger">Rejected</span>
395
- {% elif swf.status == 'in_progress' %}
396
- <span class="badge bg-primary">In Progress</span>
397
- {% else %}
398
- <span class="badge bg-secondary">Pending</span>
399
- {% endif %}
400
- </td>
401
- <td>{{ swf.created_at|date:"M d, Y" }}</td>
402
- <td>
403
- <a href="{% url 'forms_workflows:sub_workflow_detail' swf.id %}" class="btn btn-sm btn-outline-secondary">
404
- <i class="bi bi-eye"></i> View
405
- </a>
406
- </td>
407
- </tr>
408
- {% endfor %}
409
- </tbody>
410
- </table>
411
- </div>
412
- </div>
413
- {% endif %}
414
- {% endwith %}
351
+
415
352
 
416
353
  <!-- Actions -->
417
354
  <div class="mt-3">
@@ -600,11 +600,54 @@ def submission_detail(request, submission_id):
600
600
  for sg in sub_workflow_groups:
601
601
  sg["section_label"] = sub_wf_config.section_label
602
602
  elif sub_wf_config:
603
- # Fall back to the sub-workflow's form definition name
604
603
  sg_name = sub_wf_config.sub_workflow.form_definition.name
605
604
  for sg in sub_workflow_groups:
606
605
  sg["section_label"] = sg_name
607
606
 
607
+ # Build merged sub-workflow instance rows that combine instance info
608
+ # (index, label, status, created) with per-instance approval task info
609
+ # (assigned_to, completed_by, completed_at) into a single table.
610
+ sub_workflow_instances_merged = None
611
+ sub_wf_section_label = None
612
+ sub_wfs = list(
613
+ submission.sub_workflows.select_related("definition")
614
+ .prefetch_related(
615
+ "approval_tasks__assigned_to",
616
+ "approval_tasks__assigned_group",
617
+ "approval_tasks__completed_by",
618
+ )
619
+ .order_by("index")
620
+ )
621
+ if sub_wfs:
622
+ swf_config = sub_wfs[0].definition if sub_wfs else None
623
+ sub_wf_section_label = (
624
+ (
625
+ swf_config.section_label
626
+ if swf_config and swf_config.section_label
627
+ else None
628
+ )
629
+ or (swf_config.sub_workflow.form_definition.name if swf_config else None)
630
+ or "Additional Approvals"
631
+ )
632
+ merged_rows = []
633
+ for swf in sub_wfs:
634
+ tasks = list(swf.approval_tasks.order_by("-completed_at", "id"))
635
+ # Pick the most relevant task for display (completed or first pending)
636
+ display_task = None
637
+ for t in tasks:
638
+ if t.status in ("approved", "rejected"):
639
+ display_task = t
640
+ break
641
+ if not display_task and tasks:
642
+ display_task = tasks[0]
643
+ merged_rows.append(
644
+ {
645
+ "instance": swf,
646
+ "task": display_task,
647
+ }
648
+ )
649
+ sub_workflow_instances_merged = merged_rows
650
+
608
651
  # Resolve fresh presigned URLs for any file-upload fields
609
652
  form_data = _resolve_form_data_urls(submission.form_data)
610
653
  form_data_ordered = _build_ordered_form_data(submission, form_data)
@@ -635,6 +678,8 @@ def submission_detail(request, submission_id):
635
678
  "approval_tasks": approval_tasks,
636
679
  "stage_groups": stage_groups,
637
680
  "sub_workflow_groups": sub_workflow_groups,
681
+ "sub_workflow_instances_merged": sub_workflow_instances_merged,
682
+ "sub_wf_section_label": sub_wf_section_label,
638
683
  "form_data": form_data,
639
684
  "form_data_ordered": form_data_ordered,
640
685
  "approval_field_names": approval_field_names,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-forms-workflows"
3
- version = "0.20.0"
3
+ version = "0.20.2"
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"