sprintf('
', 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());
}
}
}