Test Failed
Push — develop ( 6bf0ad...eec332 )
by Reüel
04:35
created

Gateway   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 34
Bugs 0 Features 2
Metric Value
eloc 151
dl 0
loc 357
ccs 0
cts 197
cp 0
rs 9.2
c 34
b 0
f 2
wmc 40

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 2
A get_supported_payment_methods() 0 8 1
B handle_merchant_order_status_changed() 0 45 7
A maybe_update_access_token() 0 29 5
B update_status() 0 44 6
F start() 0 139 16
A handle_notification() 0 8 3

How to fix   Complexity   

Complex Class

Complex classes like Gateway 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 Gateway, and based on these observations, apply Extract Interface, too.

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\Gateways\OmniKassa2
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\OmniKassa2;
12
13
use Pronamic\WordPress\Pay\Core\Gateway as Core_Gateway;
14
use Pronamic\WordPress\Pay\Core\PaymentMethods;
15
use Pronamic\WordPress\Pay\Payments\Payment;
16
17
/**
18
 * Gateway
19
 *
20
 * @author  Remco Tolsma
21
 * @version 2.1.8
22
 * @since   1.0.0
23
 */
24
class Gateway extends Core_Gateway {
25
	/**
26
	 * Client.
27
	 *
28
	 * @var Client
29
	 */
30
	private $client;
31
32
	/**
33
	 * Constructs and initializes an OmniKassa 2.0 gateway.
34
	 *
35
	 * @param Config $config Config.
36
	 */
37
	public function __construct( Config $config ) {
38
		parent::__construct( $config );
39
40
		$this->set_method( self::METHOD_HTTP_REDIRECT );
41
42
		// Supported features.
43
		$this->supports = array(
44
			'webhook_log',
45
		);
46
47
		// Client.
48
		$this->client = new Client();
49
50
		$url = Client::URL_PRODUCTION;
51
52
		if ( self::MODE_TEST === $config->mode ) {
53
			$url = Client::URL_SANDBOX;
54
		}
55
56
		$this->client->set_url( $url );
57
		$this->client->set_refresh_token( $config->refresh_token );
58
		$this->client->set_signing_key( $config->signing_key );
59
	}
60
61
	/**
62
	 * Get supported payment methods.
63
	 *
64
	 * @see \Pronamic_WP_Pay_Gateway::get_supported_payment_methods()
65
	 * @return array<string>
66
	 */
67
	public function get_supported_payment_methods() {
68
		return array(
69
			PaymentMethods::AFTERPAY,
70
			PaymentMethods::BANCONTACT,
71
			PaymentMethods::CREDIT_CARD,
72
			PaymentMethods::IDEAL,
73
			PaymentMethods::MAESTRO,
74
			PaymentMethods::PAYPAL,
75
		);
76
	}
77
78
	/**
79
	 * Start.
80
	 *
81
	 * @see Core_Gateway::start()
82
	 * @param Payment $payment Payment.
83
	 */
84
	public function start( Payment $payment ) {
85
		// Merchant order ID.
86
		$merchant_order_id = $payment->format_string( $this->config->order_id );
87
88
		$payment->set_meta( 'omnikassa_2_merchant_order_id', $merchant_order_id );
89
90
		// New order.
91
		$merchant_return_url = $payment->get_return_url();
92
		$merchant_return_url = \apply_filters( 'pronamic_pay_omnikassa_2_merchant_return_url', $merchant_return_url );
93
94
		try {
95
			$order = new Order(
96
				$merchant_order_id,
97
				MoneyTransformer::transform( $payment->get_total_amount() ),
98
				$merchant_return_url
99
			);
100
101
			// Shipping address.
102
			$order->set_shipping_detail( AddressTransformer::transform( $payment->get_shipping_address() ) );
103
104
			// Billing address.
105
			$order->set_billing_detail( AddressTransformer::transform( $payment->get_billing_address() ) );
106
107
			// Customer information.
108
			$customer = $payment->get_customer();
109
110
			if ( null !== $customer ) {
111
				// Language.
112
				$language = $customer->get_language();
113
114
				if ( null !== $language ) {
115
					$order->set_language( \strtoupper( $language ) );
116
				}
117
118
				// Customer information.
119
				$customer_information = new CustomerInformation();
120
121
				$customer_information->set_email_address( $customer->get_email() );
122
				$customer_information->set_date_of_birth( $customer->get_birth_date() );
123
				$customer_information->set_gender( Gender::transform( $customer->get_gender() ) );
124
				$customer_information->set_telephone_number( $customer->get_phone() );
125
126
				$name = $customer->get_name();
127
128
				if ( null !== $name ) {
129
					$customer_information->set_initials( $name->get_initials() );
130
				}
131
132
				$order->set_customer_information( $customer_information );
133
			}
134
135
			// Payment brand.
136
			$payment_brand = PaymentBrands::transform( $payment->get_method() );
137
138
			$order->set_payment_brand( $payment_brand );
139
140
			if ( null !== $payment_brand ) {
141
				// Payment brand force should only be set if payment brand is not empty.
142
				$order->set_payment_brand_force( PaymentBrandForce::FORCE_ONCE );
143
			}
144
145
			// Description.
146
			$order->set_description( DataHelper::sanitize_an( $payment->get_description(), 35 ) );
147
148
			// Lines.
149
			$lines = $payment->get_lines();
150
151
			if ( null !== $lines ) {
152
				$order_items = $order->new_items();
153
154
				$i = 1;
155
156
				foreach ( $lines as $line ) {
157
					$name = \sprintf(
158
						/* translators: %s: item index */
159
						\__( 'Item %s', 'pronamic_ideal' ),
160
						$i++
161
					);
162
163
					if ( null !== $line->get_name() && '' !== $line->get_name() ) {
164
						$name = $line->get_name();
165
					}
166
167
					$item = $order_items->new_item(
168
						DataHelper::sanitize_an( $name, 50 ),
169
						$line->get_quantity(),
170
						// The amount in cents, including VAT, of the item each, see below for more details.
171
						MoneyTransformer::transform( $line->get_unit_price() ),
172
						ProductCategories::transform( $line->get_type() )
173
					);
174
175
					$item->set_id( $line->get_id() );
176
177
					// Description.
178
					$description = $line->get_description();
179
180
					if ( empty( $description ) && PaymentBrands::AFTERPAY === $payment_brand ) {
181
						/*
182
						 * The `OrderItem.description` field is documentated as `0..1` (optional),
183
						 * but for AfterPay payments it is required.
184
						 *
185
						 * @link https://github.com/wp-pay-gateways/omnikassa-2/tree/feature/post-pay/documentation#error-5024
186
						 */
187
						$description = $name;
188
					}
189
190
					if ( null !== $description ) {
191
						$description = DataHelper::sanitize_an( $description, 100 );
192
					}
193
194
					$item->set_description( $description );
195
196
					$tax_amount = $line->get_unit_price()->get_tax_amount();
197
198
					if ( null !== $tax_amount ) {
199
						// The VAT of the item each, see below for more details.
200
						$item->set_tax( MoneyTransformer::transform( $tax_amount ) );
201
					}
202
				}
203
			}
204
		} catch ( \Exception $e ) {
205
			throw new \Pronamic\WordPress\Pay\GatewayException( 'omnikassa_2', $e->getMessage() );
0 ignored issues
show
Bug introduced by
The type Pronamic\WordPress\Pay\GatewayException 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...
206
		}
207
208
		// Maybe update access token.
209
		$this->maybe_update_access_token();
210
211
		// Announce order.
212
		$response = $this->client->order_announce( $this->config, $order );
213
214
		if ( false === $response ) {
215
			return;
216
		}
217
218
		if ( ! $response->is_valid( $this->config->signing_key ) ) {
219
			return;
220
		}
221
222
		$payment->set_action_url( $response->get_redirect_url() );
223
	}
224
225
	/**
226
	 * Update status of the specified payment.
227
	 *
228
	 * @param Payment $payment Payment.
229
	 */
230
	public function update_status( Payment $payment ) {
231
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
232
		if ( ! ReturnParameters::contains( $_GET ) ) {
233
			return;
234
		}
235
236
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
237
		$parameters = ReturnParameters::from_array( $_GET );
238
239
		// Note.
240
		$note_values = array(
241
			'order_id'  => $parameters->get_order_id(),
242
			'status'    => $parameters->get_status(),
243
			'signature' => $parameters->get_signature(),
244
			'valid'     => $parameters->is_valid( $this->config->signing_key ) ? 'true' : 'false',
245
		);
246
247
		$note = '';
248
249
		$note .= '<p>';
250
		$note .= \__( 'OmniKassa 2.0 return URL requested:', 'pronamic_ideal' );
251
		$note .= '</p>';
252
253
		$note .= '<dl>';
254
255
		foreach ( $note_values as $key => $value ) {
256
			$note .= \sprintf( '<dt>%s</dt>', \esc_html( $key ) );
257
			$note .= \sprintf( '<dd>%s</dd>', \esc_html( $value ) );
258
		}
259
260
		$note .= '</dl>';
261
262
		$payment->add_note( $note );
263
264
		// Validate.
265
		if ( ! $parameters->is_valid( $this->config->signing_key ) ) {
266
			return;
267
		}
268
269
		// Status.
270
		$pronamic_status = Statuses::transform( $parameters->get_status() );
271
272
		if ( null !== $pronamic_status ) {
273
			$payment->set_status( $pronamic_status );
274
		}
275
	}
276
277
	/**
278
	 * Handle notification.
279
	 *
280
	 * @param Notification $notification Notification.
281
	 * @return void
282
	 */
283
	public function handle_notification( Notification $notification ) {
284
		if ( ! $notification->is_valid( $this->config->signing_key ) ) {
285
			return;
286
		}
287
288
		switch ( $notification->get_event_name() ) {
289
			case 'merchant.order.status.changed':
290
				$this->handle_merchant_order_status_changed( $notification );
291
		}
292
	}
293
294
	/**
295
	 * Handle `merchant.order.status.changed` event.
296
	 *
297
	 * @param Notification $notification Notification.
298
	 * @return void
299
	 */
300
	private function handle_merchant_order_status_changed( Notification $notification ) {
301
		do {
302
			$order_results = $this->client->get_order_results( $notification->get_authentication() );
303
304
			if ( false === $order_results ) {
305
				return;
306
			}
307
308
			if ( ! $order_results->is_valid( $this->config->signing_key ) ) {
309
				return;
310
			}
311
312
			foreach ( $order_results as $order_result ) {
313
				$payment = \get_pronamic_payment_by_meta( '_pronamic_payment_omnikassa_2_merchant_order_id', $order_result->get_merchant_order_id() );
314
315
				// Log webhook request.
316
				\do_action( 'pronamic_pay_webhook_log_payment', $payment );
317
318
				if ( empty( $payment ) ) {
319
					continue;
320
				}
321
322
				$payment->set_transaction_id( $order_result->get_omnikassa_order_id() );
323
324
				$pronamic_status = Statuses::transform( $order_result->get_order_status() );
325
326
				if ( null !== $pronamic_status ) {
327
					$payment->set_status( $pronamic_status );
328
				}
329
330
				// Note.
331
				$note = '';
332
333
				$note .= '<p>';
334
				$note .= \__( 'OmniKassa 2.0 webhook URL requested:', 'pronamic_ideal' );
335
				$note .= '</p>';
336
				$note .= '<pre>';
337
				$note .= \wp_json_encode( $order_result->get_json(), \JSON_PRETTY_PRINT );
338
				$note .= '</pre>';
339
340
				$payment->add_note( $note );
341
342
				$payment->save();
343
			}
344
		} while ( $order_results->more_available() );
345
	}
346
347
	/**
348
	 * Maybe update access token.
349
	 *
350
	 * @return void
351
	 */
352
	private function maybe_update_access_token() {
353
		if ( $this->config->is_access_token_valid() ) {
354
			return;
355
		}
356
357
		$data = $this->client->get_access_token_data();
358
359
		if ( ! \is_object( $data ) ) {
360
			return;
361
		}
362
363
		if ( isset( $data->token ) ) {
364
			$this->config->access_token = $data->token;
365
366
			\update_post_meta( $this->config->post_id, '_pronamic_gateway_omnikassa_2_access_token', $data->token );
367
		}
368
369
		/*
370
		 * @codingStandardsIgnoreStart
371
		 *
372
		 * Ignore coding standards because of sniff WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
373
		 */
374
		if ( isset( $data->validUntil ) ) {
375
			$this->config->access_token_valid_until = $data->validUntil;
376
377
			\update_post_meta(
378
				$this->config->post_id,
379
				'_pronamic_gateway_omnikassa_2_access_token_valid_until',
380
				$data->validUntil
381
			);
382
		}
383
		// @codingStandardsIgnoreEnd
384
	}
385
}
386