PluginProbe
PayPlug for WooCommerce (Official) / 3.1.0
PayPlug for WooCommerce (Official) v3.1.0
3.1.0 3.0.0 2.18.0 1.0.17 1.0.18 1.0.19 1.0.20 1.0.21 1.0.22 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1.0 1.10.0 1.10.1 1.2.1 1.2.10 1.2.11 1.2.2 1.2.3 1.2.4 1.2.5 All 102 releases
← All changes | src/Gateway/PayplugResponse.php +449 -260 1.0.22 → 3.1.0 View file →
@@ -2,335 +2,524 @@
2 2
3 3 namespace Payplug\PayplugWoocommerce\Gateway;
4 4
5 5 // Exit if accessed directly
6 -if ( ! defined( 'ABSPATH' ) ) {
7 - exit;
6 +if (!defined('ABSPATH')) {
7 + exit;
8 8 }
9 9
10 +use Automattic\WooCommerce\Utilities\OrderUtil;
10 11 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
11 12 use Payplug\Resource\IVerifiableAPIResource;
12 13 use Payplug\Resource\Payment as PaymentResource;
13 14 use Payplug\Resource\Refund as RefundResource;
14 15 use WC_Payment_Token_CC;
16 +use WC_Payment_Tokens;
15 17
16 18 /**
17 19 * Process responses from PayPlug.
18 - *
19 - * @package Payplug\PayplugWoocommerce\Gateway
20 20 */
21 -class PayplugResponse {
21 +class PayplugResponse
22 +{
23 + private $gateway;
22 24
23 - private $gateway;
25 + public function __construct(PayplugGateway $gateway)
26 + {
27 + $this->gateway = $gateway;
28 + }
24 29
25 - public function __construct( PayplugGateway $gateway ) {
26 - $this->gateway = $gateway;
27 - }
30 + /**
31 + * Process payment.
32 + *
33 + * @param $resource
34 + * @param $is_payment_with_token
35 + *
36 + * @throws \WC_Data_Exception
37 + *
38 + * @return void
39 + */
40 + public function process_payment($resource, $is_payment_with_token = false, $source = ''): void
41 + {
42 + $order_id = wc_clean($resource->metadata['order_id']);
28 43
29 - /**
30 - * Process payment.
31 - *
32 - * @param $resource
33 - * @param $is_payment_with_token
34 - *
35 - * @return void
36 - * @throws \WC_Data_Exception
37 - */
38 - public function process_payment( $resource, $is_payment_with_token = false ) {
39 - $order_id = wc_clean( $resource->metadata['order_id'] );
40 - $order = wc_get_order( $order_id );
41 - if ( ! $order ) {
42 - PayplugGateway::log( sprintf( 'Coudn\'t find order #%s (Transaction %s).', $order_id, wc_clean( $resource->id ) ), 'error' );
44 + $order = wc_get_order($order_id);
45 + $gateway_id = $order->get_payment_method();
46 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($resource);
43 47
44 - return;
45 - }
48 + // Ignore undefined orders
49 + if (!$order) {
50 + PayplugGateway::log(sprintf('Coudn\'t find order #%s (Transaction %s).', $order_id, wc_clean($resource->id)), 'error');
46 51
47 - PayplugGateway::log( sprintf( 'Order #%s : Begin processing payment IPN %s', $order_id, $resource->id ) );
52 + return;
53 + }
48 54
49 - // Ignore paid orders
50 - if ( $order->is_paid() ) {
51 - PayplugGateway::log( sprintf( 'Order #%s : Order is already complete. Ignoring IPN.', $order_id ) );
55 + /**
56 + * Checking if it is coming from the order confirmation page or the IPN
57 + */
58 + if (($gateway_id == $this->gateway->id) || (!empty($source) && ($source === 'ipn'))) {
59 + // Ignore cancelled orders
60 + if ($order->has_status('refunded')) {
61 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' order has been refunded. Ignoring IPN', $order_id));
52 62
53 - return;
54 - }
63 + return;
64 + }
65 + $paid_date = $order->get_date_paid();
66 + if (isset($paid_date) && !$order->is_paid()) {
67 + $finished_status = wc_get_is_paid_statuses();
68 + $order->set_status($finished_status[0]);
69 + }
55 70
56 - // Ignore cancelled orders
57 - if ( $order->has_status( 'refunded' ) ) {
58 - PayplugGateway::log( sprintf( 'Order #%s : Order has been refunded. Ignoring IPN', $order_id ) );
71 + // Ignore paid orders
72 + if ($order->is_paid()) {
73 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' order is already complete. Ignoring IPN. "' . !empty($source) ? '[IPN]' : '' . '"', $order_id));
59 74
60 - return;
61 - }
75 + return;
76 + }
62 77
63 - $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $resource );
64 - PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
78 + // Handle failed payments
79 + if (!empty($resource->failure)) {
80 + if ($order->get_status() != 'failed') {
81 + $order->update_status('failed', sprintf(__('PayPlug %s OK | Transaction %s failed : %s', 'payplug'), strtoupper($source), $resource->id, wc_clean($resource->failure->message)));
82 + }
65 83
66 - if ( $resource->is_paid ) {
84 + /** This action is documented in src/Gateway/PayplugResponse */
85 + \do_action('payplug_gateway_payment_response_processed', $order_id, $resource);
86 + PayplugWoocommerceHelper::set_flag_ipn_order($order, $metadata, false);
87 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' payment IPN %s processing completed but failed.', $order_id, $resource->id));
88 + wc_increase_stock_levels($order);
67 89
68 - if ( ! $is_payment_with_token ) {
69 - $this->maybe_save_card( $resource );
70 - }
90 + return;
91 + } elseif (($resource->failure == null) && !empty($resource->payment_method['is_pending'])
92 + && ($resource->payment_method['is_pending'] == true)) {
93 + $this->handle_pending_oney($order, $resource, $source);
94 + }
71 95
72 - $this->maybe_save_address_hash( $resource );
96 + // Save Logs of the payment for the different payment gateways:
97 + // For Oney 4 gateways & Bancontact gateway: "$resource->payment_method" exists and is an array
98 + // but not for Payplug credit card gateway (in this case we check the payment_method from the order itself not the $resource)
99 + if (isset($resource->payment_method) && is_array($resource->payment_method)) {
100 + $gateway_id = $resource->payment_method['type'];
73 101
74 - $order->add_order_note( sprintf( __( 'PayPlug IPN OK | Transaction %s', 'payplug' ), wc_clean( $resource->id ) ) );
75 - $order->payment_complete( wc_clean( $resource->id ) );
76 - if ( PayplugWoocommerceHelper::is_pre_30() ) {
77 - $order->reduce_order_stock();
78 - }
102 + switch ($gateway_id) {
103 + case 'oney_' === substr($gateway_id, 0, 5):
104 + $this->oney_ipn($resource);
105 + break;
106 + case 'bancontact':
107 + $this->bancontact_ipn($resource, $source);
108 + break;
109 + case 'apple_pay':
110 + $this->apple_pay_ipn($resource, $source);
111 + break;
112 + case 'american_express':
113 + $this->amex_ipn($resource, $source);
114 + break;
115 + }
116 + } elseif ('payplug' == $gateway_id) {
117 + if (!$is_payment_with_token) {
118 + $this->payplug_ipn($resource, $source);
119 + }
120 + }
79 121
80 - /**
81 - * Fires once a payment response has been processed.
82 - *
83 - * @param int $order_id Order ID
84 - * @param PaymentResource $resource Payment resource
85 - */
86 - \do_action( 'payplug_gateway_payment_response_processed', $order_id, $resource );
122 + // Handle successful payments
123 + if ($resource->is_paid) {
124 + if (!$is_payment_with_token) {
125 + $this->maybe_save_card($resource);
126 + }
127 + $this->maybe_save_address_hash($resource);
128 + $order->add_order_note(sprintf(__('PayPlug %s OK | Transaction %s', 'payplug'), strtoupper($source), wc_clean($resource->id)));
129 + $order->payment_complete(wc_clean($resource->id));
130 + if (PayplugWoocommerceHelper::is_pre_30()) {
131 + $order->reduce_order_stock();
132 + }
133 + /**
134 + * Fires once a payment response has been processed.
135 + *
136 + * @param int $order_id Order ID
137 + * @param PaymentResource $resource Payment resource
138 + */
139 + \do_action('payplug_gateway_payment_response_processed', $order_id, $resource);
140 + PayplugWoocommerceHelper::set_flag_ipn_order($order, $metadata, false);
141 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' payment %s %s processing completed successfully.', strtoupper($source), $order_id, $resource->id));
142 + }
143 + }
144 + }
87 145
88 - PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
146 + /**
147 + * Handle pending oney payments orders
148 + *
149 + * @param $order
150 + * @param $resource
151 + *
152 + * @return void
153 + */
154 + public function handle_pending_oney($order, $resource, $source): void
155 + {
156 + $order->add_order_note(sprintf(__('PayPlug %s OK | Transaction %s | Payment PENDING to be checked by an Oney agent', 'payplug'), strtoupper($source), wc_clean($resource->id)));
157 + wc_reduce_stock_levels($order);
158 + }
89 159
90 - return;
91 - }
160 + /**
161 + * Payplug IPN
162 + *
163 + * @param $resource
164 + */
165 + public function payplug_ipn($resource, $source): void
166 + {
167 + $order_id = wc_clean($resource->metadata['order_id']);
168 + PayplugGateway::log(sprintf('Order #%s : Begin processing Payplug payment %s %s', $order_id, strtoupper($source), $resource->id));
169 + }
92 170
93 - if ( ! empty( $resource->failure ) ) {
94 - $order->update_status(
95 - 'failed',
96 - sprintf( __( 'PayPlug IPN OK | Transaction %s failed : %s', 'payplug' ), $resource->id, wc_clean( $resource->failure->message ) )
97 - );
171 + /**
172 + * Bancontact IPN
173 + *
174 + * @param $resource
175 + */
176 + public function bancontact_ipn($resource, $source): void
177 + {
178 + $order_id = wc_clean($resource->metadata['order_id']);
179 + PayplugGateway::log(sprintf('Order #%s : Begin processing Bancontact payment %s %s', $order_id, strtoupper($source), $resource->id));
180 + }
98 181
99 - /** This action is documented in src/Gateway/PayplugResponse */
100 - \do_action( 'payplug_gateway_payment_response_processed', $order_id, $resource );
182 + /**
183 + * Apple Pay IPN
184 + *
185 + * @param $resource
186 + */
187 + public function apple_pay_ipn($resource, $source): void
188 + {
189 + $order_id = wc_clean($resource->metadata['order_id']);
190 + PayplugGateway::log(sprintf('Order #%s : Begin processing Apple Pay payment %s %s', $order_id, strtoupper($source), $resource->id));
191 + }
101 192
102 - PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
193 + /**
194 + * American Express IPN
195 + *
196 + * @param $resource
197 + */
198 + public function amex_ipn($resource, $source): void
199 + {
200 + $order_id = wc_clean($resource->metadata['order_id']);
201 + PayplugGateway::log(sprintf('Order #%s : Begin processing Amex payment %s %s', $order_id, strtoupper($source), $resource->id));
202 + }
103 203
104 - return;
105 - }
106 - }
204 + /**
205 + * Oney IPN
206 + *
207 + * @param $resource
208 + */
209 + public function oney_ipn($resource): void
210 + {
211 + $gateway_id = $resource->payment_method['type'];
212 + $order_id = wc_clean($resource->metadata['order_id']);
107 213
108 - /**
109 - * Process refund.
110 - *
111 - * @param $resource
112 - * @param bool $ignore_woocommerce_refund Flag to determine if IPN notification for refunds created by WooCommerce
113 - * should be ignored or not. Default to true.
114 - *
115 - * @throws \Exception
116 - */
117 - public function process_refund( $resource, $ignore_woocommerce_refund = true ) {
118 - $refund_id = wc_clean( $resource->id );
119 - $transaction_id = wc_clean( $resource->payment_id );
120 - $order = $this->get_order_from_transaction_id( $transaction_id );
121 - if ( ! $order ) {
122 - PayplugGateway::log( sprintf( 'Coudn\'t find order for transaction %s (Refund %s).', wc_clean( $resource->payment_id ), wc_clean( $resource->id ) ), 'error' );
214 + if (($resource->is_paid == true) && ($resource->failure == null)) {
215 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' payment SUCCESS', $order_id));
216 + }
123 217
124 - return;
125 - }
126 - $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
218 + if (($resource->is_paid == false) && ($resource->failure != null)) {
219 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' payment FAILED', $order_id));
220 + }
127 221
128 - PayplugGateway::log( sprintf( 'Order #%s : Begin processing refund IPN %s', $order_id, $resource->id ) );
222 + if (($resource->is_paid == false) && ($resource->failure == null) && ($resource->payment_method['is_pending'] == true)) {
223 + PayplugGateway::log(sprintf('Order #%s : ' . $this->gateway_name($gateway_id) . ' payment PENDING and checked by an Oney agent', $order_id));
224 + }
225 + }
129 226
130 - $refund_exist = $this->refund_exist_for_order( $order_id, $refund_id );
131 - if ( $refund_exist ) {
132 - PayplugGateway::log( sprintf( 'Order #%s : Refund has already been processed. Ignoring IPN.', $order_id ) );
227 + /**
228 + * Get the gateway name from the gateway_id
229 + *
230 + * @param $gateway_id
231 + */
232 + private function gateway_name($gateway_id)
233 + {
234 + return ucwords(str_replace('_', ' ', $gateway_id));
235 + }
133 236
134 - return;
135 - }
237 + /**
238 + * Process refund.
239 + *
240 + * @param $resource
241 + * @param bool $ignore_woocommerce_refund Flag to determine if IPN notification for refunds created by WooCommerce
242 + * should be ignored or not. Default to true.
243 + *
244 + * @throws \Exception
245 + */
246 + public function process_refund($resource, $ignore_woocommerce_refund = true): void
247 + {
248 + $refund_id = wc_clean($resource->id);
249 + $transaction_id = wc_clean($resource->payment_id);
250 + $order = $this->get_order_from_transaction_id($transaction_id);
251 + if (!$order) {
252 + PayplugGateway::log(sprintf('Coudn\'t find order for transaction %s (Refund %s).', wc_clean($resource->payment_id), wc_clean($resource->id)), 'error');
136 253
137 - // Since refund notification doesn't contain the full resource, we need to retrieve
138 - // the refund resource to access its metadata.
139 - try {
140 - $refund = $this->gateway->api->refund_retrieve( $transaction_id, $refund_id );
141 - } catch ( \Exception $e ) {
142 - PayplugGateway::log( sprintf( 'Order #%s : Fail to retrieve refund data with error %s', $order_id, $e->getMessage() ) );
254 + return;
255 + }
256 + $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
143 257
144 - return;
145 - }
258 + PayplugGateway::log(sprintf('Order #%s : Begin processing refund IPN %s', $order_id, $resource->id));
146 259
147 - if (
148 - $ignore_woocommerce_refund
149 - && isset( $refund->metadata['refund_from'] )
150 - && 'woocommerce' === $refund->metadata['refund_from']
151 - ) {
152 - PayplugGateway::log( sprintf( 'Order #%s : Refund created by WooCommerce. Ignoring IPN.', $order_id ) );
260 + $refund_exist = $this->refund_exist_for_order($order_id, $refund_id);
261 + if ($refund_exist) {
262 + PayplugGateway::log(sprintf('Order #%s : Refund has already been processed. Ignoring IPN.', $order_id));
153 263
154 - return;
155 - }
264 + return;
265 + }
156 266
157 - $refund = wc_create_refund( [
158 - 'amount' => ( (int) $resource->amount ) / 100,
159 - 'reason' => isset( $resource->metadata['reason'] ) ? $resource->metadata['reason'] : null,
160 - 'order_id' => (int) $order_id,
161 - 'refund_id' => 0,
162 - 'refund_payment' => false,
163 - ] );
164 - if ( is_wp_error( $refund ) ) {
165 - PayplugGateway::log( $refund->get_error_message() );
166 - }
267 + // Since refund notification doesn't contain the full resource, we need to retrieve
268 + // the refund resource to access its metadata.
269 + try {
270 + $refund = $this->gateway->payplug_api->refund_retrieve($transaction_id, $refund_id);
271 + } catch (\Exception $e) {
272 + PayplugGateway::log(sprintf('Order #%s : Fail to retrieve refund data with error %s', $order_id, $e->getMessage()));
167 273
168 - $refund_meta_key = sprintf( '_pr_%s', wc_clean( $resource->id ) );
169 - if ( PayplugWoocommerceHelper::is_pre_30() ) {
170 - update_post_meta( $order_id, $refund_meta_key, $resource->id );
171 - } else {
172 - $order->add_meta_data( $refund_meta_key, $resource->id, true );
173 - $order->save();
174 - }
274 + return;
275 + }
175 276
176 - $note = sprintf( __( 'Refund %s : Refunded %s', 'payplug' ), wc_clean( $resource->id ), wc_price( ( (int) $resource->amount ) / 100 ) );
177 - if ( ! empty( $resource->metadata['reason'] ) ) {
178 - $note .= sprintf( ' (%s)', esc_html( $resource->metadata['reason'] ) );
179 - }
180 - $order->add_order_note( $note );
277 + if (
278 + $ignore_woocommerce_refund
279 + && isset($refund->metadata['refund_from'])
280 + && 'woocommerce' === $refund->metadata['refund_from']
281 + ) {
282 + PayplugGateway::log(sprintf('Order #%s : Refund created by WooCommerce. Ignoring IPN.', $order_id));
181 283
182 - /**
183 - * Fires once a refund response has been processed.
184 - *
185 - * @param int $order_id Order ID
186 - * @param RefundResource $resource Refund resource
187 - */
188 - \do_action( 'payplug_gateway_refund_response_processed', $order_id, $resource );
284 + return;
285 + }
189 286
190 - try {
191 - $payment = $this->gateway->api->payment_retrieve( $transaction_id );
192 - $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $payment );
193 - PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
194 - } catch ( \Exception $e ) {}
287 + $refund = wc_create_refund([
288 + 'amount' => ((int) $resource->amount) / 100,
289 + 'reason' => isset($resource->metadata['reason']) ? $resource->metadata['reason'] : null,
290 + 'order_id' => (int) $order_id,
291 + 'refund_id' => 0,
292 + 'refund_payment' => false,
293 + ]);
294 + if (is_wp_error($refund)) {
295 + PayplugGateway::log($refund->get_error_message());
296 + }
195 297
196 - PayplugGateway::log( sprintf( 'Order #%s : Refund IPN %s processing completed.', $order_id, $resource->id ) );
197 - }
298 + $refund_meta_key = sprintf('_pr_%s', wc_clean($resource->id));
299 + if (PayplugWoocommerceHelper::is_pre_30()) {
300 + update_post_meta($order_id, $refund_meta_key, $resource->id);
301 + } else {
302 + $order->add_meta_data($refund_meta_key, $resource->id, true);
303 + $order->save();
304 + }
198 305
199 - /**
200 - * Get an order from its transaction id.
201 - *
202 - * @param int $transaction_id
203 - *
204 - * @return bool|\WC_Order
205 - */
206 - protected function get_order_from_transaction_id( $transaction_id ) {
207 - global $wpdb;
306 + $note = sprintf(__('Refund %s : Refunded %s', 'payplug'), wc_clean($resource->id), wc_price(((int) $resource->amount) / 100));
307 + if (!empty($resource->metadata['reason'])) {
308 + $note .= sprintf(' (%s)', esc_html($resource->metadata['reason']));
309 + }
310 + $order->add_order_note($note);
208 311
209 - $order_id = $wpdb->get_var(
210 - $wpdb->prepare(
211 - "
212 - SELECT post_id
213 - FROM $wpdb->postmeta
214 - WHERE meta_key = '_transaction_id'
215 - AND meta_value = %s
216 - ",
217 - $transaction_id
218 - )
219 - );
312 + /**
313 + * Fires once a refund response has been processed.
314 + *
315 + * @param int $order_id Order ID
316 + * @param RefundResource $resource Refund resource
317 + */
318 + \do_action('payplug_gateway_refund_response_processed', $order_id, $resource);
220 319
221 - return ! is_null( $order_id ) ? wc_get_order( $order_id ) : false;
222 - }
320 + try {
321 + $payment = $this->gateway->payplug_api->payment_retrieve($transaction_id);
322 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
323 + PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
324 + } catch (\Exception $e) {
325 + }
223 326
224 - /**
225 - * Check if a refund id already exist for the order.
226 - *
227 - * @param string $refund_id
228 - *
229 - * @return bool
230 - */
231 - protected function refund_exist_for_order( $order_id, $refund_id ) {
232 - global $wpdb;
327 + PayplugGateway::log(sprintf('Order #%s : Refund IPN %s processing completed.', $order_id, $resource->id));
328 + }
233 329
234 - $sql = "
330 + /**
331 + * Get an order from its transaction id.
332 + *
333 + * @param int $transaction_id
334 + *
335 + * @return bool|\WC_Order
336 + */
337 + protected function get_order_from_transaction_id($transaction_id)
338 + {
339 + global $wpdb;
340 +
341 + if (OrderUtil::custom_orders_table_usage_is_enabled()) {
342 + $orders = wc_get_orders(
343 + [
344 + 'field_query' => [
345 + [
346 + 'field' => 'transaction_id',
347 + 'value' => $transaction_id,
348 + ],
349 + ],
350 + ]
351 + );
352 + $order = $orders[0];
353 + $order_id = $order->get_id();
354 + //$sql = "SELECT o.id FROM $wpdb->wc_orders o WHERE o.transaction_id = %s";
355 + } else {
356 + $order_id = $wpdb->get_var(
357 + $wpdb->prepare(
358 + "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_transaction_id' AND meta_value = %s",
359 + $transaction_id
360 + )
361 + );
362 + }
363 +
364 + return !is_null($order_id) ? wc_get_order($order_id) : false;
365 + }
366 +
367 + /**
368 + * Check if a refund id already exist for the order.
369 + *
370 + * @param string $refund_id
371 + *
372 + * @return bool
373 + */
374 + protected function refund_exist_for_order($order_id, $refund_id)
375 + {
376 + global $wpdb;
377 +
378 + if (OrderUtil::custom_orders_table_usage_is_enabled()) {
379 + $results = wc_get_orders(
380 + [
381 + 'meta_query' => [
382 + [
383 + 'field_query' => [
384 + 'relation' => 'AND',
385 + [
386 + 'field' => 'meta_key',
387 + 'value' => '_pr_' . esc_sql($refund_id),
388 + ],
389 + [
390 + 'field' => 'meta_value',
391 + 'value' => $refund_id,
392 + ],
393 + [
394 + 'field' => 'order_id',
395 + 'value' => (int) $order_id,
396 + ],
397 + ],
398 + ],
399 + ],
400 + ]
401 + );
402 + } else {
403 + $sql = "
235 404 SELECT p.ID
236 - FROM $wpdb->posts p
237 - INNER JOIN $wpdb->postmeta pm
238 - ON p.ID = pm.post_id
239 - WHERE 1=1
240 - AND p.post_type = %s
241 - AND p.ID = %d
242 - AND pm.meta_key LIKE '_pr_" . esc_sql( $refund_id ) . "'
243 - AND pm.meta_value = %s
405 + FROM $wpdb->posts p
406 + INNER JOIN $wpdb->postmeta pm
407 + ON p.ID = pm.post_id
408 + WHERE 1=1
409 + AND p.post_type = %s
410 + AND p.ID = %d
411 + AND pm.meta_key LIKE '_pr_" . esc_sql($refund_id) . "'
412 + AND pm.meta_value = %s
244 413 LIMIT 1
245 - ";
414 + ";
246 415
247 - $results = $wpdb->get_col(
248 - $wpdb->prepare(
249 - $sql,
250 - 'shop_order',
251 - (int) $order_id,
252 - $refund_id
253 - )
254 - );
416 + $results = $wpdb->get_col(
417 + $wpdb->prepare(
418 + $sql,
419 + 'shop_order',
420 + (int) $order_id,
421 + $refund_id
422 + )
423 + );
424 + }
255 425
256 - return ! empty( $results ) ? true : false;
257 - }
426 + return !empty($results) ? true : false;
427 + }
258 428
259 - /**
260 - * Save card from the transaction.
261 - *
262 - * @param IVerifiableAPIResource $resource
263 - *
264 - * @return bool
265 - */
266 - protected function maybe_save_card( $resource ) {
429 + /**
430 + * Save card from the transaction.
431 + *
432 + * @param IVerifiableAPIResource $resource
433 + *
434 + * @return bool
435 + */
436 + protected function maybe_save_card($resource)
437 + {
438 + if (!isset($resource->card) || empty($resource->card->id)) {
439 + return false;
440 + }
267 441
268 - if ( ! isset( $resource->card ) || empty( $resource->card->id ) ) {
269 - return false;
270 - }
442 + if (!isset($resource->metadata['customer_id'])) {
443 + return false;
444 + }
271 445
272 - if ( ! isset( $resource->metadata['customer_id'] ) ) {
273 - return false;
274 - }
446 + $customer = get_user_by('id', $resource->metadata['customer_id']);
447 + if (!$customer || 0 === (int) $customer->ID) {
448 + return false;
449 + }
275 450
276 - $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
277 - if ( ! $customer || 0 === (int) $customer->ID ) {
278 - return false;
279 - }
451 + $merchant_id = $this->gateway->get_merchant_id();
452 + if (empty($merchant_id)) {
453 + return false;
454 + }
280 455
281 - $merchant_id = $this->gateway->get_merchant_id();
282 - if ( empty( $merchant_id ) ) {
283 - return false;
284 - }
456 + PayplugGateway::log(sprintf('Saving card from transaction %s for customer %s', wc_clean($resource->id), $customer->ID));
285 457
286 - PayplugGateway::log( sprintf( 'Saving card from transaction %s for customer %s', wc_clean( $resource->id ), $customer->ID ) );
458 + $token = new WC_Payment_Token_CC();
459 + $existing_tokens = WC_Payment_Tokens::get_customer_tokens($customer->ID, $this->gateway->id);
460 + $set_token = wc_clean($resource->card->id);
461 + $set_last4 = wc_clean($resource->card->last4);
462 + $set_expiry_year = wc_clean($resource->card->exp_year);
463 + $set_expiry_month = zeroise((int) wc_clean($resource->card->exp_month), 2);
464 + $set_card_type = \strtolower(wc_clean($resource->card->brand));
465 + if (!empty($existing_tokens)) {
466 + foreach ($existing_tokens as $token_id => $existing_token) {
467 + $current_data = $existing_token->get_data();
468 + if ($current_data['token'] === $set_token &&
469 + $current_data['last4'] === $set_last4 &&
470 + $current_data['expiry_year'] === $set_expiry_year &&
471 + $current_data['expiry_month'] === $set_expiry_month &&
472 + $current_data['card_type'] === $set_card_type) {
473 + $token->set_id($current_data['id']);
474 + }
475 + }
476 + }
287 477
288 - $token = new WC_Payment_Token_CC();
289 - $token->set_token( wc_clean( $resource->card->id ) );
290 - $token->set_gateway_id( 'payplug' );
291 - $token->set_last4( wc_clean( $resource->card->last4 ) );
292 - $token->set_expiry_year( wc_clean( $resource->card->exp_year ) );
293 - $token->set_expiry_month( zeroise( (int) wc_clean( $resource->card->exp_month ), 2 ) );
294 - $token->set_card_type( \strtolower( wc_clean( $resource->card->brand ) ) );
295 - $token->set_user_id( $customer->ID );
296 - $token->add_meta_data( 'mode', $resource->is_live ? 'live' : 'test', true );
297 - $token->add_meta_data( 'payplug_account', \wc_clean( $merchant_id ), true );
298 - $token->save();
478 + $token->set_token($set_token);
479 + $token->set_gateway_id('payplug');
480 + $token->set_last4($set_last4);
481 + $token->set_expiry_year($set_expiry_year);
482 + $token->set_expiry_month($set_expiry_month);
483 + $token->set_card_type($set_card_type);
484 + $token->set_user_id($customer->ID);
485 + $token->add_meta_data('mode', $resource->is_live ? 'live' : 'test', true);
486 + $token->add_meta_data('payplug_account', \wc_clean($merchant_id), true);
487 + $token->save();
299 488
300 - PayplugGateway::log( sprintf( 'Payment card saved', wc_clean( $resource->id ), $customer->ID ) );
489 + PayplugGateway::log(sprintf('Payment card saved', wc_clean($resource->id), $customer->ID));
301 490
302 - return true;
303 - }
491 + return true;
492 + }
304 493
305 - /**
306 - * Save shipping address.
307 - *
308 - * @param IVerifiableAPIResource $resource
309 - *
310 - * @return bool
311 - */
312 - protected function maybe_save_address_hash( $resource ) {
494 + /**
495 + * Save shipping address.
496 + *
497 + * @param IVerifiableAPIResource $resource
498 + *
499 + * @return bool
500 + */
501 + protected function maybe_save_address_hash($resource)
502 + {
503 + if (!isset($resource->metadata['customer_id'])) {
504 + return false;
505 + }
313 506
314 - if ( ! isset( $resource->metadata['customer_id'] ) ) {
315 - return false;
316 - }
507 + $customer = get_user_by('id', $resource->metadata['customer_id']);
508 + if (!$customer || 0 === (int) $customer->ID) {
509 + return false;
510 + }
317 511
318 - $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
319 - if ( ! $customer || 0 === (int) $customer->ID ) {
320 - return false;
321 - }
512 + $shipping = [];
513 + foreach (PayplugAddressData::$address_fields as $field) {
514 + $shipping[$field] = $resource->shipping->{$field};
515 + }
322 516
323 - $shipping = [];
324 - foreach ( PayplugAddressData::$address_fields as $field ) {
325 - $shipping[ $field ] = $resource->shipping->{$field};
326 - }
517 + $shipping_hash = PayplugAddressData::hash_address($shipping);
518 + $hash_list = PayplugAddressData::get_customer_addresses_hash($customer->ID);
519 + $hash_list[] = $shipping_hash;
520 + $hash_list = array_unique($hash_list);
521 + PayplugAddressData::update_customer_addresses_hash($customer->ID, $hash_list);
327 522
328 - $shipping_hash = PayplugAddressData::hash_address( $shipping );
329 - $hash_list = PayplugAddressData::get_customer_addresses_hash( $customer->ID );
330 - $hash_list[] = $shipping_hash;
331 - $hash_list = array_unique( $hash_list );
332 - PayplugAddressData::update_customer_addresses_hash( $customer->ID, $hash_list );
333 -
334 - return true;
335 - }
523 + return true;
524 + }
336 525 }