Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 264
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
MesurementGenerator
0.00% covered (danger)
0.00%
0 / 264
0.00% covered (danger)
0.00%
0 / 11
2862
0.00% covered (danger)
0.00%
0 / 1
 addGlobalOverview
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
90
 ActionTypeTable
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
110
 ProtectionActionAppliedAnnexeTable
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 ProtectionActionAppliedTable
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 ActionPlanTable
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
12
 ColorCellPriority
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 addSyntheticView
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
12
 addActionPlanSyntheticView
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 addDetailedView
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
90
 sortMesurementByDate
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 sortMesurementByPriority
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
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
22declare(strict_types=1);
23
24namespace App\Domain\Reporting\Generator\Word;
25
26use App\Domain\Registry\Dictionary\MesurementPriorityDictionary;
27use App\Domain\Registry\Dictionary\MesurementStatusDictionary;
28use App\Domain\Registry\Model\Mesurement;
29use PhpOffice\PhpWord\Element\Section;
30use PhpOffice\PhpWord\Element\Table;
31use PhpOffice\PhpWord\SimpleType\TblWidth;
32
33class 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}