Failed Conditions
Push — develop ( 0344f1...06c8da )
by Reüel
06:40
created

src/Gateway.php (4 issues)

1
<?php
2
/**
3
 * Gateway
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Payments
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Sisow;
12
13
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
14
use Pronamic\WordPress\Pay\Core\PaymentMethods;
15
use Pronamic\WordPress\Pay\Core\Util as Core_Util;
16
use Pronamic\WordPress\Pay\Payments\BankAccountDetails;
0 ignored issues
show
The type Pronamic\WordPress\Pay\Payments\BankAccountDetails 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 Pronamic\WordPress\Pay\Payments\PaymentStatus as Core_Statuses;
18
use Pronamic\WordPress\Pay\Payments\Payment;
19
use Pronamic\WordPress\Pay\Payments\PaymentLineType;
20
21
/**
22
 * Title: Sisow gateway
23
 * Description:
24
 * Copyright: 2005-2019 Pronamic
25
 * Company: Pronamic
26
 *
27
 * @author  Remco Tolsma
28
 * @version 2.0.3
29
 * @since   1.0.0
30
 */
31
class Gateway extends Core_Gateway {
32
	/**
33
	 * Client.
34
	 *
35
	 * @var Client
36
	 */
37
	protected $client;
38
39
	/**
40
	 * Constructs and initialize an Sisow gateway
41
	 *
42
	 * @param Config $config Config.
43
	 */
44
	public function __construct( Config $config ) {
45
		parent::__construct( $config );
46
47
		$this->set_method( self::METHOD_HTTP_REDIRECT );
48
49
		// Supported features.
50
		$this->supports = array(
51
			'payment_status_request',
52
			'reservation_payments',
53
		);
54
55
		// Client.
56
		$this->client = new Client( $config->merchant_id, $config->merchant_key );
57
		$this->client->set_test_mode( self::MODE_TEST === $config->mode );
58
	}
59
60
	/**
61
	 * Get issuers
62
	 *
63
	 * @see Core_Gateway::get_issuers()
64
	 */
65
	public function get_issuers() {
66
		$groups = array();
67
68
		$result = $this->client->get_directory();
69
70
		if ( $result ) {
71
			$groups[] = array(
72
				'options' => $result,
73
			);
74
		} else {
75
			$this->error = $this->client->get_error();
0 ignored issues
show
The method get_error() does not exist on Pronamic\WordPress\Pay\Gateways\Sisow\Client. ( Ignorable by Annotation )

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

75
			/** @scrutinizer ignore-call */ 
76
   $this->error = $this->client->get_error();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
76
		}
77
78
		return $groups;
79
	}
80
81
	/**
82
	 * Get available payment methods.
83
	 *
84
	 * @see Core_Gateway::get_available_payment_methods()
85
	 */
86
	public function get_available_payment_methods() {
87
		if ( self::MODE_TEST === $this->config->mode ) {
88
			return null;
89
		}
90
91
		$payment_methods = array();
92
93
		// Merchant request.
94
		$request = new MerchantRequest( $this->config->merchant_id );
95
96
		// Get merchant.
97
		try {
98
			$result = $this->client->get_merchant( $request );
99
		} catch ( \Exception $e ) {
100
			$this->error = new \WP_Error( 'sisow_error', $e->getMessage() );
101
102
			return $payment_methods;
103
		}
104
105
		foreach ( $result->payments as $method ) {
106
			// Transform to WordPress payment methods.
107
			$payment_method = Methods::transform_gateway_method( $method );
108
109
			if ( $payment_method ) {
110
				$payment_methods[] = $payment_method;
111
			}
112
		}
113
114
		/**
115
		 * Add active payment methods which are not returned by Sisow in merchant response.
116
		 *
117
		 * @link https://github.com/wp-pay-gateways/sisow/issues/1
118
		 */
119
		if ( false !== \array_search( PaymentMethods::IDEAL, $payment_methods, true ) ) {
120
			$payment_methods[] = PaymentMethods::BANCONTACT;
121
			$payment_methods[] = PaymentMethods::BANK_TRANSFER;
122
			$payment_methods[] = PaymentMethods::BELFIUS;
123
			$payment_methods[] = PaymentMethods::BUNQ;
124
			$payment_methods[] = PaymentMethods::EPS;
125
			$payment_methods[] = PaymentMethods::GIROPAY;
126
			$payment_methods[] = PaymentMethods::IDEALQR;
127
			$payment_methods[] = PaymentMethods::KBC;
128
			$payment_methods[] = PaymentMethods::SOFORT;
129
130
			$payment_methods = \array_unique( $payment_methods );
131
132
			// Renumber keys.
133
			$payment_methods = \array_values( $payment_methods );
134
		}
135
136
		return $payment_methods;
137
	}
138
139
	/**
140
	 * Get supported payment methods
141
	 *
142
	 * @see Pronamic_WP_Pay_Gateway::get_supported_payment_methods()
143
	 */
144
	public function get_supported_payment_methods() {
145
		return array(
146
			PaymentMethods::AFTERPAY,
147
			PaymentMethods::BANK_TRANSFER,
148
			PaymentMethods::BANCONTACT,
149
			PaymentMethods::BELFIUS,
150
			PaymentMethods::BILLINK,
151
			PaymentMethods::BUNQ,
152
			PaymentMethods::CAPAYABLE,
153
			PaymentMethods::IN3,
154
			PaymentMethods::CREDIT_CARD,
155
			PaymentMethods::FOCUM,
156
			PaymentMethods::GIROPAY,
157
			PaymentMethods::IDEAL,
158
			PaymentMethods::IDEALQR,
159
			PaymentMethods::KLARNA_PAY_LATER,
160
			PaymentMethods::PAYPAL,
161
			PaymentMethods::SOFORT,
162
		);
163
	}
164
165
	/**
166
	 * Is payment method required to start transaction?
167
	 *
168
	 * @see Core_Gateway::payment_method_is_required()
169
	 */
170
	public function payment_method_is_required() {
171
		return true;
172
	}
173
174
	/**
175
	 * Start
176
	 *
177
	 * @param Payment $payment Payment.
178
	 *
179
	 * @throws \Exception Throws exception on transaction error.
180
	 * @see Core_Gateway::start()
181
	 */
182
	public function start( Payment $payment ) {
183
		// Order and purchase ID.
184
		$order_id    = $payment->get_order_id();
185
		$purchase_id = strval( empty( $order_id ) ? $payment->get_id() : $order_id );
186
187
		// Maximum length for purchase ID is 16 characters, otherwise an error will occur:
188
		// ideal_sisow_error - purchaseid too long (16).
189
		$purchase_id = substr( $purchase_id, 0, 16 );
190
191
		// New transaction request.
192
		$request = new TransactionRequest(
193
			$this->config->merchant_id,
194
			$this->config->shop_id
195
		);
196
197
		$request->merge_parameters(
198
			array(
199
				'payment'      => Methods::transform( $payment->get_method(), $payment->get_method() ),
200
				'purchaseid'   => substr( $purchase_id, 0, 16 ),
201
				'entrancecode' => $payment->get_entrance_code(),
202
				'amount'       => $payment->get_total_amount()->get_cents(),
203
				'description'  => substr( $payment->get_description(), 0, 32 ),
204
				'testmode'     => ( self::MODE_TEST === $this->config->mode ) ? 'true' : 'false',
205
				'returnurl'    => $payment->get_return_url(),
206
				'cancelurl'    => $payment->get_return_url(),
207
				'notifyurl'    => $payment->get_return_url(),
208
				'callbackurl'  => $payment->get_return_url(),
209
				// Other parameters.
210
				'issuerid'     => $payment->get_issuer(),
211
				'billing_mail' => $payment->get_email(),
212
			)
213
		);
214
215
		// Payment method.
216
		$this->set_payment_method( null === $payment->get_method() ? PaymentMethods::IDEAL : $payment->get_method() );
217
218
		// Additional parameters for payment method.
219
		if ( PaymentMethods::IDEALQR === $payment->get_method() ) {
220
			$request->set_parameter( 'qrcode', 'true' );
221
		}
222
223
		// Customer.
224
		if ( null !== $payment->get_customer() ) {
225
			$customer = $payment->get_customer();
226
227
			$request->merge_parameters(
228
				array(
229
					'ipaddress' => $customer->get_ip_address(),
230
					'gender'    => $customer->get_gender(),
231
				)
232
			);
233
234
			if ( null !== $customer->get_locale() ) {
235
				/*
236
				 * @link https://github.com/wp-pay-gateways/sisow/tree/feature/post-pay/documentation#parameter-locale
237
				 */
238
				$sisow_locale = strtoupper( substr( $customer->get_locale(), -2 ) );
239
240
				$request->set_parameter( 'locale', $sisow_locale );
241
			}
242
243
			if ( null !== $customer->get_birth_date() ) {
244
				$request->set_parameter( 'birthdate', $customer->get_birth_date()->format( 'dmY' ) );
245
			}
246
		}
247
248
		// Billing address.
249
		if ( null !== $payment->get_billing_address() ) {
250
			$address = $payment->get_billing_address();
251
252
			if ( null !== $address->get_name() ) {
253
				$name = $address->get_name();
254
255
				$request->merge_parameters(
256
					array(
257
						'billing_firstname' => $name->get_first_name(),
258
						'billing_lastname'  => $name->get_last_name(),
259
					)
260
				);
261
262
				// Remove accents from first name for AfterPay.
263
				if ( PaymentMethods::AFTERPAY === $payment->get_method() ) {
264
					$request->set_parameter( 'billing_firstname', remove_accents( $name->get_first_name() ) );
265
				}
266
			}
267
268
			$request->merge_parameters(
269
				array(
270
					'billing_mail'        => $address->get_email(),
271
					'billing_company'     => $address->get_company_name(),
272
					'billing_coc'         => $address->get_coc_number(),
273
					'billing_address1'    => $address->get_line_1(),
274
					'billing_address2'    => $address->get_line_2(),
275
					'billing_zip'         => $address->get_postal_code(),
276
					'billing_city'        => $address->get_city(),
277
					'billing_country'     => $address->get_country_name(),
278
					'billing_countrycode' => $address->get_country_code(),
279
					'billing_phone'       => $address->get_phone(),
280
				)
281
			);
282
		}
283
284
		// Shipping address.
285
		if ( null !== $payment->get_shipping_address() ) {
286
			$address = $payment->get_shipping_address();
287
288
			if ( null !== $address->get_name() ) {
289
				$name = $address->get_name();
290
291
				$request->merge_parameters(
292
					array(
293
						'shipping_firstname' => $name->get_first_name(),
294
						'shipping_lastname'  => $name->get_last_name(),
295
					)
296
				);
297
			}
298
299
			$request->merge_parameters(
300
				array(
301
					'shipping_mail'        => $address->get_email(),
302
					'shipping_company'     => $address->get_company_name(),
303
					'shipping_address1'    => $address->get_line_1(),
304
					'shipping_address2'    => $address->get_line_2(),
305
					'shipping_zip'         => $address->get_postal_code(),
306
					'shipping_city'        => $address->get_city(),
307
					'shipping_country'     => $address->get_country_name(),
308
					'shipping_countrycode' => $address->get_country_code(),
309
					'shipping_phone'       => $address->get_phone(),
310
				)
311
			);
312
		}
313
314
		// Lines.
315
		$lines = $payment->get_lines();
316
317
		if ( null !== $lines ) {
318
			$x = 1;
319
320
			foreach ( $lines as $line ) {
321
				// Product ID.
322
				$product_id = $line->get_id();
323
324
				switch ( $line->get_type() ) {
325
					case PaymentLineType::SHIPPING:
326
						$product_id = 'shipping';
327
328
						break;
329
					case PaymentLineType::FEE:
330
						$product_id = 'paymentfee';
331
332
						break;
333
				}
334
335
				// Price.
336
				$unit_price = null;
337
338
				if ( null !== $line->get_unit_price() ) {
339
					$unit_price = $line->get_unit_price()->get_excluding_tax()->get_cents();
340
				}
341
342
				// Request parameters.
343
				$request->merge_parameters(
344
					array(
345
						'product_id_' . $x          => $product_id,
346
						'product_description_' . $x => $line->get_name(),
347
						'product_quantity_' . $x    => $line->get_quantity(),
348
						'product_netprice_' . $x    => $unit_price,
349
						'product_total_' . $x       => $line->get_total_amount()->get_including_tax()->get_cents(),
350
						'product_nettotal_' . $x    => $line->get_total_amount()->get_excluding_tax()->get_cents(),
351
					)
352
				);
353
354
				// Tax request parameters.
355
				$tax_amount = $line->get_tax_amount();
356
357
				if ( null !== $tax_amount ) {
358
					$request->set_parameter( 'product_tax_' . $x, $tax_amount->get_cents() );
359
				}
360
361
				$tax_percentage = $line->get_total_amount()->get_tax_percentage();
362
363
				if ( null !== $tax_percentage ) {
364
					$request->set_parameter( 'product_taxrate_' . $x, $tax_percentage * 100 );
365
				}
366
367
				$x++;
368
			}
369
		}
370
371
		// Create transaction.
372
		$result = $this->client->create_transaction( $request );
373
374
		if ( false !== $result ) {
375
			$payment->set_transaction_id( $result->id );
376
			$payment->set_action_url( $result->issuer_url );
377
		}
378
	}
379
380
	/**
381
	 * Update status of the specified payment
382
	 *
383
	 * @param Payment $payment Payment.
384
	 */
385
	public function update_status( Payment $payment ) {
386
		$transaction_id = $payment->get_transaction_id();
387
		$merchant_id    = $this->config->merchant_id;
388
389
		// Process notify and callback requests for payments without transaction ID.
390
		if ( empty( $transaction_id ) && Core_Util::input_has_vars( \INPUT_GET, array( 'trxid', 'ec', 'status', 'sha1' ) ) ) {
391
			$transaction_id = \filter_input( \INPUT_GET, 'trxid' );
392
			$entrance_code  = \filter_input( \INPUT_GET, 'ec' );
393
			$status         = \filter_input( \INPUT_GET, 'status' );
394
			$signature      = \filter_input( \INPUT_GET, 'sha1' );
395
396
			$notify = new NotifyRequest( $transaction_id, $entrance_code, $status, $merchant_id );
397
398
			// Set status if signature validates.
399
			if ( $notify->get_signature( $this->config->merchant_key ) === $signature ) {
400
				$payment->set_status( Statuses::transform( $status ) );
401
			}
402
403
			return;
404
		}
405
406
		// Status request.
407
		$request = new StatusRequest(
408
			$transaction_id,
409
			$merchant_id,
410
			$this->config->shop_id
411
		);
412
413
		try {
414
			$result = $this->client->get_status( $request );
415
416
			if ( false === $result ) {
417
				return;
418
			}
419
		} catch ( \Exception $e ) {
420
			$this->error = new \WP_Error( 'sisow_error', $e->getMessage() );
421
422
			return;
423
		}
424
425
		// Set status.
426
		$payment->set_status( Statuses::transform( $result->status ) );
427
428
		// Set consumer details.
429
		$consumer_details = $payment->get_consumer_bank_details();
0 ignored issues
show
The method get_consumer_bank_details() does not exist on Pronamic\WordPress\Pay\Payments\Payment. ( Ignorable by Annotation )

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

429
		/** @scrutinizer ignore-call */ 
430
  $consumer_details = $payment->get_consumer_bank_details();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
430
431
		if ( null === $consumer_details ) {
432
			$consumer_details = new BankAccountDetails();
433
434
			$payment->set_consumer_bank_details( $consumer_details );
0 ignored issues
show
The method set_consumer_bank_details() does not exist on Pronamic\WordPress\Pay\Payments\Payment. Did you maybe mean set_consumer_bic()? ( Ignorable by Annotation )

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

434
			$payment->/** @scrutinizer ignore-call */ 
435
             set_consumer_bank_details( $consumer_details );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
435
		}
436
437
		$consumer_details->set_name( $result->consumer_name );
438
		$consumer_details->set_account_number( $result->consumer_account );
439
		$consumer_details->set_city( $result->consumer_city );
440
		$consumer_details->set_iban( $result->consumer_iban );
441
		$consumer_details->set_bic( $result->consumer_bic );
442
	}
443
444
	/**
445
	 * Create invoice.
446
	 *
447
	 * @param Payment $payment Payment.
448
	 *
449
	 * @return bool|Invoice
450
	 */
451
	public function create_invoice( $payment ) {
452
		$transaction_id = $payment->get_transaction_id();
453
454
		if ( empty( $transaction_id ) ) {
455
			return false;
456
		}
457
458
		// Invoice request.
459
		$request = new InvoiceRequest(
460
			$this->config->merchant_id,
461
			$this->config->shop_id
462
		);
463
464
		$request->set_parameter( 'trxid', $transaction_id );
465
466
		// Create invoice.
467
		$result = $this->client->create_invoice( $request );
468
469
		// Handle errors.
470
		if ( false === $result ) {
471
			$this->error = $this->client->get_error();
472
473
			return false;
474
		}
475
476
		$payment->set_status( Core_Statuses::SUCCESS );
477
478
		$payment->save();
479
480
		return $result;
481
	}
482
483
	/**
484
	 * Cancel reservation.
485
	 *
486
	 * @param Payment $payment Payment.
487
	 *
488
	 * @return bool|Reservation
489
	 */
490
	public function cancel_reservation( $payment ) {
491
		$transaction_id = $payment->get_transaction_id();
492
493
		if ( empty( $transaction_id ) ) {
494
			return false;
495
		}
496
497
		// Cancel reservation request.
498
		$request = new CancelReservationRequest(
499
			$this->config->merchant_id,
500
			$this->config->shop_id
501
		);
502
503
		$request->set_parameter( 'trxid', $transaction_id );
504
505
		// Cancel reservation.
506
		$result = $this->client->cancel_reservation( $request );
507
508
		// Handle errors.
509
		if ( false === $result ) {
510
			$this->error = $this->client->get_error();
511
512
			return false;
513
		}
514
515
		if ( isset( $result->status ) ) {
516
			$payment->set_status( Statuses::transform( $result->status ) );
517
518
			$payment->save();
519
		}
520
521
		return $result;
522
	}
523
}
524