1 | <?php |
||||
2 | |||||
3 | namespace Pronamic\WordPress\Pay\Gateways\Buckaroo; |
||||
4 | |||||
5 | use Pronamic\WordPress\Money\Money; |
||||
6 | use Pronamic\WordPress\Pay\Banks\BankAccountDetails; |
||||
7 | use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway; |
||||
8 | use Pronamic\WordPress\Pay\Core\PaymentMethods as Core_PaymentMethods; |
||||
9 | use Pronamic\WordPress\Pay\Payments\Payment; |
||||
10 | use Pronamic\WordPress\Pay\Payments\PaymentStatus; |
||||
11 | use WP_Error; |
||||
12 | |||||
13 | /** |
||||
14 | * Title: Buckaroo gateway |
||||
15 | * Description: |
||||
16 | * Copyright: 2005-2022 Pronamic |
||||
17 | * Company: Pronamic |
||||
18 | * |
||||
19 | * @author Remco Tolsma |
||||
20 | * @version 2.0.4 |
||||
21 | * @since 1.0.0 |
||||
22 | */ |
||||
23 | class Gateway extends Core_Gateway { |
||||
24 | /** |
||||
25 | * Constructs and initializes an Buckaroo gateway |
||||
26 | * |
||||
27 | * @param Config $config Config. |
||||
28 | */ |
||||
29 | public function __construct( Config $config ) { |
||||
30 | parent::__construct( $config ); |
||||
31 | |||||
32 | $this->set_method( self::METHOD_HTTP_REDIRECT ); |
||||
33 | |||||
34 | // Supported features. |
||||
35 | $this->supports = array( |
||||
36 | 'payment_status_request', |
||||
37 | 'refunds', |
||||
38 | 'webhook', |
||||
39 | 'webhook_log', |
||||
40 | 'webhook_no_config', |
||||
41 | ); |
||||
42 | } |
||||
43 | |||||
44 | /** |
||||
45 | * Get issuers. |
||||
46 | * |
||||
47 | * @since 1.2.4 |
||||
48 | * @see Core_Gateway::get_issuers() |
||||
49 | */ |
||||
50 | public function get_issuers() { |
||||
51 | $groups = array(); |
||||
52 | |||||
53 | // Check non-empty keys in configuration. |
||||
54 | if ( empty( $this->config->website_key ) || empty( $this->config->secret_key ) ) { |
||||
55 | return $groups; |
||||
56 | } |
||||
57 | |||||
58 | // Get iDEAL issuers. |
||||
59 | try { |
||||
60 | $object = $this->request( 'GET', 'Transaction/Specification/ideal?serviceVersion=2' ); |
||||
61 | } catch ( \Exception $e ) { |
||||
62 | $this->set_error( new WP_Error( 'buckaroo_error', $e->getMessage() ) ); |
||||
63 | |||||
64 | return $groups; |
||||
65 | } |
||||
66 | |||||
67 | if ( \property_exists( $object, 'Actions' ) ) { |
||||
68 | foreach ( $object->Actions as $action ) { |
||||
69 | // Check action name. |
||||
70 | if ( 'Pay' !== $action->Name ) { |
||||
71 | continue; |
||||
72 | } |
||||
73 | |||||
74 | foreach ( $action->RequestParameters as $request_parameter ) { |
||||
75 | // Check request parameter name. |
||||
76 | if ( 'issuer' !== $request_parameter->Name ) { |
||||
77 | continue; |
||||
78 | } |
||||
79 | |||||
80 | foreach ( $request_parameter->ListItemDescriptions as $item ) { |
||||
81 | // Make sure to add group. |
||||
82 | if ( ! array_key_exists( $item->GroupName, $groups ) ) { |
||||
83 | $groups[ $item->GroupName ] = array( |
||||
84 | 'name' => $item->GroupName, |
||||
85 | 'options' => array(), |
||||
86 | ); |
||||
87 | } |
||||
88 | |||||
89 | // Add issuer to group. |
||||
90 | $groups[ $item->GroupName ]['options'][ $item->Value ] = $item->Description; |
||||
91 | } |
||||
92 | } |
||||
93 | } |
||||
94 | } |
||||
95 | |||||
96 | return $groups; |
||||
97 | } |
||||
98 | |||||
99 | /** |
||||
100 | * Get supported payment methods |
||||
101 | * |
||||
102 | * @see Core_Gateway::get_supported_payment_methods() |
||||
103 | */ |
||||
104 | public function get_supported_payment_methods() { |
||||
105 | return array( |
||||
106 | Core_PaymentMethods::AMERICAN_EXPRESS, |
||||
107 | Core_PaymentMethods::BANK_TRANSFER, |
||||
108 | Core_PaymentMethods::BANCONTACT, |
||||
109 | Core_PaymentMethods::CREDIT_CARD, |
||||
110 | Core_PaymentMethods::GIROPAY, |
||||
111 | Core_PaymentMethods::IDEAL, |
||||
112 | Core_PaymentMethods::MAESTRO, |
||||
113 | Core_PaymentMethods::MASTERCARD, |
||||
114 | Core_PaymentMethods::PAYPAL, |
||||
115 | Core_PaymentMethods::SOFORT, |
||||
116 | Core_PaymentMethods::V_PAY, |
||||
117 | Core_PaymentMethods::VISA, |
||||
118 | ); |
||||
119 | } |
||||
120 | |||||
121 | /** |
||||
122 | * Start |
||||
123 | * |
||||
124 | * @param Payment $payment Payment. |
||||
125 | * |
||||
126 | * @see Core_Gateway::start() |
||||
127 | */ |
||||
128 | public function start( Payment $payment ) { |
||||
129 | /** |
||||
130 | * Currency. |
||||
131 | */ |
||||
132 | $currency_code = $payment->get_total_amount()->get_currency()->get_alphabetic_code(); |
||||
133 | |||||
134 | /** |
||||
135 | * Push URL. |
||||
136 | */ |
||||
137 | $push_url = \rest_url( Integration::REST_ROUTE_NAMESPACE . '/push' ); |
||||
138 | |||||
139 | /** |
||||
140 | * Filters the Buckaroo push URL. |
||||
141 | * |
||||
142 | * If you want to debug the Buckaroo report URL you can use this filter |
||||
143 | * to override the push URL. You could for example use a service like |
||||
144 | * https://webhook.site/ to inspect the push requests from Buckaroo. |
||||
145 | * |
||||
146 | * @param string $push_url Buckaroo push URL. |
||||
147 | */ |
||||
148 | $push_url = \apply_filters( 'pronamic_pay_buckaroo_push_url', $push_url ); |
||||
149 | |||||
150 | /** |
||||
151 | * JSON Transaction. |
||||
152 | * |
||||
153 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
154 | */ |
||||
155 | $data = (object) array( |
||||
156 | 'Currency' => $currency_code, |
||||
157 | /** |
||||
158 | * The debit amount for the request. This is in decimal format, |
||||
159 | * with a point as the decimal separator. For example, if the |
||||
160 | * currency is specified as EUR, sending “1” will mean that 1 euro |
||||
161 | * will be paid. “1.00” is also 1 euro. “0.01” means 1 cent. |
||||
162 | * Please note, a transaction must have either a debit amount or a |
||||
163 | * credit amount and it cannot have both. |
||||
164 | * |
||||
165 | * @link https://dev.buckaroo.nl/Apis |
||||
166 | */ |
||||
167 | 'AmountDebit' => $payment->get_total_amount()->number_format( null, '.', '' ), |
||||
168 | 'Description' => $payment->get_description(), |
||||
169 | 'Invoice' => Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment ), |
||||
170 | 'ReturnURL' => $payment->get_return_url(), |
||||
171 | 'ReturnURLCancel' => \add_query_arg( |
||||
172 | 'buckaroo_return_url_cancel', |
||||
173 | true, |
||||
174 | $payment->get_return_url() |
||||
175 | ), |
||||
176 | 'ReturnURLError' => \add_query_arg( |
||||
177 | 'buckaroo_return_url_error', |
||||
178 | true, |
||||
179 | $payment->get_return_url() |
||||
180 | ), |
||||
181 | 'ReturnURLReject' => \add_query_arg( |
||||
182 | 'buckaroo_return_url_reject', |
||||
183 | true, |
||||
184 | $payment->get_return_url() |
||||
185 | ), |
||||
186 | /** |
||||
187 | * Push URL. |
||||
188 | * |
||||
189 | * When provided, this push URL overrides all the push URLs as configured in the payment plaza under websites for the associated website key |
||||
190 | * |
||||
191 | * @link https://dev.buckaroo.nl/Apis |
||||
192 | */ |
||||
193 | 'PushURL' => $push_url, |
||||
194 | /** |
||||
195 | * Push URL Failure. |
||||
196 | * |
||||
197 | * When provided, this push URL overrides the push URL for failed transactions as configured in the payment plaza under websites for the associated website key. |
||||
198 | * |
||||
199 | * @link https://dev.buckaroo.nl/Apis |
||||
200 | */ |
||||
201 | 'PushURLFailure' => $push_url, |
||||
202 | /** |
||||
203 | * Services. |
||||
204 | * |
||||
205 | * Specifies which service (can be a payment method and/or additional service) is being called upon in the request. |
||||
206 | * |
||||
207 | * @link https://dev.buckaroo.nl/Apis |
||||
208 | */ |
||||
209 | 'Services' => (object) array( |
||||
210 | 'ServiceList' => array(), |
||||
211 | ), |
||||
212 | /** |
||||
213 | * Continue On Incomplete. |
||||
214 | * |
||||
215 | * Specifies if a redirecturl to a payment form will be returned to |
||||
216 | * which a customer should be sent if no paymentmethod is selected |
||||
217 | * or if any required parameter which the customer may provide is |
||||
218 | * missing or incorrect. Possible Values: |
||||
219 | * |
||||
220 | * · No: This is the default. The request will fail if not all the |
||||
221 | * needed information is provided. |
||||
222 | * |
||||
223 | * · RedirectToHTML: A redirect to the HTML gateway is provided if |
||||
224 | * a recoverable problems are detected in the request. The customer |
||||
225 | * can then provide the needed information there. |
||||
226 | * |
||||
227 | * @link https://dev.buckaroo.nl/Apis |
||||
228 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
229 | * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ContinueOnIncomplete |
||||
230 | */ |
||||
231 | 'ContinueOnIncomplete' => 'RedirectToHTML', |
||||
232 | /** |
||||
233 | * Services Excluded For Client. |
||||
234 | * |
||||
235 | * If no primary service is provided and ContinueOnIncomplete is |
||||
236 | * set, this list of comma separated servicescodes can be used to |
||||
237 | * limit the number of services from which the customer may choose |
||||
238 | * once he is redirected to the payment form. Services which are |
||||
239 | * entered in this field are not selectable. |
||||
240 | * This field is optional. |
||||
241 | * |
||||
242 | * @link https://dev.buckaroo.nl/Apis |
||||
243 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
244 | */ |
||||
245 | 'ServicesExcludedForClient' => $this->config->get_excluded_services(), |
||||
246 | /** |
||||
247 | * Custom parameters. |
||||
248 | * |
||||
249 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
250 | */ |
||||
251 | 'CustomParameters' => array( |
||||
252 | (object) array( |
||||
253 | 'Name' => 'pronamic_payment_id', |
||||
254 | 'Value' => $payment->get_id(), |
||||
255 | ), |
||||
256 | ), |
||||
257 | ); |
||||
258 | |||||
259 | /** |
||||
260 | * Client IP. |
||||
261 | * |
||||
262 | * In this field the IP address of the customer (or employee) for which |
||||
263 | * the action is being performed can be passed. Please note, If this |
||||
264 | * field is not sent to our gateway, your server IP address will be |
||||
265 | * used as the clientIP. This may result in unwanted behaviour for |
||||
266 | * anti-fraud checks. Also, certain payment methods perform checks on |
||||
267 | * the IP address, if an IP address is overused, the request could be |
||||
268 | * blocked. This field is sent in the following format, where |
||||
269 | * type 0 = IPv4 and type 1 = IPv6: |
||||
270 | * "ClientIP": { "Type": 0, "Address": "0.0.0.0" }, |
||||
271 | * |
||||
272 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
273 | * @link https://stackoverflow.com/questions/1448871/how-to-know-which-version-of-the-internet-protocol-ip-a-client-is-using-when-c/1448901 |
||||
274 | */ |
||||
275 | $customer = $payment->get_customer(); |
||||
276 | |||||
277 | if ( null !== $customer ) { |
||||
278 | $ip_address = $customer->get_ip_address(); |
||||
279 | |||||
280 | if ( null !== $ip_address ) { |
||||
281 | $data->ClientIP = (object) array( |
||||
282 | 'Type' => false === \strpos( $ip_address, ':' ) ? 0 : 1, |
||||
283 | 'Address' => $ip_address, |
||||
284 | ); |
||||
285 | } |
||||
286 | } |
||||
287 | |||||
288 | /** |
||||
289 | * Payment method. |
||||
290 | * |
||||
291 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
292 | * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServicesRequest |
||||
293 | * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=ServiceRequest |
||||
294 | */ |
||||
295 | switch ( $payment->get_payment_method() ) { |
||||
296 | /** |
||||
297 | * Payment method American Express. |
||||
298 | * |
||||
299 | * @link |
||||
300 | */ |
||||
301 | case Core_PaymentMethods::AMERICAN_EXPRESS: |
||||
302 | $data->Services->ServiceList[] = (object) array( |
||||
303 | 'Action' => 'Pay', |
||||
304 | 'Name' => PaymentMethods::AMERICAN_EXPRESS, |
||||
305 | ); |
||||
306 | |||||
307 | break; |
||||
308 | /** |
||||
309 | * Payment method creditcard. |
||||
310 | * |
||||
311 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#pay |
||||
312 | */ |
||||
313 | case Core_PaymentMethods::CREDIT_CARD: |
||||
314 | $data->Services->ServiceList[] = (object) array( |
||||
315 | 'Action' => 'Pay', |
||||
316 | 'Name' => PaymentMethods::AMERICAN_EXPRESS, |
||||
317 | ); |
||||
318 | |||||
319 | $data->Services->ServiceList[] = (object) array( |
||||
320 | 'Action' => 'Pay', |
||||
321 | 'Name' => PaymentMethods::MAESTRO, |
||||
322 | ); |
||||
323 | |||||
324 | $data->Services->ServiceList[] = (object) array( |
||||
325 | 'Action' => 'Pay', |
||||
326 | 'Name' => PaymentMethods::MASTERCARD, |
||||
327 | ); |
||||
328 | |||||
329 | $data->Services->ServiceList[] = (object) array( |
||||
330 | 'Action' => 'Pay', |
||||
331 | 'Name' => PaymentMethods::VISA, |
||||
332 | ); |
||||
333 | |||||
334 | break; |
||||
335 | /** |
||||
336 | * Payment method iDEAL. |
||||
337 | * |
||||
338 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal#pay |
||||
339 | */ |
||||
340 | case Core_PaymentMethods::IDEAL: |
||||
341 | $data->Services->ServiceList[] = (object) array( |
||||
342 | 'Action' => 'Pay', |
||||
343 | 'Name' => 'ideal', |
||||
344 | 'Parameters' => array( |
||||
345 | array( |
||||
346 | 'Name' => 'issuer', |
||||
347 | 'Value' => $payment->get_meta( 'issuer' ), |
||||
348 | ), |
||||
349 | ), |
||||
350 | ); |
||||
351 | |||||
352 | break; |
||||
353 | /** |
||||
354 | * Payment method transfer. |
||||
355 | * |
||||
356 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/transfer#pay |
||||
357 | */ |
||||
358 | case Core_PaymentMethods::BANK_TRANSFER: |
||||
359 | $data->Services->ServiceList[] = (object) array( |
||||
360 | 'Action' => 'Pay', |
||||
361 | 'Name' => 'transfer', |
||||
362 | ); |
||||
363 | |||||
364 | break; |
||||
365 | /** |
||||
366 | * Payment method Bancontact. |
||||
367 | * |
||||
368 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/bancontact#pay |
||||
369 | */ |
||||
370 | case Core_PaymentMethods::BANCONTACT: |
||||
371 | case Core_PaymentMethods::MISTER_CASH: |
||||
372 | $data->Services->ServiceList[] = (object) array( |
||||
373 | 'Action' => 'Pay', |
||||
374 | 'Name' => 'bancontactmrcash', |
||||
375 | ); |
||||
376 | |||||
377 | break; |
||||
378 | /** |
||||
379 | * Payment method Maestro. |
||||
380 | * |
||||
381 | * @link |
||||
382 | */ |
||||
383 | case Core_PaymentMethods::MAESTRO: |
||||
384 | $data->Services->ServiceList[] = (object) array( |
||||
385 | 'Action' => 'Pay', |
||||
386 | 'Name' => PaymentMethods::MAESTRO, |
||||
387 | ); |
||||
388 | |||||
389 | break; |
||||
390 | /** |
||||
391 | * Payment method Mastercard. |
||||
392 | * |
||||
393 | * @link |
||||
394 | */ |
||||
395 | case Core_PaymentMethods::MASTERCARD: |
||||
396 | $data->Services->ServiceList[] = (object) array( |
||||
397 | 'Action' => 'Pay', |
||||
398 | 'Name' => PaymentMethods::MASTERCARD, |
||||
399 | ); |
||||
400 | |||||
401 | break; |
||||
402 | /** |
||||
403 | * Payment method Giropay. |
||||
404 | * |
||||
405 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/giropay#pay |
||||
406 | */ |
||||
407 | case Core_PaymentMethods::GIROPAY: |
||||
408 | $data->Services->ServiceList[] = (object) array( |
||||
409 | 'Action' => 'Pay', |
||||
410 | 'Name' => 'giropay', |
||||
411 | ); |
||||
412 | |||||
413 | break; |
||||
414 | /** |
||||
415 | * Payment method PayPal. |
||||
416 | * |
||||
417 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/paypal#pay |
||||
418 | */ |
||||
419 | case Core_PaymentMethods::PAYPAL: |
||||
420 | $data->Services->ServiceList[] = (object) array( |
||||
421 | 'Action' => 'Pay', |
||||
422 | 'Name' => 'paypal', |
||||
423 | ); |
||||
424 | |||||
425 | break; |
||||
426 | /** |
||||
427 | * Payment method Sofort. |
||||
428 | * |
||||
429 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort#pay |
||||
430 | */ |
||||
431 | case Core_PaymentMethods::SOFORT: |
||||
432 | $data->Services->ServiceList[] = (object) array( |
||||
433 | 'Action' => 'Pay', |
||||
434 | 'Name' => 'sofortueberweisung', |
||||
435 | ); |
||||
436 | |||||
437 | break; |
||||
438 | /** |
||||
439 | * Payment method V PAY. |
||||
440 | * |
||||
441 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#top |
||||
442 | */ |
||||
443 | case Core_PaymentMethods::V_PAY: |
||||
444 | $data->Services->ServiceList[] = (object) array( |
||||
445 | 'Action' => 'Pay', |
||||
446 | 'Name' => PaymentMethods::V_PAY, |
||||
447 | ); |
||||
448 | |||||
449 | break; |
||||
450 | /** |
||||
451 | * Payment method Visa. |
||||
452 | * |
||||
453 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/creditcards#top |
||||
454 | */ |
||||
455 | case Core_PaymentMethods::VISA: |
||||
456 | $data->Services->ServiceList[] = (object) array( |
||||
457 | 'Action' => 'Pay', |
||||
458 | 'Name' => PaymentMethods::VISA, |
||||
459 | ); |
||||
460 | |||||
461 | break; |
||||
462 | } |
||||
463 | |||||
464 | /** |
||||
465 | * Request. |
||||
466 | */ |
||||
467 | $object = $this->request( 'POST', 'Transaction', $data ); |
||||
468 | |||||
469 | /** |
||||
470 | * Buckaroo keys. |
||||
471 | * |
||||
472 | * @link https://testcheckout.buckaroo.nl/json/Docs/ResourceModel?modelName=TransactionResponse |
||||
473 | */ |
||||
474 | if ( \property_exists( $object, 'Key' ) ) { |
||||
475 | $payment->set_transaction_id( $object->Key ); |
||||
476 | } |
||||
477 | |||||
478 | if ( \property_exists( $object, 'PaymentKey' ) ) { |
||||
479 | $payment->set_meta( 'buckaroo_transaction_payment_key', $object->PaymentKey ); |
||||
480 | } |
||||
481 | |||||
482 | /** |
||||
483 | * Request Errors. |
||||
484 | * |
||||
485 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/POST-json-Transaction |
||||
486 | */ |
||||
487 | if ( \property_exists( $object, 'RequestErrors' ) && null !== $object->RequestErrors ) { |
||||
488 | $exception = null; |
||||
489 | |||||
490 | foreach ( $object->RequestErrors as $errors ) { |
||||
491 | foreach ( $errors as $error ) { |
||||
492 | // Add exception. |
||||
493 | $exception = new \Exception( $error->ErrorMessage, 0, $exception ); |
||||
494 | } |
||||
495 | } |
||||
496 | |||||
497 | if ( null !== $exception ) { |
||||
498 | throw $exception; |
||||
499 | } |
||||
500 | } |
||||
501 | |||||
502 | /** |
||||
503 | * Required Action. |
||||
504 | */ |
||||
505 | if ( null !== $object->RequiredAction ) { |
||||
506 | if ( 'Redirect' !== $object->RequiredAction->Name ) { |
||||
507 | throw new \Exception( |
||||
508 | \sprintf( |
||||
509 | 'Unsupported Buckaroo action: %s', |
||||
510 | $object->RequiredAction->Name |
||||
511 | ) |
||||
512 | ); |
||||
513 | } |
||||
514 | |||||
515 | // Set action URL. |
||||
516 | if ( \property_exists( $object->RequiredAction, 'RedirectURL' ) ) { |
||||
517 | $payment->set_action_url( $object->RequiredAction->RedirectURL ); |
||||
518 | } |
||||
519 | } |
||||
520 | |||||
521 | // Failure. |
||||
522 | if ( \property_exists( $object, 'Status' ) && \property_exists( $object->Status, 'Code' ) ) { |
||||
523 | $status = Statuses::transform( (string) $object->Status->Code->Code ); |
||||
524 | |||||
525 | if ( PaymentStatus::FAILURE === $status ) { |
||||
526 | throw new \Exception( |
||||
527 | \sprintf( |
||||
528 | /* translators: 1: payment provider name, 2: status message, 3: status sub message*/ |
||||
529 | __( 'Unable to create payment at gateway: %1$s%2$s', 'pronamic_ideal' ), |
||||
530 | $object->Status->Code->Description, |
||||
531 | \property_exists( $object->Status, 'SubCode' ) ? ' – ' . $object->Status->SubCode->Description : '' |
||||
532 | ) |
||||
533 | ); |
||||
534 | } |
||||
535 | } |
||||
536 | } |
||||
537 | |||||
538 | /** |
||||
539 | * JSON API Request. |
||||
540 | * |
||||
541 | * @param string $method HTTP request method. |
||||
542 | * @param string $endpoint JSON API endpoint. |
||||
543 | * @param object|null $data Data. |
||||
544 | * @return object |
||||
545 | */ |
||||
546 | public function request( $method, $endpoint, $data = null ) { |
||||
547 | $host = 'checkout.buckaroo.nl'; |
||||
548 | |||||
549 | if ( self::MODE_TEST === $this->config->mode ) { |
||||
550 | $host = 'testcheckout.buckaroo.nl'; |
||||
551 | } |
||||
552 | |||||
553 | /** |
||||
554 | * Authentication. |
||||
555 | * |
||||
556 | * The HMAC SHA256 is calculated over a concatenated string (as raw data/binary/bytes) of the following values: WebsiteKey, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String. See the next table for more information about these values. Please note: the Base64 hash should be a string of 44 characters. If yours is longer, it is probably in hexadecimal format. |
||||
557 | * |
||||
558 | * @link https://dev.buckaroo.nl/Apis/Description/json |
||||
559 | * @link https://testcheckout.buckaroo.nl/json/Docs/Authentication |
||||
560 | */ |
||||
561 | $website_key = $this->config->website_key; |
||||
562 | $request_http_method = $method; |
||||
563 | $request_uri = $host . '/json/' . $endpoint; |
||||
564 | $request_timestamp = \strval( \time() ); |
||||
565 | $nonce = \wp_generate_password( 32 ); |
||||
566 | $request_content = null === $data ? '' : \wp_json_encode( $data ); |
||||
567 | |||||
568 | $values = \implode( |
||||
569 | '', |
||||
570 | array( |
||||
571 | $website_key, |
||||
572 | $request_http_method, |
||||
573 | \strtolower( \rawurlencode( $request_uri ) ), |
||||
574 | $request_timestamp, |
||||
575 | $nonce, |
||||
576 | // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode |
||||
577 | null === $data ? '' : \base64_encode( \md5( (string) $request_content, true ) ), |
||||
578 | ) |
||||
579 | ); |
||||
580 | |||||
581 | $hash = \hash_hmac( 'sha256', $values, $this->config->secret_key, true ); |
||||
582 | |||||
583 | // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode |
||||
584 | $hmac = \base64_encode( $hash ); |
||||
585 | |||||
586 | $authorization = \sprintf( |
||||
587 | 'hmac %s:%s:%s:%s', |
||||
588 | $this->config->website_key, |
||||
589 | $hmac, |
||||
590 | $nonce, |
||||
591 | $request_timestamp |
||||
592 | ); |
||||
593 | |||||
594 | $response = \Pronamic\WordPress\Http\Facades\Http::request( |
||||
595 | 'https://' . $request_uri, |
||||
596 | array( |
||||
597 | 'method' => $request_http_method, |
||||
598 | 'headers' => array( |
||||
599 | 'Authorization' => $authorization, |
||||
600 | 'Content-Type' => 'application/json', |
||||
601 | ), |
||||
602 | 'body' => $request_content, |
||||
603 | ) |
||||
604 | ); |
||||
605 | |||||
606 | try { |
||||
607 | $object = $response->json(); |
||||
608 | } catch ( \Exception $e ) { |
||||
609 | // JSON error. |
||||
610 | $json_error = \json_last_error(); |
||||
611 | |||||
612 | // Check authorization error. |
||||
613 | if ( \JSON_ERROR_NONE !== $json_error && 400 === $response->status() ) { |
||||
614 | throw new \Exception( $response->body() ); |
||||
615 | } |
||||
616 | |||||
617 | // Re-throw original response exception. |
||||
618 | throw $e; |
||||
619 | } |
||||
620 | |||||
621 | /** |
||||
622 | * OK. |
||||
623 | */ |
||||
624 | return $object; |
||||
625 | } |
||||
626 | |||||
627 | /** |
||||
628 | * Update status of the specified payment |
||||
629 | * |
||||
630 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-Status-transactionKey |
||||
631 | * @param Payment $payment Payment. |
||||
632 | */ |
||||
633 | public function update_status( Payment $payment ) { |
||||
634 | $transaction_key = $payment->get_transaction_id(); |
||||
635 | |||||
636 | if ( empty( $transaction_key ) ) { |
||||
637 | return; |
||||
638 | } |
||||
639 | |||||
640 | $result = $this->request( 'GET', 'Transaction/Status/' . $transaction_key ); |
||||
641 | |||||
642 | $payment->set_status( Statuses::transform( \strval( $result->Status->Code->Code ) ) ); |
||||
643 | |||||
644 | /** |
||||
645 | * Consumer bank details. |
||||
646 | */ |
||||
647 | $consumer_bank_details = $payment->get_consumer_bank_details(); |
||||
648 | |||||
649 | if ( null === $consumer_bank_details ) { |
||||
650 | $consumer_bank_details = new BankAccountDetails(); |
||||
651 | |||||
652 | $payment->set_consumer_bank_details( $consumer_bank_details ); |
||||
653 | } |
||||
654 | |||||
655 | /** |
||||
656 | * Services. |
||||
657 | */ |
||||
658 | foreach ( $result->Services as $service ) { |
||||
659 | foreach ( $service->Parameters as $parameter ) { |
||||
660 | if ( 'consumerName' === $parameter->Name ) { |
||||
661 | $consumer_bank_details->set_name( $parameter->Value ); |
||||
662 | } |
||||
663 | |||||
664 | if ( \in_array( |
||||
665 | $parameter->Name, |
||||
666 | array( |
||||
667 | /** |
||||
668 | * Payment method iDEAL. |
||||
669 | * |
||||
670 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal |
||||
671 | */ |
||||
672 | 'consumerIBAN', |
||||
673 | /** |
||||
674 | * Payment method Sofort. |
||||
675 | * |
||||
676 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort |
||||
677 | */ |
||||
678 | 'CustomerIBAN', |
||||
679 | ), |
||||
680 | true |
||||
681 | ) ) { |
||||
682 | $consumer_bank_details->set_iban( $parameter->Value ); |
||||
683 | } |
||||
684 | |||||
685 | if ( \in_array( |
||||
686 | $parameter->Name, |
||||
687 | array( |
||||
688 | /** |
||||
689 | * Payment method iDEAL. |
||||
690 | * |
||||
691 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/ideal |
||||
692 | */ |
||||
693 | 'consumerName', |
||||
694 | /** |
||||
695 | * Payment method Sofort. |
||||
696 | * |
||||
697 | * @link https://dev.buckaroo.nl/PaymentMethods/Description/sofort |
||||
698 | */ |
||||
699 | 'CustomerBIC', |
||||
700 | ), |
||||
701 | true |
||||
702 | ) ) { |
||||
703 | $consumer_bank_details->set_bic( $parameter->Value ); |
||||
704 | } |
||||
705 | } |
||||
706 | } |
||||
707 | |||||
708 | /** |
||||
709 | * Refunds. |
||||
710 | * |
||||
711 | * @link https://testcheckout.buckaroo.nl/json/Docs/Api/GET-json-Transaction-RefundInfo-transactionKey |
||||
712 | */ |
||||
713 | $result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_key ); |
||||
714 | |||||
715 | if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) { |
||||
716 | $refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency ); |
||||
717 | |||||
718 | $payment->set_refunded_amount( $refunded_amount ); |
||||
719 | } |
||||
720 | } |
||||
721 | |||||
722 | /** |
||||
723 | * Create refund. |
||||
724 | * |
||||
725 | * @param string $transaction_id Transaction ID. |
||||
726 | * @param Money $amount Amount to refund. |
||||
727 | * @param string $description Refund reason. |
||||
728 | * @return null|string |
||||
729 | */ |
||||
730 | public function create_refund( $transaction_id, Money $amount, $description = null ) { |
||||
0 ignored issues
–
show
|
|||||
731 | $original_transaction = $this->request( 'GET', 'Transaction/Status/' . $transaction_id ); |
||||
732 | |||||
733 | if ( ! \is_object( $original_transaction ) ) { |
||||
734 | throw new \Exception( |
||||
735 | sprintf( |
||||
736 | /* translators: %s: transaction key */ |
||||
737 | __( 'Unable to create refund for transaction with transaction key: %s', 'pronamic_ideal' ), |
||||
738 | $transaction_id |
||||
739 | ) |
||||
740 | ); |
||||
741 | } |
||||
742 | |||||
743 | $service_name = Util::get_transaction_service( $original_transaction ); |
||||
744 | |||||
745 | if ( null === $service_name ) { |
||||
746 | throw new \Exception( |
||||
747 | sprintf( |
||||
748 | /* translators: %s: transaction key */ |
||||
749 | __( 'Unable to create refund for transaction without service name. Transaction key: %s', 'pronamic_ideal' ), |
||||
750 | $transaction_id |
||||
751 | ) |
||||
752 | ); |
||||
753 | } |
||||
754 | |||||
755 | // Invoice. |
||||
756 | $payment = \get_pronamic_payment_by_transaction_id( $transaction_id ); |
||||
757 | |||||
758 | $invoice = null; |
||||
759 | |||||
760 | if ( null !== $payment ) { |
||||
761 | $invoice = Util::get_invoice_number( (string) $this->config->get_invoice_number(), $payment ); |
||||
762 | } |
||||
763 | |||||
764 | // Refund request. |
||||
765 | $data = (object) array( |
||||
766 | 'Channel' => 'Web', |
||||
767 | 'Currency' => $amount->get_currency()->get_alphabetic_code(), |
||||
768 | /** |
||||
769 | * The credit amount for the request. This is in decimal format, |
||||
770 | * with a point as the decimal separator. For example, if the |
||||
771 | * currency is specified as EUR, sending “1” will mean that 1 euro |
||||
772 | * will be paid. “1.00” is also 1 euro. “0.01” means 1 cent. |
||||
773 | * Please note, a transaction must have either a debit amount or a |
||||
774 | * credit amount and it cannot have both. |
||||
775 | * |
||||
776 | * @link https://dev.buckaroo.nl/Apis |
||||
777 | */ |
||||
778 | 'AmountCredit' => $amount->format( null, '.', '' ), |
||||
0 ignored issues
–
show
The call to
Pronamic\WordPress\Money\Money::format() has too many arguments starting with '.' .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||
779 | 'Invoice' => $invoice, |
||||
780 | 'OriginalTransactionKey' => $transaction_id, |
||||
781 | 'Services' => array( |
||||
782 | 'ServiceList' => array( |
||||
783 | array( |
||||
784 | 'Name' => $service_name, |
||||
785 | 'Action' => 'Refund', |
||||
786 | ), |
||||
787 | ), |
||||
788 | ), |
||||
789 | ); |
||||
790 | |||||
791 | $refund = $this->request( 'POST', 'Transaction', $data ); |
||||
792 | |||||
793 | // Check refund object. |
||||
794 | if ( ! \is_object( $refund ) ) { |
||||
795 | return null; |
||||
796 | } |
||||
797 | |||||
798 | // Check refund status. |
||||
799 | if ( \property_exists( $refund, 'Status' ) && \property_exists( $refund->Status, 'Code' ) ) { |
||||
800 | $status = Statuses::transform( (string) $refund->Status->Code->Code ); |
||||
801 | |||||
802 | if ( PaymentStatus::SUCCESS !== $status ) { |
||||
803 | throw new \Exception( |
||||
804 | \sprintf( |
||||
805 | /* translators: 1: payment provider name, 2: status message, 3: status sub message*/ |
||||
806 | __( 'Unable to create refund at %1$s gateway: %2$s%3$s', 'pronamic_ideal' ), |
||||
807 | __( 'Buckaroo', 'pronamic_ideal' ), |
||||
808 | $refund->Status->Code->Description, |
||||
809 | \property_exists( $refund->Status, 'SubCode' ) ? ' – ' . $refund->Status->SubCode->Description : '' |
||||
810 | ) |
||||
811 | ); |
||||
812 | } |
||||
813 | } |
||||
814 | |||||
815 | // Update payment refunded amount. |
||||
816 | if ( null !== $payment ) { |
||||
817 | $result = $this->request( 'GET', 'Transaction/RefundInfo/' . $transaction_id ); |
||||
818 | |||||
819 | if ( \property_exists( $result, 'RefundedAmount' ) && ! empty( $result->RefundedAmount ) ) { |
||||
820 | $refunded_amount = new Money( $result->RefundedAmount, $result->RefundCurrency ); |
||||
821 | |||||
822 | $payment->set_refunded_amount( $refunded_amount ); |
||||
823 | } |
||||
824 | } |
||||
825 | |||||
826 | // Return. |
||||
827 | $refund_id = \property_exists( $refund, 'Key' ) ? $refund->Key : null; |
||||
828 | |||||
829 | return $refund_id; |
||||
830 | } |
||||
831 | } |
||||
832 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.