Failed Conditions
Push — master ( 7c4d30...258d19 )
by Adrien
07:17
created

DatatransAction::createTransactions()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 44
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 4.0195

Importance

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