SubscriptionManager::syncStatus()   B
last analyzed

Complexity

Conditions 9
Paths 19

Size

Total Lines 33
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 25
c 1
b 0
f 0
nc 19
nop 1
dl 0
loc 33
rs 8.0555
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright (C) 2020-2025 Iain Cambridge
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
10
 * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Parthenon\Payments\Stripe;
23
24
use Parthenon\Common\Exception\GeneralException;
25
use Parthenon\Common\LoggerAwareTrait;
26
use Parthenon\Payments\Entity\Subscription;
27
use Parthenon\Payments\SubscriptionManagerInterface;
28
use Stripe\StripeClient;
29
30
final class SubscriptionManager implements SubscriptionManagerInterface
31
{
32
    use LoggerAwareTrait;
33
34
    public function __construct(private StripeClient $client, private Config $config)
35
    {
36
    }
37
38
    public function cancel(Subscription $subscription)
39
    {
40
        try {
41
            if (!empty($subscription->getPaymentId())) {
42
                $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
43
                if ('canceled' !== $stripeSubscription->status) {
44
                    $stripeSubscription->cancel();
45
                }
46
            }
47
            $subscription->setStatus(Subscription::STATUS_CANCELLED);
48
        } catch (\Exception $e) {
49
            $this->getLogger()->error('An error occurred while trying to cancel a subscription.', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
50
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
51
        }
52
    }
53
54
    public function change(Subscription $subscription)
55
    {
56
        $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
57
58
        if (!isset($stripeSubscription->items->data[0]->id)) {
59
            $this->getLogger()->error('EmbeddedSubscription is itemless', ['subscription_payment_id' => $subscription->getPaymentId()]);
60
            throw new GeneralException('EmbeddedSubscription is itemless');
61
        }
62
        try {
63
            $this->client->subscriptions->update($subscription->getPaymentId(), [
64
                'cancel_at_period_end' => false,
65
                'proration_behavior' => 'create_prorations',
66
                'items' => [
67
                    [
68
                        'id' => $stripeSubscription->items->data[0]->id,
69
                        'price' => $subscription->getPriceId(),
70
                    ],
71
                ],
72
            ]);
73
        } catch (\Exception $e) {
74
            $this->getLogger()->error('An error occurred while trying to change a subscription.', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
75
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
76
        }
77
    }
78
79
    public function getInvoiceUrl(Subscription $subscription)
80
    {
81
        try {
82
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
83
84
            return $this->client->invoices->retrieve($stripeSubscription->latest_invoice)->invoice_pdf;
85
        } catch (\Exception $e) {
86
            $this->getLogger()->error('An error occurred while trying to get an invocie URL', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
87
88
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
89
        }
90
    }
91
92
    public function syncStatus(Subscription $subscription): Subscription
93
    {
94
        try {
95
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
96
97
            $validUntil = new \DateTime('now', new \DateTimeZone('UTC'));
98
            $validUntil->setTimestamp($stripeSubscription->current_period_end);
99
100
            $subscription->setValidUntil($validUntil);
101
102
            switch ($stripeSubscription->status) {
103
                case 'incomplete':
104
                case 'past_due':
105
                    $subscription->setStatus(Subscription::STATUS_OVERDUE);
106
                    break;
107
                case 'incomplete_expired':
108
                case 'unpaid':
109
                case 'canceled':
110
                    $subscription->setStatus(Subscription::STATUS_CANCELLED);
111
                    break;
112
                case 'active':
113
                    $subscription->setStatus(Subscription::STATUS_ACTIVE);
114
                    break;
115
                case 'trialing':
116
                    $subscription->setStatus(Subscription::STATUS_TRIAL);
117
                    break;
118
            }
119
120
            return $subscription;
121
        } catch (\Exception $e) {
122
            $this->getLogger()->error('An error occurred while trying to sync status', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
123
124
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
125
        }
126
    }
127
128
    public function getBillingPortal(Subscription $subscription): string
129
    {
130
        try {
131
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
132
            $session = $this->client->billingPortal->sessions->create(['customer' => $stripeSubscription->customer, 'return_url' => $this->config->getReturnUrl()]);
133
134
            return (string) $session->url;
135
        } catch (\Exception $e) {
136
            $this->getLogger()->error('An error occurred while trying get the billing portal url', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
137
138
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
139
        }
140
    }
141
}
142