Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 362
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConformiteTraitementGenerator
0.00% covered (danger)
0.00%
0 / 362
0.00% covered (danger)
0.00%
0 / 9
5402
0.00% covered (danger)
0.00%
0 / 1
 addGlobalOverview
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1806
 colorCell
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 valueCell
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 / 24
0.00% covered (danger)
0.00%
0 / 1
12
 addDetailedView
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
56
 sortTreatmentByConformiteTraitementByLevelAndTreatmentName
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 sortReponseByQuestionPosition
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 SyntheticAnnexeList
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
182
 BgColorSyntheticTreatment
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
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\Calculator\Completion\ConformiteTraitementCompletion;
27use App\Domain\Registry\Dictionary\ConformiteTraitementLevelDictionary;
28use App\Domain\Registry\Model\ConformiteTraitement\Reponse;
29use App\Domain\Registry\Model\Mesurement;
30use App\Domain\Registry\Model\Treatment;
31use PhpOffice\PhpWord\Element\Section;
32use PhpOffice\PhpWord\Element\Table;
33use PhpOffice\PhpWord\Shared\Converter;
34use PhpOffice\PhpWord\SimpleType\TblWidth;
35use PhpOffice\PhpWord\Style\ListItem;
36
37class ConformiteTraitementGenerator extends AbstractGenerator implements ImpressionGeneratorInterface
38{
39    /**
40     * Global overview : Information to display for conformiteTraitement in overview report.
41     */
42    public function addGlobalOverview(Section $section, array $data, $withAIPD = true, $withConform = true): void
43    {
44        if (empty($data)) {
45            return;
46        }
47        $tableStyleConformite = [
48            'borderColor' => '006699',
49            'borderSize'  => 6,
50            'cellMargin'  => 100,
51            'unit'        => TblWidth::PERCENT,
52            'width'       => 100 * 50,
53        ];
54
55        if ($withConform) {
56            $section->addTitle('Analyse de la conformité des traitements', 2);
57
58            uasort($data, [$this, 'sortTreatmentByConformiteTraitementByLevelAndTreatmentName']);
59
60            // Table data
61            // Add header
62            $tableData = [
63                [
64                    'Traitement',
65                    'Gestionnaire',
66                    'Date de révision de la conformité',
67                    'Conformité',
68                ],
69            ];
70
71            $chartCategories = [];
72            $chartData       = [];
73            $conformites     = ConformiteTraitementLevelDictionary::getConformites();
74            foreach ($conformites as $key => $label) {
75                $chartCategories[] = $label;
76                $chartData[$key]   = 0;
77            }
78
79            /** @var Treatment $treatment */
80            foreach ($data as $treatment) {
81                $conformiteTraitement = $treatment->getConformiteTraitement();
82                $level                = ConformiteTraitementCompletion::getConformiteTraitementLevel($conformiteTraitement);
83
84                $date = null;
85                if (!\is_null($conformiteTraitement)) {
86                    $date = $conformiteTraitement->getCreatedAt();
87                }
88
89                $tableData[] = [
90                    $treatment->getName(),
91                    $treatment->getManager(),
92                    ConformiteTraitementLevelDictionary::getConformites()[$level],
93                    $this->getDate($date, 'd/m/Y'),
94                ];
95
96                ++$chartData[$level];
97            }
98
99            $section->addText('Les 10 critères suivants correspondent aux principes fondamentaux du RGPD et ont fait l’objet d’une évaluation :');
100            $listStyle = ['listType' => ListItem::TYPE_NUMBER];
101            $section->addListItem('Finalités', 0, null, $listStyle);
102            $section->addListItem('Licéité', 0, null, $listStyle);
103            $section->addListItem('Minimisation des données', 0, null, $listStyle);
104            $section->addListItem('Qualité des données', 0, null, $listStyle);
105            $section->addListItem('Durée de conservation', 0, null, $listStyle);
106            $section->addListItem('Information des personnes concernées', 0, null, $listStyle);
107            $section->addListItem('Recueil de consentement', 0, null, $listStyle);
108            $section->addListItem('Exercice des différents droits', 0, null, $listStyle);
109            $section->addListItem('Sous-traitance', 0, null, $listStyle);
110            $section->addListItem('Transferts en dehors de l’union européenne', 0, null, $listStyle);
111
112            $textrun = $section->addTextRun();
113            $textrun->addText('Une synthèse de l’analyse de la conformité des traitements et à valeur de preuve ');
114            $textrun->addLink('listConformityTreatments', 'figure en annexe', ['underline' => 'single'], [], true);
115            $textrun->addText('.');
116
117            $section->addText('Ci-dessous l’évaluation de la conformité des traitements au ' . date('d/m/Y') . ' :');
118
119            $chart = $section->addChart(
120                'pie',
121                $chartCategories,
122                $chartData,
123                [
124                    'height' => Converter::cmToEmu(11),
125                    'width'  => Converter::cmToEmu(15),
126                ]
127            );
128
129            $chart->getStyle()->setColors(\array_values(ConformiteTraitementLevelDictionary::getHexaConformitesColors()));
130
131            $countTypes          = array_count_values(array_column($tableData, '2'));
132            $conformes           = array_key_exists('Conforme', $countTypes) ? $countTypes['Conforme'] : 0;
133            $nonConformesMineurs = array_key_exists('Non-conformité mineure', $countTypes) ? $countTypes['Non-conformité mineure'] : 0;
134            $nonConformesMajeurs = array_key_exists('Non-conformité majeure', $countTypes) ? $countTypes['Non-conformité majeure'] : 0;
135            $NonEvalues          = array_key_exists('Non évalué', $countTypes) ? $countTypes['Non évalué'] : 0;
136
137            $section->addText('Sur les ' . (count($tableData) - 1) . ' traitements :');
138            $section->addListItem('Conforme(s) : ' . $conformes);
139            $section->addListItem('Non-conformité(s) mineure(s) : ' . $nonConformesMineurs);
140            $section->addListItem('Non-conformité(s) majeure(s) : ' . $nonConformesMajeurs);
141            $section->addListItem('Non évalué(s) : ' . $NonEvalues);
142
143            $tableConformite = $section->addTable($tableStyleConformite);
144            $headersTable    = $tableData[0];
145            $tableConformite->addRow(null, ['tblHeader' => true, 'cantsplit' => true]);
146            foreach ($headersTable as $element) {
147                $cell = $tableConformite->addCell(2500, $this->cellHeadStyle);
148                $cell->addText($element, $this->textHeadStyle);
149            }
150            unset($tableData[0]);
151            foreach ($tableData as $line) {
152                $tableConformite->addRow(null, ['cantsplit' => true]);
153                $cell1 = $tableConformite->addCell(2500);
154                $cell1->addText($line[0]);
155                $cell2 = $tableConformite->addCell(2500);
156                $cell2->addText($line[1]);
157                $cell3 = $tableConformite->addCell(2500);
158                $cell3->addText($line[3]);
159                $styleCellConformite = match ($line[2]) {
160                    'Conforme'               => ['bgColor' => 'bce292'],
161                    'Non-conformité mineure' => ['bgColor' => 'fac9ad'],
162                    'Non-conformité majeure' => ['bgColor' => 'ffa7a7'],
163                    'Non évalué'             => ['bgColor' => 'ffffff'],
164                };
165                $cell4 = $tableConformite->addCell(2500, $styleCellConformite);
166                $cell4->addText($line[2], ['bold' => true]);
167            }
168        }
169
170        if (false === $withAIPD) {
171            return;
172        }
173        // Analyse impact
174        $section->addTitle('Analyse d’impact', 2);
175
176        $cntAipdToDo     = 0;
177        $cntAipdRealised = 0;
178        foreach ($data as $treatment) {
179            $conformite = $treatment->getConformiteTraitement();
180            $aipd       = null;
181            if ($conformite) {
182                $aipd = $conformite->getLastAnalyseImpact();
183            }
184
185            if ($conformite && $conformite->getNeedsAipd()) {
186                ++$cntAipdToDo;
187            }
188
189            if ($aipd) {
190                ++$cntAipdRealised;
191            }
192        }
193
194        $section->addText("Une analyse d’impact sur la protection des données est une étude, qui doit être réalisée si possible en amont du projet, sur des traitements contenant des critères susceptibles d'engendrer un risque élevé pour les droits et libertés des personnes concernées. ");
195        if (0 === $cntAipdRealised) {
196            $section->addText('À ce jour, il n’y a pas eu d’Analyse d’impact réalisées.');
197        }
198
199        $textrun = $section->addTextRun();
200        $textrun->addText('Le tableau des traitements à risque et à valeur de preuve ');
201        $textrun->addLink('AipdRisks', 'figure en annexe.', ['underline' => 'single'], [], true);
202
203        $section->addText('Ci-dessous, la liste des traitements pour lequel une analyse d’impact sur la protection des données est requise. Au vu des critères, il semble que ' . $cntAipdToDo . ' traitements requière(nt) une analyse d’impact.');
204
205        $tableNeedAipd = $section->addTable($tableStyleConformite);
206        $tableNeedAipd->addRow(null, ['tblHeader' => true, 'cantsplit' => true]);
207        foreach (['Nom du traitement', 'Données sensibles', 'Critères de risques'] as $element) {
208            $cell = $tableNeedAipd->addCell(2500, $this->cellHeadStyle);
209            $cell->addText($element, $this->textHeadStyle);
210        }
211
212        $aipdFinished = [];
213        foreach ($data as $treatment) {
214            $cnt_sensible                                                             = 0;
215            $sensibleDatas                                                            = [];
216            $specificTreatments                                                       = [];
217            $treatment->isLargeScaleCollection() ? $specificTreatments[]              = 'Collecte à large échelle' : null;
218            $treatment->isDataCrossing() ? $specificTreatments[]                      = 'Croisement d\'ensemble de données' : null;
219            $treatment->isAutomatedDecisionsWithLegalEffect() ? $specificTreatments[] = 'Décision automatique avec effet juridique' : null;
220            $treatment->isEvaluationOrRating() ? $specificTreatments[]                = 'Évaluation ou notation' : null;
221            $treatment->isAutomaticExclusionService() ? $specificTreatments[]         = 'Exclusion du bénéfice d\'un droit, d’un service ou contrat' : null;
222            $treatment->isVulnerablePeople() ? $specificTreatments[]                  = 'Personnes vulnérables' : null;
223            $treatment->isSystematicMonitoring() ? $specificTreatments[]              = 'Surveillance systématique' : null;
224            $treatment->isInnovativeUse() ? $specificTreatments[]                     = 'Usage innovant' : null;
225
226            foreach ($treatment->getDataCategories() as $category) {
227                if ($category->isSensible()) {
228                    $sensibleDatas[] = $category;
229                }
230            }
231            if ($treatment->getConformiteTraitement() && $treatment->getConformiteTraitement()->getNeedsAipd()) {
232                $tableNeedAipd->addRow(null, ['cantsplit' => true]);
233                $cell = $tableNeedAipd->addCell(2500);
234                $cell->addText($treatment->getName());
235                $cell = $tableNeedAipd->addCell(2500);
236                foreach ($sensibleDatas as $sensibleData) {
237                    $cell->addListItem(htmlspecialchars((string) $sensibleData, ENT_COMPAT, 'UTF-8'), (int) null, [], [], ['spaceAfter' => 0]);
238                }
239                $cell = $tableNeedAipd->addCell(2500);
240                foreach ($specificTreatments as $specificTreatment) {
241                    $cell->addListItem($specificTreatment, (int) null, [], [], ['spaceAfter' => 0]);
242                }
243            }
244
245            if ($treatment->getConformiteTraitement() && $aipd = $treatment->getConformiteTraitement()->getLastAnalyseImpact()) {
246                if ('non_realisee' !== $aipd->getStatut() && 'en_cours' !== $aipd->getStatut()) {
247                    $aipdFinished[] = [
248                        $treatment->getName(),
249                        $treatment->getConformiteTraitement()->getLastAnalyseImpact()->getUpdatedAt(),
250                        $treatment->getConformiteTraitement()->getLastAnalyseImpact()->getAvisReferent(),
251                        $treatment->getConformiteTraitement()->getLastAnalyseImpact()->getAvisDpd(),
252                        $treatment->getConformiteTraitement()->getLastAnalyseImpact()->getAvisRepresentant(),
253                        $treatment->getConformiteTraitement()->getLastAnalyseImpact()->getAvisResponsable(),
254                    ];
255                }
256            }
257        }
258
259        $section->addTextBreak();
260        $text = match (count($aipdFinished)) {
261            0       => "Aucun traitement n'a fait l'objet d'une analyse d'impact.",
262            1       => "1 traitement a fait l'objet d'une analyse d'impact.",
263            default => count($aipdFinished) . ' traitements ont fait l’objet d’une analyse d’impact.',
264        };
265        $section->addText($text);
266
267        $tableAipdExist = $section->addTable($tableStyleConformite);
268        $tableAipdExist->addRow(null, ['tblHeader' => true, 'cantSplit' => true]);
269        foreach (['Traitements', 'Date de réalisation de l’AIPD', 'Avis du référent RGPD', 'Avis du DPD', 'Avis des représentants des personnes concernées', 'Validation du responsable du traitement'] as $element) {
270            $cell = $tableAipdExist->addCell(1000, $this->cellHeadStyle);
271            $cell->addText($element, $this->textHeadStyle);
272        }
273        foreach ($aipdFinished as $line) {
274            $tableAipdExist->addRow(null, ['cantSplit' => true]);
275            $cell = $tableAipdExist->addCell(1000);
276            $cell->addText($line[0]);
277            $cell = $tableAipdExist->addCell(1000);
278            $cell->addText($line[1]->format('d/m/Y'));
279            for ($i = 2; $i <= 5; ++$i) {
280                $cell = $tableAipdExist->addCell(1000, ['bgColor' => $this->colorCell($line[$i]->getReponse())]);
281                $cell->addText($this->valueCell($line[$i]->getReponse()));
282            }
283        }
284    }
285
286    private function colorCell($value)
287    {
288        $return_value = match ($value) {
289            'favorable'         => 'bce292',
290            'defavorable'       => 'ffa7a7',
291            'pas_de_reponse'    => 'ffffff',
292            'favorable_reserve' => 'fac9ad',
293        };
294
295        return $return_value;
296    }
297
298    private function valueCell($value)
299    {
300        $return_value = match ($value) {
301            'favorable'         => 'Favorable',
302            'defavorable'       => 'Défavorable',
303            'pas_de_reponse'    => 'Pas de réponse',
304            'favorable_reserve' => 'Favorable avec réserve',
305        };
306
307        return $return_value;
308    }
309
310    public function addSyntheticView(Section $section, array $data): void
311    {
312        $section->addTitle('Liste des traitements', 1);
313        $section->addBookmark('Traitements en annexe');
314
315        uasort($data, [$this, 'sortTreatmentByConformiteTraitementByLevelAndTreatmentName']);
316
317        // Table data
318        // Add header
319        $tableData = [
320            [
321                'Traitement',
322                'Gestionnaire',
323                'Date de révision de la conformité',
324                'Conformité',
325            ],
326        ];
327
328        /** @var Treatment $treatment */
329        foreach ($data as $treatment) {
330            $conformiteTraitement = $treatment->getConformiteTraitement();
331            $level                = ConformiteTraitementCompletion::getConformiteTraitementLevel($conformiteTraitement);
332
333            $date = null;
334            if (!\is_null($conformiteTraitement)) {
335                $date = $conformiteTraitement->getCreatedAt();
336            }
337
338            $tableData[] = [
339                $treatment->getName(),
340                $treatment->getManager(),
341                $this->getDate($date, 'd/m/Y'),
342                ConformiteTraitementLevelDictionary::getConformites()[$level],
343            ];
344        }
345
346        $this->addTable($section, $tableData, true, self::TABLE_ORIENTATION_HORIZONTAL);
347    }
348
349    public function addDetailedView(Section $section, array $data): void
350    {
351        $section->addTitle('Détail des traitements', 1);
352
353        /** @var Treatment $treatment */
354        foreach ($data as $key => $treatment) {
355            $conformiteTraitement = $treatment->getConformiteTraitement();
356            if (\is_null($conformiteTraitement)) {
357                continue;
358            }
359
360            if (0 != $key) {
361                $section->addPageBreak();
362            }
363
364            $questionsData = [
365                [
366                    'data' => [
367                        'Principes fondamentaux',
368                        ['text' => 'Conformité', 'style' => $this->textHeadStyle],
369                        ['text' => 'Actions de protections', 'style' => $this->textHeadStyle],
370                    ],
371                    'style' => [
372                        'bgColor' => '3c8dbc',
373                        'bold'    => true,
374                        'color'   => 'ffffff',
375                    ],
376                ],
377            ];
378
379            $reponses = \iterable_to_array($conformiteTraitement->getReponses());
380
381            uasort($reponses, [$this, 'sortReponseByQuestionPosition']);
382
383            foreach ($reponses as $reponse) {
384                $actionsProtections = \array_map(function (Mesurement $mesurement) {
385                    return $mesurement->getName();
386                }, \iterable_to_array($reponse->getActionProtections()));
387
388                $questionsData[] = [
389                    $reponse->getQuestion()->getQuestion(),
390                    $reponse->isConforme() ? 'Conforme' : 'Non-conforme',
391                    !empty($actionsProtections) ? join(', ', $actionsProtections) : 'Pas d\'action',
392                ];
393            }
394
395            $section->addTitle($conformiteTraitement->getTraitement()->getName(), 3);
396            $this->addTable($section, $questionsData, true, self::TABLE_ORIENTATION_VERTICAL);
397
398            $historyData = [
399                [
400                    'Date de création',
401                    $this->getDate($conformiteTraitement->getCreatedAt()),
402                ],
403                [
404                    'Date de modification',
405                    $this->getDate($conformiteTraitement->getUpdatedAt()),
406                ],
407                [
408                    'Modifié par',
409                    $conformiteTraitement->getUpdatedBy(),
410                ],
411            ];
412
413            $section->addTitle('Historique', 3);
414            $this->addTable($section, $historyData, false, self::TABLE_ORIENTATION_VERTICAL);
415        }
416    }
417
418    private function sortTreatmentByConformiteTraitementByLevelAndTreatmentName(Treatment $a, Treatment $b)
419    {
420        $weightA = ConformiteTraitementLevelDictionary::getConformitesWeight()[ConformiteTraitementCompletion::getConformiteTraitementLevel($a->getConformiteTraitement())];
421        $weightB = ConformiteTraitementLevelDictionary::getConformitesWeight()[ConformiteTraitementCompletion::getConformiteTraitementLevel($b->getConformiteTraitement())];
422
423        if ($weightA === $weightB) {
424            return strcmp($a->getName(), $b->getName());
425        }
426
427        return ($weightA < $weightB) ? -1 : 1;
428    }
429
430    private function sortReponseByQuestionPosition(Reponse $a, Reponse $b)
431    {
432        $orderA = $a->getQuestion()->getPosition();
433        $orderB = $b->getQuestion()->getPosition();
434
435        return ($orderA < $orderB) ? -1 : 1;
436    }
437
438    public function SyntheticAnnexeList($section, $treatments)
439    {
440        $section->addBookmark('listConformityTreatments');
441        $section->addTitle('Synthèse de la conformité des traitements évalués', 2);
442        $section->addText('Légende :');
443        $section->AddListItem('C = Conforme');
444        $section->AddListItem('NCM = Non conforme mineure');
445        $section->AddListItem('NC = Non conforme majeure');
446
447        $styleCellHeader = ['textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR, 'bgColor' => '3c8dbc', 'vAlign' => 'center'];
448
449        // Affichage du header du tableau
450        $tableSyntheticAnnexeList = $section->addTable($this->tableStyle);
451        $tableSyntheticAnnexeList->addRow(2000, ['tblHeader' => true, 'cantsplit' => true]);
452        $cell = $tableSyntheticAnnexeList->addCell(1000, ['bgColor' => '3c8dbc', 'vAlign' => 'bottom']);
453        $cell->addText('Traitements', $this->textHeadStyle);
454
455        $ConformiteNames = ['Finalités', 'Licéité du traitement', 'Minimisation des données', 'Qualité des données', 'Durées de conservation', 'Information des personnes', 'Recueil du consentement', "Droit d'Accès", 'Droit de rectification', 'Droit de limitation', 'Droit de portabilité', "Droit d'effacement", "Droit d'opposition", 'Sous-traitance', 'Transferts hors UE'];
456        foreach ($ConformiteNames as $item) {
457            $cell = $tableSyntheticAnnexeList->addCell(300, $styleCellHeader);
458            $cell->addText($item, $this->textHeadStyle);
459        }
460
461        $cell = $tableSyntheticAnnexeList->addCell(100, ['borderTopColor' => 'ffffff', 'borderTopSize' => 2, 'borderBottomColor' => 'ffffff', 'borderBottomSize' => 2]);
462        $cell->addText('');
463        $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => '3c8dbc', 'vAlign' => 'bottom']);
464        $cell->addText('C', $this->textHeadStyle);
465        $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => '3c8dbc', 'vAlign' => 'bottom']);
466        $cell->addText('NCM', $this->textHeadStyle);
467        $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => '3c8dbc', 'vAlign' => 'bottom']);
468        $cell->addText('NC', $this->textHeadStyle);
469
470        // End header
471
472        $listConformityName = [
473            'C'   => [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0],
474            'NC'  => [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0],
475            'NCM' => [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0, 7 => 0, 8 => 0, 9 => 0, 10 => 0, 11 => 0, 12 => 0, 13 => 0, 14 => 0, 15 => 0],
476        ];
477
478        // Affichage des données de chaque conformité de traitement
479        foreach ($treatments as $treatment) {
480            if ($treatment->getConformiteTraitement()) {
481                $ConformityTreatmentValues = [];
482                $sorted                    = $treatment->getConformiteTraitement()->getReponses()->toArray();
483                usort($sorted, function (Reponse $rep1, Reponse $rep2) {
484                    return $rep1->getQuestion()->getPosition() - $rep2->getQuestion()->getPosition();
485                });
486                /** @var Reponse $response */
487                foreach ($sorted as $response) {
488                    // get number of planned actions for this response
489                    $plannedActions = 0;
490                    /** @var Mesurement $actionProtection */
491                    foreach ($response->getActionProtections() as $actionProtection) {
492                        if (!\is_null($actionProtection->getPlanificationDate())) {
493                            ++$plannedActions;
494                        }
495                    }
496                    $NonConformityValue                                                 = $plannedActions > 0 ? 'NCM' : 'NC';
497                    $ConformityTreatmentValues[$response->getQuestion()->getPosition()] = $response->isConforme() ? 'C' : $NonConformityValue;
498                }
499
500                $tableSyntheticAnnexeList->addRow();
501                $cell = $tableSyntheticAnnexeList->addCell(1000);
502                $cell->addText($treatment->getName(), ['size' => 8]);
503
504                $C   = 0;
505                $NC  = 0;
506                $NCM = 0;
507
508                foreach ($ConformityTreatmentValues as $key => $value) {
509                    // For each question add a cell saying if conforme or not
510                    $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => $this->BgColorSyntheticTreatment($value), 'vAlign' => 'center']);
511                    $cell->addText($value, ['size' => 8], ['alignment' => 'center']);
512                    ++$listConformityName[$value][$key];
513
514                    match ($value) {
515                        'C'   => $C++,
516                        'NC'  => $NC++,
517                        'NCM' => $NCM++,
518                    };
519                }
520
521                $cell = $tableSyntheticAnnexeList->addCell(100, ['borderTopColor' => 'ffffff', 'borderTopSize' => 2, 'borderBottomColor' => 'ffffff', 'borderBottomSize' => 2]);
522                $cell->addText('');
523                $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => 'bce292', 'vAlign' => 'center']);
524                $cell->addText($C, ['bold' => true], ['alignment' => 'center']);
525                $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => 'ffff80', 'vAlign' => 'center']);
526                $cell->addText($NCM, ['bold' => true], ['alignment' => 'center']);
527                $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => 'ffa7a7', 'vAlign' => 'center']);
528                $cell->addText($NC, ['bold' => true], ['alignment' => 'center']);
529            }
530        }
531
532        $tableSyntheticAnnexeList->addRow(60, ['exactHeight' => true]);
533        $cell = $tableSyntheticAnnexeList->addCell(1000, ['borderTopColor' => 'ffffff', 'borderTopSize' => 2, 'borderBottomColor' => 'ffffff', 'borderBottomSize' => 2, 'borderLeftColor' => 'ffffff', 'borderLeftSize' => 2, 'borderRightColor' => 'ffffff', 'borderRightSize' => 2]);
534        $cell->addText('');
535
536        foreach ($listConformityName as $key => $datas) {
537            $tableSyntheticAnnexeList->addRow(400, ['exactHeight' => true]);
538            $cell = $tableSyntheticAnnexeList->addCell(1000, ['bgColor' => '3c8dbc']);
539            $cell->addText($key, $this->textHeadStyle, ['alignment' => 'right']);
540            foreach ($datas as $key1 => $item) {
541                $cell = $tableSyntheticAnnexeList->addCell(300, ['bgColor' => $this->BgColorSyntheticTreatment($key)]);
542                $cell->addText($item, ['bold' => true], ['alignment' => 'center']);
543
544                if (15 === $key1) {
545                    $cell = $tableSyntheticAnnexeList->addCell(100, ['borderTopColor' => 'ffffff', 'borderTopSize' => 2, 'borderRightColor' => 'ffffff', 'BorderRightSize' => 2, 'borderBottomColor' => 'ffffff', 'borderBottomSize' => 2]);
546                    $cell->addText('');
547                }
548            }
549        }
550    }
551
552    private function BgColorSyntheticTreatment($value)
553    {
554        $return_value = match ($value) {
555            'C'   => 'bce292',
556            'NC'  => 'ffa7a7',
557            'NCM' => 'ffff80',
558        };
559
560        return $return_value;
561    }
562}