Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
42 / 48
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
EnvelopeProgressService
87.50% covered (warning)
87.50%
42 / 48
33.33% covered (danger)
33.33%
2 / 6
24.03
0.00% covered (danger)
0.00%
0 / 1
 computeProgress
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
5.27
 resetSignerCounts
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 aggregateSignerProgress
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
7.01
 applyProgressToFileData
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 buildSignerKey
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 buildSignerKeyFromEnvelopeSigner
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
1<?php
2
3declare(strict_types=1);
4
5/**
6 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
7 * SPDX-License-Identifier: AGPL-3.0-or-later
8 */
9
10namespace OCA\Libresign\Service\File;
11
12use OCA\Libresign\Db\SignRequest;
13use stdClass;
14
15class EnvelopeProgressService {
16    /**
17     * Compute progress.
18     *
19     * $signRequestsByFileId is a map: fileId => SignRequest[]
20     * $identifyMethodsBySignRequest is a map: signRequestId => array of identify-method wrappers
21     */
22    public function computeProgress(stdClass $fileData, $envelope, array $childrenFiles, array $signRequestsByFileId, array $identifyMethodsBySignRequest): void {
23        if (!$envelope || $envelope->getParentFileId()) {
24            return;
25        }
26
27        if (empty($fileData->signers)) {
28            return;
29        }
30
31        if (empty($childrenFiles)) {
32            $this->resetSignerCounts($fileData);
33            return;
34        }
35
36        $signerProgress = $this->aggregateSignerProgress($childrenFiles, $signRequestsByFileId, $identifyMethodsBySignRequest);
37        $this->applyProgressToFileData($fileData, $signerProgress);
38    }
39
40    private function resetSignerCounts(stdClass $fileData): void {
41        foreach ($fileData->signers as $idx => $_) {
42            $fileData->signers[$idx]->totalDocuments = 0;
43            $fileData->signers[$idx]->documentsSignedCount = 0;
44        }
45    }
46
47    /**
48     * Aggregate signer progress across all children files.
49     * Returns map signerKey => ['total' => int, 'signed' => int]
50     *
51     * @return array<string,array{total:int,signed:int}>
52     */
53    private function aggregateSignerProgress(array $childrenFiles, array $signRequestsByFileId, array $identifyMethodsBySignRequest): array {
54        $signerProgress = [];
55        foreach ($childrenFiles as $childFile) {
56            $signRequests = $signRequestsByFileId[$childFile->getId()] ?? [];
57            foreach ($signRequests as $signRequest) {
58                if ($signRequest instanceof SignRequest && $signRequest->isObserver()) {
59                    continue;
60                }
61
62                $signRequestId = $signRequest->getId();
63                $identifyMethods = $identifyMethodsBySignRequest[$signRequestId] ?? [];
64
65                $signerKey = $this->buildSignerKey($identifyMethods);
66                if (!isset($signerProgress[$signerKey])) {
67                    $signerProgress[$signerKey] = ['total' => 0, 'signed' => 0];
68                }
69
70                $signerProgress[$signerKey]['total']++;
71                if ($signRequest->getSigned()) {
72                    $signerProgress[$signerKey]['signed']++;
73                }
74            }
75        }
76        return $signerProgress;
77    }
78
79    private function applyProgressToFileData(stdClass $fileData, array $signerProgress): void {
80        foreach ($fileData->signers as $index => $signer) {
81            $signerKey = $this->buildSignerKeyFromEnvelopeSigner($signer);
82            if (isset($signerProgress[$signerKey])) {
83                $fileData->signers[$index]->totalDocuments = $signerProgress[$signerKey]['total'];
84                $fileData->signers[$index]->documentsSignedCount = $signerProgress[$signerKey]['signed'];
85            } else {
86                $fileData->signers[$index]->totalDocuments = 0;
87                $fileData->signers[$index]->documentsSignedCount = 0;
88            }
89        }
90    }
91
92    private function buildSignerKey(array $identifyMethods): string {
93        $keys = [];
94        foreach ($identifyMethods as $methods) {
95            foreach ($methods as $identifyMethod) {
96                $entity = $identifyMethod->getEntity();
97                $keys[] = $entity->getUniqueIdentifier();
98            }
99        }
100        sort($keys);
101        return implode('|', $keys);
102    }
103
104    private function buildSignerKeyFromEnvelopeSigner(stdClass $signer): string {
105        if (empty($signer->identifyMethods)) {
106            return '';
107        }
108        $keys = [];
109        foreach ($signer->identifyMethods as $method) {
110            $keys[] = $method['method'] . ':' . $method['value'];
111        }
112        sort($keys);
113        return implode('|', $keys);
114    }
115}