Passed
Push — main ( dc7994...b21dd6 )
by Iain
05:08
created

SubscriptionController::cancelSubscription()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 12
rs 10
c 0
b 0
f 0
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\Controller;
16
17
use Obol\Exception\UnsupportedFunctionalityException;
18
use Parthenon\Billing\CustomerProviderInterface;
19
use Parthenon\Billing\Dto\StartSubscriptionDto;
20
use Parthenon\Billing\Exception\NoCustomerException;
21
use Parthenon\Billing\Exception\NoPlanFoundException;
22
use Parthenon\Billing\Exception\NoPlanPriceFoundException;
23
use Parthenon\Billing\Repository\CustomerRepositoryInterface;
24
use Parthenon\Billing\Repository\SubscriptionRepositoryInterface;
25
use Parthenon\Billing\Response\StartSubscriptionResponse;
26
use Parthenon\Billing\Subscription\SubscriptionManagerInterface;
27
use Parthenon\Common\Exception\NoEntityFoundException;
28
use Parthenon\Common\LoggerAwareTrait;
29
use Symfony\Component\HttpFoundation\JsonResponse;
30
use Symfony\Component\HttpFoundation\Request;
31
use Symfony\Component\HttpFoundation\Response;
32
use Symfony\Component\Routing\Annotation\Route;
33
use Symfony\Component\Serializer\SerializerInterface;
34
use Symfony\Component\Validator\Validator\ValidatorInterface;
35
36
class SubscriptionController
37
{
38
    use LoggerAwareTrait;
39
40
    #[Route('/billing/subscription/{subscriptionId}/cancel', name: 'parthenon_billing_subscription_cancel', methods: ['POST'])]
41
    public function cancelSubscription(Request $request, SubscriptionRepositoryInterface $subscriptionRepository, SubscriptionManagerInterface $subscriptionManager): Response
42
    {
43
        try {
44
            $subscription = $subscriptionRepository->getById($request->get('subscriptionId'));
45
        } catch (NoEntityFoundException $E) {
46
            return new JsonResponse(status: JsonResponse::HTTP_NOT_FOUND);
47
        }
48
49
        $subscriptionManager->cancelSubscriptionAtEndOfCurrentPeriod($subscription);
50
51
        return new JsonResponse(status: JsonResponse::HTTP_ACCEPTED);
52
    }
53
54
    #[Route('/billing/subscription/start', name: 'parthenon_billing_subscription_start_with_payment_details', methods: ['POST'])]
55
    public function startSubscriptionWithPaymentDetails(
56
        Request $request,
57
        CustomerProviderInterface $customerProvider,
58
        SerializerInterface $serializer,
59
        CustomerRepositoryInterface $customerRepository,
60
        ValidatorInterface $validator,
61
        SubscriptionManagerInterface $subscriptionManager,
62
    ): Response {
63
        $this->getLogger()->info('Starting the subscription');
64
65
        try {
66
            $customer = $customerProvider->getCurrentCustomer();
67
        } catch (NoCustomerException $exception) {
68
            $this->getLogger()->error('No customer found when starting subscription with payment details - probable misconfigured firewall.');
69
70
            return new JsonResponse(StartSubscriptionResponse::createGeneralError(), JsonResponse::HTTP_BAD_REQUEST);
71
        }
72
73
        try {
74
            /** @var StartSubscriptionDto $subscriptionDto */
75
            $subscriptionDto = $serializer->deserialize($request->getContent(), StartSubscriptionDto::class, 'json');
76
77
            $errors = $validator->validate($subscriptionDto);
78
79
            if (count($errors) > 0) {
80
                return new JsonResponse(StartSubscriptionResponse::createInvalidRequestResponse($errors), JsonResponse::HTTP_BAD_REQUEST);
81
            }
82
83
            $subscription = $subscriptionManager->startSubscriptionWithDto($customer, $subscriptionDto);
84
85
            $customerRepository->save($customer);
86
        } catch (NoEntityFoundException $exception) {
87
            return new JsonResponse(StartSubscriptionResponse::createGeneralError(), JsonResponse::HTTP_BAD_REQUEST);
88
        } catch (NoPlanPriceFoundException $exception) {
89
            $this->getLogger()->warning('No price plan found');
90
91
            return new JsonResponse(StartSubscriptionResponse::createPlanPriceNotFound(), JsonResponse::HTTP_BAD_REQUEST);
92
        } catch (NoPlanFoundException $exception) {
93
            $this->getLogger()->warning('No plan found');
94
95
            return new JsonResponse(StartSubscriptionResponse::createPlanNotFound(), JsonResponse::HTTP_BAD_REQUEST);
96
        } catch (UnsupportedFunctionalityException $exception) {
97
            $this->getLogger()->error('Payment provider does not support payment details');
98
99
            return new JsonResponse(StartSubscriptionResponse::createUnsupportedPaymentProvider(), JsonResponse::HTTP_BAD_REQUEST);
100
        } catch (\Throwable $t) {
101
            $this->getLogger()->error('Unknown error while starting a subscription');
102
103
            throw $t;
104
        }
105
106
        return new JsonResponse(StartSubscriptionResponse::createSuccessResponse($subscription), JsonResponse::HTTP_CREATED);
107
    }
108
}
109