Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 263 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
MesurementGenerator | |
0.00% |
0 / 263 |
|
0.00% |
0 / 11 |
2862 | |
0.00% |
0 / 1 |
addGlobalOverview | |
0.00% |
0 / 53 |
|
0.00% |
0 / 1 |
90 | |||
ActionTypeTable | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
110 | |||
ProtectionActionAppliedAnnexeTable | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
ProtectionActionAppliedTable | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
ActionPlanTable | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
12 | |||
ColorCellPriority | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
addSyntheticView | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
addActionPlanSyntheticView | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
6 | |||
addDetailedView | |
0.00% |
0 / 78 |
|
0.00% |
0 / 1 |
90 | |||
sortMesurementByDate | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
sortMesurementByPriority | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | |
3 | /** |
4 | * This file is part of the MADIS - RGPD Management application. |
5 | * |
6 | * @copyright Copyright (c) 2018-2019 Soluris - Solutions Numériques Territoriales Innovantes |
7 | * |
8 | * This program is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU Affero General Public License as published by |
10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU Affero General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Affero General Public License |
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
20 | */ |
21 | |
22 | declare(strict_types=1); |
23 | |
24 | namespace App\Domain\Reporting\Generator\Word; |
25 | |
26 | use App\Domain\Registry\Dictionary\MesurementPriorityDictionary; |
27 | use App\Domain\Registry\Dictionary\MesurementStatusDictionary; |
28 | use App\Domain\Registry\Model\Mesurement; |
29 | use PhpOffice\PhpWord\Element\Section; |
30 | use PhpOffice\PhpWord\Element\Table; |
31 | use PhpOffice\PhpWord\SimpleType\TblWidth; |
32 | |
33 | class MesurementGenerator extends AbstractGenerator implements ImpressionGeneratorInterface |
34 | { |
35 | protected $tableStyleConformite; |
36 | |
37 | /** |
38 | * Global overview : Information to display for mesurement in overview report. |
39 | */ |
40 | public function addGlobalOverview(Section $section, array $data): void |
41 | { |
42 | if ($this->collectivity) { |
43 | $collectivity = $this->collectivity; |
44 | } else { |
45 | $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity(); |
46 | } |
47 | |
48 | $actionPlan = [ |
49 | [ |
50 | 'Priorité', |
51 | 'Action', |
52 | 'Date', |
53 | 'Responsable de l\'action', |
54 | 'Observations', |
55 | ], |
56 | ]; |
57 | |
58 | $this->tableStyleConformite = [ |
59 | 'borderColor' => '006699', |
60 | 'borderSize' => 6, |
61 | 'cellMargin' => 100, |
62 | 'unit' => TblWidth::PERCENT, |
63 | 'width' => 100 * 50, |
64 | ]; |
65 | |
66 | uasort($data, [$this, 'sortMesurementByDate']); |
67 | |
68 | $appliedMesurement = []; |
69 | $actionPlan = []; |
70 | foreach ($data as $mesurement) { |
71 | if (MesurementStatusDictionary::STATUS_APPLIED === $mesurement->getStatus()) { |
72 | $appliedMesurement[] = [ |
73 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format('d/m/Y') : '', |
74 | $mesurement->getName(), |
75 | ]; |
76 | } elseif (!\is_null($mesurement->getPlanificationDate()) && MesurementStatusDictionary::STATUS_NOT_APPLIED === $mesurement->getStatus()) { |
77 | $actionPlan[] = [ |
78 | 'data' => [ |
79 | $mesurement->getPriority(), |
80 | $mesurement->getName(), |
81 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format(self::DATE_FORMAT) : '', |
82 | $mesurement->getManager(), |
83 | $mesurement->getComment(), |
84 | ], |
85 | 'style' => [ |
86 | 'bgColor' => $mesurement->getPriority() ? $this->ColorCellPriority($mesurement->getPriority()) : '', |
87 | ], |
88 | ]; |
89 | } |
90 | } |
91 | |
92 | $section->addTitle('Actions de protection mises en place', 2); |
93 | $textrun = $section->addTextRun(); |
94 | $textrun->addText('Des actions de protection ont été mises en place afin de protéger les données à caractère personnel. Une '); |
95 | $textrun->addLink('ActionsImplemented', 'liste exhaustive des actions de protection mises en place', ['underline' => 'single'], [], true); |
96 | $textrun->addText(' figure en annexe. Ci-dessous, les 20 dernières actions :'); |
97 | |
98 | $this->ProtectionActionAppliedTable($section, $appliedMesurement, false); |
99 | |
100 | $section->addTitle("Plan d'actions", 2); |
101 | $section->addText('Un plan d’action a été établi comme suit.'); |
102 | $this->ActionPlanTable($section, $actionPlan); |
103 | |
104 | $section->addTextBreak(); |
105 | |
106 | $section->addText('Le tableau ci-dessous représente le nombre d’actions de protection affectées par type de registre :'); |
107 | $this->ActionTypeTable($section, $data); |
108 | } |
109 | |
110 | private function ActionTypeTable($section, $data) |
111 | { |
112 | $tableActionType = $section->addTable($this->tableStyleConformite); |
113 | $tableActionType->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
114 | $cell = $tableActionType->addCell(6000, $this->cellHeadStyle); |
115 | $cell->addText('Type de registre', $this->textHeadStyle); |
116 | $cell = $tableActionType->addCell(3000, $this->cellHeadStyle); |
117 | $cell->addText('Nombre d’actions de protection affectées', $this->textHeadStyle); |
118 | |
119 | $cntTreatment = 0; |
120 | $cntContractors = 0; |
121 | $cntTools = 0; |
122 | $cntViolations = 0; |
123 | $cntRequests = 0; |
124 | foreach ($data as $item) { |
125 | $cntTreatment = $item->getTreatments() ? $cntTreatment + count($item->getTreatments()) : $cntTreatment; |
126 | $cntContractors = $item->getContractors() ? $cntContractors + count($item->getContractors()) : $cntContractors; |
127 | $cntTools = $item->getTools() ? $cntTools + count($item->getTools()) : $cntTools; |
128 | $cntViolations = $item->getViolations() ? $cntViolations + count($item->getViolations()) : $cntViolations; |
129 | $cntRequests = $item->getRequests() ? $cntRequests + count($item->getRequests()) : $cntRequests; |
130 | } |
131 | |
132 | if ($this->collectivity) { |
133 | $collectivity = $this->collectivity; |
134 | } else { |
135 | $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity(); |
136 | } |
137 | $arrayTypes = $collectivity->isHasModuleTools() ? |
138 | [['type' => 'Traitements', 'count' => $cntTreatment], ['type' => 'Sous-traitants', 'count' => $cntContractors], ['type' => 'Logiciels ou supports', 'count' => $cntTools], ['type' => 'Violations de données', 'count' => $cntViolations], ['type' => 'Demandes', 'count' => $cntRequests]] : |
139 | [['type' => 'Traitements', 'count' => $cntTreatment], ['type' => 'Sous-traitants', 'count' => $cntContractors], ['type' => 'Violations de données', 'count' => $cntViolations], ['type' => 'Demandes', 'count' => $cntRequests]]; |
140 | |
141 | foreach ($arrayTypes as $item) { |
142 | $tableActionType->addRow(); |
143 | $cell = $tableActionType->addCell(6000); |
144 | $cell->addText($item['type']); |
145 | $cell = $tableActionType->addCell(3000); |
146 | $cell->addText($item['count']); |
147 | } |
148 | } |
149 | |
150 | public function ProtectionActionAppliedAnnexeTable($section, $data) |
151 | { |
152 | $section->addBookmark('ActionsImplemented'); |
153 | $section->addTitle('Liste des actions de protection mises en place', 2); |
154 | |
155 | uasort($data, [$this, 'sortMesurementByDate']); |
156 | $appliedMesurement = []; |
157 | /** @var Mesurement $mesurement */ |
158 | foreach ($data as $mesurement) { |
159 | if (MesurementStatusDictionary::STATUS_APPLIED === $mesurement->getStatus()) { |
160 | $appliedMesurement[] = [ |
161 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format('d/m/Y') : '', |
162 | $mesurement->getName(), |
163 | ]; |
164 | } |
165 | } |
166 | $this->ProtectionActionAppliedTable($section, $appliedMesurement, true); |
167 | } |
168 | |
169 | public function ProtectionActionAppliedTable($section, $appliedMesurement, $isAnnexe) |
170 | { |
171 | $tableProtectionActionApplied = $section->addTable($this->tableStyleConformite); |
172 | $tableProtectionActionApplied->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
173 | $cell = $tableProtectionActionApplied->addCell(1500, $this->cellHeadStyle); |
174 | $cell->addText('Date', $this->textHeadStyle); |
175 | $cell = $tableProtectionActionApplied->addCell(7500, $this->cellHeadStyle); |
176 | $cell->addText('Action', $this->textHeadStyle); |
177 | |
178 | if ($appliedMesurement) { |
179 | $limit = $isAnnexe ? count($appliedMesurement) : 20; |
180 | |
181 | foreach (array_slice($appliedMesurement, 0, $limit) as $line) { |
182 | $tableProtectionActionApplied->addRow(400, ['exactHeight' => true, 'cantsplit' => true]); |
183 | $cell1 = $tableProtectionActionApplied->addCell(1500); |
184 | $cell1->addText($line[0], [], ['alignment' => 'center']); |
185 | $cell2 = $tableProtectionActionApplied->addCell(7500); |
186 | $cell2->addText($line[1]); |
187 | } |
188 | } |
189 | } |
190 | |
191 | private function ActionPlanTable($section, $actionPlan) |
192 | { |
193 | $tableActionPlan = $section->addTable($this->tableStyleConformite); |
194 | $tableActionPlan->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
195 | $cell = $tableActionPlan->addCell(1000, $this->cellHeadStyle); |
196 | $cell->addText('Priorité', $this->textHeadStyle); |
197 | $cell = $tableActionPlan->addCell(2000, $this->cellHeadStyle); |
198 | $cell->addText('Action', $this->textHeadStyle); |
199 | $cell = $tableActionPlan->addCell(1000, $this->cellHeadStyle); |
200 | $cell->addText('Date', $this->textHeadStyle); |
201 | $cell = $tableActionPlan->addCell(1500, $this->cellHeadStyle); |
202 | $cell->addText('Responsable de l\'action', $this->textHeadStyle); |
203 | $cell = $tableActionPlan->addCell(1500, $this->cellHeadStyle); |
204 | $cell->addText('Observations', $this->textHeadStyle); |
205 | |
206 | if ($actionPlan) { |
207 | foreach ($actionPlan as $line) { |
208 | $tableActionPlan->addRow(null, ['cantSplit' => true]); |
209 | $cell1 = $tableActionPlan->addCell(1000, ['bgColor' => $line['style']['bgColor']]); |
210 | $priority = match ($line['data'][0]) { |
211 | 'low' => 'Basse', |
212 | 'normal' => 'Normale', |
213 | 'high' => 'Haute', |
214 | null => 'Aucune', |
215 | }; |
216 | $cell1->addText($priority, ['bold' => true]); |
217 | $cell2 = $tableActionPlan->addCell(2000); |
218 | $cell2->addText($line['data'][1]); |
219 | $cell1 = $tableActionPlan->addCell(1000); |
220 | $cell1->addText($line['data'][2]); |
221 | $cell2 = $tableActionPlan->addCell(1500); |
222 | $cell2->addText($line['data'][3]); |
223 | $cell2 = $tableActionPlan->addCell(1500); |
224 | $cell2->addText($line['data'][4]); |
225 | } |
226 | } |
227 | } |
228 | |
229 | private function ColorCellPriority($priority) |
230 | { |
231 | $returned_value = match ($priority) { |
232 | 'low' => 'ffff80', |
233 | 'normal' => 'fac9ad', |
234 | 'high' => 'ffa7a7', |
235 | '' => 'ffffff', |
236 | }; |
237 | |
238 | return $returned_value; |
239 | } |
240 | |
241 | public function addSyntheticView(Section $section, array $data): void |
242 | { |
243 | $section->addTitle('Liste des actions de protection', 1); |
244 | |
245 | // Table data |
246 | // Add header |
247 | $tableData = [ |
248 | [ |
249 | 'Nom', |
250 | 'Statut', |
251 | 'Priorité', |
252 | ], |
253 | ]; |
254 | |
255 | uasort($data, [$this, 'sortMesurementByPriority']); |
256 | |
257 | // Add content |
258 | foreach ($data as $mesurement) { |
259 | $tableData[] = [ |
260 | $mesurement->getName(), |
261 | MesurementStatusDictionary::getStatus()[$mesurement->getStatus()], |
262 | $mesurement->getPriority() ? MesurementPriorityDictionary::getPriorities()[$mesurement->getPriority()] : '', |
263 | ]; |
264 | } |
265 | |
266 | $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL); |
267 | } |
268 | |
269 | public function addActionPlanSyntheticView(Section $section, array $data): void |
270 | { |
271 | $section->addTitle('Liste des actions de protection planifiées', 1); |
272 | |
273 | // Table data |
274 | // Add header |
275 | $tableData = [ |
276 | [ |
277 | 'Nom', |
278 | 'Échéance', |
279 | "Responsable d'action", |
280 | ], |
281 | ]; |
282 | |
283 | uasort($data, [$this, 'sortMesurementByPriority']); |
284 | |
285 | // Add content |
286 | foreach ($data as $mesurement) { |
287 | $tableData[] = [ |
288 | $mesurement->getName(), |
289 | $this->getDate($mesurement->getPlanificationDate()), |
290 | $mesurement->getManager(), |
291 | ]; |
292 | } |
293 | |
294 | $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL); |
295 | } |
296 | |
297 | public function addDetailedView(Section $section, array $data, $actionPlan = false): void |
298 | { |
299 | if ($actionPlan) { |
300 | $section->addTitle('Détail des actions de protection planifiées', 1); |
301 | } else { |
302 | $section->addTitle('Détail des actions de protection', 1); |
303 | } |
304 | |
305 | foreach ($data as $key => $mesurement) { |
306 | if (0 != $key) { |
307 | $section->addPageBreak(); |
308 | } |
309 | $section->addTitle($mesurement->getName(), 2); |
310 | |
311 | $generalInformationsData = [ |
312 | [ |
313 | 'Nom', |
314 | $mesurement->getName(), |
315 | ], |
316 | ]; |
317 | |
318 | // Ajouter les services si le module est actif |
319 | if ($mesurement->getCollectivity()->getIsServicesEnabled()) { |
320 | $generalInformationsData[] = [ |
321 | 'Service', |
322 | $mesurement->getService(), |
323 | ]; |
324 | } |
325 | |
326 | $generalInformationsData = array_merge($generalInformationsData, [ |
327 | [ |
328 | 'Description', |
329 | $mesurement->getDescription() ? \preg_split('/\R/', $mesurement->getDescription()) : null, |
330 | ], |
331 | [ |
332 | 'Responsable d\'action', |
333 | $mesurement->getManager(), |
334 | ], |
335 | [ |
336 | 'Priorité', |
337 | !\is_null($mesurement->getPriority()) ? MesurementPriorityDictionary::getPriorities()[$mesurement->getPriority()] : '', |
338 | ], |
339 | [ |
340 | 'Coût', |
341 | $mesurement->getCost(), |
342 | ], |
343 | [ |
344 | 'Charge', |
345 | $mesurement->getCharge(), |
346 | ], |
347 | ]); |
348 | |
349 | $applicationData = [ |
350 | [ |
351 | 'Statut', |
352 | MesurementStatusDictionary::getStatus()[$mesurement->getStatus()], |
353 | ], |
354 | [ |
355 | 'Échéance', |
356 | MesurementStatusDictionary::STATUS_NOT_APPLICABLE !== $mesurement->getStatus() |
357 | ? ($mesurement->getPlanificationDate() ? $this->getDate($mesurement->getPlanificationDate(), 'd/m/Y') : null) |
358 | : 'Non applicable', |
359 | ], |
360 | [ |
361 | 'Observations', |
362 | $mesurement->getComment(), |
363 | ], |
364 | ]; |
365 | |
366 | $historyData = [ |
367 | [ |
368 | 'Date de création', |
369 | $this->getDate($mesurement->getCreatedAt()), |
370 | ], |
371 | [ |
372 | 'Date de modification', |
373 | $this->getDate($mesurement->getUpdatedAt()), |
374 | ], |
375 | [ |
376 | 'Modifié par', |
377 | $mesurement->getUpdatedBy(), |
378 | ], |
379 | ]; |
380 | |
381 | $section->addTitle('Informations générales', 3); |
382 | $this->addTable($section, $generalInformationsData, false, self::TABLE_ORIENTATION_VERTICAL); |
383 | |
384 | $section->addTitle('Application', 3); |
385 | $this->addTable($section, $applicationData, false, self::TABLE_ORIENTATION_VERTICAL); |
386 | |
387 | $section->addTitle('Éléments associés', 3); |
388 | $this->addLinkedData($section, $mesurement); |
389 | |
390 | $section->addTitle('Historique', 3); |
391 | $this->addTable($section, $historyData, false, self::TABLE_ORIENTATION_VERTICAL); |
392 | } |
393 | } |
394 | |
395 | private function sortMesurementByDate(Mesurement $a, Mesurement $b) |
396 | { |
397 | if ($a->getPlanificationDate() === $b->getPlanificationDate()) { |
398 | return strcmp($b->getName(), $a->getName()); |
399 | } |
400 | |
401 | return ($a->getPlanificationDate() < $b->getPlanificationDate()) ? 1 : -1; |
402 | } |
403 | |
404 | private function sortMesurementByPriority(Mesurement $a, Mesurement $b) |
405 | { |
406 | $weightA = \is_null($a->getPriority()) ? 0 : MesurementPriorityDictionary::getWeightPriorities()[$a->getPriority()]; |
407 | $weightB = \is_null($b->getPriority()) ? 0 : MesurementPriorityDictionary::getWeightPriorities()[$b->getPriority()]; |
408 | |
409 | if ($weightA === $weightB) { |
410 | return 0; |
411 | } |
412 | |
413 | return ($weightA < $weightB) ? 1 : -1; |
414 | } |
415 | } |