Failed Conditions
Push — master ( 11b762...8f3f2d )
by Adrien
07:08
created

DatatransAction::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
nc 1
nop 2
dl 0
loc 4
c 0
b 0
f 0
cc 1
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Action;
6
7
use Application\Model\Transaction;
8
use Application\Model\TransactionLine;
9
use Application\Model\User;
10
use Cake\Chronos\Date;
11
use Doctrine\ORM\EntityManager;
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\ServerRequestInterface;
14
use Psr\Http\Server\RequestHandlerInterface;
15
use Zend\Diactoros\Response\HtmlResponse;
16
use Zend\Expressive\Template\TemplateRendererInterface;
17
18
class DatatransAction extends AbstractAction
19
{
20
    /** @var TemplateRendererInterface */
21
    private $template;
22
23
    /**
24
     * @var EntityManager
25
     */
26
    private $entityManager;
27
28 3
    public function __construct(EntityManager $entityManager, TemplateRendererInterface $template)
29
    {
30 3
        $this->entityManager = $entityManager;
31 3
        $this->template = $template;
32 3
    }
33
34
    /**
35
     * Webhook called by datatrans when a payment was made
36
     *
37
     * See documentation: https://api-reference.datatrans.ch/#failed-unsuccessful-authorization-response
38
     *
39
     * @param ServerRequestInterface $request
40
     * @param RequestHandlerInterface $handler
41
     *
42
     * @return ResponseInterface
43
     */
44 3
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
45
    {
46 3
        $request->getMethod();
47 3
        $body = $request->getParsedBody();
48 3
        if (!is_array($body)) {
49
            throw new \Exception('Parsed body is expected to be an array but got: ' . gettype($body));
50
        }
51
52 3
        $status = $body['status'] ?? '';
53
54 3
        switch ($status) {
55 3
            case 'success':
56 1
                $this->createTransactions($body);
57
                $message = [
58 1
                    'type' => $status,
59 1
                    'message' => $body['responseMessage'],
60 1
                    'detail' => $body,
61
                ];
62
63 1
                break;
64 2
            case 'error':
65
                $message = [
66 1
                    'type' => $status,
67 1
                    'message' => $body['errorMessage'],
68 1
                    'detail' => $body,
69
                ];
70
71 1
                break;
72 1
            case 'cancel':
73
                $message = [
74 1
                    'type' => 'error', // Here we cheat because the JS cannot handle 'cancel' status
75 1
                    'message' => 'Cancelled',
76 1
                    'detail' => $body,
77
                ];
78
79 1
                break;
80
            default:
81
                throw new \Exception('Unsupported status in Datatrans data: ' . $status);
82
        }
83
84
        $viewModel = [
85 3
            'message' => $message,
86
        ];
87
88 3
        return new HtmlResponse($this->template->render('app::datatrans', $viewModel));
89
    }
90
91 1
    private function createTransactions(array $body): void
92
    {
93 1
        $userId = $body['refno'];
94
95
        /** @var User $user */
96 1
        $user = $this->entityManager->getRepository(User::class)->getOneById((int) $userId);
97 1
        if (!$user) {
98
            throw new \Exception('Cannot create transactions without a user');
99
        }
100
101 1
        $account = $user->getAccount();
102 1
        if (!$account) {
103
            throw new \Exception('Cannot create transactions for a user who does not have an account');
104
        }
105
106 1
        if (!array_key_exists('amount', $body)) {
107
            // Do not support "registrations"
108
            throw new \Exception('Cannot create transactions without an amount');
109
        }
110
111 1
        $currency = $body['currency'] ?? '';
112 1
        if ($currency !== 'CHF') {
113
            throw new \Exception('Can only create transactions for CHF, but got: ' . $currency);
114
        }
115
116 1
        $now = Date::today();
117 1
        $datatransRef = $body['uppTransactionId'];
118 1
        $name = 'Datatrans: ' . $datatransRef;
119
120 1
        $transaction = new Transaction();
121 1
        $this->entityManager->persist($transaction);
122 1
        $transaction->setName($name);
123 1
        $transaction->setTransactionDate($now);
124
125 1
        $line = new TransactionLine();
126 1
        $this->entityManager->persist($line);
127 1
        $line->setName($name);
128 1
        $line->setTransactionDate($now);
129 1
        $line->setBalance((string) ($body['amount'] / 100));
130 1
        $line->setDatatransRef($datatransRef);
131 1
        $line->setTransaction($transaction);
132 1
        $line->setCredit($account);
133
134
        // This could be removed later on. For now it's mostly for debugging
135 1
        $line->setRemarks(json_encode($body, JSON_PRETTY_PRINT));
136
137 1
        $this->entityManager->flush();
138 1
    }
139
}
140