Passed
Push — main ( 44657d...ffb381 )
by Iain
04:31
created

SubscriptionManager::startSubscription()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 52
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 36
nc 17
nop 5
dl 0
loc 52
rs 8.7217
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Subscription;
22
use Parthenon\Billing\Obol\BillingDetailsFactoryInterface;
23
use Parthenon\Billing\Obol\PaymentFactoryInterface;
24
use Parthenon\Billing\Obol\SubscriptionFactoryInterface;
25
use Parthenon\Billing\Plan\Plan;
26
use Parthenon\Billing\Plan\PlanManagerInterface;
27
use Parthenon\Billing\Plan\PlanPrice;
28
use Parthenon\Billing\Repository\PaymentDetailsRepositoryInterface;
29
use Parthenon\Billing\Repository\PaymentRepositoryInterface;
30
use Parthenon\Billing\Repository\PriceRepositoryInterface;
31
use Parthenon\Billing\Repository\SubscriptionPlanRepositoryInterface;
32
use Parthenon\Billing\Repository\SubscriptionRepositoryInterface;
33
use Parthenon\Common\Exception\GeneralException;
34
35
class SubscriptionManager implements SubscriptionManagerInterface
36
{
37
    public function __construct(
38
        private PaymentDetailsRepositoryInterface $paymentDetailsRepository,
39
        private ProviderInterface $provider,
40
        private BillingDetailsFactoryInterface $billingDetailsFactory,
41
        private PaymentFactoryInterface $paymentFactory,
42
        private SubscriptionFactoryInterface $subscriptionFactory,
43
        private PaymentRepositoryInterface $paymentRepository,
44
        private PlanManagerInterface $planManager,
45
        private SubscriptionPlanRepositoryInterface $subscriptionPlanRepository,
46
        private PriceRepositoryInterface $priceRepository,
47
        private SubscriptionRepositoryInterface $subscriptionRepository,
48
    ) {
49
    }
50
51
    public function startSubscription(CustomerInterface $customer, Plan $plan, PlanPrice $planPrice, PaymentDetails $paymentDetails, int $seatNumbers): Subscription
52
    {
53
        $billingDetails = $this->billingDetailsFactory->createFromCustomerAndPaymentDetails($customer, $paymentDetails);
54
        $obolSubscription = $this->subscriptionFactory->createSubscription($billingDetails, $planPrice, $seatNumbers);
55
56
        if ($this->subscriptionRepository->hasActiveMainSubscription($customer)) {
57
            $main = false;
58
            $subscription = $this->subscriptionRepository->getActiveMainSubscription($customer);
59
60
            if ($subscription->getCurrency() != $planPrice->getCurrency()) {
61
                throw new GeneralException("Can't add a child subscription for a different currency");
62
            }
63
64
            $obolSubscription->setParentReference($subscription->getExternalReference());
65
        } else {
66
            $main = true;
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($plan->getName());
79
        $subscription->setPaymentSchedule($planPrice->getSchedule());
80
        $subscription->setActive(true);
81
        $subscription->setMoneyAmount($planPrice->getPriceAsMoney());
82
        $subscription->setStatus(\Parthenon\Billing\Entity\EmbeddedSubscription::STATUS_ACTIVE);
83
        $subscription->setExternalReference($subscriptionCreationResponse->getSubscriptionId());
84
        $subscription->setSeats($seatNumbers);
85
        $subscription->setCreatedAt(new \DateTime());
86
        $subscription->setUpdatedAt(new \DateTime());
87
        $subscription->setCustomer($customer);
88
        $subscription->setMainSubscription($main);
89
90
        if ($plan->hasEntityId()) {
91
            $subscriptionPlan = $this->subscriptionPlanRepository->findById($plan->getEntityId());
92
            $subscription->setSubscriptionPlan($subscriptionPlan);
93
        }
94
95
        if ($planPrice->hasEntityId()) {
96
            $price = $this->priceRepository->findById($planPrice->getEntityId());
97
            $subscription->setPrice($price);
98
        }
99
100
        $this->subscriptionRepository->save($subscription);
101
102
        return $subscription;
103
    }
104
105
    public function startSubscriptionWithDto(CustomerInterface $customer, StartSubscriptionDto $startSubscriptionDto): Subscription
106
    {
107
        if (!$startSubscriptionDto->getPaymentDetailsId()) {
108
            $paymentDetails = $this->paymentDetailsRepository->getDefaultPaymentDetailsForCustomer($customer);
109
        } else {
110
            $paymentDetails = $this->paymentDetailsRepository->findById($startSubscriptionDto->getPaymentDetailsId());
111
        }
112
113
        $plan = $this->planManager->getPlanByName($startSubscriptionDto->getPlanName());
114
        $planPrice = $plan->getPriceForPaymentSchedule($startSubscriptionDto->getSchedule(), $startSubscriptionDto->getCurrency());
115
116
        return $this->startSubscription($customer, $plan, $planPrice, $paymentDetails, $startSubscriptionDto->getSeatNumbers());
117
    }
118
}
119