sprintf('%s', esc_url(PAYPLUG_GATEWAY_PLUGIN_URL . '/assets/images/checkout/' . $this->image), $this->id . ' Icon'), ]); $icons_str = ''; foreach ($icons as $icon) { $icons_str .= $icon; } return $icons_str; } /** * @return void */ public function display_notice(): void { $error_message = 'payplug_' . $this->id . '_unauthorized_message'; ?>

settings['enabled']) || !$this->settings['enabled']) { return false; } // todo: delete this usage to avoid call to getAccount resource each checkout loading $account = PayplugWoocommerceHelper::generic_get_account_data_from_options($this->id); $options = PayplugWoocommerceHelper::get_payplug_options(); if (!$this->check_api_gateway_enable($account)) { return false; } if (!isset($options['payment_methods']) || empty($options['payment_methods'])) { return false; } if (!$options['payment_methods']['configuration'][$this->id]['active']) { return false; } $is_order_pay = is_wc_endpoint_url('order-pay'); $country_code_billing = null; if (!is_admin() && (!PayplugWoocommerceHelper::is_checkout_block() || $is_order_pay)) { if (empty(WC()->cart) && !is_admin() && !$is_order_pay) { return false; } //for backend orders if (!empty(get_query_var('order-pay'))) { $order = wc_get_order((int) get_query_var('order-pay')); $items = $order->get_items(); $country_code_billing = $order->get_billing_country(); // Skip cart population for subscription renewals: WC Subscriptions manages the cart // itself and adding items here would cause a double entry in the order summary. $is_renewal = function_exists('wcs_order_contains_renewal') && wcs_order_contains_renewal($order); if (!$is_renewal) { if (is_null(WC()->cart)) { wc_load_cart(); } $this->order_items_to_cart(WC()->cart, $items); } } $source_before_fallback = $country_code_billing; if (empty($country_code_billing)) { $country_code_billing = method_exists(WC()->customer, 'get_billing_country') ? WC()->customer->get_billing_country() : null; } $permission_result = $this->check_billing_country_permissions($account, $country_code_billing); if (!$permission_result) { return false; } } return true; } /** * check if payment is enable and customer has permissions * * @param $account * * @return bool */ protected function check_api_gateway_enable($account) { if ( isset($account['payment_methods']) && empty($account['payment_methods'][$this->id]) && !$account['payment_methods'][$this->id]['enabled'] ) { return false; } return true; } /** * Check if billing country can use this payment method * * @param $account * @param $billing_code * * @return bool */ public function check_billing_country_permissions($account, $billing_code) { if (!isset($account['payment_methods'][$this->id]['allowed_countries'])) { return true; } $this->allowed_country_codes = $account['payment_methods'][$this->id]['allowed_countries']; if (is_array($this->allowed_country_codes)) { if (in_array('ALL', $this->allowed_country_codes) || empty($this->allowed_country_codes)) { return true; } //check if country is allowed if (in_array($billing_code, $this->allowed_country_codes)) { return true; } else { return false; } } return false; } /** * if payment was generated by an intend, we shouldn't generate another one and try to pay it, this would generate duplications * * @param $order * * @throws \Exception * * @return array|null */ private function process_standard_intent_payment($order) { $embedded_mode = $this->settings['payment_methods']['configuration']['payplug']['embedded_mode']; // This can run from AJAX endpoints whose own request URL never carries the order-pay // query var, so is_wc_endpoint_url() alone can't detect that context here: fall back // to the order_key/order_pay_key sent by the order-pay AJAX flows. $is_order_pay = $this->is_order_pay_request($order); if (!$is_order_pay && empty($_POST['payplug_non_blocks']) && PayplugWoocommerceHelper::is_checkout_block() && ( ($this->id === 'payplug' && in_array($embedded_mode, ['integrated', 'popup'])) || ($this->id === 'american_express' && 'popup' == $embedded_mode) ) && !empty($order->get_transaction_id())) { $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id(); try { $payment = $this->payplug_api->payment_retrieve($order->get_transaction_id()); if (ob_get_length() > 0) { ob_clean(); } // Save transaction id for the order PayplugWoocommerceHelper::is_pre_30() ? update_post_meta($order_id, '_transaction_id', $payment->id) : $order->set_transaction_id($payment->id); if (is_callable([$order, 'save'])) { $order->save(); } /** * Fires once a payment has been created. * * @param int $order_id Order ID * @param PaymentResource $payment Payment resource */ \do_action('payplug_gateway_payment_created', $order_id, $payment); $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment); PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata); PayplugGateway::log(sprintf('Payment intent created for order #%s', $order_id)); $return_url = esc_url_raw($order->get_checkout_order_received_url()); $result = [ 'payment_id' => $payment->id, 'result' => 'success', 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url, 'cancel' => !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : null, ]; // wp_send_json_success() calls die(), which is only safe for the classic // wc-ajax request this was written for: the Store API checkout flow (used by // the checkout block) calls process_payment() through the REST framework, // and killing the process mid-request there produces a broken response. if (wp_doing_ajax()) { wp_send_json_success($result); } return $result; } catch (HttpException $e) { PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error'); throw new \Exception(__('Payment processing failed. Please retry.', 'payplug')); } catch (\Exception $e) { PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error'); throw new \Exception(__('Payment processing failed. Please retry.', 'payplug')); } } return null; } public function process_standard_payment($order, $amount, $customer_id) { $intent = $this->process_standard_intent_payment($order); if (!empty($intent)) { return $intent; } $order_id = PayplugWoocommerceHelper::is_pre_30() ? $order->id : $order->get_id(); try { //if there's no auth to process payment if (!$this->checkGateway()) { throw new \Exception(__('Payment processing failed. Please retry.', 'payplug')); } $address_data = PayplugAddressData::from_order($order); $return_url = esc_url_raw($order->get_checkout_order_received_url()); if (!(substr($return_url, 0, 4) === 'http')) { $return_url = get_site_url() . $return_url; } $payment_data = [ 'amount' => $amount, 'currency' => get_woocommerce_currency(), 'payment_method' => $this->id, 'billing' => $address_data->get_billing(), 'shipping' => $address_data->get_shipping(), 'hosted_payment' => [ 'return_url' => $return_url, 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()), ], 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')), 'metadata' => [ 'order_id' => $order_id, 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest', 'domain' => $this->limit_length(esc_url_raw(home_url()), 500), ], 'save_card' => false, 'force_3ds' => false, ]; if (!empty($payment_data['billing']['landline_phone_number'])) { $payment_data['billing']['mobile_phone_number'] = $payment_data['billing']['landline_phone_number']; } if (PayplugWoocommerceHelper::is_checkout_block() && is_checkout()) { $payment_data['metadata']['woocommerce_block'] = 'CHECKOUT'; } elseif (PayplugWoocommerceHelper::is_cart_block() && is_cart()) { $payment_data['metadata']['woocommerce_block'] = 'CART'; } /** * Filter the payment data before it's used * * @param array $payment_data * @param int $order_id * @param array $customer_details * @param PayplugAddressData $address_data */ $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data); $payment = $this->payplug_api->payment_create($payment_data); // Save transaction id for the order PayplugWoocommerceHelper::is_pre_30() ? update_post_meta($order_id, '_transaction_id', $payment->id) : $order->set_transaction_id($payment->id); $order->set_payment_method($this->id); $order->set_payment_method_title($this->method_title); if (is_callable([$order, 'save'])) { $order->save(); } /** * Fires once a payment has been created. * * @param int $order_id Order ID * @param PaymentResource $payment Payment resource */ \do_action('payplug_gateway_payment_created', $order_id, $payment); $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment); PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata); PayplugGateway::log(sprintf('Payment creation complete for order #%s', $order_id)); return [ 'result' => 'success', 'redirect' => $payment->hosted_payment->payment_url, 'cancel' => $payment->hosted_payment->cancel_url, ]; } catch (HttpException $e) { PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error'); throw new \Exception(__('Payment processing failed. Please retry.', 'payplug')); } catch (\Exception $e) { PayplugGateway::log(sprintf('Error while processing order #%s : %s', $order_id, $e->getMessage()), 'error'); throw new \Exception(__('Payment processing failed. Please retry.', 'payplug')); } } /** * Process refund for an order paid with PayPlug gateway. * * @param int $order_id * @param null $amount * @param string $reason * * @return bool|\WP_Error */ public function process_refund($order_id, $amount = null, $reason = '') { PayplugGateway::log(sprintf('Processing refund for order #%s', $order_id)); if (!$this->user_logged_in()) { PayplugGateway::log(__('You must be logged in with your PayPlug account.', 'payplug'), 'error'); return new \WP_Error('process_refund_error', __('You must be logged in with your PayPlug account.', 'payplug')); } $order = wc_get_order($order_id); if (!$order instanceof \WC_Order) { PayplugGateway::log(sprintf('The order #%s does not exist.', $order_id), 'error'); return new \WP_Error('process_refund_error', sprintf(__('The order %s does not exist.', 'payplug'), $order_id)); } if ($order->get_status() === 'cancelled') { PayplugGateway::log(sprintf('The order #%s cannot be refund.', $order_id), 'error'); return new \WP_Error('process_refund_error', sprintf(__('The order %s cannot be refund.', 'payplug'), $order_id)); } $transaction_id = PayplugWoocommerceHelper::is_pre_30() ? get_post_meta($order_id, '_transaction_id', true) : $order->get_transaction_id(); if (empty($transaction_id)) { PayplugGateway::log(sprintf('The order #%s does not have PayPlug transaction ID associated with it.', $order_id), 'error'); return new \WP_Error('process_refund_error', __('No PayPlug transaction was found for this order. The refund could not be processed.', 'payplug')); } /** * PPRO gateways feature! */ if (isset($this->enable_refund) && $this->enable_refund === false) { PayplugGateway::log(__('payplug_refund_disabled_error', 'payplug'), 'error'); return new \WP_Error('process_refund_error', __('payplug_refund_disabled_error', 'payplug')); } $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id(); $data = [ 'metadata' => [ 'order_id' => $order_id, 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest', 'refund_from' => 'woocommerce', ], ]; if (!is_null($amount)) { $data['amount'] = PayplugWoocommerceHelper::get_payplug_amount($amount); } if (!empty($reason)) { $data['metadata']['reason'] = $reason; } /** * Filter the refund data before it's used. * * @param array $data * @param int $order_id * @param string $transaction_id */ $data = apply_filters('payplug_gateway_refund_data', $data, $order_id, $transaction_id); try { $refund = $this->payplug_api->refund_create($transaction_id, $data); if ($refund->object === 'error') { PayplugGateway::log(__('payplug_ppro_flag_error', 'payplug'), 'error'); return new \WP_Error('process_refund_error', __('payplug_ppro_flag_error', 'payplug')); } /** * Fires once a refund has been created. * * @param int $order_id Order ID * @param RefundResource $refund Refund resource * @param string $transaction_id Transaction id */ \do_action('payplug_gateway_refund_created', $order_id, $refund, $transaction_id); $refund_meta_key = sprintf('_pr_%s', wc_clean($refund->id)); if (PayplugWoocommerceHelper::is_pre_30()) { update_post_meta($order_id, $refund_meta_key, $refund->id); } else { $order->add_meta_data($refund_meta_key, $refund->id, true); $order->save(); } $note = sprintf(__('Refund %s : Refunded %s', 'payplug'), wc_clean($refund->id), wc_price(((int) $refund->amount) / 100)); if (!empty($refund->metadata['reason'])) { $note .= sprintf(' (%s)', esc_html($refund->metadata['reason'])); } $order->add_order_note($note); try { $payment = $this->payplug_api->payment_retrieve($transaction_id); $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment); PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata); } catch (\Exception $e) { } PayplugGateway::log('Refund process complete for the order.'); return true; } catch (HttpException $e) { PayplugGateway::log(sprintf('Refund request error for the order %s from PayPlug API : %s', $order_id, wc_print_r($e->getErrorObject(), true)), 'error'); return new \WP_Error('process_refund_error', __('The transaction could not be refunded. Please try again.', 'payplug')); } catch (\Exception $e) { PayplugGateway::log(sprintf('Refund request error for the order %s : %s', $order_id, wc_clean($e->getMessage())), 'error'); return new \WP_Error('process_refund_error', __('The transaction could not be refunded. Please try again.', 'payplug')); } } /** * Avoid usage of button refund on the BO * * @param int $item_id * @param \WC_Order_Item|null $item * @param mixed $product * * @return false|void */ public function hide_wc_refund_button($item_id, $item = null, $product = null) { if (!$item instanceof \WC_Order_Item) { return false; } $order = $item->get_order(); if (!$order instanceof \WC_Order) { return false; } if ($order->get_payment_method() === $this->id && isset($this->enable_refund) && $this->enable_refund === false) { ?> id === $order->get_payment_method() && isset($this->enable_refund) && $this->enable_refund === false) { echo "

" . __('payplug_refund_disabled_error', 'payplug') . '

'; } } /** * Empty the cart and add all order_items * * @param $cart * @param $items * * @return void */ private function order_items_to_cart($cart, $items): void { $cart->empty_cart(); foreach ($items as $item) { $cart->add_to_cart($item->get_product_id(), $item->get_quantity(), $item->get_variation_id()); } } }