Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.55% covered (success)
96.55%
28 / 29
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConsentCopy
96.55% covered (success)
96.55%
28 / 29
50.00% covered (danger)
50.00%
1 / 2
3
0.00% covered (danger)
0.00%
0 / 1
 all
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 current
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
1<?php
2
3declare(strict_types=1);
4
5namespace App\Domain\Consent\Data;
6
7use InvalidArgumentException;
8
9/**
10 * Server-owned, versioned consent copy (FSC-87).
11 *
12 * The exact wording is authoritative here, never supplied by the client: the
13 * server records the `language` it served alongside each consent so we can
14 * prove what the user saw (TCPA requirement). `label` is the short UI string
15 * (checkbox label); `language` is the full verbatim text persisted to the
16 * consent_records ledger.
17 *
18 * PLACEHOLDER copy pending counsel's finalized language (FSC-90). When any
19 * wording changes, bump {@see VERSION} — new consents are then recorded under
20 * the new version while historical rows keep the text they were shown.
21 */
22final class ConsentCopy
23{
24    /** Bump on any wording change; stored with every consent record. */
25    public const string VERSION = '2026.1';
26
27    /**
28     * @return array<string, array{version: string, label: string, language: string}>
29     */
30    public static function all(): array
31    {
32        return [
33            ConsentType::TRANSACTIONAL => [
34                'version' => self::VERSION,
35                'label' => 'I agree to receive transactional communications (required)',
36                'language' => 'I agree to receive transactional communications from FlowState '
37                    . 'Capital related to my account, including service, security, and '
38                    . 'account-activity messages. These communications are required to operate '
39                    . 'your account.',
40            ],
41            ConsentType::SMS => [
42                'version' => self::VERSION,
43                'label' => 'I consent to receive SMS/text messages (optional)',
44                'language' => 'I consent to receive SMS/text messages from FlowState Capital, '
45                    . 'including alerts, account information, and marketing. Message frequency '
46                    . 'varies. Message and data rates may apply. Reply STOP to opt out, HELP for '
47                    . 'help. Consent is not a condition of any service.',
48            ],
49            ConsentType::AUTOMATED_CALLS => [
50                'version' => self::VERSION,
51                'label' => 'I consent to receive automated calls and prerecorded messages (optional)',
52                'language' => 'I consent to receive automated calls and prerecorded voice messages '
53                    . 'from FlowState Capital at the phone number I provided, including for '
54                    . 'marketing. Consent is not a condition of any purchase or service.',
55            ],
56        ];
57    }
58
59    /**
60     * @param string $consentType
61     * @return array{version: string, label: string, language: string}
62     */
63    public static function current(string $consentType): array
64    {
65        $all = self::all();
66
67        if (!isset($all[$consentType])) {
68            throw new InvalidArgumentException(sprintf('Unknown consent type "%s".', $consentType));
69        }
70
71        return $all[$consentType];
72    }
73}