Passed
Push — master ( c89864...65eac8 )
by Jan
17:55 queued 12s
created

PaymentOrderController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU Affero General Public License as published
7
 * by the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License
16
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Controller;
20
21
use App\Audit\UserProvider;
22
use App\Entity\PaymentOrder;
23
use App\Event\PaymentOrderSubmittedEvent;
24
use App\Form\PaymentOrderConfirmationType;
25
use App\Form\PaymentOrderType;
26
use App\Services\PaymentReferenceGenerator;
27
use DateTime;
28
use Doctrine\ORM\EntityManagerInterface;
29
use InvalidArgumentException;
30
use RuntimeException;
31
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
32
use Symfony\Component\Form\Form;
33
use Symfony\Component\HttpFoundation\Request;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\Routing\Annotation\Route;
36
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
37
38
/**
39
 * This controller handles the payment order submit form.
40
 *
41
 * @Route("/payment_order")
42
 */
43
class PaymentOrderController extends AbstractController
44
{
45
    private $userProvider;
46
47
    public function __construct(UserProvider $userProvider)
48
    {
49
        $this->userProvider = $userProvider;
50
    }
51
52
    /**
53
     * @Route("/new", name="payment_order_new")
54
     */
55
    public function new(Request $request, EntityManagerInterface $entityManager, EventDispatcherInterface $dispatcher,
56
        PaymentReferenceGenerator $paymentReferenceGenerator): Response
57
    {
58
        $new_order = new PaymentOrder();
59
60
        $form = $this->createForm(PaymentOrderType::class, $new_order);
61
62
        if (!$form instanceof Form) {
63
            throw new InvalidArgumentException('$form must be a Form object!');
64
        }
65
66
        $form->handleRequest($request);
67
68
        if ($form->isSubmitted()) {
69
            if ($form->isValid()) {
70
                $entityManager->persist($new_order);
71
72
                $username = sprintf('%s %s (%s) [New PaymentOrder]',
73
                    $new_order->getFirstName(),
74
                    $new_order->getLastName(),
75
                    $new_order->getContactEmail()
76
                );
77
                $this->userProvider->setManualUsername($username, $new_order->getContactEmail());
78
79
                $entityManager->flush();
80
81
82
                //We have to do this after the first flush, as we need to know the ID
83
                $this->userProvider->setManualUsername('[Automatic payment reference generation]', UserProvider::INTERNAL_USER_IDENTIFIER);
84
                $paymentReferenceGenerator->setPaymentReference($new_order);
85
                $entityManager->flush();
86
87
                $this->addFlash('success', 'flash.saved_successfully');
88
89
                //Dispatch event so an email can be sent
90
                $event = new PaymentOrderSubmittedEvent($new_order);
91
                $dispatcher->dispatch($event, $event::NAME);
92
93
                //Redirect to homepage, if no further paymentOrders should be submitted
94
                //Otherwise create a new form for further ones
95
                if ('submit' === $form->getClickedButton()->getName()) {
96
                    return $this->redirectToRoute('homepage');
97
                }
98
99
                if ('submit_new' === $form->getClickedButton()->getName()) {
100
                    $old_order = $new_order;
101
                    $new_order = new PaymentOrder();
102
                    $this->copyProperties($old_order, $new_order);
103
104
                    $form = $this->createForm(PaymentOrderType::class, $new_order);
105
                }
106
            } else {
107
                $this->addFlash('error', 'flash.error.check_input');
108
            }
109
        }
110
111
        return $this->render('PaymentOrder/form.html.twig', [
112
            'form' => $form->createView(),
113
            'entity' => $new_order,
114
        ]);
115
    }
116
117
    private function copyProperties(PaymentOrder $source, PaymentOrder $target): void
118
    {
119
        $target->setFirstName($source->getFirstName());
120
        $target->setLastName($source->getLastName());
121
        $target->setContactEmail($source->getContactEmail());
122
        $target->setDepartment($source->getDepartment());
123
        $target->setBankInfo($source->getBankInfo());
124
    }
125
126
    /**
127
     * @Route("/{id}/confirm", name="payment_order_confirm")
128
     */
129
    public function confirmation(PaymentOrder $paymentOrder, Request $request, EntityManagerInterface $em): Response
130
    {
131
        //Check if we have one of the valid confirm numbers
132
        $confirm_step = $request->query->getInt('confirm');
133
        if (1 !== $confirm_step && 2 !== $confirm_step) {
134
            //$this->createNotFoundException('Invalid confirmation step! Only 1 or 2 are allowed.');
135
            $this->addFlash('error', 'payment_order.confirmation.invalid_step');
136
137
            return $this->redirectToRoute('homepage');
138
        }
139
140
        //Check if given token is correct for this step
141
        $correct_token = (1 === $confirm_step) ? $paymentOrder->getConfirm1Token() : $paymentOrder->getConfirm2Token();
142
        if (null === $correct_token) {
143
            throw new RuntimeException('This payment_order can not be confirmed! No token is set.');
144
        }
145
146
        $given_token = (string) $request->query->get('token');
147
        if (!password_verify($given_token, $correct_token)) {
148
            $this->addFlash('error', 'payment_order.confirmation.invalid_token');
149
150
            return $this->redirectToRoute('homepage');
151
        }
152
153
        //Check if it was already confirmed from this side and disable form if needed
154
        $confirm_timestamp = (1 === $confirm_step) ? $paymentOrder->getConfirm1Timestamp() : $paymentOrder->getConfirm2Timestamp();
155
        if (null !== $confirm_timestamp) {
156
            $this->addFlash('info', 'payment_order.confirmation.already_confirmed');
157
        }
158
        $form = $this->createForm(PaymentOrderConfirmationType::class, null, [
159
            'disabled' => null !== $confirm_timestamp,
160
        ]);
161
162
        $form->handleRequest($request);
163
        if ($form->isSubmitted() && $form->isValid()) {
164
            $this->addFlash('success', 'payment_order.confirmation.success');
165
            //Write confirmation to DB
166
            if (1 === $confirm_step) {
167
                $paymentOrder->setConfirm1Timestamp(new DateTime());
168
            } elseif (2 === $confirm_step) {
169
                $paymentOrder->setConfirm2Timestamp(new DateTime());
170
            }
171
172
            //Add hintful information about who did this, to audit log
173
            $emails = (1 === $confirm_step) ? $paymentOrder->getDepartment()->getEmailHhv() : $paymentOrder->getDepartment()->getEmailTreasurer();
174
            $username = sprintf('%s [Confirmation %d]', implode(', ', $emails), $confirm_step);
175
            $this->userProvider->setManualUsername($username, implode(',', $emails));
176
            $em->flush();
177
178
            //Rerender form if it was confirmed, to apply the disabled state
179
            $form = $this->createForm(PaymentOrderConfirmationType::class, null, [
180
                'disabled' => true,
181
            ]);
182
            $this->addFlash('info', 'payment_order.confirmation.already_confirmed');
183
        }
184
185
        return $this->render('PaymentOrder/confirm/confirm.html.twig', [
186
            'entity' => $paymentOrder,
187
            'confirmation_nr' => $confirm_step,
188
            'form' => $form->createView(),
189
        ]);
190
    }
191
}
192