Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.37% covered (success)
97.37%
37 / 38
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
StripeService
97.37% covered (success)
97.37%
37 / 38
90.91% covered (success)
90.91%
10 / 11
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
1
 licenseCheckout
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 ticketCheckout
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 connect
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 connectStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 onConnect
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 onRefresh
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 licensePayStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 ticketPayStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 reconcileAsync
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handleWebhook
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace UppServices;
6
7use UppServices\stripe\Checkout;
8use UppServices\stripe\Connect;
9use UppServices\stripe\Reconcile;
10use UppServices\stripe\Webhook;
11use UppServices\stripe\async\Sweep;
12
13/**
14 * Stripe domain service: license checkout, Connect onboarding, guest ticket checkout,
15 * reconcile, sweep worker, and webhooks.
16 *
17 * Public HTTP boundary for StripeController. Work lives in Services/stripe/
18 * (Checkout / Connect / Reconcile / Webhook) and async workers in Services/stripe/async/
19 * (Sweep) — same layout as PlaceService + place/ actions.
20 */
21class StripeService
22{
23    private readonly Checkout $checkout;
24    private readonly Connect $connectAction;
25    private readonly Reconcile $reconcile;
26    private readonly Sweep $sweep;
27    private readonly Webhook $webhook;
28
29    /**
30     * @param callable|null $stripeClientFactory Optional for tests: fn(): object with checkout->sessions->create
31     * @param callable|null $constructEvent Optional for tests: fn(string $payload, string $sig): object
32     * @param callable|null $conxFactory Optional for tests: fn(): \ConxHelper (reconcile / connect)
33     * @param callable|null $addAuthorization Optional for tests
34     * @param callable|null $useAuthorization Optional for tests
35     * @param callable|null $delAuthorization Optional for tests
36     * @param callable|null $publishStripe Optional for tests
37     */
38    public function __construct(
39        SessionService $sessionService,
40        LoggerFactory $loggerFactory,
41        LicenseService $licenseService,
42        ?callable $stripeClientFactory = null,
43        ?callable $constructEvent = null,
44        ?callable $conxFactory = null,
45        ?callable $addAuthorization = null,
46        ?callable $useAuthorization = null,
47        ?callable $delAuthorization = null,
48        ?callable $publishStripe = null,
49    ) {
50        $this->checkout = new Checkout(
51            $sessionService,
52            $loggerFactory,
53            $licenseService,
54            $stripeClientFactory
55        );
56
57        $this->connectAction = new Connect(
58            $sessionService,
59            $loggerFactory,
60            $stripeClientFactory,
61            $conxFactory,
62            $addAuthorization,
63            $useAuthorization,
64            $delAuthorization,
65            $publishStripe
66        );
67
68        $this->reconcile = new Reconcile(
69            $sessionService,
70            $loggerFactory,
71            $stripeClientFactory,
72            $conxFactory
73        );
74
75        $this->sweep = new Sweep(
76            $loggerFactory,
77            $this->reconcile,
78            $conxFactory
79        );
80        
81        $this->webhook = new Webhook($loggerFactory, $constructEvent);
82    }
83
84    /**
85     * POST /stripe/licensecheckout — create Stripe Checkout for a license renewal.
86     *
87     * @param array<string, mixed> $query Query: device, session, place, period, amount, lang?, totalWithTax?
88     * @return array{errorcode: int, url?: string, payment?: string}
89     */
90    public function licenseCheckout(array $query): array
91    {
92        return $this->checkout->licenseCheckout($query);
93    }
94
95    /**
96     * POST /guest/payment/checkout — Stripe Checkout for guest tickets (Connect).
97     *
98     * @param array<string, mixed> $query device, session, tickets?, amount, lang?, table?, validQR?
99     * @param array<string, mixed> $payload optional JSON { tickets: string[] }
100     * @return array{errorcode: int, url?: string, payment?: string}
101     */
102    public function ticketCheckout(array $query, array $payload = []): array
103    {
104        return $this->checkout->ticketCheckout($query, $payload);
105    }
106
107    /**
108     * POST /stripe/connect — start Connect onboarding Account Link.
109     *
110     * @param array<string, mixed> $query device, session, place, lang, token
111     * @return array{errorcode: int, url?: string}
112     */
113    public function connect(array $query): array
114    {
115        return $this->connectAction->connect($query);
116    }
117
118    /**
119     * POST /stripe/connectstatus — UI poll: refresh STRIPE.status from Stripe Accounts v2.
120     *
121     * @param array<string, mixed> $query device, session, place
122     * @return array{errorcode: int, status?: string}
123     */
124    public function connectStatus(array $query): array
125    {
126        return $this->connectAction->connectStatus($query);
127    }
128
129    /**
130     * GET /stripe/on-connect — return URL after Account Link; redirect to IonUrl landing.
131     *
132     * @param array<string, mixed> $query lang, place, token, account, auth
133     * @return array{errorcode: int, redirect: string, httpStatus: int}
134     */
135    public function onConnect(array $query): array
136    {
137        return $this->connectAction->onConnect($query);
138    }
139
140    /**
141     * GET /stripe/on-refresh — refresh Account Link; redirect to Stripe or failure landing.
142     *
143     * @param array<string, mixed> $query lang, place, token, account, auth
144     * @return array{errorcode: int, redirect?: string, httpStatus: int}
145     */
146    public function onRefresh(array $query): array
147    {
148        return $this->connectAction->onRefresh($query);
149    }
150
151    /**
152     * POST /stripe/licensepaystatus — UI poll: confirm pending license payment via Stripe API.
153     *
154     * @param array<string, mixed> $query Query: device, session, place, payment
155     * @return array{errorcode: int, status?: string}
156     */
157    public function licensePayStatus(array $query): array
158    {
159        return $this->reconcile->licensePayStatus($query);
160    }
161
162    /**
163     * POST /guest/payment/status — UI poll: confirm pending guest ticket payment via Stripe API.
164     *
165     * @param array<string, mixed> $query Query: device, session, payment
166     * @return array{errorcode: int, status?: string}
167     */
168    public function ticketPayStatus(array $query): array
169    {
170        return $this->reconcile->ticketPayStatus($query);
171    }
172
173    /**
174     * POST /stripe/reconcile-async — internal place sweep (LocalUrl self-call / future cron).
175     * Not a POS/guest product API.
176     *
177     * @return array{errorcode: int, status?: string}
178     */
179    public function reconcileAsync(string $rawBody): array
180    {
181        return $this->sweep->handleAsync($rawBody);
182    }
183
184    /**
185     * POST /stripe/webhook — handle Stripe webhook payload.
186     *
187     * @return array{errorcode: int, received?: bool}
188     */
189    public function handleWebhook(string $rawBody, string $signatureHeader): array
190    {
191        return $this->webhook->handle($rawBody, $signatureHeader);
192    }
193}