Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 264 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
MesurementGenerator | |
0.00% |
0 / 264 |
|
0.00% |
0 / 11 |
2862 | |
0.00% |
0 / 1 |
addGlobalOverview | |
0.00% |
0 / 54 |
|
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 | 'layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED, |
65 | ]; |
66 | |
67 | uasort($data, [$this, 'sortMesurementByDate']); |
68 | |
69 | $appliedMesurement = []; |
70 | $actionPlan = []; |
71 | foreach ($data as $mesurement) { |
72 | if (MesurementStatusDictionary::STATUS_APPLIED === $mesurement->getStatus()) { |
73 | $appliedMesurement[] = [ |
74 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format('d/m/Y') : '', |
75 | $mesurement->getName(), |
76 | ]; |
77 | } elseif (!\is_null($mesurement->getPlanificationDate()) && MesurementStatusDictionary::STATUS_NOT_APPLIED === $mesurement->getStatus()) { |
78 | $actionPlan[] = [ |
79 | 'data' => [ |
80 | $mesurement->getPriority(), |
81 | $mesurement->getName(), |
82 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format(self::DATE_FORMAT) : '', |
83 | $mesurement->getManager(), |
84 | $mesurement->getComment(), |
85 | ], |
86 | 'style' => [ |
87 | 'bgColor' => $mesurement->getPriority() ? $this->ColorCellPriority($mesurement->getPriority()) : '', |
88 | ], |
89 | ]; |
90 | } |
91 | } |
92 | |
93 | $section->addTitle('Actions de protection mises en place', 2); |
94 | $textrun = $section->addTextRun(); |
95 | $textrun->addText('Des actions de protection ont été mises en place afin de protéger les données à caractère personnel. Une '); |
96 | $textrun->addLink('ActionsImplemented', 'liste exhaustive des actions de protection mises en place', ['underline' => 'single'], [], true); |
97 | $textrun->addText(' figure en annexe. Ci-dessous, les 20 dernières actions :'); |
98 | |
99 | $this->ProtectionActionAppliedTable($section, $appliedMesurement, false); |
100 | |
101 | $section->addTitle("Plan d'actions", 2); |
102 | $section->addText('Un plan d’action a été établi comme suit.'); |
103 | $this->ActionPlanTable($section, $actionPlan); |
104 | |
105 | $section->addTextBreak(); |
106 | |
107 | $section->addText('Le tableau ci-dessous représente le nombre d’actions de protection affectées par type de registre :'); |
108 | $this->ActionTypeTable($section, $data); |
109 | } |
110 | |
111 | private function ActionTypeTable($section, $data) |
112 | { |
113 | $tableActionType = $section->addTable($this->tableStyleConformite); |
114 | $tableActionType->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
115 | $cell = $tableActionType->addCell(6000, $this->cellHeadStyle); |
116 | $cell->addText('Type de registre', $this->textHeadStyle); |
117 | $cell = $tableActionType->addCell(3000, $this->cellHeadStyle); |
118 | $cell->addText('Nombre d’actions de protection affectées', $this->textHeadStyle); |
119 | |
120 | $cntTreatment = 0; |
121 | $cntContractors = 0; |
122 | $cntTools = 0; |
123 | $cntViolations = 0; |
124 | $cntRequests = 0; |
125 | foreach ($data as $item) { |
126 | $cntTreatment = $item->getTreatments() ? $cntTreatment + count($item->getTreatments()) : $cntTreatment; |
127 | $cntContractors = $item->getContractors() ? $cntContractors + count($item->getContractors()) : $cntContractors; |
128 | $cntTools = $item->getTools() ? $cntTools + count($item->getTools()) : $cntTools; |
129 | $cntViolations = $item->getViolations() ? $cntViolations + count($item->getViolations()) : $cntViolations; |
130 | $cntRequests = $item->getRequests() ? $cntRequests + count($item->getRequests()) : $cntRequests; |
131 | } |
132 | |
133 | if ($this->collectivity) { |
134 | $collectivity = $this->collectivity; |
135 | } else { |
136 | $collectivity = $this->userProvider->getAuthenticatedUser()->getCollectivity(); |
137 | } |
138 | $arrayTypes = $collectivity->isHasModuleTools() ? |
139 | [['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]] : |
140 | [['type' => 'Traitements', 'count' => $cntTreatment], ['type' => 'Sous-traitants', 'count' => $cntContractors], ['type' => 'Violations de données', 'count' => $cntViolations], ['type' => 'Demandes', 'count' => $cntRequests]]; |
141 | |
142 | foreach ($arrayTypes as $item) { |
143 | $tableActionType->addRow(); |
144 | $cell = $tableActionType->addCell(6000); |
145 | $cell->addText($item['type']); |
146 | $cell = $tableActionType->addCell(3000); |
147 | $cell->addText($item['count']); |
148 | } |
149 | } |
150 | |
151 | public function ProtectionActionAppliedAnnexeTable($section, $data) |
152 | { |
153 | $section->addBookmark('ActionsImplemented'); |
154 | $section->addTitle('Liste des actions de protection mises en place', 2); |
155 | |
156 | uasort($data, [$this, 'sortMesurementByDate']); |
157 | $appliedMesurement = []; |
158 | /** @var Mesurement $mesurement */ |
159 | foreach ($data as $mesurement) { |
160 | if (MesurementStatusDictionary::STATUS_APPLIED === $mesurement->getStatus()) { |
161 | $appliedMesurement[] = [ |
162 | $mesurement->getPlanificationDate() ? $mesurement->getPlanificationDate()->format('d/m/Y') : '', |
163 | $mesurement->getName(), |
164 | ]; |
165 | } |
166 | } |
167 | $this->ProtectionActionAppliedTable($section, $appliedMesurement, true); |
168 | } |
169 | |
170 | public function ProtectionActionAppliedTable($section, $appliedMesurement, $isAnnexe) |
171 | { |
172 | $tableProtectionActionApplied = $section->addTable($this->tableStyleConformite); |
173 | $tableProtectionActionApplied->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
174 | $cell = $tableProtectionActionApplied->addCell(1500, $this->cellHeadStyle); |
175 | $cell->addText('Date', $this->textHeadStyle); |
176 | $cell = $tableProtectionActionApplied->addCell(7500, $this->cellHeadStyle); |
177 | $cell->addText('Action', $this->textHeadStyle); |
178 | |
179 | if ($appliedMesurement) { |
180 | $limit = $isAnnexe ? count($appliedMesurement) : 20; |
181 | |
182 | foreach (array_slice($appliedMesurement, 0, $limit) as $line) { |
183 | $tableProtectionActionApplied->addRow(400, ['exactHeight' => true, 'cantsplit' => true]); |
184 | $cell1 = $tableProtectionActionApplied->addCell(1500); |
185 | $cell1->addText($line[0], [], ['alignment' => 'center']); |
186 | $cell2 = $tableProtectionActionApplied->addCell(7500); |
187 | $cell2->addText($line[1]); |
188 | } |
189 | } |
190 | } |
191 | |
192 | private function ActionPlanTable($section, $actionPlan) |
193 | { |
194 | $tableActionPlan = $section->addTable($this->tableStyleConformite); |
195 | $tableActionPlan->addRow(null, ['tblHeader' => true, 'cantSplit' => true]); |
196 | $cell = $tableActionPlan->addCell(1000, $this->cellHeadStyle); |
197 | $cell->addText('Priorité', $this->textHeadStyle); |
198 | $cell = $tableActionPlan->addCell(2000, $this->cellHeadStyle); |
199 | $cell->addText('Action', $this->textHeadStyle); |
200 | $cell = $tableActionPlan->addCell(1000, $this->cellHeadStyle); |
201 | $cell->addText('Date', $this->textHeadStyle); |
202 | $cell = $tableActionPlan->addCell(1500, $this->cellHeadStyle); |
203 | $cell->addText('Responsable de l\'action', $this->textHeadStyle); |
204 | $cell = $tableActionPlan->addCell(1500, $this->cellHeadStyle); |
205 | $cell->addText('Observations', $this->textHeadStyle); |
206 | |
207 | if ($actionPlan) { |
208 | foreach ($actionPlan as $line) { |
209 | $tableActionPlan->addRow(null, ['cantSplit' => true]); |
210 | $cell1 = $tableActionPlan->addCell(1000, ['bgColor' => $line['style']['bgColor']]); |
211 | $priority = match ($line['data'][0]) { |
212 | 'low' => 'Basse', |
213 | 'normal' => 'Normale', |
214 | 'high' => 'Haute', |
215 | null => 'Aucune', |
216 | }; |
217 | $cell1->addText($priority, ['bold' => true]); |
218 | $cell2 = $tableActionPlan->addCell(2000); |
219 | $cell2->addText($line['data'][1]); |
220 | $cell1 = $tableActionPlan->addCell(1000); |
221 | $cell1->addText($line['data'][2]); |
222 | $cell2 = $tableActionPlan->addCell(1500); |
223 | $cell2->addText($line['data'][3]); |
224 | $cell2 = $tableActionPlan->addCell(1500); |
225 | $cell2->addText($line['data'][4]); |
226 | } |
227 | } |
228 | } |
229 | |
230 | private function ColorCellPriority($priority) |
231 | { |
232 | $returned_value = match ($priority) { |
233 | 'low' => 'ffff80', |
234 | 'normal' => 'fac9ad', |
235 | 'high' => 'ffa7a7', |
236 | '' => 'ffffff', |
237 | }; |
238 | |
239 | return $returned_value; |
240 | } |
241 | |
242 | public function addSyntheticView(Section $section, array $data): void |
243 | { |
244 | $section->addTitle('Liste des actions de protection', 1); |
245 | |
246 | // Table data |
247 | // Add header |
248 | $tableData = [ |
249 | [ |
250 | 'Nom', |
251 | 'Statut', |
252 | 'Priorité', |
253 | ], |
254 | ]; |
255 | |
256 | uasort($data, [$this, 'sortMesurementByPriority']); |
257 | |
258 | // Add content |
259 | foreach ($data as $mesurement) { |
260 | $tableData[] = [ |
261 | $mesurement->getName(), |
262 | MesurementStatusDictionary::getStatus()[$mesurement->getStatus()], |
263 | $mesurement->getPriority() ? MesurementPriorityDictionary::getPriorities()[$mesurement->getPriority()] : '', |
264 | ]; |
265 | } |
266 | |
267 | $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL); |
268 | } |
269 | |
270 | public function addActionPlanSyntheticView(Section $section, array $data): void |
271 | { |
272 | $section->addTitle('Liste des actions de protection planifiées', 1); |
273 | |
274 | // Table data |
275 | // Add header |
276 | $tableData = [ |
277 | [ |
278 | 'Nom', |
279 | 'Échéance', |
280 | "Responsable d'action", |
281 | ], |
282 | ]; |
283 | |
284 | uasort($data, [$this, 'sortMesurementByPriority']); |
285 | |
286 | // Add content |
287 | foreach ($data as $mesurement) { |
288 | $tableData[] = [ |
289 | $mesurement->getName(), |
290 | $this->getDate($mesurement->getPlanificationDate()), |
291 | $mesurement->getManager(), |
292 | ]; |
293 | } |
294 | |
295 | $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL); |
296 | } |
297 | |
298 | public function addDetailedView(Section $section, array $data, $actionPlan = false): void |
299 | { |
300 | if ($actionPlan) { |
301 | $section->addTitle('Détail des actions de protection planifiées', 1); |
302 | } else { |
303 | $section->addTitle('Détail des actions de protection', 1); |
304 | } |
305 | |
306 | foreach ($data as $key => $mesurement) { |
307 | if (0 != $key) { |
308 | $section->addPageBreak(); |
309 | } |
310 | $section->addTitle($mesurement->getName(), 2); |
311 | |
312 | $generalInformationsData = [ |
313 | [ |
314 | 'Nom', |
315 | $mesurement->getName(), |
316 | ], |
317 | ]; |
318 | |
319 | // Ajouter les services si le module est actif |
320 | if ($mesurement->getCollectivity()->getIsServicesEnabled()) { |
321 | $generalInformationsData[] = [ |
322 | 'Service', |
323 | $mesurement->getService(), |
324 | ]; |
325 | } |
326 | |
327 | $generalInformationsData = array_merge($generalInformationsData, [ |
328 | [ |
329 | 'Description', |
330 | $mesurement->getDescription() ? \preg_split('/\R/', $mesurement->getDescription()) : null, |
331 | ], |
332 | [ |
333 | 'Responsable d\'action', |
334 | $mesurement->getManager(), |
335 | ], |
336 | [ |
337 | 'Priorité', |
338 | !\is_null($mesurement->getPriority()) ? MesurementPriorityDictionary::getPriorities()[$mesurement->getPriority()] : '', |
339 | ], |
340 | [ |
341 | 'Coût', |
342 | $mesurement->getCost(), |
343 | ], |
344 | [ |
345 | 'Charge', |
346 | $mesurement->getCharge(), |
347 | ], |
348 | ]); |
349 | |
350 | $applicationData = [ |
351 | [ |
352 | 'Statut', |
353 | MesurementStatusDictionary::getStatus()[$mesurement->getStatus()], |
354 | ], |
355 | [ |
356 | 'Échéance', |
357 | MesurementStatusDictionary::STATUS_NOT_APPLICABLE !== $mesurement->getStatus() |
358 | ? ($mesurement->getPlanificationDate() ? $this->getDate($mesurement->getPlanificationDate(), 'd/m/Y') : null) |
359 | : 'Non applicable', |
360 | ], |
361 | [ |
362 | 'Observations', |
363 | $mesurement->getComment(), |
364 | ], |
365 | ]; |
366 | |
367 | $historyData = [ |
368 | [ |
369 | 'Date de création', |
370 | $this->getDate($mesurement->getCreatedAt()), |
371 | ], |
372 | [ |
373 | 'Date de modification', |
374 | $this->getDate($mesurement->getUpdatedAt()), |
375 | ], |
376 | [ |
377 | 'Modifié par', |
378 | $mesurement->getUpdatedBy(), |
379 | ], |
380 | ]; |
381 | |
382 | $section->addTitle('Informations générales', 3); |
383 | $this->addTable($section, $generalInformationsData, false, self::TABLE_ORIENTATION_VERTICAL); |
384 | |
385 | $section->addTitle('Application', 3); |
386 | $this->addTable($section, $applicationData, false, self::TABLE_ORIENTATION_VERTICAL); |
387 | |
388 | $section->addTitle('Éléments associés', 3); |
389 | $this->addLinkedData($section, $mesurement); |
390 | |
391 | $section->addTitle('Historique', 3); |
392 | $this->addTable($section, $historyData, false, self::TABLE_ORIENTATION_VERTICAL); |
393 | } |
394 | } |
395 | |
396 | private function sortMesurementByDate(Mesurement $a, Mesurement $b) |
397 | { |
398 | if ($a->getPlanificationDate() === $b->getPlanificationDate()) { |
399 | return strcmp($b->getName(), $a->getName()); |
400 | } |
401 | |
402 | return ($a->getPlanificationDate() < $b->getPlanificationDate()) ? 1 : -1; |
403 | } |
404 | |
405 | private function sortMesurementByPriority(Mesurement $a, Mesurement $b) |
406 | { |
407 | $weightA = \is_null($a->getPriority()) ? 0 : MesurementPriorityDictionary::getWeightPriorities()[$a->getPriority()]; |
408 | $weightB = \is_null($b->getPriority()) ? 0 : MesurementPriorityDictionary::getWeightPriorities()[$b->getPriority()]; |
409 | |
410 | if ($weightA === $weightB) { |
411 | return 0; |
412 | } |
413 | |
414 | return ($weightA < $weightB) ? 1 : -1; |
415 | } |
416 | } |