Passed
Branch main (b6a268)
by Iain
04:11
created

SubscriptionManager::syncStatus()   B

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 Humbly Arrogant Ltd 2020-2022.
7
 *
8
 * Use of this software is governed by the Business Source License included in the LICENSE file and at https://getparthenon.com/docs/next/license.
9
 *
10
 * Change Date: TBD ( 3 years after 2.0.0 release )
11
 *
12
 * On the date above, in accordance with the Business Source License, use of this software will be governed by the open source license specified in the LICENSE file.
13
 */
14
15
namespace Parthenon\Payments\Stripe;
16
17
use Parthenon\Common\Exception\GeneralException;
18
use Parthenon\Common\LoggerAwareTrait;
19
use Parthenon\Subscriptions\Entity\Subscription;
20
use Parthenon\Subscriptions\SubscriptionManagerInterface;
21
use Stripe\StripeClient;
22
23
final class SubscriptionManager implements SubscriptionManagerInterface
24
{
25
    use LoggerAwareTrait;
26
27
    public function __construct(private StripeClient $client, private Config $config)
28
    {
29
    }
30
31
    public function cancel(Subscription $subscription)
32
    {
33
        try {
34
            if (!empty($subscription->getPaymentId())) {
35
                $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
36
                if ('canceled' !== $stripeSubscription->status) {
37
                    $stripeSubscription->cancel();
38
                }
39
            }
40
            $subscription->setStatus(Subscription::STATUS_CANCELLED);
41
        } catch (\Exception $e) {
42
            $this->getLogger()->error('An error occurred while trying to cancel a subscription.', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
43
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
44
        }
45
    }
46
47
    public function change(Subscription $subscription)
48
    {
49
        $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
50
51
        if (!isset($stripeSubscription->items->data[0]->id)) {
52
            $this->getLogger()->error('Subscription is itemless', ['subscription_payment_id' => $subscription->getPaymentId()]);
53
            throw new GeneralException('Subscription is itemless');
54
        }
55
        try {
56
            $this->client->subscriptions->update($subscription->getPaymentId(), [
57
                'cancel_at_period_end' => false,
58
                'proration_behavior' => 'create_prorations',
59
                'items' => [
60
                    [
61
                        'id' => $stripeSubscription->items->data[0]->id,
62
                        'price' => $subscription->getPriceId(),
63
                    ],
64
                ],
65
            ]);
66
        } catch (\Exception $e) {
67
            $this->getLogger()->error('An error occurred while trying to change a subscription.', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
68
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
69
        }
70
    }
71
72
    public function getInvoiceUrl(Subscription $subscription)
73
    {
74
        try {
75
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
76
77
            return $this->client->invoices->retrieve($stripeSubscription->latest_invoice)->invoice_pdf;
78
        } catch (\Exception $e) {
79
            $this->getLogger()->error('An error occurred while trying to get an invocie URL', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
80
81
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
82
        }
83
    }
84
85
    public function syncStatus(Subscription $subscription): Subscription
86
    {
87
        try {
88
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
89
90
            $validUntil = new \DateTime('now', new \DateTimeZone('UTC'));
91
            $validUntil->setTimestamp($stripeSubscription->current_period_end);
92
93
            $subscription->setValidUntil($validUntil);
94
95
            switch ($stripeSubscription->status) {
96
                case 'incomplete':
97
                case 'past_due':
98
                    $subscription->setStatus(Subscription::STATUS_OVERDUE);
99
                    break;
100
                case 'incomplete_expired':
101
                case 'unpaid':
102
                case 'canceled':
103
                    $subscription->setStatus(Subscription::STATUS_CANCELLED);
104
                    break;
105
                case 'active':
106
                    $subscription->setStatus(Subscription::STATUS_ACTIVE);
107
                    break;
108
                case 'trialing':
109
                    $subscription->setStatus(Subscription::STATUS_TRIAL);
110
                    break;
111
            }
112
113
            return $subscription;
114
        } catch (\Exception $e) {
115
            $this->getLogger()->error('An error occurred while trying to sync status', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
116
117
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
118
        }
119
    }
120
121
    public function getBillingPortal(Subscription $subscription): string
122
    {
123
        try {
124
            $stripeSubscription = $this->client->subscriptions->retrieve($subscription->getPaymentId());
125
            $session = $this->client->billingPortal->sessions->create(['customer' => $stripeSubscription->customer, 'return_url' => $this->config->getReturnUrl()]);
126
127
            return (string) $session->url;
128
        } catch (\Exception $e) {
129
            $this->getLogger()->error('An error occurred while trying get the billing portal url', ['exception_message' => $e->getMessage(), 'subscription_payment_id' => $subscription->getPaymentId()]);
130
131
            throw new GeneralException($e->getMessage(), $e->getCode(), $e);
132
        }
133
    }
134
}
135