Passed
Pull Request — master (#74)
by oleksandr
04:18
created

preparePartialCaptureOrderItems()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 24
c 1
b 0
f 0
dl 0
loc 35
rs 9.536
cc 3
nc 3
nop 2
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\Payment\RequestSender;
9
10
use Generated\Shared\Transfer\CaptureResponseTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfer\CaptureResponseTransfer 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 Generated\Shared\Transfer\ItemTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfer\ItemTransfer 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 Generated\Shared\Transfer\OrderTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfer\OrderTransfer 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 Generated\Shared\Transfer\PayoneOrderItemFilterTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfe...OrderItemFilterTransfer 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 Generated\Shared\Transfer\PayonePartialOperationRequestTransfer;
0 ignored issues
show
Bug introduced by
The type Generated\Shared\Transfe...perationRequestTransfer 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...
15
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...
16
use Orm\Zed\Payone\Persistence\SpyPaymentPayoneApiLog;
0 ignored issues
show
Bug introduced by
The type Orm\Zed\Payone\Persistence\SpyPaymentPayoneApiLog 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...
17
use Spryker\Shared\Shipment\ShipmentConfig;
18
use SprykerEco\Shared\Payone\PayoneApiConstants;
19
use SprykerEco\Shared\Payone\PayoneTransactionStatusConstants;
20
use SprykerEco\Zed\Payone\Business\Api\Adapter\AdapterInterface;
21
use SprykerEco\Zed\Payone\Business\Api\Request\Container\AbstractRequestContainer;
22
use SprykerEco\Zed\Payone\Business\Api\Request\Container\Capture\BusinessContainer;
23
use SprykerEco\Zed\Payone\Business\Api\Response\Container\CaptureResponseContainer;
24
use SprykerEco\Zed\Payone\Business\Api\Response\Mapper\CaptureResponseMapperInterface;
25
use SprykerEco\Zed\Payone\Business\Distributor\OrderPriceDistributorInterface;
26
use SprykerEco\Zed\Payone\Business\Payment\DataMapper\ExpenseMapperInterface;
27
use SprykerEco\Zed\Payone\Business\Payment\DataMapper\ShipmentMapperInterface;
28
use SprykerEco\Zed\Payone\Business\Payment\DataMapper\StandartParameterMapperInterface;
29
use SprykerEco\Zed\Payone\Business\Payment\PaymentMapperReaderInterface;
30
use SprykerEco\Zed\Payone\Persistence\PayoneEntityManagerInterface;
31
use SprykerEco\Zed\Payone\Persistence\PayoneRepositoryInterface;
32
33
class PayonePartialCaptureRequestSender extends AbstractPayoneRequestSender implements PayonePartialCaptureRequestSenderInterface
34
{
35
    /**
36
     * @var string
37
     */
38
    protected const ITEM_STATE_SHIPPED = 'shipped';
39
40
    /**
41
     * @var \SprykerEco\Zed\Payone\Business\Api\Adapter\AdapterInterface
42
     */
43
    protected $executionAdapter;
44
45
    /**
46
     * @var \Generated\Shared\Transfer\PayoneStandardParameterTransfer
47
     */
48
    protected $standardParameter;
49
50
    /**
51
     * @var \SprykerEco\Zed\Payone\Persistence\PayoneEntityManagerInterface
52
     */
53
    protected $payoneEntityManager;
54
55
    /**
56
     * @var \SprykerEco\Zed\Payone\Business\Distributor\OrderPriceDistributorInterface
57
     */
58
    protected $orderPriceDistributor;
59
60
    /**
61
     * @var \SprykerEco\Zed\Payone\Business\Payment\DataMapper\StandartParameterMapperInterface
62
     */
63
    protected $standardParameterMapper;
64
65
    /**
66
     * @var \SprykerEco\Zed\Payone\Business\Payment\DataMapper\ShipmentMapperInterface
67
     */
68
    protected $shipmentMapper;
69
70
    /**
71
     * @var \SprykerEco\Zed\Payone\Business\Payment\PaymentMapperReaderInterface
72
     */
73
    protected $paymentMapperReader;
74
75
    /**
76
     * @var \SprykerEco\Zed\Payone\Business\Payment\DataMapper\ExpenseMapperInterface
77
     */
78
    protected $expenseMapper;
79
80
    /**
81
     * @var \SprykerEco\Zed\Payone\Business\Api\Response\Mapper\CaptureResponseMapperInterface
82
     */
83
    protected $captureResponseMapper;
84
85
    /**
86
     * @param \SprykerEco\Zed\Payone\Business\Api\Adapter\AdapterInterface $executionAdapter
87
     * @param \SprykerEco\Zed\Payone\Persistence\PayoneRepositoryInterface $payoneRepository
88
     * @param \SprykerEco\Zed\Payone\Business\Payment\PaymentMapperReaderInterface $paymentMapperReader
89
     * @param \SprykerEco\Zed\Payone\Business\Payment\DataMapper\ExpenseMapperInterface $expenseMapper
90
     * @param \Generated\Shared\Transfer\PayoneStandardParameterTransfer $standardParameter
91
     * @param \SprykerEco\Zed\Payone\Persistence\PayoneEntityManagerInterface $payoneEntityManager
92
     * @param \SprykerEco\Zed\Payone\Business\Distributor\OrderPriceDistributorInterface $orderPriceDistributor
93
     * @param \SprykerEco\Zed\Payone\Business\Payment\DataMapper\StandartParameterMapperInterface $standardParameterMapper
94
     * @param \SprykerEco\Zed\Payone\Business\Payment\DataMapper\ShipmentMapperInterface $shipmentMapper
95
     * @param \SprykerEco\Zed\Payone\Business\Api\Response\Mapper\CaptureResponseMapperInterface $captureResponseMapper
96
     */
97
    public function __construct(
98
        AdapterInterface $executionAdapter,
99
        PayoneRepositoryInterface $payoneRepository,
100
        PaymentMapperReaderInterface $paymentMapperReader,
101
        ExpenseMapperInterface $expenseMapper,
102
        PayoneStandardParameterTransfer $standardParameter,
103
        PayoneEntityManagerInterface $payoneEntityManager,
104
        OrderPriceDistributorInterface $orderPriceDistributor,
105
        StandartParameterMapperInterface $standardParameterMapper,
106
        ShipmentMapperInterface $shipmentMapper,
107
        CaptureResponseMapperInterface $captureResponseMapper
108
    ) {
109
        parent::__construct($payoneRepository, $paymentMapperReader);
110
        $this->executionAdapter = $executionAdapter;
111
        $this->standardParameter = $standardParameter;
112
        $this->payoneEntityManager = $payoneEntityManager;
113
        $this->orderPriceDistributor = $orderPriceDistributor;
114
        $this->standardParameterMapper = $standardParameterMapper;
115
        $this->shipmentMapper = $shipmentMapper;
116
        $this->expenseMapper = $expenseMapper;
117
        $this->captureResponseMapper = $captureResponseMapper;
118
    }
119
120
    /**
121
     * @param \Generated\Shared\Transfer\PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
122
     *
123
     * @return \Generated\Shared\Transfer\CaptureResponseTransfer
124
     */
125
    public function executePartialCapture(
126
        PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
127
    ): CaptureResponseTransfer {
128
        $distributedPriceOrderTransfer = $this->orderPriceDistributor->distributeOrderPrice(
129
            $payonePartialOperationRequestTransfer->getOrderOrFail(),
130
        );
131
        $payonePartialOperationRequestTransfer->setOrder($distributedPriceOrderTransfer);
132
133
        $paymentPayoneEntity = $this->getPaymentEntity($payonePartialOperationRequestTransfer->getOrderOrFail()->getIdSalesOrderOrFail());
134
        $paymentMethodMapper = $this->getPaymentMethodMapper($paymentPayoneEntity);
135
136
        /** @var \SprykerEco\Zed\Payone\Business\Api\Request\Container\AbstractRequestContainer $requestContainer */
137
        $requestContainer = $paymentMethodMapper->mapPaymentToCapture($paymentPayoneEntity);
138
        $requestContainer = $this->preparePartialCaptureOrderItems($payonePartialOperationRequestTransfer, $requestContainer);
139
        $captureAmount = $this->calculatePartialCaptureItemsAmount($payonePartialOperationRequestTransfer);
140
141
        if ($this->checkThatDeliveryCostsAreRequired($payonePartialOperationRequestTransfer)) {
142
            $captureAmount += $this->getDeliveryCosts($payonePartialOperationRequestTransfer->getOrderOrFail());
143
            $requestContainer = $this->shipmentMapper->mapShipment($payonePartialOperationRequestTransfer->getOrder(), $requestContainer);
144
        }
145
146
        $captureAmount += $this->calculateExpensesCost($payonePartialOperationRequestTransfer->getOrderOrFail());
147
        /** @var \SprykerEco\Zed\Payone\Business\Api\Request\Container\CaptureContainer $requestContainer */
148
        $requestContainer = $this->expenseMapper->mapExpenses($payonePartialOperationRequestTransfer->getOrderOrFail(), $requestContainer);
149
        $businessContainer = new BusinessContainer();
150
        $businessContainer->setSettleAccount(PayoneApiConstants::SETTLE_ACCOUNT_YES);
151
        $requestContainer->setBusiness($businessContainer);
152
153
        $requestContainer->setAmount($captureAmount);
154
        $this->standardParameterMapper->setStandardParameter($requestContainer, $this->standardParameter);
155
156
        $apiLogEntity = $this->initializeApiLog($paymentPayoneEntity, $requestContainer);
157
158
        $rawResponse = $this->executionAdapter->sendRequest($requestContainer);
159
        $responseContainer = new CaptureResponseContainer($rawResponse);
160
161
        $this->updateApiLogAfterCapture($apiLogEntity, $responseContainer);
162
        $this->updatePaymentPayoneOrderItemsWithStatus(
163
            $payonePartialOperationRequestTransfer,
164
            $this->getPartialCaptureStatus($responseContainer),
165
        );
166
167
        return $this->captureResponseMapper->getCaptureResponseTransfer($responseContainer);
168
    }
169
170
    /**
171
     * @param \Orm\Zed\Payone\Persistence\SpyPaymentPayoneApiLog $apiLogEntity
172
     * @param \SprykerEco\Zed\Payone\Business\Api\Response\Container\CaptureResponseContainer $responseContainer
173
     *
174
     * @return void
175
     */
176
    protected function updateApiLogAfterCapture(SpyPaymentPayoneApiLog $apiLogEntity, CaptureResponseContainer $responseContainer): void
177
    {
178
        $apiLogEntity->setStatus($responseContainer->getStatus());
179
        $apiLogEntity->setTransactionId($responseContainer->getTxid());
180
        $apiLogEntity->setErrorMessageInternal($responseContainer->getErrormessage());
181
        $apiLogEntity->setErrorMessageUser($responseContainer->getCustomerMessage());
182
        $apiLogEntity->setErrorCode($responseContainer->getErrorcode());
183
184
        $apiLogEntity->setRawResponse((string)json_encode($responseContainer->toArray()));
185
        $apiLogEntity->save();
186
    }
187
188
    /**
189
     * @param \Generated\Shared\Transfer\PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
190
     * @param \SprykerEco\Zed\Payone\Business\Api\Request\Container\AbstractRequestContainer $container
191
     *
192
     * @return \SprykerEco\Zed\Payone\Business\Api\Request\Container\AbstractRequestContainer
193
     */
194
    protected function preparePartialCaptureOrderItems(
195
        PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer,
196
        AbstractRequestContainer $container
197
    ): AbstractRequestContainer {
198
        $arrayIt = [];
199
        $arrayId = [];
200
        $arrayPr = [];
201
        $arrayNo = [];
202
        $arrayDe = [];
203
        $arrayVa = [];
204
205
        $key = 1;
206
207
        foreach ($payonePartialOperationRequestTransfer->getOrder()->getItems() as $itemTransfer) {
208
            if (!in_array($itemTransfer->getIdSalesOrderItem(), $payonePartialOperationRequestTransfer->getSalesOrderItemIds())) {
209
                continue;
210
            }
211
212
            $arrayIt[$key] = PayoneApiConstants::INVOICING_ITEM_TYPE_GOODS;
213
            $arrayId[$key] = substr((string)$itemTransfer->getSku(), 0, 32);
214
            $arrayPr[$key] = $itemTransfer->getUnitPriceToPayAggregation();
215
            $arrayNo[$key] = $itemTransfer->getQuantity();
216
            $arrayDe[$key] = $itemTransfer->getName();
217
            $arrayVa[$key] = (int)$itemTransfer->getTaxRate();
218
            $key++;
219
        }
220
221
        $container->setIt($arrayIt);
222
        $container->setId($arrayId);
223
        $container->setPr($arrayPr);
224
        $container->setNo($arrayNo);
225
        $container->setDe($arrayDe);
226
        $container->setVa($arrayVa);
227
228
        return $container;
229
    }
230
231
    /**
232
     * @param \Generated\Shared\Transfer\PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
233
     *
234
     * @return int
235
     */
236
    protected function calculatePartialCaptureItemsAmount(PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer): int
237
    {
238
        $itemsAmount = 0;
239
        foreach ($payonePartialOperationRequestTransfer->getOrder()->getItems() as $itemTransfer) {
240
            if (in_array($itemTransfer->getIdSalesOrderItem(), $payonePartialOperationRequestTransfer->getSalesOrderItemIds())) {
241
                $itemsAmount += $itemTransfer->getSumPriceToPayAggregation();
242
            }
243
        }
244
245
        return $itemsAmount;
246
    }
247
248
    /**
249
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
250
     *
251
     * @return int
252
     */
253
    protected function getDeliveryCosts(OrderTransfer $orderTransfer): int
254
    {
255
        foreach ($orderTransfer->getExpenses() as $expense) {
256
            if ($expense->getType() === ShipmentConfig::SHIPMENT_EXPENSE_TYPE) {
257
                return (int)$expense->getSumGrossPrice();
258
            }
259
        }
260
261
        return 0;
262
    }
263
264
    /**
265
     * @param \Generated\Shared\Transfer\PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
266
     *
267
     * @return bool
268
     */
269
    protected function checkThatDeliveryCostsAreRequired(PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer): bool
270
    {
271
        foreach ($payonePartialOperationRequestTransfer->getOrder()->getItems() as $itemTransfer) {
272
            if (in_array($itemTransfer->getIdSalesOrderItem(), $payonePartialOperationRequestTransfer->getSalesOrderItemIds(), true)) {
273
                continue;
274
            }
275
            if ($this->isItemTransferWasShipped($itemTransfer)) {
276
                return false;
277
            }
278
        }
279
280
        return true;
281
    }
282
283
    /**
284
     * @param \Generated\Shared\Transfer\ItemTransfer $itemTransfer
285
     *
286
     * @return bool
287
     */
288
    protected function isItemTransferWasShipped(ItemTransfer $itemTransfer): bool
289
    {
290
        foreach ($itemTransfer->getStateHistory() as $itemState) {
291
            if ($itemState->getName() === static::ITEM_STATE_SHIPPED) {
292
                return true;
293
            }
294
        }
295
296
        return false;
297
    }
298
299
    /**
300
     * @param \Generated\Shared\Transfer\OrderTransfer $orderTransfer
301
     *
302
     * @return int
303
     */
304
    protected function calculateExpensesCost(OrderTransfer $orderTransfer): int
305
    {
306
        $expensesCostAmount = 0;
307
308
        foreach ($orderTransfer->getExpenses() as $expense) {
309
            if ($expense->getType() !== ShipmentConfig::SHIPMENT_EXPENSE_TYPE) {
310
                $expensesCostAmount += $expense->getSumGrossPrice();
311
            }
312
        }
313
314
        return $expensesCostAmount;
315
    }
316
317
    /**
318
     * @param \Generated\Shared\Transfer\PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer
319
     * @param string $refundStatus
320
     *
321
     * @return void
322
     */
323
    protected function updatePaymentPayoneOrderItemsWithStatus(
324
        PayonePartialOperationRequestTransfer $payonePartialOperationRequestTransfer,
325
        string $refundStatus
326
    ): void {
327
        $payoneOrderItemFilterTransfer = (new PayoneOrderItemFilterTransfer())
328
            ->setIdSalesOrder($payonePartialOperationRequestTransfer->getOrder()->getIdSalesOrder())
329
            ->setSalesOrderItemIds($payonePartialOperationRequestTransfer->getSalesOrderItemIds());
330
331
        $payoneOrderItemTransfers = $this->payoneRepository->findPaymentPayoneOrderItemByFilter($payoneOrderItemFilterTransfer);
332
333
        foreach ($payoneOrderItemTransfers as $payoneOrderItemTransfer) {
334
            $payoneOrderItemTransfer->setStatus($refundStatus);
335
            $this->payoneEntityManager->updatePaymentPayoneOrderItem($payoneOrderItemTransfer);
336
        }
337
    }
338
339
    /**
340
     * @param \SprykerEco\Zed\Payone\Business\Api\Response\Container\CaptureResponseContainer $responseContainer
341
     *
342
     * @return string
343
     */
344
    protected function getPartialCaptureStatus(CaptureResponseContainer $responseContainer): string
345
    {
346
        if ($responseContainer->getStatus() === PayoneApiConstants::RESPONSE_TYPE_APPROVED) {
347
            return PayoneTransactionStatusConstants::STATUS_CAPTURE_APPROVED;
348
        }
349
350
        return PayoneTransactionStatusConstants::STATUS_CAPTURE_FAILED;
351
    }
352
}
353