Failed Conditions
Push — feature/webhook-status ( e55647 )
by Reüel
05:56
created

src/Client.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
4
5
use Pronamic\WordPress\DateTime\DateTime;
6
use Pronamic\WordPress\Pay\Core\XML\Security;
7
use WP_Error;
8
9
/**
10
 * Title: Mollie
11
 * Description:
12
 * Copyright: 2005-2019 Pronamic
13
 * Company: Pronamic
14
 *
15
 * @author  Remco Tolsma
16
 * @version 2.0.0
17
 * @since   1.0.0
18
 */
19
class Client {
20
	/**
21
	 * Mollie API endpoint URL
22
	 *
23
	 * @var string
24
	 */
25
	const API_URL = 'https://api.mollie.nl/v1/';
26
27
	/**
28
	 * Mollie API Key ID
29
	 *
30
	 * @var string
31
	 */
32
	private $api_key;
33
34
	/**
35
	 * Mode
36
	 *
37
	 * @since 1.1.9
38
	 * @var string
39
	 */
40
	private $mode;
41
42
	/**
43
	 * Error
44
	 *
45
	 * @var WP_Error
46
	 */
47
	private $error;
48
49
	/**
50
	 * Constructs and initializes an Mollie client object
51
	 *
52
	 * @param string $api_key Mollie API key.
53
	 */
54 40
	public function __construct( $api_key ) {
55 40
		$this->api_key = $api_key;
56 40
	}
57
58
	/**
59
	 * Set mode
60
	 *
61
	 * @since 1.1.9
62
	 * @param string $mode Mode (test or live).
63
	 */
64 40
	public function set_mode( $mode ) {
65 40
		$this->mode = $mode;
66 40
	}
67
68
	/**
69
	 * Error
70
	 *
71
	 * @return WP_Error
72
	 */
73 5
	public function get_error() {
74 5
		return $this->error;
75
	}
76
77
	/**
78
	 * Send request with the specified action and parameters
79
	 *
80
	 * @param string $end_point              Requested endpoint.
81
	 * @param string $method                 HTTP method to use.
82
	 * @param array  $data                   Request data.
83
	 * @param int    $expected_response_code Expected response code.
84
	 *
85
	 * @return bool|object
86
	 */
87 10
	private function send_request( $end_point, $method = 'GET', array $data = array(), $expected_response_code = 200 ) {
88
		// Request.
89 10
		$url = self::API_URL . $end_point;
90
91 10
		$response = wp_remote_request(
92 10
			$url,
93
			array(
94 10
				'method'  => $method,
95
				'headers' => array(
96 10
					'Authorization' => 'Bearer ' . $this->api_key,
97
				),
98 10
				'body'    => $data,
99
			)
100
		);
101
102
		// Response code.
103 10
		$response_code = wp_remote_retrieve_response_code( $response );
0 ignored issues
show
It seems like $response can also be of type WP_Error; however, parameter $response of wp_remote_retrieve_response_code() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

103
		$response_code = wp_remote_retrieve_response_code( /** @scrutinizer ignore-type */ $response );
Loading history...
104
105 10
		if ( $expected_response_code != $response_code ) { // WPCS: loose comparison ok.
106 10
			$this->error = new WP_Error( 'mollie_error', 'Unexpected response code.' );
107
		}
108
109
		// Body.
110 10
		$body = wp_remote_retrieve_body( $response );
0 ignored issues
show
It seems like $response can also be of type WP_Error; however, parameter $response of wp_remote_retrieve_body() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

110
		$body = wp_remote_retrieve_body( /** @scrutinizer ignore-type */ $response );
Loading history...
111
112 10
		$data = json_decode( $body );
113
114 10
		if ( ! is_object( $data ) ) {
115
			$this->error = new WP_Error( 'mollie_error', 'Could not parse response.' );
116
117
			return false;
118
		}
119
120
		// Mollie error.
121 10
		if ( isset( $data->error, $data->error->message ) ) {
122 10
			$this->error = new \WP_Error( 'mollie_error', $data->error->message, $data->error );
123
124 10
			return false;
125
		}
126
127
		return $data;
128
	}
129
130
	/**
131
	 * Create payment.
132
	 *
133
	 * @param PaymentRequest $request Payment request.
134
	 *
135
	 * @return bool|object
136
	 */
137
	public function create_payment( PaymentRequest $request ) {
138
		return $this->send_request( 'payments/', 'POST', $request->get_array(), 201 );
139
	}
140
141
	/**
142
	 * Get payments.
143
	 *
144
	 * @return bool|object
145
	 */
146
	public function get_payments() {
147
		return $this->send_request( 'payments/', 'GET' );
148
	}
149
150
	/**
151
	 * Get payment.
152
	 *
153
	 * @param string $payment_id Payment ID.
154
	 *
155
	 * @return bool|object
156
	 */
157
	public function get_payment( $payment_id ) {
158
		if ( empty( $payment_id ) ) {
159
			return false;
160
		}
161
162
		return $this->send_request( 'payments/' . $payment_id, 'GET' );
163
	}
164
165
	/**
166
	 * Get issuers
167
	 *
168
	 * @return array|bool
169
	 */
170 3
	public function get_issuers() {
171 3
		$response = $this->send_request( 'issuers/', 'GET' );
172
173 3
		if ( false === $response ) {
174 3
			return false;
175
		}
176
177
		$issuers = array();
178
179
		if ( isset( $response->data ) ) {
180
			foreach ( $response->data as $issuer ) {
181
				if ( Methods::IDEAL === $issuer->method ) {
182
					$id   = Security::filter( $issuer->id );
183
					$name = Security::filter( $issuer->name );
184
185
					$issuers[ $id ] = $name;
186
				}
187
			}
188
		}
189
190
		return $issuers;
191
	}
192
193
	/**
194
	 * Get payment methods
195
	 *
196
	 * @param string $recurring_type Recurring type.
197
	 *
198
	 * @return array|bool
199
	 */
200 2
	public function get_payment_methods( $recurring_type = '' ) {
201 2
		$data = array();
202
203 2
		if ( '' !== $recurring_type ) {
204 2
			$data['recurringType'] = $recurring_type;
205
		}
206
207 2
		$response = $this->send_request( 'methods/', 'GET', $data );
208
209 2
		if ( false === $response ) {
210 2
			return false;
211
		}
212
213
		$payment_methods = array();
214
215
		if ( isset( $response->data ) ) {
216
			foreach ( $response->data as $payment_method ) {
217
				$id   = Security::filter( $payment_method->id );
218
				$name = Security::filter( $payment_method->description );
219
220
				$payment_methods[ $id ] = $name;
221
			}
222
		}
223
224
		return $payment_methods;
225
	}
226
227
	/**
228
	 * Create customer.
229
	 *
230
	 * @since 1.1.6
231
	 *
232
	 * @param string $email Customer email address.
233
	 * @param string $name  Customer name.
234
	 *
235
	 * @return string|bool
236
	 */
237
	public function create_customer( $email, $name ) {
238
		if ( empty( $email ) ) {
239
			return false;
240
		}
241
242
		$response = $this->send_request(
243
			'customers/',
244
			'POST',
245
			array(
246
				'name'  => $name,
247
				'email' => $email,
248
			),
249
			201
250
		);
251
252
		if ( false === $response ) {
253
			return false;
254
		}
255
256
		if ( ! isset( $response->id ) ) {
257
			return false;
258
		}
259
260
		return $response->id;
261
	}
262
263
	/**
264
	 * Get customer.
265
	 *
266
	 * @param string $customer_id Mollie customer ID.
267
	 *
268
	 * @since unreleased
269
	 *
270
	 * @return object|bool
271
	 */
272 5
	public function get_customer( $customer_id ) {
273 5
		if ( empty( $customer_id ) ) {
274
			return false;
275
		}
276
277 5
		$response = $this->send_request( 'customers/' . $customer_id, 'GET', array(), 200 );
278
279 5
		if ( false === $response ) {
280 5
			return false;
281
		}
282
283
		if ( is_wp_error( $this->error ) ) {
284
			return false;
285
		}
286
287
		return $response;
288
	}
289
290
	/**
291
	 * Get mandates for customer.
292
	 *
293
	 * @param string $customer_id Mollie customer ID.
294
	 *
295
	 * @return object|bool
296
	 */
297
	public function get_mandates( $customer_id ) {
298
		if ( '' === $customer_id ) {
299
			return false;
300
		}
301
302
		return $this->send_request( 'customers/' . $customer_id . '/mandates?count=250', 'GET' );
303
	}
304
305
	/**
306
	 * Is there a valid mandate for customer?
307
	 *
308
	 * @param string      $customer_id    Mollie customer ID.
309
	 * @param string|null $payment_method Payment method to find mandates for.
310
	 *
311
	 * @return boolean
312
	 */
313
	public function has_valid_mandate( $customer_id, $payment_method = null ) {
314
		$mandates = $this->get_mandates( $customer_id );
315
316
		if ( ! $mandates ) {
317
			return false;
318
		}
319
320
		$mollie_method = Methods::transform( $payment_method );
321
322
		foreach ( $mandates->data as $mandate ) {
323
			if ( $mollie_method !== $mandate->method ) {
324
				continue;
325
			}
326
327
			if ( 'valid' === $mandate->status ) {
328
				return true;
329
			}
330
		}
331
332
		return false;
333
	}
334
335
	/**
336
	 * Get formatted date and time of first valid mandate.
337
	 *
338
	 * @param string $customer_id    Mollie customer ID.
339
	 * @param string $payment_method Payment method.
340
	 *
341
	 * @return null|DateTime
342
	 */
343
	public function get_first_valid_mandate_datetime( $customer_id, $payment_method = null ) {
344
		$mandates = $this->get_mandates( $customer_id );
345
346
		if ( ! $mandates ) {
347
			return null;
348
		}
349
350
		$mollie_method = Methods::transform( $payment_method );
351
352
		foreach ( $mandates->data as $mandate ) {
353
			if ( $mollie_method !== $mandate->method ) {
354
				continue;
355
			}
356
357
			if ( 'valid' !== $mandate->status ) {
358
				continue;
359
			}
360
361
			if ( ! isset( $valid_mandates ) ) {
362
				$valid_mandates = array();
363
			}
364
365
			// @codingStandardsIgnoreStart
366
			$valid_mandates[ $mandate->createdDatetime ] = $mandate;
367
			// @codingStandardsIgnoreEnd
368
		}
369
370
		if ( isset( $valid_mandates ) ) {
371
			ksort( $valid_mandates );
372
373
			$mandate = array_shift( $valid_mandates );
374
375
			// @codingStandardsIgnoreStart
376
			$create_date = new DateTime( $mandate->createdDatetime );
377
			// @codingStandardsIgnoreEnd
378
379
			return $create_date;
380
		}
381
382
		return null;
383
	}
384
}
385