Passed
Pull Request — master (#74)
by
unknown
05:21
created

TransactionStatusUpdateManager   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 43
eloc 129
dl 0
loc 418
rs 8.96
c 5
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A isPayment() 0 10 2
A createErrorResponse() 0 6 1
A isPaymentOther() 0 22 3
A isPaymentCapture() 0 5 1
A transformCurrency() 0 23 4
A getUnprocessedTransactionStatusLogs() 0 21 3
A isPaymentNotificationAvailable() 0 3 1
A isPaymentAppointed() 0 5 1
A hasUnprocessedTransactionStatusLogs() 0 5 1
A findPaymentByTransactionId() 0 3 1
A isPaymentUnderpaid() 0 5 1
A getFirstUnprocessedTransactionStatusLog() 0 18 4
A saveSpyPaymentPayoneTransactionStatusLogOrderItem() 0 6 1
A validate() 0 16 4
A isPaymentOverpaid() 0 14 3
A processTransactionStatusUpdate() 0 21 4
A isPaymentPaid() 0 14 3
A isPaymentRefund() 0 5 1
A createSuccessResponse() 0 3 1
A __construct() 0 8 1
A persistRequest() 0 23 2

How to fix   Complexity   

Complex Class

Complex classes like TransactionStatusUpdateManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TransactionStatusUpdateManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * MIT License
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace SprykerEco\Zed\Payone\Business\TransactionStatus;
9
10
use Generated\Shared\Transfer\PayoneStandardParameterTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfe...andardParameterTransfer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Orm\Zed\Payone\Persistence\SpyPaymentPayone;
0 ignored issues
show
Bug introduced by
The type Orm\Zed\Payone\Persistence\SpyPaymentPayone was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog;
0 ignored issues
show
Bug introduced by
The type Orm\Zed\Payone\Persisten...oneTransactionStatusLog was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLogOrderItem;
0 ignored issues
show
Bug introduced by
The type Orm\Zed\Payone\Persisten...ctionStatusLogOrderItem was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use SprykerEco\Shared\Payone\Dependency\TransactionStatusUpdateInterface;
15
use SprykerEco\Shared\Payone\PayoneTransactionStatusConstants;
16
use SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusRequest;
17
use SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusResponse;
18
use SprykerEco\Zed\Payone\Business\Key\HashGeneratorInterface;
19
use SprykerEco\Zed\Payone\Persistence\PayoneQueryContainerInterface;
20
21
class TransactionStatusUpdateManager implements TransactionStatusUpdateManagerInterface
22
{
23
    /**
24
     * @var string
25
     */
26
    protected const STATUS_UPDATE_ERROR_NO_TXID = 'Payone transaction status update: txid is not provided!';
27
28
    /**
29
     * @var \SprykerEco\Zed\Payone\Persistence\PayoneQueryContainerInterface
30
     */
31
    protected $queryContainer;
32
33
    /**
34
     * @var \Generated\Shared\Transfer\PayoneStandardParameterTransfer
35
     */
36
    protected $standardParameter;
37
38
    /**
39
     * @var \SprykerEco\Zed\Payone\Business\Key\HashGeneratorInterface
40
     */
41
    protected $hashGenerator;
42
43
    /**
44
     * @param \SprykerEco\Zed\Payone\Persistence\PayoneQueryContainerInterface $queryContainer
45
     * @param \Generated\Shared\Transfer\PayoneStandardParameterTransfer $standardParameter
46
     * @param \SprykerEco\Zed\Payone\Business\Key\HashGeneratorInterface $hashGenerator
47
     */
48
    public function __construct(
49
        PayoneQueryContainerInterface $queryContainer,
50
        PayoneStandardParameterTransfer $standardParameter,
51
        HashGeneratorInterface $hashGenerator
52
    ) {
53
        $this->queryContainer = $queryContainer;
54
        $this->standardParameter = $standardParameter;
55
        $this->hashGenerator = $hashGenerator;
56
    }
57
58
    /**
59
     * @param \SprykerEco\Shared\Payone\Dependency\TransactionStatusUpdateInterface $request
60
     *
61
     * @return \SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusResponse
62
     */
63
    public function processTransactionStatusUpdate(TransactionStatusUpdateInterface $request): TransactionStatusResponse
64
    {
65
        $validationResult = $this->validate($request);
66
        if ($validationResult instanceof TransactionStatusResponse) {
67
            return $validationResult;
68
        }
69
        $this->transformCurrency($request);
70
71
        if ($request->getTxid() === null) {
72
            return $this->createErrorResponse(static::STATUS_UPDATE_ERROR_NO_TXID);
73
        }
74
75
        $paymentPayoneEntity = $this->findPaymentByTransactionId($request->getTxid());
76
77
        if (!$paymentPayoneEntity) {
78
            return $this->createErrorResponse('Payone transaction status update: Payment was not found!');
79
        }
80
81
        $this->persistRequest($request, $paymentPayoneEntity);
82
83
        return $this->createSuccessResponse();
84
    }
85
86
    /**
87
     * @param \SprykerEco\Shared\Payone\Dependency\TransactionStatusUpdateInterface $request
88
     * @param \Orm\Zed\Payone\Persistence\SpyPaymentPayone|null $paymentPayoneEntity
89
     *
90
     * @return void
91
     */
92
    protected function persistRequest(TransactionStatusUpdateInterface $request, ?SpyPaymentPayone $paymentPayoneEntity = null): void
93
    {
94
        if (!$paymentPayoneEntity) {
95
            return;
96
        }
97
98
        $paymentPayoneTransactionStatusLogEntity = new SpyPaymentPayoneTransactionStatusLog();
99
        $paymentPayoneTransactionStatusLogEntity->setFkPaymentPayone($paymentPayoneEntity->getIdPaymentPayone());
100
        $paymentPayoneTransactionStatusLogEntity->setTransactionId($request->getTxid());
101
        $paymentPayoneTransactionStatusLogEntity->setReferenceId($request->getReference());
102
        $paymentPayoneTransactionStatusLogEntity->setMode($request->getMode());
103
        $paymentPayoneTransactionStatusLogEntity->setStatus($request->getTxaction());
104
        $paymentPayoneTransactionStatusLogEntity->setTransactionTime($request->getTxtime());
105
        $paymentPayoneTransactionStatusLogEntity->setSequenceNumber($request->getSequencenumber());
106
        $paymentPayoneTransactionStatusLogEntity->setClearingType($request->getClearingtype());
107
        $paymentPayoneTransactionStatusLogEntity->setPortalId($request->getPortalid());
108
        $paymentPayoneTransactionStatusLogEntity->setPrice($request->getPrice());
109
        $paymentPayoneTransactionStatusLogEntity->setBalance($request->getBalance());
110
        $paymentPayoneTransactionStatusLogEntity->setReceivable($request->getReceivable());
111
        $paymentPayoneTransactionStatusLogEntity->setReminderLevel($request->getReminderlevel());
112
        $paymentPayoneTransactionStatusLogEntity->setRawRequest($request);
113
114
        $paymentPayoneTransactionStatusLogEntity->save();
115
    }
116
117
    /**
118
     * @param int $idSalesOrder
119
     * @param int $idSalesOrderItem
120
     *
121
     * @return bool
122
     */
123
    public function isPaymentNotificationAvailable(int $idSalesOrder, int $idSalesOrderItem): bool
124
    {
125
        return $this->hasUnprocessedTransactionStatusLogs($idSalesOrder, $idSalesOrderItem);
126
    }
127
128
    /**
129
     * @param \SprykerEco\Shared\Payone\Dependency\TransactionStatusUpdateInterface $request
130
     *
131
     * @return void
132
     */
133
    protected function transformCurrency(TransactionStatusUpdateInterface $request): void
134
    {
135
        $balance = $request->getBalance();
136
        $balanceAmountInCents = round((float)$balance * 100);
137
138
        $isTransactionStatusRequest = $request instanceof TransactionStatusRequest;
139
140
        if ($isTransactionStatusRequest) {
141
            $request->setBalance($balanceAmountInCents);
142
        }
143
144
        $receivable = $request->getReceivable();
145
        $receivableAmountInCents = round((float)$receivable * 100);
146
147
        if ($isTransactionStatusRequest) {
148
            $request->setReceivable($receivableAmountInCents);
0 ignored issues
show
Bug introduced by
The method setReceivable() does not exist on SprykerEco\Shared\Payone...onStatusUpdateInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to SprykerEco\Shared\Payone...onStatusUpdateInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

148
            $request->/** @scrutinizer ignore-call */ 
149
                      setReceivable($receivableAmountInCents);
Loading history...
149
        }
150
151
        $price = $request->getPrice();
152
        $priceAmountInCents = round((float)$price * 100);
153
154
        if ($isTransactionStatusRequest) {
155
            $request->setPrice($priceAmountInCents);
0 ignored issues
show
Bug introduced by
The method setPrice() does not exist on SprykerEco\Shared\Payone...onStatusUpdateInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to SprykerEco\Shared\Payone...onStatusUpdateInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

155
            $request->/** @scrutinizer ignore-call */ 
156
                      setPrice($priceAmountInCents);
Loading history...
156
        }
157
    }
158
159
    /**
160
     * @param \SprykerEco\Shared\Payone\Dependency\TransactionStatusUpdateInterface $request
161
     *
162
     * @return \SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusResponse|bool
163
     */
164
    protected function validate(TransactionStatusUpdateInterface $request)
165
    {
166
        $systemHashedKey = $this->hashGenerator->hash($this->standardParameter->getKeyOrFail());
167
        if ($request->getKey() !== $systemHashedKey) {
168
            return $this->createErrorResponse('Payone transaction status update: Given and internal key do not match!');
169
        }
170
171
        if ((int)$request->getAid() !== (int)$this->standardParameter->getAid()) {
172
            return $this->createErrorResponse('Payone transaction status update: Invalid Aid! System: ' . $this->standardParameter->getAid() . ' Request: ' . $request->getAid());
173
        }
174
175
        if ((int)$request->getPortalid() !== (int)$this->standardParameter->getPortalId()) {
176
            return $this->createErrorResponse('Payone transaction status update: Invalid Portalid! System: ' . $this->standardParameter->getPortalId() . ' Request: ' . $request->getPortalid());
177
        }
178
179
        return true;
180
    }
181
182
    /**
183
     * @param string $errorMessage
184
     *
185
     * @return \SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusResponse
186
     */
187
    protected function createErrorResponse(string $errorMessage): TransactionStatusResponse
188
    {
189
        $response = new TransactionStatusResponse(false);
190
        $response->setErrorMessage($errorMessage);
191
192
        return $response;
193
    }
194
195
    /**
196
     * @return \SprykerEco\Zed\Payone\Business\Api\TransactionStatus\TransactionStatusResponse
197
     */
198
    protected function createSuccessResponse(): TransactionStatusResponse
199
    {
200
        return new TransactionStatusResponse(true);
201
    }
202
203
    /**
204
     * @param int $transactionId
205
     *
206
     * @return \Orm\Zed\Payone\Persistence\SpyPaymentPayone|null
207
     */
208
    protected function findPaymentByTransactionId(int $transactionId): ?SpyPaymentPayone
209
    {
210
        return $this->queryContainer->createPaymentByTransactionIdQuery($transactionId)->findOne();
211
    }
212
213
    /**
214
     * @param int $idSalesOrder
215
     * @param int $idSalesOrderItem
216
     *
217
     * @return bool
218
     */
219
    public function isPaymentPaid(int $idSalesOrder, int $idSalesOrderItem): bool
220
    {
221
        $status = PayoneTransactionStatusConstants::TXACTION_PAID;
222
        $statusLog = $this->getFirstUnprocessedTransactionStatusLog($idSalesOrder, $idSalesOrderItem, $status);
223
        if ($statusLog === null) {
224
            return false;
225
        }
226
        if ($statusLog->getBalance() > 0) {
227
            return false;
228
        }
229
230
        $this->saveSpyPaymentPayoneTransactionStatusLogOrderItem($idSalesOrderItem, $statusLog);
231
232
        return true;
233
    }
234
235
    /**
236
     * @param int $idSalesOrder
237
     * @param int $idSalesOrderItem
238
     *
239
     * @return bool
240
     */
241
    public function isPaymentCapture(int $idSalesOrder, int $idSalesOrderItem): bool
242
    {
243
        $status = PayoneTransactionStatusConstants::TXACTION_CAPTURE;
244
245
        return $this->isPayment($idSalesOrder, $idSalesOrderItem, $status);
246
    }
247
248
    /**
249
     * @param int $idSalesOrder
250
     * @param int $idSalesOrderItem
251
     *
252
     * @return bool
253
     */
254
    public function isPaymentOverpaid(int $idSalesOrder, int $idSalesOrderItem): bool
255
    {
256
        $status = PayoneTransactionStatusConstants::TXACTION_PAID;
257
        $statusLog = $this->getFirstUnprocessedTransactionStatusLog($idSalesOrder, $idSalesOrderItem, $status);
258
        if ($statusLog === null) {
259
            return false;
260
        }
261
        if ($statusLog->getBalance() >= 0) {
262
            return false;
263
        }
264
265
        $this->saveSpyPaymentPayoneTransactionStatusLogOrderItem($idSalesOrderItem, $statusLog);
266
267
        return true;
268
    }
269
270
    /**
271
     * @param int $idSalesOrder
272
     * @param int $idSalesOrderItem
273
     *
274
     * @return bool
275
     */
276
    public function isPaymentUnderpaid(int $idSalesOrder, int $idSalesOrderItem): bool
277
    {
278
        $status = PayoneTransactionStatusConstants::TXACTION_UNDERPAID;
279
280
        return $this->isPayment($idSalesOrder, $idSalesOrderItem, $status);
281
    }
282
283
    /**
284
     * @param int $idSalesOrder
285
     * @param int $idSalesOrderItem
286
     *
287
     * @return bool
288
     */
289
    public function isPaymentRefund(int $idSalesOrder, int $idSalesOrderItem): bool
290
    {
291
        $status = PayoneTransactionStatusConstants::TXACTION_REFUND;
292
293
        return $this->isPayment($idSalesOrder, $idSalesOrderItem, $status);
294
    }
295
296
    /**
297
     * @param int $idSalesOrder
298
     * @param int $idSalesOrderItem
299
     *
300
     * @return bool
301
     */
302
    public function isPaymentAppointed(int $idSalesOrder, int $idSalesOrderItem): bool
303
    {
304
        $status = PayoneTransactionStatusConstants::TXACTION_APPOINTED;
305
306
        return $this->isPayment($idSalesOrder, $idSalesOrderItem, $status);
307
    }
308
309
    /**
310
     * @param int $idSalesOrder
311
     * @param int $idSalesOrderItem
312
     *
313
     * @return bool
314
     */
315
    public function isPaymentOther(int $idSalesOrder, int $idSalesOrderItem): bool
316
    {
317
        $statusLogs = $this->getUnprocessedTransactionStatusLogs($idSalesOrder, $idSalesOrderItem);
318
        if (!$statusLogs) {
319
            return false;
320
        }
321
322
        /** @var \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog $statusLog */
323
        $statusLog = array_shift($statusLogs);
324
325
        $statuses = [
326
            PayoneTransactionStatusConstants::TXACTION_PAID,
327
            PayoneTransactionStatusConstants::TXACTION_APPOINTED,
328
            PayoneTransactionStatusConstants::TXACTION_UNDERPAID,
329
        ];
330
        if (in_array($statusLog->getStatus(), $statuses)) {
331
            return false;
332
        }
333
334
        $this->saveSpyPaymentPayoneTransactionStatusLogOrderItem($idSalesOrderItem, $statusLog);
335
336
        return true;
337
    }
338
339
    /**
340
     * @param int $idSalesOrder
341
     * @param int $idSalesOrderItem
342
     * @param string $status
343
     *
344
     * @return bool
345
     */
346
    protected function isPayment(int $idSalesOrder, int $idSalesOrderItem, string $status): bool
347
    {
348
        $statusLog = $this->getFirstUnprocessedTransactionStatusLog($idSalesOrder, $idSalesOrderItem, $status);
349
        if ($statusLog === null) {
350
            return false;
351
        }
352
353
        $this->saveSpyPaymentPayoneTransactionStatusLogOrderItem($idSalesOrderItem, $statusLog);
354
355
        return true;
356
    }
357
358
    /**
359
     * @param int $idSalesOrder
360
     * @param int $idSalesOrderItem
361
     *
362
     * @return bool
363
     */
364
    protected function hasUnprocessedTransactionStatusLogs(int $idSalesOrder, int $idSalesOrderItem): bool
365
    {
366
        $records = $this->getUnprocessedTransactionStatusLogs($idSalesOrder, $idSalesOrderItem);
367
368
        return $records !== [];
369
    }
370
371
    /**
372
     * @param int $idSalesOrder
373
     * @param int $idSalesOrderItem
374
     * @param string $status
375
     *
376
     * @return \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog|null
377
     */
378
    protected function getFirstUnprocessedTransactionStatusLog(int $idSalesOrder, int $idSalesOrderItem, string $status): ?SpyPaymentPayoneTransactionStatusLog
379
    {
380
        $transactionStatusLogs = $this->getUnprocessedTransactionStatusLogs($idSalesOrder, $idSalesOrderItem);
381
382
        if (!$transactionStatusLogs) {
383
            return null;
384
        }
385
386
        while (count($transactionStatusLogs)) {
387
            /** @var \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog $transactionStatusLog */
388
            $transactionStatusLog = array_shift($transactionStatusLogs);
389
390
            if ($transactionStatusLog->getStatus() == $status) {
391
                return $transactionStatusLog;
392
            }
393
        }
394
395
        return null;
396
    }
397
398
    /**
399
     * @param int $idSalesOrder
400
     * @param int $idSalesOrderItem
401
     *
402
     * @return array<\Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog>
403
     */
404
    protected function getUnprocessedTransactionStatusLogs(int $idSalesOrder, int $idSalesOrderItem): array
405
    {
406
        $transactionStatusLogs = $this->queryContainer->createTransactionStatusLogsBySalesOrder($idSalesOrder)->find();
407
408
        $ids = [];
409
410
        /** @var \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog $transactionStatusLog */
411
        foreach ($transactionStatusLogs as $transactionStatusLog) {
412
            $ids[$transactionStatusLog->getIdPaymentPayoneTransactionStatusLog()] = $transactionStatusLog;
413
        }
414
415
        $relations = $this->queryContainer
416
            ->createTransactionStatusLogOrderItemsByLogIds($idSalesOrderItem, array_keys($ids))
417
            ->find();
418
419
        /** @var \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLogOrderItem $relation */
420
        foreach ($relations as $relation) {
421
            unset($ids[$relation->getIdPaymentPayoneTransactionStatusLog()]);
422
        }
423
424
        return $ids;
425
    }
426
427
    /**
428
     * @param int $idSalesOrderItem
429
     * @param \Orm\Zed\Payone\Persistence\SpyPaymentPayoneTransactionStatusLog $statusLog
430
     *
431
     * @return void
432
     */
433
    protected function saveSpyPaymentPayoneTransactionStatusLogOrderItem(int $idSalesOrderItem, SpyPaymentPayoneTransactionStatusLog $statusLog): void
434
    {
435
        $entity = new SpyPaymentPayoneTransactionStatusLogOrderItem();
436
        $entity->setSpyPaymentPayoneTransactionStatusLog($statusLog);
437
        $entity->setIdSalesOrderItem($idSalesOrderItem);
438
        $entity->save();
439
    }
440
}
441