wbcompliance 2.2.1__py2.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.
Files changed (129) hide show
  1. wbcompliance/__init__.py +1 -0
  2. wbcompliance/admin/__init__.py +16 -0
  3. wbcompliance/admin/compliance_form.py +56 -0
  4. wbcompliance/admin/compliance_task.py +135 -0
  5. wbcompliance/admin/compliance_type.py +8 -0
  6. wbcompliance/admin/risk_management/__init__.py +3 -0
  7. wbcompliance/admin/risk_management/checks.py +7 -0
  8. wbcompliance/admin/risk_management/incidents.py +50 -0
  9. wbcompliance/admin/risk_management/rules.py +63 -0
  10. wbcompliance/admin/utils.py +46 -0
  11. wbcompliance/apps.py +14 -0
  12. wbcompliance/factories/__init__.py +21 -0
  13. wbcompliance/factories/compliance.py +246 -0
  14. wbcompliance/factories/risk_management/__init__.py +12 -0
  15. wbcompliance/factories/risk_management/backends.py +42 -0
  16. wbcompliance/factories/risk_management/checks.py +12 -0
  17. wbcompliance/factories/risk_management/incidents.py +84 -0
  18. wbcompliance/factories/risk_management/rules.py +100 -0
  19. wbcompliance/filters/__init__.py +2 -0
  20. wbcompliance/filters/compliances.py +189 -0
  21. wbcompliance/filters/risk_management/__init__.py +3 -0
  22. wbcompliance/filters/risk_management/checks.py +22 -0
  23. wbcompliance/filters/risk_management/incidents.py +113 -0
  24. wbcompliance/filters/risk_management/rules.py +110 -0
  25. wbcompliance/filters/risk_management/tables.py +112 -0
  26. wbcompliance/filters/risk_management/utils.py +3 -0
  27. wbcompliance/management/__init__.py +10 -0
  28. wbcompliance/migrations/0001_initial_squashed_squashed_0010_alter_checkedobjectincidentrelationship_resolved_by_and_more.py +1744 -0
  29. wbcompliance/migrations/0011_alter_riskrule_parameters.py +21 -0
  30. wbcompliance/migrations/0012_alter_compliancetype_options.py +20 -0
  31. wbcompliance/migrations/0013_alter_riskrule_unique_together.py +16 -0
  32. wbcompliance/migrations/0014_alter_reviewcompliancetask_year.py +27 -0
  33. wbcompliance/migrations/0015_auto_20240103_0957.py +43 -0
  34. wbcompliance/migrations/0016_checkedobjectincidentrelationship_report_details_and_more.py +37 -0
  35. wbcompliance/migrations/0017_alter_rulebackend_incident_report_template.py +20 -0
  36. wbcompliance/migrations/0018_alter_rulecheckedobjectrelationship_unique_together.py +39 -0
  37. wbcompliance/migrations/0019_rulegroup_riskrule_activation_date_and_more.py +60 -0
  38. wbcompliance/migrations/__init__.py +0 -0
  39. wbcompliance/models/__init__.py +20 -0
  40. wbcompliance/models/compliance_form.py +626 -0
  41. wbcompliance/models/compliance_task.py +800 -0
  42. wbcompliance/models/compliance_type.py +133 -0
  43. wbcompliance/models/enums.py +13 -0
  44. wbcompliance/models/risk_management/__init__.py +4 -0
  45. wbcompliance/models/risk_management/backend.py +139 -0
  46. wbcompliance/models/risk_management/checks.py +194 -0
  47. wbcompliance/models/risk_management/dispatch.py +41 -0
  48. wbcompliance/models/risk_management/incidents.py +619 -0
  49. wbcompliance/models/risk_management/mixins.py +115 -0
  50. wbcompliance/models/risk_management/rules.py +654 -0
  51. wbcompliance/permissions.py +32 -0
  52. wbcompliance/serializers/__init__.py +30 -0
  53. wbcompliance/serializers/compliance_form.py +320 -0
  54. wbcompliance/serializers/compliance_task.py +463 -0
  55. wbcompliance/serializers/compliance_type.py +26 -0
  56. wbcompliance/serializers/risk_management/__init__.py +19 -0
  57. wbcompliance/serializers/risk_management/checks.py +53 -0
  58. wbcompliance/serializers/risk_management/incidents.py +227 -0
  59. wbcompliance/serializers/risk_management/rules.py +158 -0
  60. wbcompliance/tasks.py +112 -0
  61. wbcompliance/tests/__init__.py +0 -0
  62. wbcompliance/tests/conftest.py +63 -0
  63. wbcompliance/tests/disable_signals.py +82 -0
  64. wbcompliance/tests/mixins.py +17 -0
  65. wbcompliance/tests/risk_management/__init__.py +0 -0
  66. wbcompliance/tests/risk_management/models/__init__.py +0 -0
  67. wbcompliance/tests/risk_management/models/test_backends.py +0 -0
  68. wbcompliance/tests/risk_management/models/test_checks.py +55 -0
  69. wbcompliance/tests/risk_management/models/test_incidents.py +327 -0
  70. wbcompliance/tests/risk_management/models/test_rules.py +255 -0
  71. wbcompliance/tests/signals.py +89 -0
  72. wbcompliance/tests/test_filters.py +23 -0
  73. wbcompliance/tests/test_models.py +57 -0
  74. wbcompliance/tests/test_serializers.py +48 -0
  75. wbcompliance/tests/test_views.py +377 -0
  76. wbcompliance/tests/tests.py +21 -0
  77. wbcompliance/urls.py +238 -0
  78. wbcompliance/viewsets/__init__.py +40 -0
  79. wbcompliance/viewsets/buttons/__init__.py +9 -0
  80. wbcompliance/viewsets/buttons/compliance_form.py +78 -0
  81. wbcompliance/viewsets/buttons/compliance_task.py +149 -0
  82. wbcompliance/viewsets/buttons/risk_managment/__init__.py +3 -0
  83. wbcompliance/viewsets/buttons/risk_managment/checks.py +11 -0
  84. wbcompliance/viewsets/buttons/risk_managment/incidents.py +51 -0
  85. wbcompliance/viewsets/buttons/risk_managment/rules.py +35 -0
  86. wbcompliance/viewsets/compliance_form.py +425 -0
  87. wbcompliance/viewsets/compliance_task.py +513 -0
  88. wbcompliance/viewsets/compliance_type.py +38 -0
  89. wbcompliance/viewsets/display/__init__.py +22 -0
  90. wbcompliance/viewsets/display/compliance_form.py +317 -0
  91. wbcompliance/viewsets/display/compliance_task.py +453 -0
  92. wbcompliance/viewsets/display/compliance_type.py +22 -0
  93. wbcompliance/viewsets/display/risk_managment/__init__.py +11 -0
  94. wbcompliance/viewsets/display/risk_managment/checks.py +46 -0
  95. wbcompliance/viewsets/display/risk_managment/incidents.py +155 -0
  96. wbcompliance/viewsets/display/risk_managment/rules.py +146 -0
  97. wbcompliance/viewsets/display/risk_managment/tables.py +51 -0
  98. wbcompliance/viewsets/endpoints/__init__.py +27 -0
  99. wbcompliance/viewsets/endpoints/compliance_form.py +207 -0
  100. wbcompliance/viewsets/endpoints/compliance_task.py +193 -0
  101. wbcompliance/viewsets/endpoints/compliance_type.py +9 -0
  102. wbcompliance/viewsets/endpoints/risk_managment/__init__.py +12 -0
  103. wbcompliance/viewsets/endpoints/risk_managment/checks.py +16 -0
  104. wbcompliance/viewsets/endpoints/risk_managment/incidents.py +36 -0
  105. wbcompliance/viewsets/endpoints/risk_managment/rules.py +32 -0
  106. wbcompliance/viewsets/endpoints/risk_managment/tables.py +14 -0
  107. wbcompliance/viewsets/menu/__init__.py +17 -0
  108. wbcompliance/viewsets/menu/compliance_form.py +49 -0
  109. wbcompliance/viewsets/menu/compliance_task.py +130 -0
  110. wbcompliance/viewsets/menu/compliance_type.py +17 -0
  111. wbcompliance/viewsets/menu/risk_management.py +56 -0
  112. wbcompliance/viewsets/risk_management/__init__.py +21 -0
  113. wbcompliance/viewsets/risk_management/checks.py +49 -0
  114. wbcompliance/viewsets/risk_management/incidents.py +204 -0
  115. wbcompliance/viewsets/risk_management/mixins.py +52 -0
  116. wbcompliance/viewsets/risk_management/rules.py +179 -0
  117. wbcompliance/viewsets/risk_management/tables.py +96 -0
  118. wbcompliance/viewsets/titles/__init__.py +17 -0
  119. wbcompliance/viewsets/titles/compliance_form.py +101 -0
  120. wbcompliance/viewsets/titles/compliance_task.py +60 -0
  121. wbcompliance/viewsets/titles/compliance_type.py +13 -0
  122. wbcompliance/viewsets/titles/risk_managment/__init__.py +1 -0
  123. wbcompliance/viewsets/titles/risk_managment/checks.py +0 -0
  124. wbcompliance/viewsets/titles/risk_managment/incidents.py +0 -0
  125. wbcompliance/viewsets/titles/risk_managment/rules.py +0 -0
  126. wbcompliance/viewsets/titles/risk_managment/tables.py +7 -0
  127. wbcompliance-2.2.1.dist-info/METADATA +7 -0
  128. wbcompliance-2.2.1.dist-info/RECORD +129 -0
  129. wbcompliance-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,425 @@
