PluginProbe
PayPlug for WooCommerce (Official) / 1.0.22
PayPlug for WooCommerce (Official) v1.0.22
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.0.22, at src/Gateway/PayplugResponse.php

337 lines 9.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_Token_CC;
15
16 /**
17 * Process responses from PayPlug.
18 *
19 * @package Payplug\PayplugWoocommerce\Gateway
20 */
21 class PayplugResponse {
22
23 private $gateway;
24
25 public function __construct( PayplugGateway $gateway ) {
26 $this->gateway = $gateway;
27 }
28
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' );
43
44 return;
45 }
46
47 PayplugGateway::log( sprintf( 'Order #%s : Begin processing payment IPN %s', $order_id, $resource->id ) );
48
49 // Ignore paid orders
50 if ( $order->is_paid() ) {
51 PayplugGateway::log( sprintf( 'Order #%s : Order is already complete. Ignoring IPN.', $order_id ) );
52
53 return;
54 }
55
56 // Ignore cancelled orders
57 if ( $order->has_status( 'refunded' ) ) {
58 PayplugGateway::log( sprintf( 'Order #%s : Order has been refunded. Ignoring IPN', $order_id ) );
59
60 return;
61 }
62
63 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $resource );
64 PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
65
66 if ( $resource->is_paid ) {
67
68 if ( ! $is_payment_with_token ) {
69 $this->maybe_save_card( $resource );
70 }
71
72 $this->maybe_save_address_hash( $resource );
73
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 }
79
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 );
87
88 PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
89
90 return;
91 }
92
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 );
98
99 /** This action is documented in src/Gateway/PayplugResponse */
100 \do_action( 'payplug_gateway_payment_response_processed', $order_id, $resource );
101
102 PayplugGateway::log( sprintf( 'Order #%s : Payment IPN %s processing completed.', $order_id, $resource->id ) );
103
104 return;
105 }
106 }
107
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' );
123
124 return;
125 }
126 $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
127
128 PayplugGateway::log( sprintf( 'Order #%s : Begin processing refund IPN %s', $order_id, $resource->id ) );
129
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 ) );
133
134 return;
135 }
136
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() ) );
143
144 return;
145 }
146
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 ) );
153
154 return;
155 }
156
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 }
167
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 }
175
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 );
181
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 );
189
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 ) {}
195
196 PayplugGateway::log( sprintf( 'Order #%s : Refund IPN %s processing completed.', $order_id, $resource->id ) );
197 }
198
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;
208
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 );
220
221 return ! is_null( $order_id ) ? wc_get_order( $order_id ) : false;
222 }
223
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;
233
234 $sql = "
235 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
244 LIMIT 1
245 ";
246
247 $results = $wpdb->get_col(
248 $wpdb->prepare(
249 $sql,
250 'shop_order',
251 (int) $order_id,
252 $refund_id
253 )
254 );
255
256 return ! empty( $results ) ? true : false;
257 }
258
259 /**
260 * Save card from the transaction.
261 *
262 * @param IVerifiableAPIResource $resource
263 *
264 * @return bool
265 */
266 protected function maybe_save_card( $resource ) {
267
268 if ( ! isset( $resource->card ) || empty( $resource->card->id ) ) {
269 return false;
270 }
271
272 if ( ! isset( $resource->metadata['customer_id'] ) ) {
273 return false;
274 }
275
276 $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
277 if ( ! $customer || 0 === (int) $customer->ID ) {
278 return false;
279 }
280
281 $merchant_id = $this->gateway->get_merchant_id();
282 if ( empty( $merchant_id ) ) {
283 return false;
284 }
285
286 PayplugGateway::log( sprintf( 'Saving card from transaction %s for customer %s', wc_clean( $resource->id ), $customer->ID ) );
287
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();
299
300 PayplugGateway::log( sprintf( 'Payment card saved', wc_clean( $resource->id ), $customer->ID ) );
301
302 return true;
303 }
304
305 /**
306 * Save shipping address.
307 *
308 * @param IVerifiableAPIResource $resource
309 *
310 * @return bool
311 */
312 protected function maybe_save_address_hash( $resource ) {
313
314 if ( ! isset( $resource->metadata['customer_id'] ) ) {
315 return false;
316 }
317
318 $customer = get_user_by( 'id', $resource->metadata['customer_id'] );
319 if ( ! $customer || 0 === (int) $customer->ID ) {
320 return false;
321 }
322
323 $shipping = [];
324 foreach ( PayplugAddressData::$address_fields as $field ) {
325 $shipping[ $field ] = $resource->shipping->{$field};
326 }
327
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 }
336 }
337