PluginProbe
PayPlug for WooCommerce (Official) / 1.2.2
PayPlug for WooCommerce (Official) v1.2.2
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 1.2.6 All 101 releases
payplug / src / Gateway / PayplugResponse.php

PayplugResponse.php in PayPlug for WooCommerce (Official) 1.2.2, at src/Gateway/PayplugResponse.php

357 lines 10.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Payplug\PayplugWoocommerce\Gateway;
4
5 // Exit if accessed directly
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
11 use Payplug\Resource\IVerifiableAPIResource;
12 use Payplug\Resource\Payment as PaymentResource;
13 use Payplug\Resource\Refund as RefundResource;
14 use WC_Payment_Tokens;
15 use WC_Payment_Token_CC;
16
17 /**
18 * Process responses from PayPlug.
19 *
20 * @package Payplug\PayplugWoocommerce\Gateway
21 */
22 class PayplugResponse {
23
24 private $gateway;
25
26 public function __construct( PayplugGateway $gateway ) {
27 $this->gateway = $gateway;
28 }
29
30 /**
31 * Process payment.
32 *
33 * @param $resource
34 * @param $is_payment_with_token
35 *
36 * @return void
37 * @throws \WC_Data_Exception
38 */
39 public function process_payment( $resource, $is_payment_with_token = false ) {
40 $order_id = wc_clean( $resource->metadata['order_id'] );
41 $order = wc_get_order( $order_id );
42 if ( ! $order ) {
43 PayplugGateway::log( sprintf( 'Coudn\'t find order #%s (Transaction %s).', $order_id, wc_clean( $resource->id ) ), 'error' );
44
45 return;
46 }
47
48 PayplugGateway::log( sprintf( 'Order #%s : Begin processing payment IPN %s', $order_id, $resource->id ) );
49
50 // Ignore paid orders
51 if ( $order->is_paid() ) {
52 PayplugGateway::log( sprintf( 'Order #%s : Order is already complete. Ignoring IPN.', $order_id ) );
53
54 return;
55 }
56
57 // Ignore cancelled orders
58 if ( $order->has_status( 'refunded' ) ) {
59 PayplugGateway::log( sprintf( 'Order #%s : Order has been refunded. Ignoring IPN', $order_id ) );
60
61 return;
62 }
63
64 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $resource );
65 PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
66
67 if ( $resource->is_paid ) {
68
69 if ( ! $is_payment_with_token ) {
70 $this->maybe_save_card( $resource );
71 }
72
73 $this->maybe_save_address_hash( $resource );
74
75 $order->add_order_note( sprintf( __( 'PayPlug IPN OK | Transaction %s', 'payplug' ), wc_clean( $resource->id ) ) );
76 $order->payment_complete( wc_clean( $resource->id ) );
77 if ( PayplugWoocommerceHelper::is_pre_30() ) {
78 $order->reduce_order_stock();
79 }
80
81 /**
82 * Fires once a payment response has been processed.
83 *
84 * @param int $order_id Order ID
85 * @param PaymentResource $resource Payment resource
86 */
87 \do_action( 'payplug_gateway_payment_response_processed', $order_id, $resource );
88
89 PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
90
91 return;
92 }
93
94 if ( ! empty( $resource->failure ) ) {
95 $order->update_status(
96 'failed',
97 sprintf( __( 'PayPlug IPN OK | Transaction %s failed : %s', 'payplug' ), $resource->id, wc_clean( $resource->failure->message ) )
98 );
99
100 /** This action is documented in src/Gateway/PayplugResponse */
101 \do_action( 'payplug_gateway_payment_response_processed', $order_id, $resource );
102
103 PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
104
105 return;
106 }
107 }
108
109 /**
110 * Process refund.
111 *
112 * @param $resource
113 * @param bool $ignore_woocommerce_refund Flag to determine if IPN notification for refunds created by WooCommerce
114 * should be ignored or not. Default to true.
115 *
116 * @throws \Exception
117 */
118 public function process_refund( $resource, $ignore_woocommerce_refund = true ) {
119 $refund_id = wc_clean( $resource->id );
120 $transaction_id = wc_clean( $resource->payment_id );
121 $order = $this->get_order_from_transaction_id( $transaction_id );
122 if ( ! $order ) {
123 PayplugGateway::log( sprintf( 'Coudn\'t find order for transaction %s (Refund %s).', wc_clean( $resource->payment_id ), wc_clean( $resource->id ) ), 'error' );
124
125 return;
126 }
127 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
128
129 PayplugGateway::log( sprintf( 'Order #%s : Begin processing refund IPN %s', $order_id, $resource->id ) );
130
131 $refund_exist = $this->refund_exist_for_order( $order_id, $refund_id );
132 if ( $refund_exist ) {
133 PayplugGateway::log( sprintf( 'Order #%s : Refund has already been processed. Ignoring IPN.', $order_id ) );
134
135 return;
136 }
137
138 // Since refund notification doesn't contain the full resource, we need to retrieve
139 // the refund resource to access its metadata.
140 try {
141 $refund = $this->gateway->api->refund_retrieve( $transaction_id, $refund_id );
142 } catch ( \Exception $e ) {
143 PayplugGateway::log( sprintf( 'Order #%s : Fail to retrieve refund data with error %s', $order_id, $e->getMessage() ) );
144
145 return;
146 }
147
148 if (
149 $ignore_woocommerce_refund
150 && isset( $refund->metadata['refund_from'] )
151 && 'woocommerce' === $refund->metadata['refund_from']
152 ) {
153 PayplugGateway::log( sprintf( 'Order #%s : Refund created by WooCommerce. Ignoring IPN.', $order_id ) );
154
155 return;
156 }
157
158 $refund = wc_create_refund( [
159 'amount' => ( (int) $resource->amount ) / 100,
160 'reason' => isset( $resource->metadata['reason'] ) ? $resource->metadata['reason'] : null,
161 'order_id' => (int) $order_id,
162 'refund_id' => 0,
163 'refund_payment' => false,
164 ] );
165 if ( is_wp_error( $refund ) ) {
166 PayplugGateway::log( $refund->get_error_message() );
167 }
168
169 $refund_meta_key = sprintf( '_pr_%s', wc_clean( $resource->id ) );
170 if ( PayplugWoocommerceHelper::is_pre_30() ) {
171 update_post_meta( $order_id, $refund_meta_key, $resource->id );
172 } else {
173 $order->add_meta_data( $refund_meta_key, $resource->id, true );
174 $order->save();
175 }
176
177 $note = sprintf( __( 'Refund %s : Refunded %s', 'payplug' ), wc_clean( $resource->id ), wc_price( ( (int) $resource->amount ) / 100 ) );
178 if ( ! empty( $resource->metadata['reason'] ) ) {
179 $note .= sprintf( ' (%s)', esc_html( $resource->metadata['reason'] ) );
180 }
181 $order->add_order_note( $note );
182
183 /**
184 * Fires once a refund response has been processed.
185 *
186 * @param int $order_id Order ID
187 * @param RefundResource $resource Refund resource
188 */
189 \do_action( 'payplug_gateway_refund_response_processed', $order_id, $resource );
190
191 try {
192 $payment = $this->gateway->api->payment_retrieve( $transaction_id );
193 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $payment );
194 PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
195 } catch ( \Exception $e ) {}
196
197 PayplugGateway::log( sprintf( 'Order #%s : Refund IPN %s processing completed.', $order_id, $resource->id ) );
198 }
199
200 /**
201 * Get an order from its transaction id.
202 *
203 * @param int $transaction_id
204 *
205 * @return bool|\WC_Order
206 */
207 protected function get_order_from_transaction_id( $transaction_id ) {
208 global $wpdb;
209
210 $order_id = $wpdb->get_var(
211 $wpdb->prepare(
212 "
213 SELECT post_id
214 FROM $wpdb->postmeta
215 WHERE meta_key = '_transaction_id'
216 AND meta_value = %s
217 ",
218 $transaction_id
219 )
220 );
221
222 return ! is_null( $order_id ) ? wc_get_order( $order_id ) : false;
223 }
224
225 /**
226 * Check if a refund id already exist for the order.
227 *
228 * @param string $refund_id
229 *
230 * @return bool
231 */
232 protected function refund_exist_for_order( $order_id, $refund_id ) {
233 global $wpdb;
234
235 $sql = "
236 SELECT p.ID
237 FROM $wpdb->posts p
238 INNER JOIN $wpdb->postmeta pm
239 ON p.ID = pm.post_id
240 WHERE 1=1
241 AND p.post_type = %s
242 AND p.ID = %d
243 AND pm.meta_key LIKE '_pr_" . esc_sql( $refund_id ) . "'
244 AND pm.meta_value = %s
245 LIMIT 1
246 ";
247
248 $results = $wpdb->get_col(
249 $wpdb->prepare(
250 $sql,
251 'shop_order',
252 (int) $order_id,
253 $refund_id
254 )
255 );
256
257 return ! empty( $results ) ? true : false;
258 }
259
260 /**
261 * Save card from the transaction.
262 *
263 * @param IVerifiableAPIResource $resource
264 *
265 * @return bool
266 */
267 protected function maybe_save_card( $resource ) {
268
269 if ( ! isset( $resource->card ) || empty( $resource->card->id ) ) {
270 return false;
271 }
272
273 if ( ! isset( $resource->metadata['customer_id'] ) ) {
274 return false;
275 }
276
277 $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
278 if ( ! $customer || 0 === (int) $customer->ID ) {
279 return false;
280 }
281
282 $merchant_id = $this->gateway->get_merchant_id();
283 if ( empty( $merchant_id ) ) {
284 return false;
285 }
286
287 PayplugGateway::log( sprintf( 'Saving card from transaction %s for customer %s', wc_clean( $resource->id ), $customer->ID ) );
288
289 $token = new WC_Payment_Token_CC();
290 $existing_tokens = WC_Payment_Tokens::get_customer_tokens( $customer->ID , $this->gateway->id );
291 $set_token = wc_clean( $resource->card->id );
292 $set_last4 = wc_clean( $resource->card->last4 );
293 $set_expiry_year = wc_clean( $resource->card->exp_year ) ;
294 $set_expiry_month = zeroise( (int) wc_clean( $resource->card->exp_month ), 2 ) ;
295 $set_card_type = \strtolower( wc_clean( $resource->card->brand ) ) ;
296 if(!empty($existing_tokens)) {
297 foreach($existing_tokens as $token_id => $existing_token) {
298 $current_data = $existing_token->get_data();
299 if( $current_data['token'] === $set_token &&
300 $current_data['last4'] === $set_last4 &&
301 $current_data['expiry_year'] === $set_expiry_year &&
302 $current_data['expiry_month'] === $set_expiry_month &&
303 $current_data['card_type'] === $set_card_type) {
304 $token->set_id($current_data['id']);
305 }
306 }
307 }
308
309 $token->set_token( $set_token );
310 $token->set_gateway_id( 'payplug' );
311 $token->set_last4( $set_last4 );
312 $token->set_expiry_year( $set_expiry_year );
313 $token->set_expiry_month( $set_expiry_month );
314 $token->set_card_type( $set_card_type );
315 $token->set_user_id( $customer->ID );
316 $token->add_meta_data( 'mode', $resource->is_live ? 'live' : 'test', true );
317 $token->add_meta_data( 'payplug_account', \wc_clean( $merchant_id ), true );
318 $token->save();
319
320 PayplugGateway::log( sprintf( 'Payment card saved', wc_clean( $resource->id ), $customer->ID ) );
321
322 return true;
323 }
324
325 /**
326 * Save shipping address.
327 *
328 * @param IVerifiableAPIResource $resource
329 *
330 * @return bool
331 */
332 protected function maybe_save_address_hash( $resource ) {
333
334 if ( ! isset( $resource->metadata['customer_id'] ) ) {
335 return false;
336 }
337
338 $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
339 if ( ! $customer || 0 === (int) $customer->ID ) {
340 return false;
341 }
342
343 $shipping = [];
344 foreach ( PayplugAddressData::$address_fields as $field ) {
345 $shipping[ $field ] = $resource->shipping->{$field};
346 }
347
348 $shipping_hash = PayplugAddressData::hash_address( $shipping );
349 $hash_list = PayplugAddressData::get_customer_addresses_hash( $customer->ID );
350 $hash_list[] = $shipping_hash;
351 $hash_list = array_unique( $hash_list );
352 PayplugAddressData::update_customer_addresses_hash( $customer->ID, $hash_list );
353
354 return true;
355 }
356 }
357