1
+ from django.contrib.auth import get_user_model
2
+ from django.contrib.contenttypes.models import ContentType
3
+ from django.db.models import (
4
+ BooleanField,
5
+ Case,
6
+ CharField,
7
+ ExpressionWrapper,
8
+ F,
9
+ Q,
10
+ Value,
11
+ When,
12
+ )
13
+ from django.db.models.functions import Concat
14
+ from django.shortcuts import get_object_or_404
15
+ from django.utils import timezone
16
+ from django.utils.functional import cached_property
17
+ from django.utils.translation import gettext as _
18
+ from rest_framework import filters, permissions, status
19
+ from rest_framework.decorators import action
20
+ from rest_framework.response import Response
21
+ from reversion.views import RevisionMixin
22
+ from wbcompliance.filters import ComplianceFormFilter, ComplianceFormSignatureFilter
23
+ from wbcompliance.models import (
24
+ ComplianceForm,
25
+ ComplianceFormRule,
26
+ ComplianceFormSection,
27
+ ComplianceFormSignature,
28
+ ComplianceFormSignatureRule,
29
+ ComplianceFormSignatureSection,
30
+ ComplianceFormType,
31
+ update_or_create_compliance_document,
32
+ )
33
+ from wbcompliance.serializers import (
34
+ ComplianceFormModelSerializer,
35
+ ComplianceFormRepresentationSerializer,
36
+ ComplianceFormRuleModelSerializer,
37
+ ComplianceFormSectionModelSerializer,
38
+ ComplianceFormSectionRepresentationSerializer,
39
+ ComplianceFormSignatureModelSerializer,
40
+ ComplianceFormSignatureRuleModelSerializer,
41
+ ComplianceFormSignatureSectionRepresentationSerializer,
42
+ ComplianceFormTypeModelSerializer,
43
+ ComplianceFormTypeRepresentationSerializer,
44
+ )
45
+ from wbcore import viewsets
46
+ from wbcore.contrib.authentication.authentication import JWTCookieAuthentication
47
+ from wbcore.contrib.notifications.dispatch import send_notification
48
+ from wbcore.filters import DjangoFilterBackend
49
+
50
+ from .buttons import ComplianceFormButtonConfig, ComplianceFormSignatureButtonConfig
51
+ from .compliance_type import ComplianceType
52
+ from .display import (
53
+ ComplianceFormDisplayConfig,
54
+ ComplianceFormRuleDisplayConfig,
55
+ ComplianceFormSectionDisplayConfig,
56
+ ComplianceFormSignatureDisplayConfig,
57
+ ComplianceFormSignatureSectionRuleDisplayConfig,
58
+ ComplianceFormTypeDisplayConfig,
59
+ )
60
+ from .endpoints import (
61
+ CFComplianceFormSectionEndpointConfig,
62
+ CFComplianceFormSignatureEndpointConfig,
63
+ ComplianceFormEndpointConfig,
64
+ ComplianceFormRuleEndpointConfig,
65
+ ComplianceFormSectionRuleEndpointConfig,
66
+ ComplianceFormSignatureEndpointConfig,
67
+ ComplianceFormSignatureSectionRuleEndpointConfig,
68
+ ComplianceFormTypeEndpointConfig,
69
+ )
70
+ from .titles import (
71
+ ComplianceFormSectionRuleTitleConfig,
72
+ ComplianceFormSectionTitleConfig,
73
+ ComplianceFormSignatureSectionRuleTitleConfig,
74
+ ComplianceFormSignatureTitleConfig,
75
+ ComplianceFormTitleConfig,
76
+ )
77
+
78
+ User = get_user_model()
79
+
80
+
81
+ class ComplianceFormRepresentationViewSet(viewsets.RepresentationViewSet):
82
+ IDENTIFIER = "wbcompliance:complianceformrepresentation"
83
+
84
+ queryset = ComplianceForm.objects.all()
85
+ serializer_class = ComplianceFormRepresentationSerializer
86
+
87
+
88
+ class ComplianceFormSectionRepresentationViewSet(viewsets.RepresentationViewSet):
89
+ IDENTIFIER = "wbcompliance:complianceformsectionrepresentation"
90
+
91
+ queryset = ComplianceFormSection.objects.all()
92
+ serializer_class = ComplianceFormSectionRepresentationSerializer
93
+
94
+
95
+ class ComplianceFormSignatureSectionRepresentationViewSet(viewsets.RepresentationViewSet):
96
+ IDENTIFIER = "wbcompliance:complianceformsignaturesectionrepresentation"
97
+
98
+ queryset = ComplianceFormSignatureSection.objects.all()
99
+ serializer_class = ComplianceFormSignatureSectionRepresentationSerializer
100
+
101
+
102
+ # TYPE OF THE COMPLIANCE FORM
103
+ class ComplianceFormTypeRepresentationViewSet(viewsets.RepresentationViewSet):
104
+ IDENTIFIER = "wbcompliance:complianceformtyperepresentation"
105
+ queryset = ComplianceFormType.objects.all()
106
+ serializer_class = ComplianceFormTypeRepresentationSerializer
107
+
108
+
109
+ class ComplianceFormTypeViewSet(RevisionMixin, viewsets.ModelViewSet):
110
+ endpoint_config_class = ComplianceFormTypeEndpointConfig
111
+ display_config_class = ComplianceFormTypeDisplayConfig
112
+
113
+ ordering_fields = ["name"]
114
+
115
+ serializer_class = ComplianceFormTypeModelSerializer
116
+ queryset = ComplianceFormType.objects.all()
117
+
118
+ def get_queryset(self):
119
+ if ComplianceType.is_administrator(self.request.user):
120
+ return super().get_queryset()
121
+ return ComplianceFormType.objects.none()
122
+
123
+
124
+ # SECTION OF THE COMPLIANCE FORM
125
+ class ComplianceFormSectionViewSet(RevisionMixin, viewsets.ModelViewSet):
126
+ title_config_class = ComplianceFormSectionTitleConfig
127
+ display_config_class = ComplianceFormSectionDisplayConfig
128
+
129
+ search_fields = ["name"]
130
+ ordering_fields = ["name"]
131
+ queryset = ComplianceFormSection.objects.all()
132
+ serializer_class = ComplianceFormSectionModelSerializer
133
+
134
+ def get_queryset(self):
135
+ if ComplianceType.is_administrator(self.request.user):
136
+ return ComplianceFormSection.objects.select_related("compliance_form")
137
+ return ComplianceFormSection.objects.none()
138
+
139
+
140
+ class ComplianceFormSectionComplianceFormViewSet(ComplianceFormSectionViewSet):
141
+ endpoint_config_class = CFComplianceFormSectionEndpointConfig
142
+
143
+ def get_queryset(self):
144
+ return super().get_queryset().filter(compliance_form__id=self.kwargs["compliance_form_id"])
145
+
146
+
147
+ # RULES
148
+ class ComplianceFormRuleViewSet(RevisionMixin, viewsets.ModelViewSet):
149
+ IDENTIFIER = "wbcompliance:complianceformrule"
150
+ display_config_class = ComplianceFormRuleDisplayConfig
151
+ endpoint_config_class = ComplianceFormRuleEndpointConfig
152
+
153
+ filter_backends = (
154
+ DjangoFilterBackend,
155
+ filters.OrderingFilter,
156
+ )
157
+
158
+ serializer_class = ComplianceFormRuleModelSerializer
159
+
160
+ queryset = ComplianceFormRule.objects.select_related("section")
161
+
162
+
163
+ # RULES OF THE SECTION OF THE COMPLIANCE FORM
164
+ class ComplianceFormSectionRuleViewSet(ComplianceFormRuleViewSet):
165
+ IDENTIFIER = "wbcompliance:complianceformsection-rules"
166
+ title_config_class = ComplianceFormSectionRuleTitleConfig
167
+ endpoint_config_class = ComplianceFormSectionRuleEndpointConfig
168
+
169
+ def get_queryset(self):
170
+ if ComplianceType.is_administrator(self.request.user):
171
+ return super().get_queryset().filter(section__id=self.kwargs["section_id"])
172
+ return ComplianceFormRule.objects.none()
173
+
174
+
175
+ # RULES OF THE SECTION OF THE COMPLIANCE FORM SIGNATURE
176
+ class ComplianceFormSignatureSectionRuleViewSet(RevisionMixin, viewsets.ModelViewSet):
177
+ IDENTIFIER = "wbcompliance:complianceformsignaturesection-signaturerules"
178
+ title_config_class = ComplianceFormSignatureSectionRuleTitleConfig
179
+ display_config_class = ComplianceFormSignatureSectionRuleDisplayConfig
180
+ endpoint_config_class = ComplianceFormSignatureSectionRuleEndpointConfig
181
+
182
+ serializer_class = ComplianceFormSignatureRuleModelSerializer
183
+
184
+ queryset = ComplianceFormSignatureRule.objects.all()
185
+
186
+ def get_queryset(self):
187
+ return (
188
+ super()
189
+ .get_queryset()
190
+ .filter(section__id=self.kwargs["section_id"])
191
+ .annotate(
192
+ expected_result=ComplianceFormSignatureRule.get_subquery_expected_ticked(),
193
+ same_answer=ExpressionWrapper(
194
+ Q(ticked__exact=F("expected_result")),
195
+ output_field=BooleanField(),
196
+ ),
197
+ )
198
+ )
199
+
200
+
201
+ # COMPLIANCE FORM
202
+ class ComplianceFormModelViewSet(RevisionMixin, viewsets.ModelViewSet):
203
+ IDENTIFIER = "wbcompliance:complianceform"
204
+
205
+ ordering_fields = [
206
+ "title",
207
+ "status",
208
+ "creator",
209
+ "changer",
210
+ "changed",
211
+ "start",
212
+ "end",
213
+ "version",
214
+ "form_type",
215
+ "compliance_type",
216
+ ]
217
+ ordering = ["-changed", "-created"]
218
+ search_fields = ["title"]
219
+
220
+ filterset_class = ComplianceFormFilter
221
+
222
+ display_config_class = ComplianceFormDisplayConfig
223
+ title_config_class = ComplianceFormTitleConfig
224
+ button_config_class = ComplianceFormButtonConfig
225
+ endpoint_config_class = ComplianceFormEndpointConfig
226
+
227
+ serializer_class = ComplianceFormModelSerializer
228
+ queryset = ComplianceForm.objects.select_related(
229
+ "creator",
230
+ "changer",
231
+ "form_type",
232
+ "compliance_type",
233
+ ).prefetch_related("assigned_to")
234
+
235
+ @cached_property
236
+ def user_has_compliance_admin_permission(self):
237
+ return self.request.user.has_perm("wbcompliance.administrate_compliance")
238
+
239
+ def get_queryset(self):
240
+ if ComplianceType.is_administrator(self.request.user):
241
+ qs = super().get_queryset()
242
+ qs = qs.annotate(
243
+ # is_signed = ComplianceForm.get_subquery_compliance_form_signature(self.request.user.profile),
244
+ total_compliance_form_signature=ComplianceForm.get_subquery_total_compliance_form_signature(),
245
+ total_signed=F("total_compliance_form_signature")
246
+ - ComplianceForm.get_subquery_total_compliance_form_signature(remaining_signed=True),
247
+ current_signed=ExpressionWrapper(
248
+ Concat(
249
+ Value(" ("), F("total_signed"), Value("/"), F("total_compliance_form_signature"), Value(")")
250
+ ),
251
+ output_field=CharField(),
252
+ ),
253
+ is_signed=Case(
254
+ When(total_compliance_form_signature=F("total_signed"), then=Value(True)),
255
+ default=Value(False),
256
+ output_field=BooleanField(),
257
+ ),
258
+ )
259
+ else:
260
+ qs = super().get_queryset().filter(status=ComplianceForm.Status.ACTIVE)
261
+ qs = qs.annotate(
262
+ is_signed=ComplianceForm.get_subquery_compliance_form_signature(self.request.user.profile),
263
+ ).filter(is_signed__isnull=False)
264
+ return qs
265
+
266
+ @action(detail=True, methods=["PATCH"], permission_classes=[permissions.IsAuthenticated])
267
+ def sendcomplianceformnotification(self, request, pk=None):
268
+ compliance_form = ComplianceForm.objects.get(pk=pk)
269
+ person_ids = ComplianceFormSignature.objects.filter(
270
+ compliance_form=compliance_form, version=compliance_form.version, signed=None
271
+ ).values_list("person", flat=True)
272
+
273
+ if person_ids:
274
+ msg = _("<p>{} has activated a {} {} version {} </p>").format(
275
+ str(compliance_form.creator), compliance_form.title, compliance_form.form_type, compliance_form.version
276
+ )
277
+ if compliance_form.policy and compliance_form.policy != "<p></p>" and compliance_form.policy != "null":
278
+ msg += _("</br><p><b>User's ComplianceForm:</b></p><i>{}</i>").format(compliance_form.policy)
279
+ title = _("Unsigned Compliance Form - {} Reminder : {} ").format(
280
+ compliance_form.form_type, compliance_form.title
281
+ )
282
+ compliance_form.notify(title, msg, recipients=User.objects.filter(profile__id__in=person_ids))
283
+
284
+ return Response(
285
+ {
286
+ "__notification": {
287
+ "compliance_form": compliance_form.id,
288
+ "status": "Compliance Form notification sent",
289
+ "person_signed": person_ids,
290
+ }
291
+ },
292
+ status=status.HTTP_200_OK,
293
+ )
294
+ return Response(
295
+ {
296
+ "__notification": {
297
+ "compliance_form": compliance_form.id,
298
+ "status": "Compliance Form notification not sent",
299
+ "person_signed": None,
300
+ }
301
+ },
302
+ status=status.HTTP_400_BAD_REQUEST,
303
+ )
304
+
305
+ @action(detail=True, methods=["PATCH"], authentication_classes=[JWTCookieAuthentication])
306
+ def regenerate_document(self, request, pk):
307
+ if not request.user.has_perm("wbcompliance.administrate_compliance"):
308
+ return Response(status=status.HTTP_403_FORBIDDEN)
309
+ content_type = ContentType.objects.get_for_model(ComplianceForm)
310
+ send_email = request.POST.get("send_email", "false") == "true"
311
+ update_or_create_compliance_document.delay(request.user.id, content_type.id, pk, send_email=send_email)
312
+
313
+ return Response(
314
+ {"__notification": {"title": "PDF is going to be created and sent to you."}},
315
+ status=status.HTTP_200_OK,
316
+ )
317
+
318
+
319
+ # COMPLIANCE FORM SIGNATURE
320
+ class ComplianceFormSignatureModelViewSet(RevisionMixin, viewsets.ModelViewSet):
321
+ IDENTIFIER = "wbcompliance:complianceformsignature"
322
+ display_config_class = ComplianceFormSignatureDisplayConfig
323
+ title_config_class = ComplianceFormSignatureTitleConfig
324
+ button_config_class = ComplianceFormSignatureButtonConfig
325
+ endpoint_config_class = ComplianceFormSignatureEndpointConfig
326
+
327
+ search_fields = ["compliance_form__title"]
328
+
329
+ ordering_fields = ["version", "signed", "start", "end", "person"]
330
+ ordering = ["-version", "-signed"]
331
+
332
+ filterset_class = ComplianceFormSignatureFilter
333
+
334
+ serializer_class = ComplianceFormSignatureModelSerializer
335
+ queryset = ComplianceFormSignature.objects.select_related("compliance_form", "person")
336
+
337
+ def get_queryset(self):
338
+ if ComplianceType.is_administrator(self.request.user):
339
+ qs = super().get_queryset()
340
+ else:
341
+ qs = super().get_queryset().filter(person=self.request.user.profile)
342
+ return qs.annotate(
343
+ is_signed=Case(
344
+ When(signed=None, then=Value(False)),
345
+ default=Value(True),
346
+ output_field=BooleanField(),
347
+ )
348
+ )
349
+
350
+ @action(detail=True, methods=["PATCH"], permission_classes=[permissions.IsAuthenticated])
351
+ def signature(self, request, pk=None):
352
+ compliance_form_signature = get_object_or_404(ComplianceFormSignature, pk=pk)
353
+ if request.user.profile != compliance_form_signature.person:
354
+ return Response(status=status.HTTP_403_FORBIDDEN)
355
+ compliance_form_signature.signed = timezone.now()
356
+ compliance_form_signature.remark = request.POST.get("remark")
357
+ compliance_form_signature.save()
358
+
359
+ ComplianceFormSignature.objects.filter(
360
+ Q(compliance_form=compliance_form_signature.compliance_form)
361
+ & Q(version__lt=compliance_form_signature.version)
362
+ & Q(signed__isnull=True)
363
+ & Q(person=request.user.profile)
364
+ ).update(signed=timezone.now())
365
+
366
+ if hasattr(compliance_form_signature.person, "user_account"):
367
+ msg = _("<p><b>{}</b> {} version <b>{} </b> has been signed</p>").format(
368
+ compliance_form_signature.compliance_form.title,
369
+ compliance_form_signature.compliance_form.form_type,
370
+ compliance_form_signature.version,
371
+ )
372
+ if (
373
+ compliance_form_signature.policy
374
+ and compliance_form_signature.policy != "<p></p>"
375
+ and compliance_form_signature.policy != "null"
376
+ ):
377
+ msg += _("</br><p><b>{}:</b></p> <i>{}</i>").format(
378
+ compliance_form_signature.compliance_form.form_type, compliance_form_signature.policy
379
+ )
380
+ send_notification(
381
+ code="wbcompliance.complianceformsignature.signed",
382
+ title=_("Confirmation : {} {} version {} has been signed").format(
383
+ compliance_form_signature.compliance_form.title,
384
+ compliance_form_signature.compliance_form.form_type,
385
+ compliance_form_signature.version,
386
+ ),
387
+ body=msg,
388
+ user=compliance_form_signature.person.user_account,
389
+ reverse_name="wbcompliance:complianceformsignature-detail",
390
+ reverse_args=[compliance_form_signature.id],
391
+ )
392
+
393
+ return Response(
394
+ {
395
+ "__notification": {
396
+ str(compliance_form_signature.signed): "Compliance Form signed",
397
+ "person_signed": compliance_form_signature.person.id,
398
+ }
399
+ },
400
+ status=status.HTTP_200_OK,
401
+ )
402
+
403
+ @action(detail=True, methods=["PATCH"], authentication_classes=[JWTCookieAuthentication])
404
+ def regenerate_document(self, request, pk):
405
+ compliance_form_signature = get_object_or_404(ComplianceFormSignature, pk=pk)
406
+ if (
407
+ not request.user.has_perm("wbcompliance.administrate_compliance")
408
+ and request.user.profile != compliance_form_signature.person
409
+ ):
410
+ return Response(status=status.HTTP_403_FORBIDDEN)
411
+ content_type = ContentType.objects.get_for_model(ComplianceFormSignature)
412
+ send_email = request.POST.get("send_email", "false") == "true"
413
+ update_or_create_compliance_document.delay(request.user.id, content_type.id, pk, send_email=send_email)
414
+
415
+ return Response(
416
+ {"__notification": {"title": "PDF is going to be created and sent to you."}},
417
+ status=status.HTTP_200_OK,
418
+ )
419
+
420
+
421
+ class CFComplianceFormSignatureModelViewSet(ComplianceFormSignatureModelViewSet):
422
+ endpoint_config_class = CFComplianceFormSignatureEndpointConfig
423
+
424
+ def get_queryset(self):
425
+ return super().get_queryset().filter(compliance_form__id=self.kwargs["compliance_form_id"])