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/PayplugGateway.php +1175 -1230 1.0.18 → 3.1.0 View file →
@@ -2,10 +2,10 @@
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 10 use Payplug\Authentication;
11 11 use Payplug\Exception\ConfigurationException;
@@ -10,10 +10,11 @@
10 10 use Payplug\Authentication;
11 11 use Payplug\Exception\ConfigurationException;
12 12 use Payplug\Exception\HttpException;
13 13 use Payplug\Payplug;
14 -use Payplug\PayplugWoocommerce\Admin\Ajax;
14 +use Payplug\PayplugWoocommerce\Helper\Lock;
15 15 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
16 +use Payplug\PayplugWoocommerce\Traits\ServiceGetter;
16 17 use Payplug\Resource\Payment as PaymentResource;
17 18 use Payplug\Resource\Refund as RefundResource;
18 19 use WC_Payment_Gateway_CC;
19 20 use WC_Payment_Tokens;
@@ -19,1409 +20,1353 @@
19 20 use WC_Payment_Tokens;
20 21
21 22 /**
22 23 * PayPlug WooCommerce Gateway.
23 - *
24 - * @package Payplug\PayplugWoocommerce\Gateway
25 24 */
26 -class PayplugGateway extends WC_Payment_Gateway_CC {
25 +class PayplugGateway extends WC_Payment_Gateway_CC
26 +{
27 + use ServiceGetter;
27 28
28 - /**
29 - * @var PayplugGatewayRequirements
30 - */
31 - private $requirements;
29 + public const OPTION_NAME = 'payplug_config';
32 30
33 - /**
34 - * @var PayplugPermissions
35 - */
36 - private $permissions;
31 + /**
32 + * @var string
33 + */
34 + public $mode;
35 + /**
36 + * @var bool
37 + */
38 + public $debug;
39 + /**
40 + * @var string
41 + */
42 + public $email;
43 + /**
44 + * @var string
45 + */
46 + public $embedded_mode;
47 + /**
48 + * @var bool
49 + */
50 + public $save_card;
37 51
38 - /**
39 - * @var PayplugResponse
40 - */
41 - public $response;
52 + /**
53 + * @var string
54 + */
55 + public $oney_type;
42 56
43 - /**
44 - * @var PayplugApi
45 - */
46 - public $api;
57 + /**
58 + * @var string
59 + */
60 + public $oney_product_animation;
47 61
48 - /**
49 - * @var \WC_Logger
50 - */
51 - protected static $log;
62 + /**
63 + * @var PayplugGatewayRequirements
64 + */
65 + private $requirements;
52 66
53 - /**
54 - * @var bool
55 - */
56 - protected static $log_enabled;
67 + /**
68 + * @var PayplugPermissions
69 + */
70 + private $permissions;
57 71
58 - /**
59 - * Logging method.
60 - *
61 - * @param string $message Log message.
62 - * @param string $level Optional. Default 'info'.
63 - * emergency|alert|critical|error|warning|notice|info|debug
64 - */
65 - public static function log( $message, $level = 'info' ) {
66 - if ( ! self::$log_enabled ) {
67 - return;
68 - }
72 + /**
73 + * @var PayplugResponse
74 + */
75 + public $response;
69 76
70 - if ( empty( self::$log ) ) {
71 - self::$log = PayplugWoocommerceHelper::is_pre_30() ? new \WC_Logger() : wc_get_logger();
72 - }
77 + /**
78 + * @var PayplugApi
79 + */
80 + public $payplug_api;
73 81
74 - PayplugWoocommerceHelper::is_pre_30()
75 - ? self::$log->add( 'payplug_gateway', $message )
76 - : self::$log->log( $level, $message, array( 'source' => 'payplug_gateway' ) );
77 - }
82 + /**
83 + * @var \WC_Logger
84 + */
85 + protected static $log;
78 86
79 - public function __construct() {
80 - $this->id = 'payplug';
81 - $this->icon = '';
82 - $this->has_fields = false;
83 - $this->method_title = _x( 'PayPlug', 'Gateway method title', 'payplug' );
84 - $this->method_description = __( 'Enable PayPlug for your customers.', 'payplug' );
85 - $this->supports = array(
86 - 'products',
87 - 'refunds',
88 - 'tokenization',
89 - );
90 - $this->new_method_label = __( 'Pay with another credit card', 'payplug' );
87 + /**
88 + * @var bool
89 + */
90 + protected static $log_enabled;
91 91
92 - $this->init_settings();
93 - $this->requirements = new PayplugGatewayRequirements( $this );
94 - if ( $this->user_logged_in() ) {
95 - $this->init_payplug();
96 - }
97 - $this->init_form_fields();
92 + /**
93 + * @var float
94 + */
95 + public const MIN_AMOUNT = 0.99;
98 96
99 - $this->title = $this->get_option( 'title' );
100 - $this->description = $this->get_option( 'description' );
101 - $this->mode = 'yes' === $this->get_option( 'mode', 'no' ) ? 'live' : 'test';
102 - $this->debug = 'yes' === $this->get_option( 'debug', 'no' );
103 - $this->email = $this->get_option( 'email' );
104 - $this->payment_method = $this->get_option( 'payment_method' );
105 - $this->oneclick = 'yes' === $this->get_option( 'oneclick', 'no' );
97 + /**
98 + * @var float
99 + */
100 + public const MAX_AMOUNT = 20000;
106 101
107 - add_filter( 'woocommerce_get_customer_payment_tokens', [ $this, 'filter_tokens' ], 10, 3 );
102 + /**
103 + * @var string
104 + */
105 + private $payplug_merchant_country = 'FR';
108 106
109 - self::$log_enabled = $this->debug;
107 + protected $oney_response;
108 + public $min_oney_price;
109 + public $oney_thresholds_min;
110 + public $max_oney_price;
111 + public $oney_thresholds_max;
110 112
111 - // Ensure the description is not empty to correctly display users's save cards
112 - if ( empty( $this->description ) && 0 !== count( $this->get_tokens() ) ) {
113 - $this->description = ' ';
114 - }
113 + public const ENABLE_ON_TEST_MODE = true;
115 114
116 - if ( 'test' === $this->mode ) {
117 - $this->description .= " \n";
115 + /**
116 + * Logging method.
117 + *
118 + * @param string $message Log message.
119 + * @param string $level Optional. Default 'info'.
120 + * emergency|alert|critical|error|warning|notice|info|debug
121 + */
122 + public static function log($message, $level = 'info'): void
123 + {
124 + if (!self::$log_enabled) {
125 + return;
126 + }
118 127
119 - $this->description .= __( 'You are in TEST MODE. In test mode you can use the card 4242424242424242 with any valid expiration date and CVC.', 'payplug' );
120 - $this->description = trim( $this->description );
121 - }
128 + if (empty(self::$log)) {
129 + self::$log = PayplugWoocommerceHelper::is_pre_30() ? new \WC_Logger() : wc_get_logger();
130 + }
122 131
123 - add_filter( 'woocommerce_get_order_item_totals', [ $this, 'customize_gateway_title' ], 10, 2 );
124 - add_action( 'wp_enqueue_scripts', [ $this, 'scripts' ] );
125 - add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, [ $this, 'process_admin_options' ] );
126 - add_action( 'the_post', [ $this, 'validate_payment' ] );
127 - }
132 + PayplugWoocommerceHelper::is_pre_30()
133 + ? self::$log->add('payplug_gateway', $message)
134 + : self::$log->log($level, $message, ['source' => 'payplug_gateway']);
135 + }
128 136
129 - /**
130 - * Customize gateway title in emails.
131 - *
132 - * @param array $total_rows
133 - * @param \WC_Order $order
134 - *
135 - * @return array
136 - *
137 - * @author Clément Boirie
138 - */
139 - public function customize_gateway_title( $total_rows, $order ) {
137 + /**
138 + * Construct method
139 + *
140 + * @return void
141 + */
142 + public function __construct()
143 + {
144 + //required plugin id
145 + $this->id = 'payplug';
146 + $this->supports = [
147 + 'products',
148 + 'refunds',
149 + 'tokenization',
150 + ];
140 151
141 - $payment_method = PayplugWoocommerceHelper::is_pre_30() ? $order->payment_method : $order->get_payment_method();
142 - if (
143 - $this->id !== $payment_method
144 - || ! isset( $total_rows['payment_method'] )
145 - ) {
146 - return $total_rows;
147 - }
152 + $payplug_gateways = ['payplug', 'american_express', 'apple_pay', 'bancontact', 'oney_x3_with_fees', 'oney_x3_without_fees', 'oney_x4_with_fees', 'oney_x4_without_fees', 'satispay', 'ideal', 'mybank', 'wero', 'bizum', 'scalapay'];
148 153
149 - $total_rows['payment_method']['value'] = __( 'Credit card', 'payplug' );
154 + //save buttom admin
155 + if ((!empty($_GET['section'])) && (in_array($_GET['section'], $payplug_gateways))) {
156 + $GLOBALS['hide_save_button'] = true;
157 + }
150 158
151 - return $total_rows;
152 - }
159 + $this->init_settings();
160 + $this->requirements = new PayplugGatewayRequirements($this);
161 + if ($this->user_logged_in()) {
162 + $this->init_payplug();
163 + }
153 164
154 - /**
155 - * Validate order payment when the user is redirected to the success confirmation page.
156 - *
157 - * @throws \WC_Data_Exception
158 - */
159 - public function validate_payment() {
160 - if ( ! is_wc_endpoint_url( 'order-received' ) || empty( $_GET['key'] ) ) {
161 - return;
162 - }
165 + $this->mode = (bool) $this->get_configuration()->get_option('mode') ? 'live' : 'test';
166 + $this->debug = (bool) $this->get_configuration()->get_option('debug');
167 + $this->email = (string) $this->get_configuration()->get_option('email');
163 168
164 - $order_id = wc_get_order_id_by_order_key( wc_clean( $_GET['key'] ) );
165 - if ( empty( $order_id ) ) {
166 - return;
167 - }
169 + //admin form
170 + $this->init_form_fields();
168 171
169 - $order = wc_get_order( $order_id );
170 - if ( ! $order instanceof \WC_Order ) {
171 - return;
172 - }
172 + add_filter('woocommerce_get_customer_payment_tokens', [$this, 'filter_tokens'], 10, 3);
173 173
174 - $payment_method = PayplugWoocommerceHelper::is_pre_30() ? $order->payment_method : $order->get_payment_method();
175 - if ( 'payplug' !== $payment_method ) {
176 - return;
177 - }
174 + self::$log_enabled = $this->debug;
178 175
179 - $transaction_id = PayplugWoocommerceHelper::is_pre_30() ? get_post_meta( $order_id, '_transaction_id', true ) : $order->get_transaction_id();
180 - if ( empty( $transaction_id ) ) {
181 - PayplugGateway::log( sprintf( 'Order #%s : Missing transaction id.', $order_id ), 'error' );
176 + add_filter('woocommerce_get_order_item_totals', [$this, 'customize_gateway_title'], 10, 2);
177 + add_action('woocommerce_thankyou', [$this, 'validate_payment']);
178 + add_action('the_post', [$this, 'validate_payment']);
179 + add_action('woocommerce_available_payment_gateways', [$this, 'check_gateway']);
180 + }
182 181
183 - return;
184 - }
182 + /**
183 + * @param $option
184 + * @param $value
185 + *
186 + * @return bool|void
187 + */
188 + public function update_option($option, $value = '')
189 + {
190 + if ($this->needs_setup()) {
191 + wp_send_json_error('needs_setup');
192 + wp_die();
193 + }
185 194
186 - try {
187 - $payment = $this->api->payment_retrieve( $transaction_id );
188 - } catch ( \Exception $e ) {
189 - PayplugGateway::log(
190 - sprintf( 'Order #%s : An error occurred while retrieving the payment data with the message : %s',
191 - $order_id,
192 - $e->getMessage()
193 - )
194 - );
195 + parent::update_option($option, $value);
196 + }
195 197
196 - return;
197 - }
198 + /**
199 + * this payment gateway cannot be updated on the wooco payment settings
200 + *
201 + * @return bool
202 + */
203 + public function needs_setup()
204 + {
205 + return true;
206 + }
198 207
199 - $this->response->process_payment( $payment );
200 - }
208 + /**
209 + * Customize gateway title in emails.
210 + *
211 + * @param array $total_rows
212 + * @param \WC_Order $order
213 + *
214 + * @return array
215 + *
216 + * @author Clément Boirie
217 + */
218 + public function customize_gateway_title($total_rows, $order)
219 + {
220 + $get_payment_method = $this->id;
221 + if (method_exists($order, 'get_payment_method')) {
222 + $get_payment_method = $order->get_payment_method();
223 + }
201 224
202 - /**
203 - * Get payment icons.
204 - *
205 - * @return string
206 - */
207 - public function get_icon() {
225 + $payment_method = PayplugWoocommerceHelper::is_pre_30() ? $order->payment_method : $get_payment_method;
226 + if (
227 + $this->id !== $payment_method
228 + || !isset($total_rows['payment_method'])
229 + ) {
230 + return $total_rows;
231 + }
208 232
209 - $src = ( 'it_IT' === get_locale() )
210 - ? PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/logos_scheme_PostePay.svg'
211 - : PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/logos_scheme_CB.svg';
233 + $total_rows['payment_method']['value'] = __('Credit card', 'payplug');
212 234
213 - $icons = apply_filters( 'payplug_payment_icons', [
214 - 'payplug' => sprintf( '<img src="%s" alt="Visa & Mastercard" class="payplug-payment-icon" />', esc_url( $src ) ),
215 - ] );
235 + return $total_rows;
236 + }
216 237
217 - $icons_str = '';
218 - foreach ( $icons as $icon ) {
219 - $icons_str .= $icon;
220 - }
238 + /**
239 + * Validate order payment when the user is redirected to the success confirmation page.
240 + *
241 + * @throws \WC_Data_Exception
242 + */
243 + public function validate_payment($id = null, $save_request = true, $ipn = false): void
244 + {
245 + global $wp;
221 246
222 - return $icons_str;
223 - }
247 + if (!$ipn) {
248 + if (!is_wc_endpoint_url('order-received') || (empty($_GET['key']) && empty($id))) {
249 + return;
250 + }
251 + }
224 252
225 - /**
226 - * Check if this gateway is enabled
227 - */
228 - public function is_available() {
229 - if ( 'yes' === $this->enabled ) {
230 - return $this->requirements->satisfy_requirements() && ! empty( $this->get_api_key( $this->get_current_mode() ) );
231 - }
253 + if (!empty($_GET['order-received'])) {
254 + $order_id = (int) ($_GET['order-received']);
255 + } elseif (!empty($id) && !is_object($id)) {
256 + $order_id = (int) $id;
257 + }
232 258
233 - return parent::is_available();
234 - }
259 + if (empty($order_id) && (isset($wp->query_vars['order-received']))) {
260 + $order_id = apply_filters(
261 + 'woocommerce_thankyou_order_id',
262 + absint($wp->query_vars['order-received'])
263 + );
264 + }
235 265
236 - /**
237 - * Load gateway settings.
238 - */
239 - public function init_settings() {
240 - parent::init_settings();
241 - $this->enabled = ! empty( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled'] ? 'yes' : 'no';
242 - }
266 + if (empty($order_id)) {
267 + if (empty($_GET['key']) && empty($id) && !is_object($id)) {
268 + return;
269 + }
270 + $order_id = wc_get_order_id_by_order_key(wc_clean((!empty($_GET['key']) ? $_GET['key'] : (int) $id)));
271 + }
243 272
244 - /**
245 - * Register gateway settings.
246 - */
247 - public function init_form_fields() {
248 - $fields = [
249 - 'enabled' => [
250 - 'title' => __( 'Enable/Disable', 'payplug' ),
251 - 'type' => 'checkbox',
252 - 'label' => __( 'Enable PayPlug', 'payplug' ),
253 - 'description' => __( 'Only Euro payments can be processed with PayPlug.', 'payplug' ),
254 - 'default' => 'no',
255 - ],
256 - 'title' => [
257 - 'title' => __( 'Title', 'payplug' ),
258 - 'type' => 'text',
259 - 'description' => __( 'The payment solution title displayed during checkout.', 'payplug' ),
260 - 'default' => _x( 'Credit card checkout', 'Default gateway title', 'payplug' ),
261 - 'desc_tip' => true,
262 - ],
263 - 'description' => [
264 - 'title' => __( 'Description', 'payplug' ),
265 - 'type' => 'text',
266 - 'description' => __( 'The payment solution description displayed during checkout.', 'payplug' ),
267 - 'default' => '',
268 - 'desc_tip' => true,
269 - ],
270 - 'title_connexion' => [
271 - 'title' => __( 'Connection', 'payplug' ),
272 - 'type' => 'title',
273 - ],
274 - 'email' => [
275 - 'type' => 'hidden',
276 - 'default' => '',
277 - ],
278 - 'login' => [
279 - 'type' => 'login',
280 - 'default' => '',
281 - ],
282 - 'payplug_test_key' => [
283 - 'type' => 'hidden',
284 - 'default' => '',
285 - ],
286 - 'payplug_live_key' => [
287 - 'type' => 'hidden',
288 - 'default' => '',
289 - ],
290 - 'payplug_merchant_id' => [
291 - 'type' => 'hidden',
292 - 'default' => '',
293 - ],
294 - 'title_testmode' => [
295 - 'title' => __( 'Mode', 'payplug' ),
296 - 'type' => 'title',
297 - ],
298 - 'mode' => [
299 - 'title' => '',
300 - 'label' => '',
301 - 'type' => 'yes_no',
302 - 'yes' => 'Live',
303 - 'no' => 'Test',
304 - 'description' => __( 'In TEST mode, all payments will be simulations and will not generate real transactions.', 'payplug' ),
305 - 'default' => 'no',
306 - 'hide_label' => true,
307 - ],
308 - 'title_settings' => [
309 - 'title' => __( 'Settings', 'payplug' ),
310 - 'type' => 'title',
311 - ],
312 - 'payment_method' => [
313 - 'title' => __( 'Payment page', 'payplug' ),
314 - 'type' => 'radio',
315 - 'description' => __( 'Customers will be redirected to a PayPlug payment page to finalize the transaction, or payments will be performed in an embeddable payment form on your website.', 'payplug' ),
316 - 'default' => 'redirect',
317 - 'desc_tip' => true,
318 - 'options' => array(
319 - 'redirect' => __( 'Redirect', 'payplug' ),
320 - 'embedded' => __( 'Integrated', 'payplug' ),
321 - ),
322 - ],
323 - 'debug' => [
324 - 'title' => __( 'Debug', 'payplug' ),
325 - 'type' => 'checkbox',
326 - 'description' => __( 'Debug mode saves additional information on your server for each operation done via the PayPlug plugin (Developer setting).', 'payplug' ),
327 - 'label' => __( 'Activate debug mode', 'payplug' ),
328 - 'default' => 'yes',
329 - 'desc_tip' => true,
330 - ],
331 - 'title_advanced_settings' => [
332 - 'title' => __( 'Advanced Settings', 'payplug' ),
333 - 'description' => __( 'This feature is available to PREMIUM accounts only. You can try it in TEST mode.',
334 - 'payplug' ),
335 - 'type' => 'title',
336 - ],
337 - 'oneclick' => [
338 - 'title' => __( 'One Click Payment', 'payplug' ),
339 - 'type' => 'checkbox',
340 - 'label' => __( 'Activate', 'payplug' ),
341 - 'description' => __( 'Allow your customers to save their credit card information for later purchases.', 'payplug' ),
342 - 'default' => 'no',
343 - 'desc_tip' => true,
344 - ],
345 - ];
273 + if (empty($order_id)) {
274 + return;
275 + }
346 276
347 - // Disable One-Click checkbox if the user doesn't have the permission to use it.
348 - if ( $this->user_logged_in() && 'live' === $this->get_current_mode() ) {
349 - $fields['oneclick']['disabled'] = ! $this->permissions->has_permissions( PayplugPermissions::SAVE_CARD );
350 - }
277 + $order = wc_get_order($order_id);
278 + if (!$order instanceof \WC_Order) {
279 + return;
280 + }
351 281
352 - /**
353 - * Filter PayPlug gateway settings.
354 - *
355 - * @param array $fields
356 - */
357 - $fields = apply_filters( 'payplug_gateway_settings', $fields );
358 - $this->form_fields = $fields;
359 - }
282 + $payment_method = PayplugWoocommerceHelper::is_pre_30() ? $order->payment_method : $order->get_payment_method();
283 + if (!in_array($payment_method, ['payplug', 'oney_x3_with_fees', 'oney_x4_with_fees', 'oney_x3_without_fees', 'oney_x4_without_fees', 'bancontact', 'apple_pay', 'american_express', 'satispay', 'mybank', 'ideal', 'wero', 'bizum', 'scalapay'])) {
284 + return;
285 + }
360 286
361 - /**
362 - * Set global configuration for PayPlug instance.
363 - */
364 - public function init_payplug() {
365 - $this->api = new PayplugApi( $this );
366 - $this->api->init();
287 + if ($payment_method === $this->id) {
288 + $transaction_id = PayplugWoocommerceHelper::is_pre_30() ? get_post_meta($order_id, '_transaction_id', true) : $order->get_transaction_id();
289 + if (empty($transaction_id)) {
290 + self::log(sprintf('Order #%s : Missing transaction id.', $order_id), 'error');
367 291
368 - $this->permissions = new PayplugPermissions( $this );
369 - $this->response = new PayplugResponse( $this );
292 + return;
293 + }
370 294
371 - // Register IPN handler
372 - new PayplugIpnResponse( $this );
373 - }
295 + $lock_id = Lock::handle_insert($save_request, $transaction_id);
296 + if (!$lock_id) {
297 + return;
298 + }
374 299
375 - /**
376 - * Embedded payment form scripts.
377 - *
378 - * Register scripts and additionnal data needed for the
379 - * embedded payment form.
380 - */
381 - public function scripts() {
382 - if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) && ! is_add_payment_method_page() && ! isset( $_GET['change_payment_method'] ) ) {
383 - return;
384 - }
300 + try {
301 + $payment = $this->payplug_api->payment_retrieve($transaction_id);
302 + } catch (\Exception $e) {
303 + self::log(
304 + sprintf(
305 + 'Order #%s : An error occurred while retrieving the payment data with the message : %s',
306 + $order_id,
307 + $e->getMessage()
308 + )
309 + );
385 310
386 - // If PayPlug is not enabled bail.
387 - if ( 'no' === $this->enabled ) {
388 - return;
389 - }
311 + return;
312 + }
390 313
391 - // If keys are not set bail.
392 - if ( empty( $this->get_api_key( $this->mode ) ) ) {
393 - PayplugGateway::log( 'Keys are not set correctly.' );
314 + $this->response->process_payment($payment);
394 315
395 - return;
396 - }
316 + \Payplug\PayplugWoocommerce\Model\Lock::delete_lock($lock_id);
317 + $waiting_requests = \Payplug\PayplugWoocommerce\Model\Lock::get_lock_by_payment_id($transaction_id);
397 318
398 - // Register checkout styles.
399 - wp_register_style( 'payplug-checkout', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/css/payplug-checkout.css', [], PAYPLUG_GATEWAY_VERSION );
400 - wp_enqueue_style( 'payplug-checkout' );
319 + if ($waiting_requests) {
320 + \Payplug\PayplugWoocommerce\Model\Lock::delete_lock_by_payment_id($transaction_id);
321 + $this->validate_payment($order_id, false);
322 + }
323 + }
324 + }
401 325
326 + /**
327 + * Check if this gateway is enabled
328 + */
329 + public function is_available()
330 + {
331 + if ('yes' == $this->enabled) {
332 + $available = $this->requirements->satisfy_requirements() && !empty($this->get_api_key($this->get_current_mode()));
402 333
403 - // Register scripts for embedded payment form.
404 - if ( 'embedded' !== $this->payment_method ) {
405 - return;
406 - }
334 + // $this->enabled only reflects the country/context check as it was at gateway construction time,
335 + // so re-run it here to catch context that only becomes known later in the request (e.g. order-pay).
336 + if ($available && method_exists($this, 'checkGateway')) {
337 + $available = $this->checkGateway();
338 + }
407 339
408 - wp_register_script( 'payplug', 'https://api.payplug.com/js/1/form.latest.js', [], null, true );
409 - wp_register_script( 'payplug-checkout', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-checkout.js', [
410 - 'jquery',
411 - 'payplug'
412 - ], PAYPLUG_GATEWAY_VERSION, true );
413 - wp_localize_script( 'payplug-checkout', 'payplug_checkout_params', [
414 - 'ajax_url' => \WC_AJAX::get_endpoint( 'payplug_create_order' ),
415 - 'nonce' => [
416 - 'checkout' => wp_create_nonce( 'woocommerce-process_checkout' ),
417 - ],
418 - ] );
419 - wp_enqueue_script( 'payplug-checkout' );
420 - }
340 + return $available;
341 + }
421 342
422 - /**
423 - * Filter saved tokens for the gateway.
424 - *
425 - * A token will be removed if :
426 - * - it doesn't match the current merchant logged in,
427 - * - or it doesn't match the current gateway mode,
428 - * - or it is expired.
429 - *
430 - * @param array $tokens
431 - * @param int $user_id
432 - * @param string $gateway_id
433 - *
434 - * @return array
435 - */
436 - public function filter_tokens( $tokens, $user_id, $gateway_id ) {
343 + return parent::is_available();
344 + }
437 345
438 - if ( ! is_user_logged_in() || ! class_exists( 'WC_Payment_Gateway_CC' ) ) {
439 - return $tokens;
440 - }
346 + /**
347 + * Load gateway settings.
348 + */
349 + public function init_settings(): void
350 + {
351 + parent::init_settings();
352 + $enabled = !empty($this->settings['enabled']) && (bool) $this->settings['enabled'];
353 + $this->enabled = $enabled ? 'yes' : 'no';
354 + }
441 355
442 - /* @var \WC_Payment_Token_CC $token */
443 - foreach ( $tokens as $k => $token ) {
356 + /**
357 + * Register gateway settings.
358 + */
359 + public function init_form_fields(): void
360 + {
361 + $anchor = esc_html_x(__('More informations', 'payplug'), 'modal', 'payplug');
362 + $domain = __('support.payplug.com/hc/fr/articles/4408142346002', 'payplug');
363 + $link = sprintf(' <a href="https://%s" target="_blank">%s</a>', $domain, $anchor);
444 364
445 - if ( $this->id !== $token->get_gateway_id() ) {
446 - continue;
447 - }
365 + $anchor_bancontact = esc_html_x(__('payplug_bancontact_activation_request', 'payplug'), 'modal', 'payplug');
366 + $domain_bancontact = __('payplug_bancontact_activation_url', 'payplug');
367 + $bancontact_call_to_action = sprintf(' <a id="bancontact_call_to_action" href="https://%s" target="_blank">%s</a>', $domain_bancontact, $anchor_bancontact);
448 368
449 - // check if token is associated with a merchant id and if it match the current one
450 - $token_merchant_id = $token->get_meta( 'payplug_account', true );
451 - if ( empty( $token_merchant_id ) || $this->get_merchant_id() !== $token_merchant_id ) {
452 - unset( $tokens[ $k ] );
453 - continue;
454 - }
369 + $oney_cfg = $this->get_configuration()->get_option('payment_methods.configuration.oney');
370 + if (!empty($oney_cfg)) {
371 + $oney_amount = json_decode($oney_cfg['custom_amounts'], true);
372 + $oney_amount['min'] = (float) $oney_amount['min'] / 100;
373 + $oney_amount['max'] = (float) $oney_amount['max'] / 100;
374 + } else {
375 + $oney_amount = [
376 + 'min' => 100,
377 + 'max' => 3000,
378 + ];
379 + }
380 + $fields = [
381 + 'enabled' => [
382 + 'title' => __('Enable/Disable', 'payplug'),
383 + 'type' => 'checkbox',
384 + 'label' => __('Enable PayPlug', 'payplug'),
385 + 'description' => __('Only Euro payments can be processed with PayPlug.', 'payplug'),
386 + 'default' => false,
387 + ],
388 + 'title' => [
389 + 'title' => __('Title', 'payplug'),
390 + 'type' => 'text',
391 + 'description' => __('The payment solution title displayed to your customers during checkout', 'payplug'),
392 + 'default' => _x('Credit card checkout', 'Default gateway title', 'payplug'),
393 + 'desc_tip' => false,
394 + ],
395 + 'description' => [
396 + 'title' => __('Description', 'payplug'),
397 + 'type' => 'text',
398 + 'description' => __('The payment solution description displayed to your customers during checkout', 'payplug'),
399 + 'default' => '',
400 + 'desc_tip' => false,
401 + ],
402 + 'title_connexion' => [
403 + 'title' => __('Connection', 'payplug'),
404 + 'type' => 'title',
405 + ],
406 + 'email' => [
407 + 'type' => 'hidden',
408 + 'default' => '',
409 + ],
410 + 'login' => [
411 + 'type' => 'login',
412 + 'default' => '',
413 + ],
414 + 'title_testmode' => [
415 + 'title' => __('Mode', 'payplug'),
416 + 'type' => 'title',
417 + ],
418 + 'mode' => [
419 + 'title' => '',
420 + 'label' => '',
421 + 'type' => 'yes_no',
422 + 'yes' => 'Live',
423 + 'no' => 'Test',
424 + 'description' => __('In TEST mode, all payments will be simulations and will not generate real transactions.', 'payplug'),
425 + 'default' => false,
426 + 'hide_label' => true,
427 + ],
428 + 'title_settings' => [
429 + 'title' => __('Settings', 'payplug'),
430 + 'type' => 'title',
431 + ],
432 + 'payment_method' => [
433 + 'title' => __('Payment page', 'payplug'),
434 + 'type' => 'radio',
435 + 'options' => [
436 + 'redirect' => __('Redirect', 'payplug'),
437 + 'embedded' => __('Integrated', 'payplug'),
438 + ],
439 + 'description' => __('Customers will be redirected to a PayPlug payment page to finalize the transaction, or payments will be performed in an embeddable payment form on your website.', 'payplug'),
440 + 'default' => 'redirect',
441 + 'desc_tip' => false,
442 + ],
443 + 'debug' => [
444 + 'title' => __('Debug', 'payplug'),
445 + 'type' => 'checkbox',
446 + 'description' => __('Debug mode saves additional information on your server for each operation done via the PayPlug plugin (Developer setting).', 'payplug'),
447 + 'label' => __('Activate debug mode', 'payplug'),
448 + 'default' => true,
449 + 'desc_tip' => false,
450 + ],
451 + 'title_advanced_settings' => [
452 + 'title' => __('payplug_advanced_settings', 'payplug'),
453 + 'description' => __(
454 + 'Your current offer does not allow this option. Try it on TEST mode. More information <a href="https://www.payplug.com/pricing" target="_blank">here.</a>',
455 + 'payplug'
456 + ),
457 + 'type' => 'title',
458 + ],
459 + 'save_card' => [
460 + 'title' => __('One Click Payment', 'payplug'),
461 + 'type' => 'checkbox',
462 + 'label' => __('Activate', 'payplug'),
463 + 'description' => __('Allow your customers to save their credit card information for later purchases.', 'payplug'),
464 + 'default' => false,
465 + 'desc_tip' => false,
466 + ],
467 + 'bancontact' => [
468 + 'title' => __('payplug_bancontact_activate_title', 'payplug'),
469 + 'type' => 'checkbox',
470 + 'label' => __('Activate', 'payplug'),
471 + 'description' => '<p class="description" id="bancontact_test_mode_description"> ' . __('payplug_bancontact_testmode_description', 'payplug') . ' </p>' .
472 + '<p class="description" id="bancontact_live_mode_description_disabled"> ' . __('payplug_bancontact_livemode_description_disabled', 'payplug') . ' </p>' .
473 + $bancontact_call_to_action,
474 + 'default' => false,
475 + ],
476 + 'apple_pay' => [
477 + 'title' => __('payplug_apple_pay_activate_title', 'payplug'),
478 + 'type' => 'checkbox',
479 + 'label' => __('Activate', 'payplug'),
480 + 'description' => '<p class="description" id="apple_pay_test_mode_description"> ' . __('payplug_apple_pay_testmode_description', 'payplug') . ' </p>' .
481 + '<p class="description" id="apple_pay_live_mode_description"> ' . __('payplug_apple_pay_livemode_description', 'payplug') . ' </p>',
482 + 'default' => false,
483 + ],
484 + 'american_express' => [
485 + 'title' => __('payplug_amex_title', 'payplug'),
486 + 'type' => 'checkbox',
487 + 'label' => __('payplug_amex_activate', 'payplug'),
488 + 'description' => '<p class="description" id="amex_test_mode_description"> ' . __('payplug_amex_testmode_description', 'payplug') . ' </p>' .
489 + '<p class="description" id="amex_live_mode_description"> ' . __('payplug_amex_livemode_description', 'payplug') . ' </p>',
490 + 'default' => false,
491 + ],
492 + 'oney' => [
493 + 'title' => __('3x 4x Oney payments', 'payplug'),
494 + 'type' => 'checkbox',
495 + 'label' => __('Activate', 'payplug'),
496 + // TRAD
497 + 'description' => sprintf(__('Allow your customers to split payments into 3 or 4 installments, for orders between %s€ and %s€', 'payplug'), $this->min_oney_price, $this->max_oney_price) . $link,
498 + 'default' => false,
499 + 'desc_tip' => false,
500 + ],
501 + 'oney_type' => [
502 + 'title' => '',
503 + 'type' => 'oney_type',
504 + 'options' => [
505 + 'with_fees' => __('Oney with fees', 'payplug'),
506 + 'without_fees' => __('Oney without fees', 'payplug'),
507 + ],
508 + 'descriptions' => [
509 + 'with_fees' => __('The fees are split between you and your customers', 'payplug'),
510 + 'without_fees' => __('You pay the fees', 'payplug'),
511 + ],
512 + 'description' => '',
513 + 'default' => 'with_fees',
514 + 'desc_tip' => false,
515 + ],
516 + 'oney_thresholds' => [
517 + 'title' => '',
518 + 'type' => 'oney_thresholds',
519 + 'description' => sprintf(
520 + __('I would like to offer guaranteed payment in installments for amounts between %s€ and %s€.', 'payplug'),
521 + '<b class="min">' . $oney_amount['min'] . '</b>',
522 + '<b class="max">' . $oney_amount['max'] . '</b>'
523 + ),
524 + 'desc_tip' => false,
525 + ],
526 + 'oney_product_animation' => [
527 + 'title' => __('oney_installments_pop_up', 'payplug'),
528 + 'description' => __('display_the_oney_installments_pop_up_on_the_product_page', 'payplug'),
529 + 'label' => __('Activate', 'payplug'),
530 + 'default' => false,
531 + 'desc_tip' => false,
532 + 'type' => 'oney_product_animation',
533 + ],
534 + ];
455 535
456 - // check if token is available for the current gateway mode
457 - if ( $this->mode !== $token->get_meta( 'mode', true ) ) {
458 - unset( $tokens[ $k ] );
459 - continue;
460 - }
536 + if ($this->user_logged_in()) {
537 + if ($this->permissions->has_permissions(PayplugPermissions::SAVE_CARD)) {
538 + unset($fields['title_advanced_settings']);
539 + } elseif ('live' === $this->get_current_mode()) {
540 + $fields['save_card']['disabled'] = true;
541 + }
542 + }
461 543
462 - // check if token is not expired
463 - $current_month = \absint( date( 'n' ) );
464 - $current_year = \absint( date( 'Y' ) );
465 - if ( $current_year > (int) $token->get_expiry_year() ) {
466 - unset( $tokens[ $k ] );
467 - continue;
468 - }
544 + /**
545 + * Filter PayPlug gateway settings.
546 + *
547 + * @param array $fields
548 + */
549 + $fields = apply_filters('payplug_gateway_settings', $fields);
550 + $this->form_fields = $fields;
551 + }
469 552
470 - if ( $current_year === (int) $token->get_expiry_year() && $current_month >= (int) $token->get_expiry_month() ) {
471 - unset( $tokens[ $k ] );
472 - continue;
473 - }
474 - }
553 + /**
554 + * Set global configuration for PayPlug instance.
555 + */
556 + public function init_payplug(): void
557 + {
558 + $this->payplug_api = new PayplugApi($this);
559 + $this->payplug_api->init();
475 560
476 - return $tokens;
477 - }
561 + // init() just resolved this for the same mode - reuse it instead of asking
562 + // Service\Api::get_bearer_token() to do so again right after.
563 + $this->permissions = new PayplugPermissions($this, $this->payplug_api->get_current_bearer_token());
564 + $this->response = new PayplugResponse($this);
478 565
479 - public function payment_fields() {
480 - $description = $this->get_description();
481 - if ( ! empty( $description ) ) {
482 - echo wpautop( wptexturize( $description ) );
483 - }
566 + // Register IPN handler
567 + new PayplugIpnResponse($this);
568 + }
484 569
485 - if ( $this->oneclick_available() ) {
486 - $this->tokenization_script();
487 - $this->saved_payment_methods();
488 - }
489 - }
570 + /**
571 + * Filter saved tokens for the gateway.
572 + *
573 + * A token will be removed if :
574 + * - it doesn't match the current merchant logged in,
575 + * - or it doesn't match the current gateway mode,
576 + * - or it is expired.
577 + *
578 + * @param array $tokens
579 + * @param int $user_id
580 + * @param string $gateway_id
581 + *
582 + * @return array
583 + */
584 + public function filter_tokens($tokens, $user_id, $gateway_id)
585 + {
586 + if (!is_user_logged_in() || !class_exists('WC_Payment_Gateway_CC')) {
587 + return $tokens;
588 + }
490 589
491 - /**
492 - * Handle admin display.
493 - */
494 - public function admin_options() {
495 - wp_enqueue_style(
496 - 'payplug-gateway-style',
497 - PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/css/app.css',
498 - [],
499 - PAYPLUG_GATEWAY_VERSION
500 - );
590 + $saved_card = $this->get_configuration()->get_option('payment_methods.configuration.payplug.save_card')
591 + && is_user_logged_in();
501 592
502 - if ( $this->user_logged_in() && false === $this->has_api_key( 'live' ) ) {
593 + if (!$saved_card) {
594 + foreach ($tokens as $token_id => $token) {
595 + if ('payplug' == (string) $token->get_gateway_id()) {
596 + unset($tokens[$token_id]);
597 + }
598 + }
503 599
504 - wp_enqueue_script(
505 - 'payplug-gateway-admin',
506 - PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/js/payplug-admin.js',
507 - [ 'jquery-ui-dialog' ],
508 - PAYPLUG_GATEWAY_VERSION
509 - );
600 + return $tokens;
601 + }
510 602
511 - wp_localize_script( 'payplug-gateway-admin', 'payplug_admin_config', array(
512 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
513 - 'has_live_key' => ( false === $this->has_api_key( 'live' ) ) ? false : true,
514 - 'btn_ok' => _x( 'Ok', 'modal', 'payplug' ),
515 - 'btn_label' => _x( 'Cancel', 'modal', 'payplug' ),
516 - 'general_error' => _x( 'Something went wrong. Please refresh the page and retry.', 'modal', 'payplug' ),
517 - ) );
603 + /* @var \WC_Payment_Token_CC $token */
604 + foreach ($tokens as $k => $token) {
605 + if ($this->id !== $token->get_gateway_id()) {
606 + continue;
607 + }
518 608
519 - add_action( 'admin_footer', function () {
520 - $email = $this->get_option( 'email' );
521 - ?>
522 - <div id="payplug-refresh-keys-modal" title="<?php echo esc_attr_x( 'Mode LIVE', 'modal', 'payplug' ); ?>">
523 - <form id="payplug-refresh-keys-modal__form">
524 - <p id="dialog-msg"></p>
525 - <p><?php echo esc_html_x( 'Please enter your PayPlug account password', 'modal', 'payplug' ); ?></p>
526 - <input type="password"
527 - name="password"
528 - required
529 - title="<?php echo esc_attr_x( 'Enter your PayPlug account password', 'modal', 'payplug' ); ?>"/>
530 - <input type="hidden" name="email"
531 - value="<?php echo esc_attr( $email ); ?>">
532 - <input type="hidden" name="action"
533 - value="<?php echo esc_attr( Ajax::REFRESH_KEY_ACTION ); ?>">
534 - <?php wp_nonce_field( sprintf( '%s_%s', $email, Ajax::REFRESH_KEY_ACTION ) ); ?>
535 - <input class="ui-dialog-sronly" type="submit" tabindex="-1">
536 - </form>
537 - </div>
538 - <?php
539 - } );
540 - }
609 + // check if token is associated with a merchant id and if it match the current one
610 + $token_merchant_id = $token->get_meta('payplug_account', true);
611 + if (empty($token_merchant_id) || $this->get_merchant_id() !== $token_merchant_id) {
612 + unset($tokens[$k]);
613 + continue;
614 + }
541 615
542 - $payplug_requirements = new PayplugGatewayRequirements( $this ); ?>
616 + // check if token is available for the current gateway mode
617 + if ($this->mode != $token->get_meta('mode', true)) {
618 + unset($tokens[$k]);
619 + continue;
620 + }
543 621
544 - <h2 class="title--logo"><?php esc_html( $this->get_method_title() ) ?></h2>
545 - <p><?php _e( sprintf( 'Version %s', PAYPLUG_GATEWAY_VERSION ) ); ?></p>
546 - <div class="payplug-requirements">
547 - <?php echo $payplug_requirements->curl_requirement(); ?>
548 - <?php echo $payplug_requirements->php_requirement(); ?>
549 - <?php echo $payplug_requirements->openssl_requirement(); ?>
550 - <?php echo $payplug_requirements->account_requirement(); ?>
551 - <?php echo $payplug_requirements->currency_requirement(); ?>
552 - </div>
553 - <?php echo wp_kses_post( wpautop( $this->get_method_description() ) ); ?>
622 + // check if token is not expired
623 + $current_month = \absint(date('n'));
624 + $current_year = \absint(date('Y'));
625 + if ($current_year > (int) $token->get_expiry_year()) {
626 + unset($tokens[$k]);
627 + continue;
628 + }
554 629
555 - <?php if ( $this->user_logged_in() ) : ?>
556 - <table class="form-table">
557 - <?php $this->generate_settings_html( $this->get_form_fields() ); ?>
558 - </table>
559 - <?php else:
560 - $GLOBALS['hide_save_button'] = true; ?>
561 - <h3 class="wc-settings-sub-title"><?php _e( 'Connection', 'payplug' ); ?></h3>
562 - <table class="form-table">
563 - <tbody>
564 - <tr valign="top">
565 - <th scope="row" class="titledesc">
566 - <label for="payplug_email"><?php _e( 'Email', 'payplug' ); ?></label>
567 - </th>
568 - <td class="forminp">
569 - <fieldset>
570 - <legend class="screen-reader-text"><span><?php _e( 'Email', 'payplug' ); ?></span></legend>
571 - <input class="input-text regular-input" type="text" name="payplug_email" id="payplug_email"
572 - value="" placeholder="<?php _e( '[email protected]', 'payplug' ); ?>"/>
573 - </fieldset>
574 - </td>
575 - </tr>
576 - <tr valign="top">
577 - <th scope="row" class="titledesc">
578 - <label for="payplug_password"><?php _e( 'Password', 'payplug' ); ?></label>
579 - </th>
580 - <td class="forminp">
581 - <fieldset>
582 - <legend class="screen-reader-text"><span><?php _e( 'Password', 'payplug' ); ?></span>
583 - </legend>
584 - <input class="input-text regular-input" type="password" name="payplug_password"
585 - id="payplug_password" value=""/>
586 - </fieldset>
587 - </td>
588 - </tr>
589 - <tr valign="top">
590 - <td class="forminp">
591 - <input class="button" type="submit" value="<?php _e( 'Login', 'payplug' ); ?>">
592 - <input type="hidden" name="save" value="login">
593 - <?php wp_nonce_field( 'payplug_user_login', '_loginaction' ); ?>
594 - </td>
595 - </tr>
596 - </tbody>
597 - </table>
598 - <?php
599 - endif;
600 - }
630 + if ($current_year === (int) $token->get_expiry_year() && $current_month > (int) $token->get_expiry_month()) {
631 + unset($tokens[$k]);
632 + continue;
633 + }
634 + }
601 635
602 - /**
603 - * Process admin options.
604 - *
605 - * @return bool
606 - */
607 - public function process_admin_options() {
608 - $data = $this->get_post_data();
636 + return $tokens;
637 + }
609 638
610 - // Handle logout process
611 - if (
612 - isset( $data['submit_logout'] )
613 - && false !== check_admin_referer( 'payplug_user_logout', '_logoutaction' )
614 - ) {
639 + /**
640 + * extra payment fields
641 + */
642 + public function payment_fields(): void
643 + {
644 + $description = $this->get_description();
615 645
616 - $this->permissions->clear_permissions();
646 + if (!empty($description)) {
647 + echo wpautop(wptexturize($description));
648 + }
617 649
618 - $data = get_option( $this->get_option_key() );
619 - $data['payplug_test_key'] = '';
620 - $data['payplug_live_key'] = '';
621 - $data['payplug_merchant_id'] = '';
622 - $data['enabled'] = 'no';
623 - $data['mode'] = 'no';
624 - $data['oneclick'] = 'no';
625 - update_option( $this->get_option_key(),
626 - apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $data ) );
627 - \WC_Admin_Settings::add_message( __( 'Successfully logged out.', 'payplug' ) );
650 + if ($this->save_card_available()) {
651 + $this->tokenization_script();
652 + $this->saved_payment_methods();
653 + }
654 + }
628 655
629 - return true;
630 - }
656 + /**
657 + * Handle admin display.
658 + */
659 + public function admin_options(): void
660 + {
661 + /************ VUE Code *************/
662 + wp_enqueue_script('chunk-vendors.js', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/dist/js/chunk-vendors-' . PAYPLUG_GATEWAY_VERSION . '.js', [], PAYPLUG_GATEWAY_VERSION);
663 + wp_enqueue_script('app.js', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/dist/js/app-' . PAYPLUG_GATEWAY_VERSION . '.js', [], PAYPLUG_GATEWAY_VERSION);
664 + wp_enqueue_style('app.css', PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/dist/css/app-' . PAYPLUG_GATEWAY_VERSION . '.css', [], PAYPLUG_GATEWAY_VERSION);
665 + wp_localize_script(
666 + 'app.js',
667 + 'payplug_admin_config',
668 + [
669 + 'img_path' => esc_url(PAYPLUG_GATEWAY_PLUGIN_URL . 'assets/dist/'),
670 + 'ajax_url' => get_home_url(),
671 + 'rest_url' => get_home_url() . '/?rest_route=/payplug_api/',
672 + ]
673 + ); ?>
674 + <script>window.get_data_url = "<?php echo rest_url('payplug/data'); ?>"</script>
675 + <script>window.set_data_url = "<?php echo rest_url('payplug/save_data'); ?>"</script>
676 + <div id="payplug_admin"></div>
631 677
632 - // Handle login process
633 - if (
634 - isset( $data['payplug_email'] )
635 - && false !== check_admin_referer( 'payplug_user_login', '_loginaction' )
636 - ) {
637 - $email = $data['payplug_email'];
638 - $password = wp_unslash( $data['payplug_password'] );
639 - $response = $this->retrieve_user_api_keys( $email, $password );
640 - if ( is_wp_error( $response ) ) {
641 - \WC_Admin_Settings::add_error( $response->get_error_message() );
678 + <?php
642 679
643 - return false;
644 - }
680 + /*********** End VUE Code ***********/
681 + }
645 682
646 - // try to use the api keys to retrieve the merchant id
647 - $merchant_id = isset( $response['test'] ) ? $this->retrieve_merchant_id( $response['test'] ) : '';
683 + /**
684 + * Process payment.
685 + *
686 + * @param int $order_id
687 + *
688 + * @throws \Exception
689 + *
690 + * @return array
691 + */
692 + public function process_payment($order_id)
693 + {
694 + self::log(sprintf('Processing payment for order #%s', $order_id));
648 695
649 - $this->init_form_fields();
650 - $fields = $this->get_form_fields();
651 - $data = [];
696 + $order = wc_get_order($order_id);
697 + if (!$order instanceof \WC_Order) {
698 + self::log(sprintf('Order #%s not found.', $order_id), 'error');
699 + throw new \Exception(__('Order not found.', 'payplug'));
700 + }
701 + $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
702 + $amount = (int) PayplugWoocommerceHelper::get_payplug_amount($order->get_total());
703 + $amount = $this->validate_order_amount($amount);
652 704
653 - // Load existing values if the user is re-login.
654 - foreach ( $fields as $key => $field ) {
655 - if ( in_array( $field['type'], [ 'title', 'login' ] ) ) {
656 - continue;
657 - }
705 + if (is_wp_error($amount)) {
706 + self::log(sprintf('Invalid amount %s for the order.', $order->get_total()), 'error');
707 + throw new \Exception($amount->get_error_message());
708 + }
658 709
659 - switch ( $key ) {
660 - case 'enabled':
661 - $val = 'yes';
662 - break;
663 - case 'mode':
664 - $val = 'no';
665 - break;
666 - case 'payplug_test_key':
667 - $val = esc_attr( $response['test'] );
668 - break;
669 - case 'payplug_live_key':
670 - $val = esc_attr( $response['live'] );
671 - break;
672 - case 'payplug_merchant_id':
673 - $val = esc_attr( $merchant_id );
674 - break;
675 - case 'email':
676 - $val = esc_html( $email );
677 - break;
678 - default:
679 - $val = $this->get_option( $key );
680 - }
710 + $payment_token_id = (isset($_POST['wc-' . $this->id . '-payment-token']) && 'new' !== $_POST['wc-' . $this->id . '-payment-token'])
711 + ? wc_clean($_POST['wc-' . $this->id . '-payment-token'])
712 + : false;
681 713
682 - $data[ $key ] = $val;
683 - }
714 + if ($payment_token_id && (int) $customer_id > 0) {
715 + self::log(sprintf('Payment token found.', $amount));
684 716
685 - $this->set_post_data( $data );
686 - update_option( $this->get_option_key(),
687 - apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $data ) );
688 - \WC_Admin_Settings::add_message( __( 'Successfully logged in.', 'payplug' ) );
717 + return $this->process_payment_with_token($order, $amount, $customer_id, $payment_token_id);
718 + }
689 719
690 - return true;
691 - }
720 + return $this->process_standard_payment($order, $amount, $customer_id);
721 + }
692 722
693 - // Don't let user without live key leave TEST mode.
694 - $mode_fieldkey = $this->get_field_key( 'mode' );
695 - $live_key_fieldkey = $this->get_field_key( 'payplug_live_key' );
696 - if ( isset( $data[ $mode_fieldkey ] ) && '1' === $data[ $mode_fieldkey ] && empty( $data[ $live_key_fieldkey ] ) ) {
697 - $data[ $mode_fieldkey ] = '0';
698 - $this->set_post_data( $data );
699 - \WC_Admin_Settings::add_error( __( 'Your account does not support LIVE mode at the moment, it must be validated first. If your account has already been validated, please log out and log in again.', 'payplug' ) );
700 - }
723 + /**
724 + * Whether the current request is repaying an existing order (order-pay page, or one of
725 + * the order-pay AJAX flows). The order_key/order_pay_key posted by those AJAX flows must
726 + * match the order's own key: their mere presence isn't proof of anything, since any
727 + * request can set them.
728 + *
729 + * @param \WC_Order|null $order
730 + *
731 + * @return bool
732 + */
733 + protected function is_order_pay_request($order): bool
734 + {
735 + if (is_wc_endpoint_url('order-pay')) {
736 + return true;
737 + }
701 738
702 - // Check user permissions before activating one-click feature.
703 - $oneclick_fieldkey = $this->get_field_key( 'oneclick' );
704 - if (
705 - isset( $data[ $oneclick_fieldkey ] )
706 - && '1' === $data[ $oneclick_fieldkey ]
707 - && (
708 - ! $this->user_logged_in()
709 - || false === $this->permissions->has_permissions( PayplugPermissions::SAVE_CARD )
710 - )
711 - ) {
712 - $data[ $oneclick_fieldkey ] = '0';
713 - \WC_Admin_Settings::add_error( __( 'Only PREMIUM accounts can enable the One Click option in LIVE mode.', 'payplug' ) );
714 - }
739 + $posted_key = $_POST['order_pay_key'] ?? $_POST['order_key'] ?? '';
740 + if (empty($posted_key)) {
741 + return false;
742 + }
715 743
716 - parent::process_admin_options();
717 - }
744 + return $order instanceof \WC_Order && hash_equals($order->get_order_key(), wc_clean(wp_unslash($posted_key)));
745 + }
718 746
719 - /**
720 - * Process payment.
721 - *
722 - * @param int $order_id
723 - *
724 - * @return array
725 - * @throws \Exception
726 - */
727 - public function process_payment( $order_id ) {
747 + /**
748 + * if payment was generated by an intend, we shouldn't generate another one and try to pay it, this would generate duplications
749 + *
750 + * @param $order
751 + *
752 + * @throws \Exception
753 + *
754 + * @return array|null
755 + */
756 + private function process_standard_intent_payment($order)
757 + {
758 + // This can run from AJAX endpoints whose own request URL never carries the order-pay
759 + // query var, so is_wc_endpoint_url() alone can't detect that context here: fall back
760 + // to the order_key/order_pay_key sent by the order-pay AJAX flows.
761 + $is_order_pay = $this->is_order_pay_request($order);
728 762
729 - PayplugGateway::log( sprintf( 'Processing payment for order #%s', $order_id ) );
763 + //no order-pay page, no ajax_on_order_review_page
764 + if (!$is_order_pay &&
765 + PayplugWoocommerceHelper::is_checkout_block() &&
766 + (
767 + ('payplug' == $this->id && in_array($this->embedded_mode, ['integrated', 'popup'])) ||
768 + ('american_express' == $this->id && 'popup' == $this->embedded_mode)
769 + ) &&
770 + ($_GET['wc-ajax'] ?? '') !== 'payplug_order_review_url' &&
771 + !empty($order->get_transaction_id())
772 + ) {
773 + $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
730 774
731 - $order = wc_get_order( $order_id );
732 - $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
733 - $amount = (int) PayplugWoocommerceHelper::get_payplug_amount( $order->get_total() );
734 - $amount = $this->validate_order_amount( $amount );
735 - if ( is_wp_error( $amount ) ) {
736 - PayplugGateway::log( sprintf( 'Invalid amount %s for the order.', $order->get_total() ), 'error' );
737 - throw new \Exception( $amount->get_error_message() );
738 - }
775 + try {
776 + $payment = $this->payplug_api->payment_retrieve($order->get_transaction_id());
777 + if (ob_get_length() > 0) {
778 + ob_clean();
779 + }
739 780
740 - $payment_token_id = ( isset( $_POST[ 'wc-' . $this->id . '-payment-token' ] ) && 'new' !== $_POST[ 'wc-' . $this->id . '-payment-token' ] )
741 - ? wc_clean( $_POST[ 'wc-' . $this->id . '-payment-token' ] )
742 - : false;
781 + // Save transaction id for the order
782 + PayplugWoocommerceHelper::is_pre_30()
783 + ? update_post_meta($order_id, '_transaction_id', $payment->id)
784 + : $order->set_transaction_id($payment->id);
743 785
744 - if ( $payment_token_id && $this->oneclick_available() && (int) $customer_id > 0 ) {
745 - PayplugGateway::log( sprintf( 'Payment token found.', $amount ) );
786 + if ($payment->is_paid) {
787 + $finished_status = wc_get_is_paid_statuses();
788 + $order->set_status($finished_status[0]);
789 + }
746 790
747 - return $this->process_payment_with_token( $order, $amount, $customer_id, $payment_token_id );
748 - }
791 + if (is_callable([$order, 'save'])) {
792 + $order->save();
793 + }
749 794
750 - return $this->process_standard_payment( $order, $amount, $customer_id );
751 - }
795 + /**
796 + * Fires once a payment has been created.
797 + *
798 + * @param int $order_id Order ID
799 + * @param PaymentResource $payment Payment resource
800 + */
801 + \do_action('payplug_gateway_payment_created', $order_id, $payment);
752 802
753 - /**
754 - * @param \WC_Order $order
755 - * @param int $amount
756 - * @param int $customer_id
757 - *
758 - * @return array
759 - * @throws \Exception
760 - */
761 - public function process_standard_payment( $order, $amount, $customer_id ) {
803 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
804 + PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
762 805
763 - $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
764 - $customer_details = $this->prepare_customer_data( $order );
806 + self::log(sprintf('Payment intent created for order #%s', $order_id));
765 807
766 - if (
767 - ! empty( $customer_details['country'] )
768 - && ! PayplugWoocommerceHelper::is_country_supported( $customer_details['country'] )
769 - ) {
770 - $customer_details['country'] = '';
771 - }
808 + $return_url = esc_url_raw($order->get_checkout_order_received_url());
772 809
773 - try {
774 - $payment_data = [
775 - 'amount' => $amount,
776 - 'currency' => get_woocommerce_currency(),
777 - 'allow_save_card' => $this->oneclick_available() && (int) $customer_id > 0,
778 - 'customer' => [
779 - 'first_name' => $this->limit_length( $customer_details['first_name'] ),
780 - 'last_name' => $this->limit_length( $customer_details['last_name'] ),
781 - 'email' => $this->limit_length( $customer_details['email'], 255 ),
782 - 'address1' => ( ! empty( $customer_details['address1'] ) ) ? $this->limit_length( $customer_details['address1'], 255 ) : null,
783 - 'postcode' => ( ! empty( $customer_details['postcode'] ) ) ? $this->limit_length( $customer_details['postcode'], 16 ) : null,
784 - 'city' => ( ! empty( $customer_details['city'] ) ) ? $this->limit_length( $customer_details['city'] ) : null,
785 - 'country' => ( ! empty( $customer_details['country'] ) ) ? $this->limit_length( $customer_details['country'], 2 ) : null,
786 - ],
787 - 'hosted_payment' => [
788 - 'return_url' => esc_url_raw( $order->get_checkout_order_received_url() ),
789 - 'cancel_url' => esc_url_raw( $order->get_cancel_order_url_raw() ),
790 - ],
791 - 'notification_url' => esc_url_raw( WC()->api_request_url( 'PayplugGateway' ) ),
792 - 'metadata' => [
793 - 'order_id' => $order_id,
794 - 'customer_id' => ( (int) $customer_id > 0 ) ? $customer_id : 'guest',
795 - 'domain' => $this->limit_length( esc_url_raw( home_url() ), 500 ),
796 - ],
797 - ];
810 + $result = [
811 + 'payment_id' => $payment->id,
812 + 'result' => 'success',
813 + 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url,
814 + 'cancel' => !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : null,
815 + ];
798 816
799 - /**
800 - * Filter the payment data before it's used
801 - *
802 - * @param array $payment_data
803 - * @param int $order_id
804 - * @param array $customer_details
805 - */
806 - $payment_data = apply_filters( 'payplug_gateway_payment_data', $payment_data, $order_id, $customer_details );
807 - $payment = $this->api->payment_create( $payment_data );
817 + // wp_send_json_success() calls die(), which is only safe for the classic
818 + // wc-ajax request this was written for: the Store API checkout flow (used by
819 + // the checkout block) calls process_payment() through the REST framework,
820 + // and killing the process mid-request there produces a broken response.
821 + if (wp_doing_ajax()) {
822 + wp_send_json_success($result);
823 + }
808 824
809 - // Save transaction id for the order
810 - PayplugWoocommerceHelper::is_pre_30()
811 - ? update_post_meta( $order_id, '_transaction_id', $payment->id )
812 - : $order->set_transaction_id( $payment->id );
825 + return $result;
826 + } catch (HttpException $e) {
827 + self::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
828 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
829 + } catch (\Exception $e) {
830 + self::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
831 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
832 + }
833 + }
813 834
814 - if ( is_callable( [ $order, 'save' ] ) ) {
815 - $order->save();
816 - }
835 + return null;
836 + }
817 837
818 - /**
819 - * Fires once a payment has been created.
820 - *
821 - * @param int $order_id Order ID
822 - * @param PaymentResource $payment Payment resource
823 - */
824 - \do_action( 'payplug_gateway_payment_created', $order_id, $payment );
838 + /**
839 + * @param \WC_Order $order
840 + * @param int $amount
841 + * @param int $customer_id
842 + *
843 + * @throws \Exception
844 + *
845 + * @return array
846 + */
847 + public function process_standard_payment($order, $amount, $customer_id)
848 + {
849 + $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
825 850
826 - $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $payment );
827 - PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
851 + $intent = $this->process_standard_intent_payment($order);
852 + if (!empty($intent)) {
853 + return $intent;
854 + }
828 855
829 - PayplugGateway::log( sprintf( 'Payment creation complete for order #%s', $order_id ) );
856 + try {
857 + $address_data = PayplugAddressData::from_order($order);
830 858
831 - return [
832 - 'result' => 'success',
833 - 'redirect' => $payment->hosted_payment->payment_url,
834 - 'cancel' => $payment->hosted_payment->cancel_url,
835 - ];
836 - } catch ( HttpException $e ) {
837 - PayplugGateway::log( sprintf( 'Error while processing order #%s : %s', $order_id, wc_print_r( $e->getErrorObject(), true ) ), 'error' );
838 - throw new \Exception( __( 'Payment processing failed. Please retry.', 'payplug' ) );
839 - } catch ( \Exception $e ) {
840 - PayplugGateway::log( sprintf( 'Error while processing order #%s : %s', $order_id, $e->getMessage() ), 'error' );
841 - throw new \Exception( __( 'Payment processing failed. Please retry.', 'payplug' ) );
842 - }
843 - }
859 + $return_url = esc_url_raw($order->get_checkout_order_received_url());
844 860
845 - /**
846 - * @param \WC_Order $order
847 - * @param int $amount
848 - * @param int $customer_id
849 - * @param string $token_id
850 - *
851 - * @return array
852 - * @throws \Exception
853 - */
854 - public function process_payment_with_token( $order, $amount, $customer_id, $token_id ) {
861 + if (!(substr($return_url, 0, 4) === 'http')) {
862 + $return_url = get_site_url() . $return_url;
863 + }
855 864
856 - $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
857 - $customer_details = $this->prepare_customer_data( $order );
858 - $payment_token = WC_Payment_Tokens::get( $token_id );
859 - if ( ! $payment_token || (int) $customer_id !== (int) $payment_token->get_user_id() ) {
860 - PayplugGateway::log( 'Could not find the payment token or the payment doesn\'t belong to the current user.', 'error' );
861 - throw new \Exception( __( 'Invalid payment method.', 'payplug' ) );
862 - }
865 + $payment_data = [
866 + 'amount' => $amount,
867 + 'currency' => get_woocommerce_currency(),
868 + 'allow_save_card' => $this->save_card_available() && (int) $customer_id > 0,
869 + 'billing' => $address_data->get_billing(),
870 + 'shipping' => $address_data->get_shipping(),
871 + 'hosted_payment' => [
872 + 'return_url' => $return_url,
873 + 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
874 + ],
875 + 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')),
876 + 'metadata' => [
877 + 'order_id' => $order_id,
878 + 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
879 + 'domain' => $this->limit_length(esc_url_raw(home_url()), 500),
880 + ],
881 + ];
863 882
864 - if (
865 - ! empty( $customer_details['country'] )
866 - && ! PayplugWoocommerceHelper::is_country_supported( $customer_details['country'] )
867 - ) {
868 - $customer_details['country'] = '';
869 - }
883 + if (PayplugWoocommerceHelper::is_checkout_block() && is_checkout()) {
884 + $payment_data['metadata']['woocommerce_block'] = 'CHECKOUT';
885 + } elseif (PayplugWoocommerceHelper::is_cart_block() && is_cart()) {
886 + $payment_data['metadata']['woocommerce_block'] = 'CART';
887 + }
870 888
871 - try {
872 - $payment_data = [
873 - 'amount' => $amount,
874 - 'currency' => get_woocommerce_currency(),
875 - 'payment_method' => $payment_token->get_token(),
876 - 'customer' => [
877 - 'first_name' => $this->limit_length( $customer_details['first_name'] ),
878 - 'last_name' => $this->limit_length( $customer_details['last_name'] ),
879 - 'email' => $this->limit_length( $customer_details['email'], 255 ),
880 - 'address1' => ( ! empty( $customer_details['address1'] ) ) ? $this->limit_length( $customer_details['address1'], 255 ) : null,
881 - 'postcode' => ( ! empty( $customer_details['postcode'] ) ) ? $this->limit_length( $customer_details['postcode'], 16 ) : null,
882 - 'city' => ( ! empty( $customer_details['city'] ) ) ? $this->limit_length( $customer_details['city'] ) : null,
883 - 'country' => ( ! empty( $customer_details['country'] ) ) ? $this->limit_length( $customer_details['country'], 2 ) : null,
884 - ],
885 - 'notification_url' => esc_url_raw( WC()->api_request_url( 'PayplugGateway' ) ),
886 - 'metadata' => [
887 - 'order_id' => $order_id,
888 - 'customer_id' => ( (int) $customer_id > 0 ) ? $customer_id : 'guest',
889 - 'domain' => $this->limit_length( esc_url_raw( home_url() ), 500 ),
890 - ],
891 - ];
889 + //IP request required variables
890 + if ('integrated' == $this->embedded_mode) {
891 + $payment_data['initiator'] = 'PAYER';
892 + $payment_data['integration'] = 'INTEGRATED_PAYMENT';
893 + unset($payment_data['hosted_payment']['cancel_url']);
894 + }
892 895
893 - /** This filter is documented in src/Gateway/PayplugGateway */
894 - $payment_data = apply_filters( 'payplug_gateway_payment_data', $payment_data, $order_id, $customer_details );
895 - $payment = $this->api->payment_create( $payment_data );
896 + //for subscriptions the card needs to be saved
897 + $is_subscription = PayplugWoocommerceHelper::is_subscription();
898 + if (!empty($is_subscription) && $is_subscription === true) {
899 + $payment_data['allow_save_card'] = false;
900 + $payment_data['save_card'] = true;
901 + $payment_data['force_3ds'] = true;
902 + $payment_data['metadata']['subscription'] = 'subscription';
903 + }
896 904
897 - /** This action is documented in src/Gateway/PayplugGateway */
898 - \do_action( 'payplug_gateway_payment_created', $order_id, $payment );
905 + /**
906 + * Filter the payment data before it's used
907 + *
908 + * @param array $payment_data
909 + * @param int $order_id
910 + * @param array $customer_details
911 + * @param PayplugAddressData $address_data
912 + */
913 + $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data);
914 + $payment = $this->payplug_api->payment_create($payment_data);
899 915
900 - $this->response->process_payment( $payment, true );
916 + // Save transaction id for the order
917 + PayplugWoocommerceHelper::is_pre_30()
918 + ? update_post_meta($order_id, '_transaction_id', $payment->id)
919 + : $order->set_transaction_id($payment->id);
901 920
902 - PayplugGateway::log( sprintf( 'Payment process complete for order #%s', $order_id ) );
921 + $order->set_payment_method($this->id);
922 + $order->set_payment_method_title($this->method_title);
903 923
904 - return [
905 - 'result' => 'success',
906 - 'redirect' => $order->get_checkout_order_received_url(),
907 - ];
908 - } catch ( HttpException $e ) {
909 - PayplugGateway::log( sprintf( 'Error while processing order #%s : %s', $order_id, wc_print_r( $e->getErrorObject(), true ) ), 'error' );
910 - throw new \Exception( __( 'Payment processing failed. Please retry.', 'payplug' ) );
911 - } catch ( \Exception $e ) {
912 - PayplugGateway::log( sprintf( 'Error while processing order #%s : %s', $order_id, $e->getMessage() ), 'error' );
913 - throw new \Exception( __( 'Payment processing failed. Please retry.', 'payplug' ) );
914 - }
915 - }
924 + if (is_callable([$order, 'save'])) {
925 + $order->save();
926 + }
916 927
917 - /**
918 - * Process refund for an order paid with PayPlug gateway.
919 - *
920 - * @param int $order_id
921 - * @param null $amount
922 - * @param string $reason
923 - *
924 - * @return bool|\WP_Error
925 - */
926 - public function process_refund( $order_id, $amount = null, $reason = '' ) {
928 + /**
929 + * Fires once a payment has been created.
930 + *
931 + * @param int $order_id Order ID
932 + * @param PaymentResource $payment Payment resource
933 + */
934 + \do_action('payplug_gateway_payment_created', $order_id, $payment);
927 935
928 - PayplugGateway::log( sprintf( 'Processing refund for order #%s', $order_id ) );
936 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
937 + PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
929 938
930 - $order = wc_get_order( $order_id );
931 - if ( ! $order instanceof \WC_Order ) {
932 - PayplugGateway::log( sprintf( 'The order #%s does not exist.', $order_id ), 'error' );
939 + self::log(sprintf('Payment creation complete for order #%s', $order_id));
933 940
934 - return new \WP_Error( 'process_refund_error', sprintf( __( 'The order %s does not exist.', 'payplug' ), $order_id ) );
935 - }
941 + if (ob_get_length() > 0) {
942 + ob_clean();
943 + }
936 944
937 - $transaction_id = PayplugWoocommerceHelper::is_pre_30() ? get_post_meta( $order_id, '_transaction_id', true ) : $order->get_transaction_id();
938 - if ( empty( $transaction_id ) ) {
939 - PayplugGateway::log( sprintf( 'The order does not have PayPlug transaction ID associated with it.', $order_id ), 'error' );
945 + return [
946 + 'payment_id' => $payment->id,
947 + 'result' => 'success',
948 + 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url,
949 + 'cancel' => !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : null,
950 + ];
951 + } catch (HttpException $e) {
952 + self::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
953 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
954 + } catch (\Exception $e) {
955 + self::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
956 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
957 + }
958 + }
940 959
941 - return new \WP_Error( 'process_refund_error', __( 'No PayPlug transaction was found for this order. The refund could not be processed.', 'payplug' ) );
942 - }
960 + /**
961 + * @param \WC_Order $order
962 + * @param int $amount
963 + * @param int $customer_id
964 + * @param string $token_id
965 + *
966 + * @throws \Exception
967 + *
968 + * @return array
969 + */
970 + public function process_payment_with_token($order, $amount, $customer_id, $token_id)
971 + {
972 + $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id();
973 + $payment_token = WC_Payment_Tokens::get($token_id);
974 + if (!$payment_token || (int) $customer_id !== (int) $payment_token->get_user_id()) {
975 + self::log('Could not find the payment token or the payment doesn\'t belong to the current user.', 'error');
976 + throw new \Exception(__('Invalid payment method.', 'payplug'));
977 + }
943 978
944 - $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
979 + try {
980 + $address_data = PayplugAddressData::from_order($order);
945 981
946 - $data = [
947 - 'metadata' => [
948 - 'order_id' => $order_id,
949 - 'customer_id' => ( (int) $customer_id > 0 ) ? $customer_id : 'guest',
950 - ]
951 - ];
982 + $return_url = esc_url_raw($order->get_checkout_order_received_url());
952 983
953 - if ( ! is_null( $amount ) ) {
954 - $data['amount'] = PayplugWoocommerceHelper::get_payplug_amount( $amount );
955 - }
984 + if (!(substr($return_url, 0, 4) === 'http')) {
985 + $return_url = get_site_url() . $return_url;
986 + }
956 987
957 - if ( ! empty( $reason ) ) {
958 - $data['metadata']['reason'] = $reason;
959 - }
988 + $payment_data = [
989 + 'amount' => $amount,
990 + 'currency' => get_woocommerce_currency(),
991 + 'payment_method' => $payment_token->get_token(),
992 + 'allow_save_card' => false,
993 + 'billing' => $address_data->get_billing(),
994 + 'shipping' => $address_data->get_shipping(),
995 + 'initiator' => 'PAYER',
996 + 'hosted_payment' => [
997 + 'return_url' => $return_url,
998 + 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
999 + ],
1000 + 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')),
1001 + 'metadata' => [
1002 + 'order_id' => $order_id,
1003 + 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
1004 + 'domain' => $this->limit_length(esc_url_raw(home_url()), 500),
1005 + 'woocommerce_block' => \WC_Blocks_Utils::has_block_in_page(wc_get_page_id('checkout'), 'woocommerce/checkout'),
1006 + ],
1007 + ];
960 1008
961 - /**
962 - * Filter the refund data before it's used.
963 - *
964 - * @param array $data
965 - * @param int $order_id
966 - * @param string $transaction_id
967 - */
968 - $data = apply_filters( 'payplug_gateway_refund_data', $data, $order_id, $transaction_id );
1009 + $is_subscription = PayplugWoocommerceHelper::is_subscription();
1010 + if (!empty($is_subscription) && $is_subscription === true) {
1011 + $payment_data['metadata']['subscription'] = 'subscription';
1012 + }
969 1013
970 - try {
971 - $refund = $this->api->refund_create( $transaction_id, $data );
1014 + /** This filter is documented in src/Gateway/PayplugGateway */
1015 + $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data);
1016 + $payment = $this->payplug_api->payment_create($payment_data);
972 1017
973 - /**
974 - * Fires once a refund has been created.
975 - *
976 - * @param int $order_id Order ID
977 - * @param RefundResource $refund Refund resource
978 - * @param string $transaction_id Transaction id
979 - */
980 - \do_action( 'payplug_gateway_refund_created', $order_id, $refund, $transaction_id );
1018 + // Save transaction id for the order
1019 + PayplugWoocommerceHelper::is_pre_30()
1020 + ? update_post_meta($order_id, '_transaction_id', $payment->id)
1021 + : $order->set_transaction_id($payment->id);
981 1022
982 - $refund_meta_key = sprintf( '_pr_%s', wc_clean( $refund->id ) );
983 - if ( PayplugWoocommerceHelper::is_pre_30() ) {
984 - update_post_meta( $order_id, $refund_meta_key, $refund->id );
985 - } else {
986 - $order->add_meta_data( $refund_meta_key, $refund->id, true );
987 - $order->save();
988 - }
1023 + if (is_callable([$order, 'save'])) {
1024 + $order->save();
1025 + }
989 1026
990 - $note = sprintf( __( 'Refund %s : Refunded %s', 'payplug' ), wc_clean( $refund->id ), wc_price( ( (int) $refund->amount ) / 100 ) );
991 - if ( ! empty( $refund->metadata['reason'] ) ) {
992 - $note .= sprintf( ' (%s)', esc_html( $refund->metadata['reason'] ) );
993 - }
994 - $order->add_order_note( $note );
1027 + /** This action is documented in src/Gateway/PayplugGateway */
1028 + \do_action('payplug_gateway_payment_created', $order_id, $payment);
995 1029
996 - try {
997 - $payment = $this->api->payment_retrieve( $transaction_id );
998 - $metadata = PayplugWoocommerceHelper::extract_transaction_metadata( $payment );
999 - PayplugWoocommerceHelper::save_transaction_metadata( $order, $metadata );
1000 - } catch ( \Exception $e ) {
1001 - }
1030 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
1031 + PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
1002 1032
1003 - PayplugGateway::log( 'Refund process complete for the order.' );
1033 + $this->response->process_payment($payment, true);
1034 + if (($payment->__get('is_paid'))) {
1035 + $redirect = $order->get_checkout_order_received_url();
1036 + } elseif (isset($payment->__get('hosted_payment')->payment_url)) {
1037 + $redirect = $payment->__get('hosted_payment')->payment_url;
1038 + } else {
1039 + $redirect = $return_url;
1040 + }
1004 1041
1005 - return true;
1006 - } catch ( HttpException $e ) {
1007 - PayplugGateway::log( sprintf( 'Refund request error for the order %s from PayPlug API : %s', $order_id, wc_print_r( $e->getErrorObject(), true ) ), 'error' );
1042 + return [
1043 + 'payment_id' => $payment->id,
1044 + 'result' => 'success',
1045 + 'is_paid' => $payment->__get('is_paid'), // Use for path redirect before DSP2
1046 + 'redirect' => $redirect,
1047 + ];
1048 + } catch (HttpException $e) {
1049 + self::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
1050 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
1051 + } catch (\Exception $e) {
1052 + self::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error');
1053 + throw new \Exception(__('Payment processing failed. Please retry.', 'payplug'));
1054 + }
1055 + }
1008 1056
1009 - return new \WP_Error( 'process_refund_error', __( 'The transaction could not be refunded. Please try again.', 'payplug' ) );
1010 - } catch ( \Exception $e ) {
1011 - PayplugGateway::log( sprintf( 'Refund request error for the order %s : %s', $order_id, wc_clean( $e->getMessage() ) ), 'error' );
1057 + /**
1058 + * Process refund for an order paid with PayPlug gateway.
1059 + *
1060 + * @param int $order_id
1061 + * @param null $amount
1062 + * @param string $reason
1063 + *
1064 + * @return bool|\WP_Error
1065 + */
1066 + public function process_refund($order_id, $amount = null, $reason = '')
1067 + {
1068 + self::log(sprintf('Processing refund for order #%s', $order_id));
1012 1069
1013 - return new \WP_Error( 'process_refund_error', __( 'The transaction could not be refunded. Please try again.', 'payplug' ) );
1014 - }
1015 - }
1070 + if (!$this->user_logged_in()) {
1071 + self::log(__('You must be logged in with your PayPlug account.', 'payplug'), 'error');
1016 1072
1017 - /**
1018 - * @param \WC_Order $order
1019 - *
1020 - * @return array
1021 - */
1022 - public function prepare_customer_data( $order ) {
1023 - return [
1024 - 'first_name' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_first_name : $order->get_billing_first_name(),
1025 - 'last_name' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_last_name : $order->get_billing_last_name(),
1026 - 'email' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_email : $order->get_billing_email(),
1027 - 'address1' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_address_1 : $order->get_billing_address_1(),
1028 - 'address2' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_address_2 : $order->get_billing_address_2(),
1029 - 'postcode' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_postcode : $order->get_billing_postcode(),
1030 - 'city' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_city : $order->get_billing_city(),
1031 - 'country' => PayplugWoocommerceHelper::is_pre_30() ? $order->billing_country : $order->get_billing_country(),
1032 - ];
1033 - }
1073 + return new \WP_Error('process_refund_error', __('You must be logged in with your PayPlug account.', 'payplug'));
1074 + }
1034 1075
1035 - /**
1036 - * Check the order amount to ensure it's on the allowed range.
1037 - *
1038 - * @param int $amount
1039 - *
1040 - * @return int|\WP_Error
1041 - */
1042 - public function validate_order_amount( $amount ) {
1043 - if (
1044 - $amount < PayplugWoocommerceHelper::get_minimum_amount()
1045 - || $amount > PayplugWoocommerceHelper::get_maximum_amount()
1046 - ) {
1047 - return new \WP_Error(
1048 - 'invalid order amount',
1049 - sprintf( __( 'Payments for this amount (%s) are not authorised with this payment gateway.', 'payplug' ), \wc_price( $amount / 100 ) )
1050 - );
1051 - }
1076 + $order = wc_get_order($order_id);
1077 + if (!$order instanceof \WC_Order) {
1078 + self::log(sprintf('The order #%s does not exist.', $order_id), 'error');
1052 1079
1053 - return $amount;
1054 - }
1080 + return new \WP_Error('process_refund_error', sprintf(__('The order %s does not exist.', 'payplug'), $order_id));
1081 + }
1055 1082
1056 - /**
1057 - * Limit string length.
1058 - *
1059 - * @param string $value
1060 - * @param int $maxlength
1061 - *
1062 - * @return string
1063 - */
1064 - public function limit_length( $value, $maxlength = 100 ) {
1065 - return ( strlen( $value ) > $maxlength ) ? substr( $value, 0, $maxlength ) : $value;
1066 - }
1083 + if ($order->get_status() === 'cancelled') {
1084 + self::log(sprintf('The order #%s cannot be refund.', $order_id), 'error');
1067 1085
1068 - /**
1069 - * Get user's keys.
1070 - *
1071 - * @param string $email
1072 - * @param string $password
1073 - *
1074 - * @return array|\WP_Error
1075 - */
1076 - public function retrieve_user_api_keys( $email, $password ) {
1077 - if ( empty( $email ) || empty( $password ) ) {
1078 - return new \WP_Error( 'missing_login_data', __( 'Please fill all login fields', 'payplug' ) );
1079 - }
1086 + return new \WP_Error('process_refund_error', sprintf(__('The order %s cannot be refund.', 'payplug'), $order_id));
1087 + }
1080 1088
1081 - try {
1082 - $response = Authentication::getKeysByLogin( $email, $password );
1083 - if ( empty( $response ) || ! isset( $response['httpResponse'] ) ) {
1084 - return new \WP_Error( 'invalid_credentials', __( 'Invalid credentials.', 'payplug' ) );
1085 - }
1089 + $transaction_id = PayplugWoocommerceHelper::is_pre_30() ? get_post_meta($order_id, '_transaction_id', true) : $order->get_transaction_id();
1090 + if (empty($transaction_id)) {
1091 + self::log(sprintf('The order #%s does not have PayPlug transaction ID associated with it.', $order_id), 'error');
1086 1092
1087 - return $response['httpResponse']['secret_keys'];
1088 - } catch ( HttpException $e ) {
1089 - return new \WP_Error( 'invalid_credentials', __( 'Invalid credentials.', 'payplug' ) );
1090 - }
1091 - }
1093 + return new \WP_Error('process_refund_error', __('No PayPlug transaction was found for this order. The refund could not be processed.', 'payplug'));
1094 + }
1092 1095
1093 - /**
1094 - * Get user merchant id.
1095 - *
1096 - * This method might be called during the login process before the global PayPlug
1097 - * configuration is set. In that case you can pass a valid token to make the request.
1098 - *
1099 - * @param string|null $key
1100 - *
1101 - * @return string
1102 - */
1103 - public function retrieve_merchant_id( $key = null ) {
1104 - try {
1105 - $response = ! is_null( $key ) ? Authentication::getAccount( new Payplug( $key ) ) : Authentication::getAccount();
1106 - $merchant_id = isset( $response['httpResponse']['id'] ) ? $response['httpResponse']['id'] : '';
1107 - } catch ( ConfigurationException $e ) {
1108 - PayplugGateway::log( sprintf( 'Missing API key for PayPlug client : %s', wc_print_r( $e->getMessage(), true ) ), 'error' );
1096 + $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
1109 1097
1110 - $merchant_id = '';
1111 - } catch ( HttpException $e ) {
1112 - PayplugGateway::log( sprintf( 'Account request error from PayPlug API : %s', wc_print_r( $e->getErrorObject(), true ) ), 'error' );
1098 + $data = [
1099 + 'metadata' => [
1100 + 'order_id' => $order_id,
1101 + 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
1102 + 'refund_from' => 'woocommerce',
1103 + ],
1104 + ];
1113 1105
1114 - $merchant_id = '';
1115 - } catch ( \Exception $e ) {
1116 - PayplugGateway::log( sprintf( 'Account request error : %s', wc_clean( $e->getMessage() ) ), 'error' );
1106 + if (!is_null($amount)) {
1107 + $data['amount'] = PayplugWoocommerceHelper::get_payplug_amount($amount);
1108 + }
1117 1109
1118 - $merchant_id = '';
1119 - }
1110 + if (!empty($reason)) {
1111 + $data['metadata']['reason'] = $reason;
1112 + }
1120 1113
1121 - return $merchant_id;
1122 - }
1114 + /**
1115 + * Filter the refund data before it's used.
1116 + *
1117 + * @param array $data
1118 + * @param int $order_id
1119 + * @param string $transaction_id
1120 + */
1121 + $data = apply_filters('payplug_gateway_refund_data', $data, $order_id, $transaction_id);
1123 1122
1124 - /**
1125 - * Generate Hidden HTML.
1126 - *
1127 - * @param string $key
1128 - * @param array $data
1129 - *
1130 - * @return string
1131 - */
1132 - public function generate_hidden_html( $key, $data ) {
1133 - $field_key = $this->get_field_key( $key );
1134 - $defaults = array(
1135 - 'title' => '',
1136 - 'disabled' => false,
1137 - 'class' => '',
1138 - 'css' => '',
1139 - 'placeholder' => '',
1140 - 'type' => 'text',
1141 - 'desc_tip' => false,
1142 - 'description' => '',
1143 - 'custom_attributes' => array(),
1144 - );
1123 + try {
1124 + $refund = $this->payplug_api->refund_create($transaction_id, $data);
1145 1125
1146 - $data = wp_parse_args( $data, $defaults );
1126 + /**
1127 + * Fires once a refund has been created.
1128 + *
1129 + * @param int $order_id Order ID
1130 + * @param RefundResource $refund Refund resource
1131 + * @param string $transaction_id Transaction id
1132 + */
1133 + \do_action('payplug_gateway_refund_created', $order_id, $refund, $transaction_id);
1147 1134
1148 - ob_start();
1149 - ?>
1150 - <input
1151 - type="<?php echo esc_attr( $data['type'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>"
1152 - id="<?php echo esc_attr( $field_key ); ?>"
1153 - value="<?php echo esc_attr( $this->get_option( $key ) ); ?>"/>
1154 - <?php
1135 + $refund_meta_key = sprintf('_pr_%s', wc_clean($refund->id));
1136 + if (PayplugWoocommerceHelper::is_pre_30()) {
1137 + update_post_meta($order_id, $refund_meta_key, $refund->id);
1138 + } else {
1139 + $order->add_meta_data($refund_meta_key, $refund->id, true);
1140 + $order->save();
1141 + }
1155 1142
1156 - return ob_get_clean();
1157 - }
1143 + $note = sprintf(__('Refund %s : Refunded %s', 'payplug'), wc_clean($refund->id), wc_price(((int) $refund->amount) / 100));
1144 + if (!empty($refund->metadata['reason'])) {
1145 + $note .= sprintf(' (%s)', esc_html($refund->metadata['reason']));
1146 + }
1147 + $order->add_order_note($note);
1158 1148
1159 - /**
1160 - * Generate Yes/No Input HTML.
1161 - *
1162 - * @param string $key
1163 - * @param array $data
1164 - *
1165 - * @return string
1166 - */
1167 - public function generate_yes_no_html( $key, $data ) {
1168 - $field_key = $this->get_field_key( $key );
1169 - $defaults = array(
1170 - 'title' => '',
1171 - 'no' => 'No',
1172 - 'yes' => 'Yes',
1173 - 'disabled' => false,
1174 - 'class' => '',
1175 - 'css' => '',
1176 - 'placeholder' => '',
1177 - 'type' => 'text',
1178 - 'desc_tip' => false,
1179 - 'description' => '',
1180 - 'custom_attributes' => [],
1181 - 'hide_label' => false,
1182 - );
1149 + try {
1150 + $payment = $this->payplug_api->payment_retrieve($transaction_id);
1151 + $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
1152 + PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
1153 + } catch (\Exception $e) {
1154 + }
1183 1155
1184 - $data = wp_parse_args( $data, $defaults );
1185 - $checked = 'yes' === $this->get_option( $key ) ? '1' : '0';
1156 + self::log('Refund process complete for the order.');
1186 1157
1187 - ob_start();
1188 - ?>
1189 - <tr valign="top">
1190 - <?php if ( ! $data['hide_label'] ) : ?>
1191 - <th scope="row" class="titledesc">
1192 - <label for="<?php echo esc_attr( $field_key ); ?>">
1193 - <?php echo wp_kses_post( $data['title'] ); ?>
1194 - <?php echo $this->get_tooltip_html( $data ); ?>
1195 - </label>
1196 - </th>
1197 - <?php endif; ?>
1198 - <td class="forminp">
1199 - <fieldset>
1200 - <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span>
1201 - </legend>
1202 - <div class="radio--custom">
1203 - <input class="radio radio-yes <?php echo esc_attr( $data['class'] ); ?>"
1204 - type="radio"
1205 - name="<?php echo esc_attr( $field_key ); ?>"
1206 - id="<?php echo esc_attr( $field_key ); ?>-yes"
1207 - value="1"
1208 - <?php checked( '1', $checked ); ?>
1209 - <?php disabled( $data['disabled'], true ); ?>
1210 - <?php echo $this->get_custom_attribute_html( $data ); ?>>
1211 - <label for="<?php echo esc_attr( $field_key ); ?>-yes"><?php echo esc_html( $data['yes'] ); ?></label>
1212 - </div>
1213 - <div class="radio--custom">
1214 - <input class="radio radio-no <?php echo esc_attr( $data['class'] ); ?>"
1215 - type="radio"
1216 - name="<?php echo esc_attr( $field_key ); ?>"
1217 - id="<?php echo esc_attr( $field_key ); ?>-no"
1218 - value="0"
1219 - <?php checked( '0', $checked ); ?>
1220 - <?php disabled( $data['disabled'], true ); ?>
1221 - <?php echo $this->get_custom_attribute_html( $data ); ?>>
1222 - <label for="<?php echo esc_attr( $field_key ); ?>-no"><?php echo esc_html( $data['no'] ); ?></label>
1223 - </div>
1224 - <?php echo $this->get_description_html( $data ); ?>
1225 - </fieldset>
1226 - </td>
1227 - </tr>
1228 - <?php
1158 + return true;
1159 + } catch (HttpException $e) {
1160 + self::log(sprintf('Refund request error for the order %s from PayPlug API : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error');
1229 1161
1230 - return ob_get_clean();
1231 - }
1162 + return new \WP_Error('process_refund_error', __('The transaction could not be refunded. Please try again.', 'payplug'));
1163 + } catch (\Exception $e) {
1164 + self::log(sprintf('Refund request error for the order %s : %s', $order_id, wc_clean($e->getMessage())), 'error');
1232 1165
1233 - /**
1234 - * Generate Radio Input HTML.
1235 - *
1236 - * @param string $key
1237 - * @param array $data
1238 - *
1239 - * @return string
1240 - */
1241 - public function generate_radio_html( $key, $data ) {
1242 - $field_key = $this->get_field_key( $key );
1243 - $defaults = array(
1244 - 'title' => '',
1245 - 'disabled' => false,
1246 - 'class' => '',
1247 - 'css' => '',
1248 - 'placeholder' => '',
1249 - 'type' => 'text',
1250 - 'desc_tip' => false,
1251 - 'description' => '',
1252 - 'custom_attributes' => [],
1253 - 'options' => [],
1254 - );
1166 + return new \WP_Error('process_refund_error', __('The transaction could not be refunded. Please try again.', 'payplug'));
1167 + }
1168 + }
1255 1169
1256 - $data = wp_parse_args( $data, $defaults );
1170 + /**
1171 + * Check the order amount to ensure it's on the allowed range.
1172 + *
1173 + * @param int $amount
1174 + *
1175 + * @return int|\WP_Error
1176 + */
1177 + public function validate_order_amount($amount)
1178 + {
1179 + if (
1180 + $amount < PayplugWoocommerceHelper::get_minimum_amount()
1181 + || $amount > PayplugWoocommerceHelper::get_maximum_amount()
1182 + ) {
1183 + return new \WP_Error(
1184 + 'invalid order amount',
1185 + sprintf(__('Payments for this amount (%s) are not authorised with this payment gateway.', 'payplug'), \wc_price($amount / 100))
1186 + );
1187 + }
1257 1188
1258 - ob_start();
1259 - ?>
1260 - <tr valign="top">
1261 - <th scope="row" class="titledesc">
1262 - <label for="<?php echo esc_attr( $field_key ); ?>">
1263 - <?php echo wp_kses_post( $data['title'] ); ?>
1264 - <?php echo $this->get_tooltip_html( $data ); ?>
1265 - </label>
1266 - </th>
1267 - <td class="forminp">
1268 - <fieldset>
1269 - <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span>
1270 - </legend>
1271 - <?php foreach ( $data['options'] as $option_key => $option_value ) : ?>
1272 - <input class="radio <?php echo esc_attr( $data['class'] ); ?>"
1273 - type="radio"
1274 - name="<?php echo esc_attr( $field_key ); ?>"
1275 - id="<?php echo esc_attr( $field_key ); ?>-<?php echo esc_attr( $option_key ); ?>"
1276 - value="<?php echo esc_attr( $option_key ); ?>"
1277 - <?php checked( $option_key, $this->get_option( $key ) ); ?>
1278 - <?php disabled( $data['disabled'], true ); ?>
1279 - <?php echo $this->get_custom_attribute_html( $data ); ?>>
1280 - <label for="<?php echo esc_attr( $field_key ); ?>-<?php echo esc_attr( $option_key ); ?>"><?php echo esc_html( $option_value ); ?></label>
1281 - <?php endforeach; ?>
1282 - </fieldset>
1283 - </td>
1284 - </tr>
1285 - <?php
1189 + return $amount;
1190 + }
1286 1191
1287 - return ob_get_clean();
1288 - }
1192 + /**
1193 + * Limit string length.
1194 + *
1195 + * @param string $value
1196 + * @param int $maxlength
1197 + *
1198 + * @return string
1199 + */
1200 + public function limit_length($value, $maxlength = 100)
1201 + {
1202 + return (strlen($value) > $maxlength) ? substr($value, 0, $maxlength) : $value;
1203 + }
1289 1204
1290 - /**
1291 - * Generate Login HTML.
1292 - *
1293 - * @param string $key
1294 - * @param array $data
1295 - *
1296 - * @return string
1297 - */
1298 - public function generate_login_html( $key, $data ) {
1299 - $field_key = $this->get_field_key( $key );
1300 - $defaults = [];
1205 + /**
1206 + * Get user's keys.
1207 + *
1208 + * @param string $email
1209 + * @param string $password
1210 + *
1211 + * @return array|\WP_Error
1212 + */
1213 + public function retrieve_user_api_keys($email, $password)
1214 + {
1215 + if (empty($email) || empty($password)) {
1216 + return new \WP_Error('missing_login_data', __('Please fill all login fields', 'payplug'));
1217 + }
1301 1218
1302 - $data = wp_parse_args( $data, $defaults );
1219 + try {
1220 + $response = Authentication::getKeysByLogin($email, $password);
1221 + if (empty($response) || !isset($response['httpResponse']) && 'payplug' === $this->id) {
1222 + return new \WP_Error('invalid_credentials', __('Invalid credentials.', 'payplug'));
1223 + }
1303 1224
1304 - ob_start();
1305 - ?>
1306 - <tr valign="top">
1307 - <td class="forminp">
1308 - <p><?php echo $this->get_option( 'email' ); ?></p>
1309 - <p>
1310 - <input type="submit" name="submit_logout" value="<?php _e( 'Logout', 'payplug' ); ?>">
1311 - <input type="hidden" name="save" value="logout">
1312 - <?php wp_nonce_field( 'payplug_user_logout', '_logoutaction' ); ?>
1313 - |
1314 - <a href="https://portal.payplug.com"
1315 - target="_blank"><?php _e( 'Go to your PayPlug Portal', 'payplug' ); ?></a>
1316 - </p>
1317 - </td>
1318 - </tr>
1319 - <?php
1225 + return $response['httpResponse']['secret_keys'];
1226 + } catch (HttpException $e) {
1227 + if ('payplug' === $this->id) {
1228 + return new \WP_Error('invalid_credentials', __('Invalid credentials.', 'payplug'));
1229 + }
1230 + }
1231 + }
1320 1232
1321 - return ob_get_clean();
1322 - }
1233 + /**
1234 + * Get user merchant id.
1235 + *
1236 + * This method might be called during the login process before the global PayPlug
1237 + * configuration is set. In that case you can pass a valid token to make the request.
1238 + *
1239 + * @param string|null $key
1240 + *
1241 + * @return string
1242 + */
1243 + public function retrieve_merchant_id($key = null)
1244 + {
1245 + $merchant_id = '';
1246 + try {
1247 + $response = !is_null($key) && !empty($key) ? Authentication::getAccount(new Payplug($key)) : Authentication::getAccount();
1248 + PayplugWoocommerceHelper::set_transient_data($response);
1249 + $merchant_id = isset($response['httpResponse']['id']) ? $response['httpResponse']['id'] : '';
1250 + } catch (ConfigurationException $e) {
1251 + self::log(sprintf('Missing API key for PayPlug client : %s', wc_print_r($e->getMessage(), true)), 'error');
1252 + } catch (HttpException $e) {
1253 + self::log(sprintf('Account request error from PayPlug API : %s', wc_print_r($e->getErrorObject(), true)), 'error');
1254 + PayplugWoocommerceHelper::exception_handler_400_logout($e->getCode(), '', sprintf('Account request error from PayPlug API : %s', wc_print_r($e->getMessage(), true)));
1255 + } catch (\Exception $e) {
1256 + self::log(sprintf('Account request error : %s', wc_clean($e->getMessage())), 'error');
1257 + }
1323 1258
1324 - /**
1325 - * Validate Radio Field.
1326 - *
1327 - * Make sure the data is escaped correctly, etc.
1328 - *
1329 - * @param string $key
1330 - * @param string|null $value Posted Value
1331 - *
1332 - * @return string
1333 - */
1334 - public function validate_radio_field( $key, $value ) {
1335 - $value = is_null( $value ) ? '' : $value;
1259 + return $merchant_id;
1260 + }
1336 1261
1337 - return wc_clean( stripslashes( $value ) );
1338 - }
1262 + /**
1263 + * Get PayPlug gateway mode.
1264 + *
1265 + * @return string
1266 + */
1267 + public function get_current_mode()
1268 + {
1269 + return $this->get_configuration()->get_option('mode');
1270 + }
1339 1271
1340 - /**
1341 - * Validate Yes/No Field.
1342 - *
1343 - * @param string $key
1344 - * @param string $value Posted Value
1345 - *
1346 - * @return string
1347 - */
1348 - public function validate_yes_no_field( $key, $value ) {
1349 - return ( '1' === (string) $value ) ? 'yes' : 'no';
1350 - }
1272 + /**
1273 + * Get user API key.
1274 + *
1275 + * @param string $mode
1276 + *
1277 + * @return string
1278 + */
1279 + public function get_api_key($mode = 'test')
1280 + {
1281 + return $this->get_api()->get_bearer_token($mode);
1282 + }
1351 1283
1352 - /**
1353 - * Get PayPlug gateway mode.
1354 - *
1355 - * @return string
1356 - */
1357 - public function get_current_mode() {
1358 - return ( 'yes' === $this->get_option( 'mode' ) ) ? 'live' : 'test';
1359 - }
1284 + /**
1285 + * Get current merchant id.
1286 + *
1287 + * @return string
1288 + */
1289 + public function get_merchant_id()
1290 + {
1291 + return $this->get_configuration()->get_option('company_id');
1292 + }
1360 1293
1361 - /**
1362 - * Get user API key.
1363 - *
1364 - * @param string $mode
1365 - *
1366 - * @return string
1367 - */
1368 - public function get_api_key( $mode = 'test' ) {
1294 + /**
1295 + * Check if user is logged in and we have an API key for TEST mode.
1296 + *
1297 + * @return bool
1298 + */
1299 + public function user_logged_in()
1300 + {
1301 + $options = $this->get_configuration()->get_options();
1302 + if (empty($options) || !isset($options['api_key']) || !isset($options['jwt'])) {
1303 + return false;
1304 + }
1369 1305
1370 - switch ( $mode ) {
1371 - case 'test':
1372 - $key = $this->get_option( 'payplug_test_key' );
1373 - break;
1374 - case 'live':
1375 - $key = $this->get_option( 'payplug_live_key' );
1376 - break;
1377 - default:
1378 - $key = '';
1379 - break;
1380 - }
1306 + $jwt = json_decode($options['jwt'], true);
1307 + if (!empty($jwt) && isset($jwt['test']) && isset($jwt['test']['access_token'])) {
1308 + return true;
1309 + }
1381 1310
1382 - return $key;
1383 - }
1311 + $api_key = json_decode($options['api_key'], true);
1384 1312
1385 - /**
1386 - * Check if an api key exist for a mode.
1387 - *
1388 - * @param string $mode
1389 - *
1390 - * @return bool
1391 - */
1392 - public function has_api_key( $mode = 'test' ) {
1393 - $key = $this->get_api_key( $mode );
1394 - $key = trim( $key );
1313 + return !empty($api_key) && isset($api_key['test']) && !empty($api_key['test']);
1314 + }
1395 1315
1396 - return ! empty( $key );
1397 - }
1316 + /**
1317 + * Check if oneclick payment is activated and merchant can use it.
1318 + *
1319 + * @return bool
1320 + */
1321 + public function save_card_available()
1322 + {
1323 + return 'payplug' == $this->id && $this->user_logged_in()
1324 + && $this->save_card
1325 + && $this->permissions->has_permissions(PayplugPermissions::SAVE_CARD);
1326 + }
1398 1327
1399 - /**
1400 - * Get current merchant id.
1401 - *
1402 - * @return string
1403 - */
1404 - public function get_merchant_id() {
1405 - return $this->get_option( 'payplug_merchant_id', '' );
1406 - }
1328 + /**
1329 + * Check if the gatteway is allowed for the order amount
1330 + *
1331 + * @param array
1332 + *
1333 + * @return array
1334 + */
1335 + public function check_gateway($gateways)
1336 + {
1337 + if (!empty(WC()->cart) && isset($gateways[$this->id]) && $gateways[$this->id]->id == $this->id) {
1338 + $order_amount = $this->get_order_total();
1339 + foreach ($gateways[$this->id]->settings['payment_methods']['permissions'] as $key => &$permission) {
1340 + $method_amounts = json_decode($permission['amounts'], true);
1341 + if ($order_amount < $method_amounts['min']['EUR'] / 100 || $order_amount > $method_amounts['max']['EUR'] / 100) {
1342 + unset($gateways[$key]);
1343 + }
1344 + }
1345 + }
1407 1346
1408 - /**
1409 - * Check if user is logged in and we have an API key for TEST mode.
1410 - *
1411 - * @return bool
1412 - */
1413 - public function user_logged_in() {
1414 - return ! empty( $this->get_option( 'payplug_test_key' ) );
1415 - }
1347 + if ((bool) $this->get_configuration()->get_option('payment_methods.configuration.oney.with_fees')) {
1348 + unset($gateways['oney_x3_without_fees']);
1349 + unset($gateways['oney_x4_without_fees']);
1350 + } else {
1351 + unset($gateways['oney_x3_with_fees']);
1352 + unset($gateways['oney_x4_with_fees']);
1353 + }
1416 1354
1417 - /**
1418 - * Check if oneclick payment is activated and merchant can use it.
1419 - *
1420 - * @return bool
1421 - */
1422 - public function oneclick_available() {
1423 - return $this->user_logged_in()
1424 - && $this->oneclick
1425 - && $this->permissions->has_permissions( PayplugPermissions::SAVE_CARD );
1426 - }
1355 + return $gateways;
1356 + }
1357 +
1358 + /**
1359 + * Can the order be refunded via this gateway?
1360 + *
1361 + *
1362 + * @param WC_Order $order Order object.
1363 + *
1364 + * @return bool If false, the automatic refund button is hidden in the UI.
1365 + */
1366 + public function can_refund_order($order)
1367 + {
1368 + $status = $order->get_status();
1369 +
1370 + return $order && $this->supports('refunds') && $status !== 'cancelled' && $status !== 'failed';
1371 + }
1427 1372 }