Passed
Push — main ( df4b88...9c2b80 )
by Leith
02:11
created

PurchaseRequest::getData()   C

Complexity

Conditions 10
Paths 144

Size

Total Lines 82
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 47
c 2
b 0
f 0
nc 144
nop 0
dl 0
loc 82
rs 6.9963

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Omnipay\Worldline\Message;
4
5
use DateTime;
6
use DateTimeZone;
7
use Money\Currency;
8
use Money\Number;
9
use Money\Parser\DecimalMoneyParser;
10
use Omnipay\Common\Message\AbstractRequest;
11
use Omnipay\Common\Exception\InvalidRequestException;
12
13
/**
14
 * Worldline Purchase Request
15
 *
16
 * @see https://docs.direct.worldline-solutions.com/en/api-reference#tag/HostedCheckout/operation/CreateHostedCheckoutApi
17
 */
18
class PurchaseRequest extends AbstractRequest
19
{
20
    /** @var string */
21
    protected $liveEndpoint = 'https://payment.direct.worldline-solutions.com';
22
    /** @var string */
23
    protected $testEndpoint = 'https://payment.preprod.direct.worldline-solutions.com';
24
25
    /** @var string  Can be "FINAL_AUTHORIZATION" "PRE_AUTHORIZATION" or "SALE" */
26
    protected $authorizationMode = 'SALE';
27
    protected $requestMethod = 'POST';
28
29
    public function getApiKey()
30
    {
31
        return $this->getParameter('apiKey');
32
    }
33
34
    public function setApiKey($value)
35
    {
36
        return $this->setParameter('apiKey', $value);
37
    }
38
39
    public function getApiSecret()
40
    {
41
        return $this->getParameter('apiSecret');
42
    }
43
44
    public function setApiSecret($value)
45
    {
46
        return $this->setParameter('apiSecret', $value);
47
    }
48
49
    public function getAvailablePaymentProducts()
50
    {
51
        return $this->getParameter('availablePaymentProducts');
52
    }
53
54
    /**
55
     * @param int[] $value  @see https://docs.direct.worldline-solutions.com/en/payment-methods-and-features/
56
     */
57
    public function setAvailablePaymentProducts($value)
58
    {
59
        return $this->setParameter('availablePaymentProducts', $value);
60
    }
61
62
    public function getExcludedPaymentProducts()
63
    {
64
        return $this->getParameter('excludedPaymentProducts');
65
    }
66
67
    /**
68
     * @param int[] $value  @see https://docs.direct.worldline-solutions.com/en/payment-methods-and-features/
69
     */
70
    public function setExcludedPaymentProducts($value)
71
    {
72
        return $this->setParameter('excludedPaymentProducts', $value);
73
    }
74
75
    public function getMerchantId()
76
    {
77
        return $this->getParameter('merchantId');
78
    }
79
80
    public function setMerchantId($value)
81
    {
82
        return $this->setParameter('merchantId', $value);
83
    }
84
85
    public function getMerchantName()
86
    {
87
        return $this->getParameter('merchantName');
88
    }
89
90
    public function setMerchantName($value)
91
    {
92
        return $this->setParameter('merchantName', $value);
93
    }
94
95
    public function getShowResultPage()
96
    {
97
        return $this->getParameter('showResultPage');
98
    }
99
100
    public function setShowResultPage($value)
101
    {
102
        return $this->setParameter('showResultPage', $value);
103
    }
104
105
    public function getSessionTimeout()
106
    {
107
        return $this->getParameter('sessionTimeout');
108
    }
109
110
    /**
111
     * Timeout is in minutes, default 180
112
     */
113
    public function setSessionTimeout($value)
114
    {
115
        return $this->setParameter('sessionTimeout', $value);
116
    }
117
118
    public function getData()
119
    {
120
        $this->validate('merchantId', 'amount', 'currency');
121
122
        $formattedItems = [];
123
        $items = $this->getItems();
124
        if ($items) {
125
            foreach ($items as $item) {
126
                $itemPrice = $this->getItemPriceInteger($item);
127
                $formattedItems[] = [
128
                    'amountOfMoney' => [
129
                        'amount' => $item->getQuantity() * $itemPrice,
130
                        'currencyCode' => $this->getCurrency(),
131
                    ],
132
                    'orderLineDetails' => [
133
                        'productName' => $item->getName(),
134
                        'productPrice' => $itemPrice,
135
                        'quantity' => (int) $item->getQuantity(),
136
                    ],
137
                ];
138
            }
139
        }
140
141
        $data = [
142
            'cardPaymentMethodSpecificInput' => [
143
                'authorizationMode' => 'SALE',
144
                'transactionChannel' => 'ECOMMERCE',
145
            ],
146
            'hostedCheckoutSpecificInput' => [
147
                // if adding locale, validate locale against known formats
148
                // @see https://docs.direct.worldline-solutions.com/en/integration/basic-integration-methods/hosted-checkout-page#chooselanguageversion
149
                // 'locale' => 'en_UK',
150
                'returnUrl' => $this->getReturnUrl(),
151
            ],
152
            'order' => [
153
                'amountOfMoney' => [
154
                    'amount' => $this->getAmountInteger(),
155
                    'currencyCode' => $this->getCurrency(),
156
                ],
157
                'references' => [
158
                    'descriptor' => $this->getMerchantName(),
159
                    'merchantReference' => $this->getTransactionId(),
160
                ],
161
                'shoppingCart' => [
162
                    'items' => $formattedItems,
163
                ],
164
            ],
165
        ];
166
167
        if ($this->getAvailablePaymentProducts() !== null) {
168
            if (!isset($data['hostedCheckoutSpecificInput']['paymentProductFilters'])) {
169
                $data['hostedCheckoutSpecificInput']['paymentProductFilters'] = [];
170
            }
171
            $data['hostedCheckoutSpecificInput']['paymentProductFilters']['restrictTo'] = [
172
                'products' => $this->getAvailablePaymentProducts(),
173
            ];
174
        }
175
176
        if ($this->getExcludedPaymentProducts() !== null) {
177
            if (!isset($data['hostedCheckoutSpecificInput']['paymentProductFilters'])) {
178
                $data['hostedCheckoutSpecificInput']['paymentProductFilters'] = [];
179
            }
180
            $data['hostedCheckoutSpecificInput']['paymentProductFilters']['exclude'] = [
181
                'products' => $this->getExcludedPaymentProducts(),
182
            ];
183
        }
184
185
        if ($this->getShowResultPage() !== null) {
186
            $data['hostedCheckoutSpecificInput']['showResultPage'] = (bool) $this->getShowResultPage();
187
        }
188
189
        if ($this->getSessionTimeout() !== null) {
190
            $data['hostedCheckoutSpecificInput']['sessionTimeout'] = (int) $this->getSessionTimeout();
191
        }
192
193
        if ($this->getNotifyUrl() !== null) {
0 ignored issues
show
introduced by
The condition $this->getNotifyUrl() !== null is always true.
Loading history...
194
            $data['feedbacks'] = [
195
                'webhookUrl' => $this->getNotifyUrl(),
196
            ];
197
        }
198
199
        return $data;
200
    }
201
202
    public function getEndpoint()
203
    {
204
        return ($this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint).$this->getAction();
205
    }
206
207
    public function sendData($data)
208
    {
209
        $contentType = $this->requestMethod == 'POST' ? 'application/json; charset=utf-8' : '';
210
        $now = new DateTime('now', new DateTimeZone('GMT'));
211
        $dateTime = $now->format("D, d M Y H:i:s T");
212
        $endpointAction = $this->getAction();
213
214
        $message = $this->requestMethod."\n".$contentType."\n".$dateTime."\n".$endpointAction."\n";
215
        $signature = $this->createSignature($message, $this->getApiSecret());
216
217
        $headers = [
218
            'Content-Type' => $contentType,
219
            'Authorization' => 'GCS v1HMAC:'.$this->getApiKey().':'.$signature,
220
            'Date' => $dateTime,
221
        ];
222
223
        $body = json_encode($data);
224
225
        $httpResponse = $this->httpClient->request(
226
            $this->requestMethod,
227
            $this->getEndpoint(),
228
            $headers,
229
            $body
230
        );
231
232
        return $this->createResponse($httpResponse->getBody()->getContents());
233
    }
234
235
    protected function createResponse($data)
236
    {
237
        return $this->response = new PurchaseResponse($this, json_decode($data));
238
    }
239
240
    /**
241
     * Create signature hash used to verify messages
242
     *
243
     * @param string $message  The message to encrypt
244
     * @param string $key      The base64-encoded key used to encrypt the message
245
     *
246
     * @return string Generated signature
247
     */
248
    protected function createSignature($message, $key)
249
    {
250
        return base64_encode(hash_hmac('sha256', $message, $key, true));
251
    }
252
253
    protected function getAction()
254
    {
255
        return '/v2/'.$this->getMerchantId().'/hostedcheckouts';
256
    }
257
258
    /**
259
     * Get integer version (sallest unit) of item price
260
     *
261
     * Copied from {@see AbstractRequest::getAmountInteger()} & {@see AbstractRequest::getMoney()}
262
     */
263
    protected function getItemPriceInteger($item)
264
    {
265
        $currencyCode = $this->getCurrency() ?: 'USD';
266
        $currency = new Currency($currencyCode);
267
        $amount = $item->getPrice();
268
269
        $moneyParser = new DecimalMoneyParser($this->getCurrencies());
270
        $number = Number::fromString($amount);
271
        // Check for rounding that may occur if too many significant decimal digits are supplied.
272
        $decimal_count = strlen($number->getFractionalPart());
273
        $subunit = $this->getCurrencies()->subunitFor($currency);
274
        if ($decimal_count > $subunit) {
275
            throw new InvalidRequestException('Amount precision is too high for currency.');
276
        }
277
        $money = $moneyParser->parse((string) $number, $currency);
278
279
        return (int) $money->getAmount();
280
    }
281
}
282