Passed
Push — main ( e4206e...255a41 )
by Iain
04:28
created

SubscriptionManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
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 10
dl 0
loc 12
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\Provider\ProviderInterface;
18
use Parthenon\Billing\Dto\StartSubscriptionDto;
19
use Parthenon\Billing\Entity\CustomerInterface;
20
use Parthenon\Billing\Entity\PaymentDetails;
21
use Parthenon\Billing\Entity\Price;
22
use Parthenon\Billing\Entity\Subscription;
23
use Parthenon\Billing\Entity\SubscriptionPlan;
24
use Parthenon\Billing\Exception\SubscriptionCreationException;
25
use Parthenon\Billing\Obol\BillingDetailsFactoryInterface;
26
use Parthenon\Billing\Obol\PaymentFactoryInterface;
27
use Parthenon\Billing\Obol\SubscriptionFactoryInterface;
28
use Parthenon\Billing\Plan\Plan;
29
use Parthenon\Billing\Plan\PlanManagerInterface;
30
use Parthenon\Billing\Plan\PlanPrice;
31
use Parthenon\Billing\Repository\PaymentDetailsRepositoryInterface;
32
use Parthenon\Billing\Repository\PaymentRepositoryInterface;
33
use Parthenon\Billing\Repository\PriceRepositoryInterface;
34
use Parthenon\Billing\Repository\SubscriptionPlanRepositoryInterface;
35
use Parthenon\Billing\Repository\SubscriptionRepositoryInterface;
36
37
final class SubscriptionManager implements SubscriptionManagerInterface
38
{
39
    public function __construct(
40
        private PaymentDetailsRepositoryInterface $paymentDetailsRepository,
41
        private ProviderInterface $provider,
42
        private BillingDetailsFactoryInterface $billingDetailsFactory,
43
        private PaymentFactoryInterface $paymentFactory,
44
        private SubscriptionFactoryInterface $subscriptionFactory,
45
        private PaymentRepositoryInterface $paymentRepository,
46
        private PlanManagerInterface $planManager,
47
        private SubscriptionPlanRepositoryInterface $subscriptionPlanRepository,
48
        private PriceRepositoryInterface $priceRepository,
49
        private SubscriptionRepositoryInterface $subscriptionRepository,
50
    ) {
51
    }
52
53
    public function startSubscriptionWithEntities(CustomerInterface $customer, SubscriptionPlan $subscriptionPlan, Price $price, PaymentDetails $paymentDetails, int $seatNumbers): Subscription
54
    {
55
        $billingDetails = $this->billingDetailsFactory->createFromCustomerAndPaymentDetails($customer, $paymentDetails);
56
        $obolSubscription = $this->subscriptionFactory->createSubscriptionWithPrice($billingDetails, $price, $seatNumbers);
57
        $obolSubscription->setStoredPaymentReference($paymentDetails->getStoredPaymentReference());
58
59
        if ($this->subscriptionRepository->hasActiveSubscription($customer)) {
60
            $subscription = $this->subscriptionRepository->getOneActiveSubscriptionForCustomer($customer);
61
62
            if ($subscription->getCurrency() != $planPrice->getCurrency()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $planPrice seems to be never defined.
Loading history...
63
                throw new SubscriptionCreationException("Can't add a child subscription for a different currency");
64
            }
65
66
            $obolSubscription->setParentReference($subscription->getMainExternalReference());
67
        }
68
69
        $subscriptionCreationResponse = $this->provider->payments()->startSubscription($obolSubscription);
70
        if ($subscriptionCreationResponse->hasCustomerCreation()) {
71
            $customer->setPaymentProviderDetailsUrl($subscriptionCreationResponse->getCustomerCreation()->getDetailsUrl());
72
            $customer->setExternalCustomerReference($subscriptionCreationResponse->getCustomerCreation()->getReference());
73
        }
74
        $payment = $this->paymentFactory->fromSubscriptionCreation($subscriptionCreationResponse);
75
        $this->paymentRepository->save($payment);
76
77
        $subscription = new Subscription();
78
        $subscription->setPlanName($subscriptionPlan->getName());
79
        $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

79
        $subscription->setPaymentSchedule(/** @scrutinizer ignore-type */ $price->getSchedule());
Loading history...
80
        $subscription->setActive(true);
81
        $subscription->setMoneyAmount($price->getAsMoney());
82
        $subscription->setStatus(\Parthenon\Billing\Entity\EmbeddedSubscription::STATUS_ACTIVE);
83
        $subscription->setMainExternalReference($subscriptionCreationResponse->getSubscriptionId());
84
        $subscription->setChildExternalReference($subscriptionCreationResponse->getLineId());
85
        $subscription->setSeats($seatNumbers);
86
        $subscription->setCreatedAt(new \DateTime());
87
        $subscription->setUpdatedAt(new \DateTime());
88
        $subscription->setValidUntil($subscriptionCreationResponse->getBilledUntil());
89
        $subscription->setCustomer($customer);
90
        $subscription->setMainExternalReferenceDetailsUrl($subscriptionCreationResponse->getDetailsUrl());
0 ignored issues
show
Bug introduced by
It seems like $subscriptionCreationResponse->getDetailsUrl() can also be of type null; however, parameter $mainExternalReferenceDetailsUrl of Parthenon\Billing\Entity...alReferenceDetailsUrl() 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

90
        $subscription->setMainExternalReferenceDetailsUrl(/** @scrutinizer ignore-type */ $subscriptionCreationResponse->getDetailsUrl());
Loading history...
91
        $subscription->setSubscriptionPlan($subscriptionPlan);
92
        $subscription->setPrice($price);
93
94
        $this->subscriptionRepository->save($subscription);
95
        $this->subscriptionRepository->updateValidUntilForAllActiveSubscriptions($customer, $subscription->getMainExternalReference(), $subscriptionCreationResponse->getBilledUntil());
96
97
        return $subscription;
98
    }
99
100
    public function startSubscription(CustomerInterface $customer, Plan $plan, PlanPrice $planPrice, PaymentDetails $paymentDetails, int $seatNumbers): Subscription
101
    {
102
        $billingDetails = $this->billingDetailsFactory->createFromCustomerAndPaymentDetails($customer, $paymentDetails);
103
        $obolSubscription = $this->subscriptionFactory->createSubscription($billingDetails, $planPrice, $seatNumbers);
104
        $obolSubscription->setStoredPaymentReference($paymentDetails->getStoredPaymentReference());
105
106
        if ($this->subscriptionRepository->hasActiveSubscription($customer)) {
107
            $subscription = $this->subscriptionRepository->getOneActiveSubscriptionForCustomer($customer);
108
109
            if ($subscription->getCurrency() != $planPrice->getCurrency()) {
110
                throw new SubscriptionCreationException("Can't add a child subscription for a different currency");
111
            }
112
113
            $obolSubscription->setParentReference($subscription->getMainExternalReference());
114
        }
115
116
        $subscriptionCreationResponse = $this->provider->payments()->startSubscription($obolSubscription);
117
        if ($subscriptionCreationResponse->hasCustomerCreation()) {
118
            $customer->setPaymentProviderDetailsUrl($subscriptionCreationResponse->getCustomerCreation()->getDetailsUrl());
119
            $customer->setExternalCustomerReference($subscriptionCreationResponse->getCustomerCreation()->getReference());
120
        }
121
        $payment = $this->paymentFactory->fromSubscriptionCreation($subscriptionCreationResponse);
122
        $this->paymentRepository->save($payment);
123
124
        $subscription = new Subscription();
125
        $subscription->setPlanName($plan->getName());
126
        $subscription->setPaymentSchedule($planPrice->getSchedule());
127
        $subscription->setActive(true);
128
        $subscription->setMoneyAmount($planPrice->getPriceAsMoney());
129
        $subscription->setStatus(\Parthenon\Billing\Entity\EmbeddedSubscription::STATUS_ACTIVE);
130
        $subscription->setMainExternalReference($subscriptionCreationResponse->getSubscriptionId());
131
        $subscription->setChildExternalReference($subscriptionCreationResponse->getLineId());
132
        $subscription->setSeats($seatNumbers);
133
        $subscription->setCreatedAt(new \DateTime());
134
        $subscription->setUpdatedAt(new \DateTime());
135
        $subscription->setValidUntil($subscriptionCreationResponse->getBilledUntil());
136
        $subscription->setCustomer($customer);
137
        $subscription->setMainExternalReferenceDetailsUrl($subscriptionCreationResponse->getDetailsUrl());
0 ignored issues
show
Bug introduced by
It seems like $subscriptionCreationResponse->getDetailsUrl() can also be of type null; however, parameter $mainExternalReferenceDetailsUrl of Parthenon\Billing\Entity...alReferenceDetailsUrl() 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

137
        $subscription->setMainExternalReferenceDetailsUrl(/** @scrutinizer ignore-type */ $subscriptionCreationResponse->getDetailsUrl());
Loading history...
138
139
        if ($plan->hasEntityId()) {
140
            $subscriptionPlan = $this->subscriptionPlanRepository->findById($plan->getEntityId());
141
            $subscription->setSubscriptionPlan($subscriptionPlan);
142
        }
143
144
        if ($planPrice->hasEntityId()) {
145
            $price = $this->priceRepository->findById($planPrice->getEntityId());
146
            $subscription->setPrice($price);
147
        }
148
149
        $this->subscriptionRepository->save($subscription);
150
        $this->subscriptionRepository->updateValidUntilForAllActiveSubscriptions($customer, $subscription->getMainExternalReference(), $subscriptionCreationResponse->getBilledUntil());
151
152
        return $subscription;
153
    }
154
155
    public function startSubscriptionWithDto(CustomerInterface $customer, StartSubscriptionDto $startSubscriptionDto): Subscription
156
    {
157
        if (!$startSubscriptionDto->getPaymentDetailsId()) {
158
            $paymentDetails = $this->paymentDetailsRepository->getDefaultPaymentDetailsForCustomer($customer);
159
        } else {
160
            $paymentDetails = $this->paymentDetailsRepository->findById($startSubscriptionDto->getPaymentDetailsId());
161
        }
162
163
        $plan = $this->planManager->getPlanByName($startSubscriptionDto->getPlanName());
164
        $planPrice = $plan->getPriceForPaymentSchedule($startSubscriptionDto->getSchedule(), $startSubscriptionDto->getCurrency());
165
166
        return $this->startSubscription($customer, $plan, $planPrice, $paymentDetails, $startSubscriptionDto->getSeatNumbers());
167
    }
168
}
169