Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.11% covered (success)
86.11%
31 / 36
84.62% covered (success)
84.62%
11 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
StripeController
86.11% covered (success)
86.11%
31 / 36
84.62% covered (success)
84.62%
11 / 13
18.87
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 json
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 redirect
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 licensecheckout
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 licensepaystatus
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 guestcheckout
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 guestpaystatus
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 connect
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 connectstatus
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 onConnect
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 onRefresh
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 reconcileAsync
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 webhook
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5use Psr\Http\Message\ResponseInterface as Response;
6use Psr\Http\Message\ServerRequestInterface as Request;
7use UppServices\StripeService;
8
9/**
10 * Slim controller for Stripe license checkout, Connect onboarding, guest ticket checkout,
11 * pay status, and webhooks.
12 */
13class StripeController
14{
15    public function __construct(
16        private readonly StripeService $stripeService,
17    ) {
18    }
19
20    private function json(Response $response, array $data, int $status = 200): Response
21    {
22        $response->getBody()->write(json_encode($data));
23        return $response->withHeader('Content-Type', 'application/json')->withStatus($status);
24    }
25
26    private function redirect(Response $response, string $location, int $status = 302): Response
27    {
28        return $response->withHeader('Location', $location)->withStatus($status);
29    }
30
31    /** POST /stripe/licensecheckout */
32    public function licensecheckout(Request $request, Response $response): Response
33    {
34        $result = $this->stripeService->licenseCheckout($request->getQueryParams());
35        $status = (($result['errorcode'] ?? 1) === 0) ? 200 : 200;
36        return $this->json($response, $result, $status);
37    }
38
39    /** POST /stripe/licensepaystatus */
40    public function licensepaystatus(Request $request, Response $response): Response
41    {
42        $result = $this->stripeService->licensePayStatus($request->getQueryParams());
43        return $this->json($response, $result, 200);
44    }
45
46    /** POST /guest/payment/checkout */
47    public function guestcheckout(Request $request, Response $response): Response
48    {
49        $parsed = $request->getParsedBody();
50        $payload = is_array($parsed) ? $parsed : [];
51        $result = $this->stripeService->ticketCheckout($request->getQueryParams(), $payload);
52        return $this->json($response, $result, 200);
53    }
54
55    /** POST /guest/payment/status */
56    public function guestpaystatus(Request $request, Response $response): Response
57    {
58        $result = $this->stripeService->ticketPayStatus($request->getQueryParams());
59        return $this->json($response, $result, 200);
60    }
61
62    /** POST /stripe/connect */
63    public function connect(Request $request, Response $response): Response
64    {
65        $result = $this->stripeService->connect($request->getQueryParams());
66        return $this->json($response, $result, 200);
67    }
68
69    /** POST /stripe/connectstatus */
70    public function connectstatus(Request $request, Response $response): Response
71    {
72        $result = $this->stripeService->connectStatus($request->getQueryParams());
73        return $this->json($response, $result, 200);
74    }
75
76    /** GET /stripe/on-connect */
77    public function onConnect(Request $request, Response $response): Response
78    {
79        $result = $this->stripeService->onConnect($request->getQueryParams());
80        return $this->redirect($response, (string) ($result['redirect'] ?? ''), (int) ($result['httpStatus'] ?? 302));
81    }
82
83    /** GET /stripe/on-refresh */
84    public function onRefresh(Request $request, Response $response): Response
85    {
86        $result = $this->stripeService->onRefresh($request->getQueryParams());
87        return $this->redirect($response, (string) ($result['redirect'] ?? ''), (int) ($result['httpStatus'] ?? 302));
88    }
89
90    /** POST /stripe/reconcile-async — internal sweep worker (not a product API). */
91    public function reconcileAsync(Request $request, Response $response): Response
92    {
93        $raw = (string) $request->getBody();
94        $result = $this->stripeService->reconcileAsync($raw);
95        return $this->json($response, $result, 200);
96    }
97
98    /** POST /stripe/webhook */
99    public function webhook(Request $request, Response $response): Response
100    {
101        $raw = (string) $request->getBody();
102        $sig = $request->getHeaderLine('Stripe-Signature');
103        $result = $this->stripeService->handleWebhook($raw, $sig);
104
105        if (($result['errorcode'] ?? 1) !== 0) {
106            // Invalid signature / params → 4xx so Stripe retries only on server errors.
107            $http = (($result['errorcode'] ?? 0) === \ApplicationError::Invalid
108                || ($result['errorcode'] ?? 0) === \ApplicationError::Parameters)
109                ? 400
110                : 500;
111            return $this->json($response, $result, $http);
112        }
113
114        return $this->json($response, ['received' => true, 'errorcode' => 0], 200);
115    }
116}