Passed
Push — main ( 0d1c63...8584cf )
by Iain
04:42
created

SubscriptionManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 11
dl 0
loc 13
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright Iain Cambridge 2020-2023.
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.2.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\Billing\Subscription;
16
17
use Obol\Model\CancelSubscription;
18
use Obol\Model\Enum\RefundType;
19
use Obol\Provider\ProviderInterface;
20
use Parthenon\Billing\Dto\StartSubscriptionDto;
21
use Parthenon\Billing\Entity\CustomerInterface;
22
use Parthenon\Billing\Entity\EmbeddedSubscription;
23
use Parthenon\Billing\Entity\PaymentDetails;
24
use Parthenon\Billing\Entity\Price;
25
use Parthenon\Billing\Entity\Subscription;
26
use Parthenon\Billing\Entity\SubscriptionPlan;
27
use Parthenon\Billing\Exception\SubscriptionCreationException;
28
use Parthenon\Billing\Obol\BillingDetailsFactoryInterface;
29
use Parthenon\Billing\Obol\PaymentFactoryInterface;
30
use Parthenon\Billing\Obol\SubscriptionFactoryInterface;
31
use Parthenon\Billing\Plan\Plan;
32
use Parthenon\Billing\Plan\PlanManagerInterface;
33
use Parthenon\Billing\Plan\PlanPrice;
34
use Parthenon\Billing\Repository\PaymentDetailsRepositoryInterface;
35
use Parthenon\Billing\Repository\PaymentRepositoryInterface;
36
use Parthenon\Billing\Repository\PriceRepositoryInterface;
37
use Parthenon\Billing\Repository\RefundRepositoryInterface;
38
use Parthenon\Billing\Repository\SubscriptionPlanRepositoryInterface;
39
use Parthenon\Billing\Repository\SubscriptionRepositoryInterface;
40
41
final class SubscriptionManager implements SubscriptionManagerInterface
42
{
43
    public function __construct(
44
        private PaymentDetailsRepositoryInterface $paymentDetailsRepository,
45
        private ProviderInterface $provider,
46
        private BillingDetailsFactoryInterface $billingDetailsFactory,
47
        private PaymentFactoryInterface $paymentFactory,
48
        private SubscriptionFactoryInterface $subscriptionFactory,
49
        private PaymentRepositoryInterface $paymentRepository,
50
        private PlanManagerInterface $planManager,
51
        private SubscriptionPlanRepositoryInterface $subscriptionPlanRepository,
52
        private PriceRepositoryInterface $priceRepository,
53
        private SubscriptionRepositoryInterface $subscriptionRepository,
54
        private RefundRepositoryInterface $refundRepository,
55
    ) {
56
    }
57
58
    public function startSubscriptionWithEntities(CustomerInterface $customer, SubscriptionPlan $subscriptionPlan, Price $price, PaymentDetails $paymentDetails, int $seatNumbers): Subscription
59
    {
60
        $billingDetails = $this->billingDetailsFactory->createFromCustomerAndPaymentDetails($customer, $paymentDetails);
61
        $obolSubscription = $this->subscriptionFactory->createSubscriptionWithPrice($billingDetails, $price, $seatNumbers);
62
        $obolSubscription->setStoredPaymentReference($paymentDetails->getStoredPaymentReference());
63
64
        if ($this->subscriptionRepository->hasActiveSubscription($customer)) {
65
            $subscription = $this->subscriptionRepository->getOneActiveSubscriptionForCustomer($customer);
66
67
            if ($subscription->getCurrency() != $price->getCurrency()) {
68
                throw new SubscriptionCreationException("Can't add a child subscription for a different currency");
69
            }
70
71
            $obolSubscription->setParentReference($subscription->getMainExternalReference());
72
        }
73
74
        $subscriptionCreationResponse = $this->provider->payments()->startSubscription($obolSubscription);
75
        if ($subscriptionCreationResponse->hasCustomerCreation()) {
76
            $customer->setPaymentProviderDetailsUrl($subscriptionCreationResponse->getCustomerCreation()->getDetailsUrl());
77
            $customer->setExternalCustomerReference($subscriptionCreationResponse->getCustomerCreation()->getReference());
78
        }
79
        $payment = $this->paymentFactory->fromSubscriptionCreation($subscriptionCreationResponse, $customer);
80
        $this->paymentRepository->save($payment);
81
82
        $subscription = new Subscription();
83
        $subscription->setPlanName($subscriptionPlan->getName());
84
        $subscription->setPaymentSchedule($price->getSchedule());
0 ignored issues
show
Bug introduced by
It seems like $price->getSchedule() can also be of type null; however, parameter $paymentSchedule of Parthenon\Billing\Entity...n::setPaymentSchedule() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

84
        $subscription->setPaymentSchedule(/** @scrutinizer ignore-type */ $price->getSchedule());
Loading history...
85
        $subscription->setActive(true);
86
        $subscription->setMoneyAmount($price->getAsMoney());
87
        $subscription->setStatus(\Parthenon\Billing\Entity\EmbeddedSubscription::STATUS_ACTIVE);
88
        $subscription->setMainExternalReference($subscriptionCreationResponse->getSubscriptionId());
89
        $subscription->setChildExternalReference($subscriptionCreationResponse->getLineId());
90
        $subscription->setSeats($seatNumbers);
91
        $subscription->setCreatedAt(new \DateTime());
92
        $subscription->setUpdatedAt(new \DateTime());
93
        $subscription->setValidUntil($subscriptionCreationResponse->getBilledUntil());
94
        $subscription->setCustomer($customer);
95
        $subscription->setMainExternalReferenceDetailsUrl($subscriptionCreationResponse->getDetailsUrl());
96
        $subscription->setSubscriptionPlan($subscriptionPlan);
97
        $subscription->setPrice($price);
98
99
        $this->subscriptionRepository->save($subscription);
100
        $this->subscriptionRepository->updateValidUntilForAllActiveSubscriptions($customer, $subscription->getMainExternalReference(), $subscriptionCreationResponse->getBilledUntil());
101
102
        return $subscription;
103
    }
104
105
    public function startSubscription(CustomerInterface $customer, Plan $plan, PlanPrice $planPrice, PaymentDetails $paymentDetails, int $seatNumbers): Subscription
106
    {
107
        $billingDetails = $this->billingDetailsFactory->createFromCustomerAndPaymentDetails($customer, $paymentDetails);
108
        $obolSubscription = $this->subscriptionFactory->createSubscription($billingDetails, $planPrice, $seatNumbers);
109
        $obolSubscription->setStoredPaymentReference($paymentDetails->getStoredPaymentReference());
110
111
        if ($this->subscriptionRepository->hasActiveSubscription($customer)) {
112
            $subscription = $this->subscriptionRepository->getOneActiveSubscriptionForCustomer($customer);
113
114
            if ($subscription->getCurrency() != $planPrice->getCurrency()) {
115
                throw new SubscriptionCreationException("Can't add a child subscription for a different currency");
116
            }
117
118
            $obolSubscription->setParentReference($subscription->getMainExternalReference());
119
        }
120
121
        $subscriptionCreationResponse = $this->provider->payments()->startSubscription($obolSubscription);
122
        if ($subscriptionCreationResponse->hasCustomerCreation()) {
123
            $customer->setPaymentProviderDetailsUrl($subscriptionCreationResponse->getCustomerCreation()->getDetailsUrl());
124
            $customer->setExternalCustomerReference($subscriptionCreationResponse->getCustomerCreation()->getReference());
125
        }
126
        $subscription = new Subscription();
127
        $subscription->setPlanName($plan->getName());
128
        $subscription->setPaymentSchedule($planPrice->getSchedule());
129
        $subscription->setActive(true);
130
        $subscription->setMoneyAmount($subscriptionCreationResponse->getPaymentDetails()->getAmount());
131
        $subscription->setStatus(\Parthenon\Billing\Entity\EmbeddedSubscription::STATUS_ACTIVE);
132
        $subscription->setMainExternalReference($subscriptionCreationResponse->getSubscriptionId());
133
        $subscription->setChildExternalReference($subscriptionCreationResponse->getLineId());
134
        $subscription->setSeats($seatNumbers);
135
        $subscription->setCreatedAt(new \DateTime());
136
        $subscription->setUpdatedAt(new \DateTime());
137
        $subscription->setValidUntil($subscriptionCreationResponse->getBilledUntil());
138
        $subscription->setCustomer($customer);
139
        $subscription->setMainExternalReferenceDetailsUrl($subscriptionCreationResponse->getDetailsUrl());
140
        $subscription->setPaymentExternalReference($subscriptionCreationResponse->getPaymentDetails()->getStoredPaymentReference());
141
142
        if ($plan->hasEntityId()) {
143
            $subscriptionPlan = $this->subscriptionPlanRepository->findById($plan->getEntityId());
144
            $subscription->setSubscriptionPlan($subscriptionPlan);
145
        }
146
147
        if ($planPrice->hasEntityId()) {
148
            $price = $this->priceRepository->findById($planPrice->getEntityId());
149
            $subscription->setPrice($price);
150
        }
151
        $this->subscriptionRepository->save($subscription);
152
        $this->subscriptionRepository->updateValidUntilForAllActiveSubscriptions($customer, $subscription->getMainExternalReference(), $subscriptionCreationResponse->getBilledUntil());
153
154
        $payment = $this->paymentFactory->fromSubscriptionCreation($subscriptionCreationResponse, $customer);
155
        $payment->addSubscription($subscription);
156
        $this->paymentRepository->save($payment);
157
158
        return $subscription;
159
    }
160
161
    public function startSubscriptionWithDto(CustomerInterface $customer, StartSubscriptionDto $startSubscriptionDto): Subscription
162
    {
163
        if (!$startSubscriptionDto->getPaymentDetailsId()) {
164
            $paymentDetails = $this->paymentDetailsRepository->getDefaultPaymentDetailsForCustomer($customer);
165
        } else {
166
            $paymentDetails = $this->paymentDetailsRepository->findById($startSubscriptionDto->getPaymentDetailsId());
167
        }
168
169
        $plan = $this->planManager->getPlanByName($startSubscriptionDto->getPlanName());
170
        $planPrice = $plan->getPriceForPaymentSchedule($startSubscriptionDto->getSchedule(), $startSubscriptionDto->getCurrency());
171
172
        return $this->startSubscription($customer, $plan, $planPrice, $paymentDetails, $startSubscriptionDto->getSeatNumbers());
173
    }
174
175
    public function cancelSubscriptionAtEndOfCurrentPeriod(Subscription $subscription): Subscription
176
    {
177
        $obolSubscription = $this->subscriptionFactory->createSubscriptionFromEntity($subscription);
178
179
        $cancelRequest = new CancelSubscription();
180
        $cancelRequest->setSubscription($obolSubscription);
181
        $cancelRequest->setInstantCancel(false);
182
        $cancelRequest->setRefundType(RefundType::NONE);
183
184
        $cancellation = $this->provider->payments()->stopSubscription($cancelRequest);
0 ignored issues
show
Unused Code introduced by
The assignment to $cancellation is dead and can be removed.
Loading history...
185
186
        $subscription->setStatus(EmbeddedSubscription::STATUS_CANCELLED);
187
        $subscription->endAtEndOfPeriod();
188
189
        return $subscription;
190
    }
191
192
    public function cancelSubscriptionInstantly(Subscription $subscription): Subscription
193
    {
194
        $obolSubscription = $this->subscriptionFactory->createSubscriptionFromEntity($subscription);
195
196
        $cancelRequest = new CancelSubscription();
197
        $cancelRequest->setSubscription($obolSubscription);
198
        $cancelRequest->setInstantCancel(true);
199
200
        $cancellation = $this->provider->payments()->stopSubscription($cancelRequest);
0 ignored issues
show
Unused Code introduced by
The assignment to $cancellation is dead and can be removed.
Loading history...
201
202
        $subscription->setStatus(EmbeddedSubscription::STATUS_CANCELLED);
203
        $subscription->setEndedAt(new \DateTime('now'));
204
205
        return $subscription;
206
    }
207
}
208