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/PayplugGatewayOney3x.php +91 -72 2.18.0 → 3.1.0 View file →
@@ -4,8 +4,9 @@
4 4
5 5 use libphonenumber\PhoneNumberType;
6 6 use libphonenumber\PhoneNumberUtil;
7 7 use Payplug\PayplugWoocommerce\Controller\PayplugGenericGateway;
8 +use Payplug\PayplugWoocommerce\Gateway\Oney\OneyAccountMapper;
8 9 use Payplug\PayplugWoocommerce\PayplugWoocommerceHelper;
9 10
10 11 // Exit if accessed directly
11 12 if (!defined('ABSPATH')) {
@@ -16,16 +17,16 @@
16 17 * PayPlug WooCommerce Gateway.
17 18 */
18 19 class PayplugGatewayOney3x extends PayplugGenericGateway
19 20 {
20 - const ONEY_UNAVAILABLE_CODE_COUNTRY_NOT_ALLOWED = 2;
21 - const ONEY_UNAVAILABLE_CODE_CART_SIZE_TOO_HIGH = 3;
22 - const ONEY_DISALBE_CHECKOUT_OPTIONS = 4;
21 + public const ONEY_UNAVAILABLE_CODE_COUNTRY_NOT_ALLOWED = 2;
22 + public const ONEY_UNAVAILABLE_CODE_CART_SIZE_TOO_HIGH = 3;
23 + public const ONEY_DISALBE_CHECKOUT_OPTIONS = 4;
23 24
24 - const ONEY_PRODUCT_QUANTITY_MAXIMUM = 1000;
25 + public const ONEY_PRODUCT_QUANTITY_MAXIMUM = 1000;
25 26
26 27 protected $oney_response;
27 - const ENABLE_ON_TEST_MODE = true;
28 + public const ENABLE_ON_TEST_MODE = true;
28 29
29 30 public $allowed_country_codes = [];
30 31
31 32 public function __construct()
@@ -34,9 +35,9 @@
34 35 $this->id = 'oney_x3_with_fees';
35 36 $this->method_title = _x('PayPlug Oney 3x', 'Gateway method title', 'payplug');
36 37 $this->method_description = __('Enable PayPlug Oney 3x for your customers.', 'payplug');
37 38 $this->title = __('Pay by card in 3x with Oney', 'payplug');
38 - $this->has_fields = false;
39 + $this->has_fields = true;
39 40
40 41 add_action('woocommerce_order_item_add_action_buttons', [$this, 'oney_refund_text']);
41 42 add_action('woocommerce_after_checkout_validation', [$this, 'validate_checkout'], 10);
42 43
@@ -41,8 +42,15 @@
41 42 add_action('woocommerce_after_checkout_validation', [$this, 'validate_checkout'], 10);
42 43
43 44 self::set_oney_configuration();
44 45
46 + // Unlike the other sub-gateways (Bancontact, AmericanExpress, PPRO methods...), Oney never
47 + // synced $this->enabled with the plugin's own "active" toggle, so disabling Oney from the
48 + // Payplug config left it shown as enabled on WooCommerce's native Payments settings page.
49 + if (!$this->checkGateway()) {
50 + $this->enabled = 'no';
51 + }
52 +
45 53 if (is_checkout()) {
46 54 if ($this->check_oney_is_available() === self::ONEY_DISALBE_CHECKOUT_OPTIONS) {
47 55 $this->enabled = 'no';
48 56 }
@@ -48,13 +56,18 @@
48 56 }
49 57 }
50 58 }
51 59
52 - public function validate_checkout()
60 + public function validate_checkout(): void
53 61 {
54 62 $posted_data = $this->get_post_data();
55 63
56 - if (in_array($posted_data['payment_method'], ['oney_x3_with_fees","oney_x4_with_fees", "oney_x3_without_fees", "oney_x4_without_fees'])) {
64 + // Was a single malformed string (missing quotes around each id) instead of a 4-element
65 + // array, so this guard never matched and the whole method was a silent no-op (PRE-3457
66 + // review / PRE-3457 follow-up fix).
67 + $oney_gateway_ids = ['oney_x3_with_fees', 'oney_x4_with_fees', 'oney_x3_without_fees', 'oney_x4_without_fees'];
68 +
69 + if (in_array($posted_data['payment_method'] ?? '', $oney_gateway_ids, true)) {
57 70 if ($this->check_oney_is_available() === self::ONEY_UNAVAILABLE_CODE_COUNTRY_NOT_ALLOWED) {
58 71 throw new \Exception(__('Unavailable for the specified country.'));
59 72 } elseif ($this->check_oney_is_available() === self::ONEY_UNAVAILABLE_CODE_CART_SIZE_TOO_HIGH) {
60 73 throw new \Exception(sprintf(__('The payment with Oney is unavailable because you have more than %s items in your cart.', 'payplug'), self::ONEY_PRODUCT_QUANTITY_MAXIMUM));
@@ -68,9 +81,9 @@
68 81 * Set oney settings
69 82 *
70 83 * @return void
71 84 */
72 - private function set_oney_configuration()
85 + private function set_oney_configuration(): void
73 86 {
74 87 $account = PayplugWoocommerceHelper::get_account_data_from_options();
75 88 if ($account) {
76 89 $oney_configuration = $account['configuration']['oney'];
@@ -86,54 +99,9 @@
86 99 * @return string
87 100 */
88 101 public function get_icon()
89 102 {
90 - $disable = '';
91 - if ($this->check_oney_is_available() === true) {
92 - $total_price = floatval(WC()->cart->total);
93 - $this->oney_response = $this->payplug_api->simulate_oney_payment($total_price, 'with_fees');
94 - $currency = get_woocommerce_currency_symbol(get_option('woocommerce_currency'));
95 - $total_price_oney = floatval($this->oney_response['x3_with_fees']['down_payment_amount']);
96 - foreach ($this->oney_response['x3_with_fees']['installments'] as $installment) {
97 - $total_price_oney = $total_price_oney + floatval($installment['amount']);
98 - }
99 - $f = function ($fn) {
100 - return $fn;
101 - };
102 -
103 - $tax_cost = floatval($this->oney_response['x3_with_fees']['total_cost']) / 100;
104 -
105 - if (is_array($this->oney_response)) {
106 - $this->description = <<<HTML
107 - <p>
108 - <div class="payplug-oney-flex">
109 - <div>{$f(__('Bring', 'payplug'))}:</div>
110 - <div>{$this->oney_response['x3_with_fees']['down_payment_amount']} {$currency}</div>
111 - </div>
112 - <div class="payplug-oney-flex">
113 - <small>( {$f(__('oney_financing_cost', 'payplug'))} <b>{$tax_cost} {$currency}</b> TAEG : <b>{$this->oney_response['x3_with_fees']['effective_annual_percentage_rate']} %</b> )</small>
114 - </div>
115 - <div class="payplug-oney-flex">
116 - <div>{$f(__('1st monthly payment', 'payplug'))}:</div>
117 - <div>{$this->oney_response['x3_with_fees']['installments'][0]['amount']} {$currency}</div>
118 - </div>
119 - <div class="payplug-oney-flex">
120 - <div>{$f(__('2nd monthly payment', 'payplug'))}:</div>
121 - <div>{$this->oney_response['x3_with_fees']['installments'][1]['amount']} {$currency}</div>
122 - </div>
123 - <div class="payplug-oney-flex">
124 - <div><b>{$f(__('oney_total', 'payplug'))}</b></div>
125 - <div><b>{$total_price_oney} {$currency}</b></div>
126 - </div>
127 - </p>
128 -HTML;
129 - } else {
130 - $this->description = $this->oney_response;
131 - }
132 - } else {
133 - $disable = 'disable-checkout-icons';
134 - }
135 -
103 + $disable = $this->check_oney_is_available() === true ? '' : 'disable-checkout-icons';
136 104 $available_img = 'x3_with_fees.svg';
137 105
138 106 $icons = apply_filters('payplug_payment_icons', [
139 107 'payplug' => sprintf('<img src="%s" alt="Oney 3x" class="payplug-payment-icon ' . $disable . '" />', esc_url(PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/checkout/' . $available_img)),
@@ -146,8 +114,48 @@
146 114 return $icons_str;
147 115 }
148 116
149 117 /**
118 + * Render the placeholder + config the official Oney widget uses to display the inline
119 + * payment-schedule section for this specific gateway (checkout obligation).
120 + */
121 + public function payment_fields(): void
122 + {
123 + if ($this->check_oney_is_available() !== true) {
124 + // check_oney_is_available() sets $this->description with the reason Oney can't be used.
125 + $description = $this->get_description();
126 +
127 + if (!empty($description)) {
128 + echo wpautop(wptexturize($description));
129 + }
130 +
131 + return;
132 + }
133 +
134 + $account = PayplugWoocommerceHelper::get_account_data_from_options();
135 + $oney_settings = $this->get_configuration()->get_option('payment_methods.configuration.oney');
136 + $country = PayplugWoocommerceHelper::getISOCountryCode();
137 + $mapper = OneyAccountMapper::map((array) $account, $oney_settings, $country);
138 + $code = $mapper->business_transaction_code_for_gateway($this->id);
139 +
140 + if (!$mapper->is_enabled() || !$code) {
141 + return;
142 + }
143 +
144 + printf(
145 + '<div id="oney-checkout-loading-%1$s" class="payplug-lds-roller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div id="oney-checkout-%1$s"></div><script type="application/json" id="oney-checkout-config-%1$s">%2$s</script>',
146 + esc_attr($this->id),
147 + wp_json_encode([
148 + 'merchant_guid' => $mapper->get_merchant_guid(),
149 + 'business_transaction_code' => $code,
150 + 'country' => $country,
151 + 'language' => strtoupper(substr(get_locale(), 0, 2)),
152 + 'payment_amount' => floatval(WC()->cart->total),
153 + ])
154 + );
155 + }
156 +
157 + /**
150 158 * Check if Oney is available
151 159 *
152 160 * @return bool|int true, false, or an ONEY_* status code
153 161 */
@@ -184,11 +192,31 @@
184 192
185 193 $country_code_shipping = $order->get_shipping_country();
186 194 $country_code_billing = $order->get_billing_country();
187 195
188 - $this->order_items_to_cart($cart, $items);
196 + // Skip cart population for subscription renewals: WC Subscriptions manages the cart
197 + // itself and adding items here would cause a double entry in the order summary.
198 + $is_renewal = function_exists('wcs_order_contains_renewal') && wcs_order_contains_renewal($order);
199 + if (!$is_renewal) {
200 + $this->order_items_to_cart($cart, $items);
201 + }
189 202 }
190 203
204 + $oney_cfg = $this->get_configuration()->get_option('payment_methods.configuration.oney');
205 + $account = PayplugWoocommerceHelper::get_account_data_from_options();
206 + $oney_account_cfg = ((array) $account)['configuration']['oney'] ?? [];
207 + // Same clamping OneyAccountMapper::map() uses for the badge/widget display, so
208 + // checkout validation and display never silently drift apart (PRE-3457 review).
209 + [$min_cents, $max_cents] = OneyAccountMapper::effective_bounds($oney_account_cfg, $oney_cfg);
210 + $oney_amount = [
211 + 'min' => $min_cents / 100,
212 + 'max' => $max_cents / 100,
213 + ];
214 + // validate_checkout() reads these to build its exception message - populate them
215 + // unconditionally (before any early return below) so they're never stale/unset there.
216 + $this->oney_thresholds_min = $oney_amount['min'];
217 + $this->oney_thresholds_max = $oney_amount['max'];
218 +
191 219 if (empty($cart->total)) {
192 220 return false;
193 221 }
194 222
@@ -198,13 +226,8 @@
198 226
199 227 $total_price = floatval($cart->total);
200 228 $products_qty = (int) $cart->cart_contents_count;
201 229
202 - $oney_cfg = $this->get_configuration()->get_option('payment_methods.configuration.oney');
203 - $oney_amount = json_decode($oney_cfg['custom_amounts'], true);
204 - $oney_amount['min'] = (float) $oney_amount['min'] / 100;
205 - $oney_amount['max'] = (float) $oney_amount['max'] / 100;
206 -
207 230 // Min and max
208 231 if ($total_price < $oney_amount['min'] || $total_price > $oney_amount['max']) {
209 232 $this->description = '<div class="payment_method_oney_x3_with_fees_disabled">' . sprintf(__('The total amount of your order should be between %s€ and %s€ to pay with Oney.', 'payplug'), $oney_amount['min'], $oney_amount['max']) . '</div>';
210 233
@@ -426,9 +449,9 @@
426 449 * Show Oney refund text
427 450 *
428 451 * @return void
429 452 */
430 - public function oney_refund_text($order)
453 + public function oney_refund_text($order): void
431 454 {
432 455 if ($this->id === $order->get_payment_method() && parent::can_refund_order($order) && $order->get_status() !== 'refunded' && $this->payplug_api) {
433 456 $order_metadata = $order->get_meta('_payplug_metadata');
434 457
@@ -446,16 +469,8 @@
446 469 }
447 470 }
448 471 }
449 472
450 - public function payment_fields()
451 - {
452 - $description = $this->get_description();
453 - if (!empty($description)) {
454 - echo wpautop(wptexturize($description));
455 - }
456 - }
457 -
458 473 /**
459 474 * Billing and shipping addresses should have the same country and allowed by Oney
460 475 * https://payplug-prod.atlassian.net/browse/WOOC-227
461 476 *
@@ -496,9 +511,9 @@
496 511 * @param $items
497 512 *
498 513 * @return void
499 514 */
500 - private function order_items_to_cart($cart, $items)
515 + private function order_items_to_cart($cart, $items): void
501 516 {
502 517 $cart->empty_cart();
503 518 foreach ($items as $item) {
504 519 $cart->add_to_cart($item->get_product_id(), $item->get_quantity(), $item->get_variation_id());
@@ -508,7 +523,11 @@
508 523 public function checkGateway()
509 524 {
510 525 $options = PayplugWoocommerceHelper::get_payplug_options();
511 526
512 - return empty($options) || !isset($options['payment_methods']) ? false : $options['payment_methods']['configuration']['oney']['active'];
527 + // Now called unconditionally from the constructor (not just at checkout via
528 + // is_available()), so a legacy account whose stored config predates the oney block
529 + // (never went through Upgrade::run_upgrade()) would otherwise throw "undefined array
530 + // key" warnings on every admin page that builds the WC gateway list (PRE-3597 review).
531 + return $options['payment_methods']['configuration']['oney']['active'] ?? false;
513 532 }
514 533 }