PluginProbe ʕ •ᴥ•ʔ
GlobalPayments Gateway Provider for WooCommerce / 1.20.2
GlobalPayments Gateway Provider for WooCommerce v1.20.2
1.20.2 1.20.1 1.19.3 1.19.2 1.19.1 1.19.0 1.18.4 1.18.3 trunk 1.0.0 1.0.0-b2 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.6 1.10.7 1.10.8 1.11.0 1.12.0 1.12.1 1.13.0 1.13.1 1.13.2 1.13.3 1.13.4 1.13.7 1.13.8 1.14.0 1.14.1 1.14.2 1.14.3 1.14.4 1.14.5 1.14.6 1.14.7 1.14.8 1.14.9 1.15.0 1.15.2 1.15.4 1.15.5 1.15.6 1.15.8 1.15.9 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.17.0 1.17.1 1.18.0 1.18.1 1.18.2 1.2.0 1.2.1 1.2.2 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.6.0 1.7.0 1.8.0 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5
global-payments-woocommerce / src / PaymentMethods / AbstractPaymentMethod.php
global-payments-woocommerce / src / PaymentMethods Last commit date
Apm 1 year ago BuyNowPayLater 1 year ago DigitalWallets 3 weeks ago OpenBanking 3 weeks ago AbstractAsyncPaymentMethod.php 1 week ago AbstractPaymentMethod.php 1 week ago AsyncPaymentMethodInterface.php 2 years ago PaymentMethodInterface.php 2 years ago
AbstractPaymentMethod.php
447 lines
1 <?php
2
3 namespace GlobalPayments\WooCommercePaymentGatewayProvider\PaymentMethods;
4
5 use GlobalPayments\Api\Entities\Exceptions\GatewayException;
6 use GlobalPayments\Api\Entities\Transaction;
7 use GlobalPayments\WooCommercePaymentGatewayProvider\Gateways\AbstractGateway;
8 use GlobalPayments\WooCommercePaymentGatewayProvider\Gateways\GpApiGateway;
9 use GlobalPayments\WooCommercePaymentGatewayProvider\Plugin;
10 use GlobalPayments\WooCommercePaymentGatewayProvider\Utils\Utils;
11 use WC_Payment_Gateway;
12
13 defined( 'ABSPATH' ) || exit;
14
15 abstract class AbstractPaymentMethod extends WC_Payment_Gateway implements PaymentMethodInterface {
16 /**
17 * Gateway.
18 *
19 * @var GlobalPayments\WooCommercePaymentGatewayProvider\Gateways;
20 */
21 public $gateway;
22
23 /**
24 * Payment method default title.
25 *
26 * @var string
27 */
28 public $default_title;
29
30 /**
31 * Action to perform at checkout
32 *
33 * Possible actions:
34 *
35 * - `authorize` - authorize the card without auto capturing
36 * - `sale` - authorize the card with auto capturing
37 * - `verify` - verify the card without authorizing
38 *
39 * @var string
40 */
41 public $payment_action;
42
43 /**
44 * Payment source.
45 *
46 * @var string
47 */
48 protected $payment_source;
49
50 public function __construct() {
51 $this->has_fields = true;
52 $this->supports = array(
53 'refunds',
54 );
55
56 $this->init_gateway();
57 $this->configure_method_settings();
58 $this->init_form_fields();
59 $this->init_settings();
60 $this->configure_merchant_settings();
61 $this->add_hooks();
62 }
63
64 /**
65 * Sets the necessary WooCommerce payment method settings for exposing the
66 * payment method in the WooCommerce Admin.
67 *
68 * @return
69 */
70 abstract public function configure_method_settings();
71
72 /**
73 * Custom admin options to configure the payment method specific credentials, features, etc.
74 *
75 * @return array
76 */
77 abstract public function get_payment_method_form_fields();
78
79 /**
80 * Required options for proper client-side configuration.
81 *
82 * @return array
83 */
84 abstract public function get_frontend_payment_method_options();
85
86 /**
87 * Request type.
88 *
89 * @return GlobalPayments\WooCommercePaymentGatewayProvider\Gateways\Requests\RequestInterface
90 */
91 abstract public function get_request_type();
92
93 /**
94 * Should be overwritten to provide additional functionality before payment gateway request.
95 *
96 * @param $request
97 * @param $order
98 */
99 public function process_payment_before_gateway_request( &$request, $order ) {
100 return;
101 }
102
103 /**
104 * Should be overwritten to provide additional functionality after payment gateway response is received.
105 *
106 * @param $gateway_response
107 * @param $is_successful
108 * @param $order
109 */
110 public function process_payment_after_gateway_response( Transaction $gateway_response, $is_successful, \WC_Order $order ) {
111 return;
112 }
113
114 /**
115 * Email address of the first-line support team.
116 *
117 * @return string
118 */
119 public function get_first_line_support_email() {
120 return $this->gateway->get_first_line_support_email();
121 }
122
123 /**
124 * @inheritdoc
125 */
126 public function init_form_fields() {
127 $this->form_fields = array_merge(
128 array(
129 'enabled' => array(
130 'title' => __( 'Enable/Disable', 'globalpayments-gateway-provider-for-woocommerce' ),
131 'type' => 'checkbox',
132 'label' => __( 'Enable payment method', 'globalpayments-gateway-provider-for-woocommerce' ),
133 'default' => 'no',
134 ),
135 'title' => array(
136 'title' => esc_html__( 'Title', 'globalpayments-gateway-provider-for-woocommerce' ),
137 'type' => 'text',
138 'description' => esc_html__( 'This controls the title which the user sees during checkout.', 'globalpayments-gateway-provider-for-woocommerce' ),
139 'default' => esc_html__( $this->default_title, 'globalpayments-gateway-provider-for-woocommerce' ),
140 'desc_tip' => true,
141 'custom_attributes' => array( 'required' => 'required' ),
142 ),
143 ),
144 $this->get_payment_method_form_fields(),
145 array(
146 'payment_action' => array(
147 'title' => __( 'Payment Action', 'globalpayments-gateway-provider-for-woocommerce' ),
148 'type' => 'select',
149 'description' => __( 'Choose whether you wish to capture funds immediately or authorize payment only for a delayed capture.', 'globalpayments-gateway-provider-for-woocommerce' ),
150 'default' => AbstractGateway::TXN_TYPE_SALE,
151 'desc_tip' => true,
152 'options' => $this->get_payment_action_options(),
153 ),
154 )
155 );
156 }
157
158 /**
159 * Get supported payment actions at checkout.
160 *
161 * @return array
162 */
163 public function get_payment_action_options() {
164 return array(
165 AbstractGateway::TXN_TYPE_SALE => __( 'Authorize + Capture', 'globalpayments-gateway-provider-for-woocommerce' ),
166 AbstractGateway::TXN_TYPE_AUTHORIZE => __( 'Authorize only', 'globalpayments-gateway-provider-for-woocommerce' ),
167 );
168 }
169
170 /**
171 * Sets the configurable merchant settings for use elsewhere in the class.
172 *
173 * @return
174 */
175 public function configure_merchant_settings() {
176 $this->title = $this->get_option( 'title' );
177 $this->enabled = $this->get_option( 'enabled' );
178 $this->payment_action = $this->get_option( 'payment_action' );
179
180 foreach ( $this->get_payment_method_form_fields() as $key => $options ) {
181 if ( ! property_exists( $this, $key ) ) {
182 continue;
183 }
184
185 $value = $this->get_option( $key );
186 if ( 'checkbox' === $options['type'] ) {
187 $value = 'yes' === $value;
188 }
189
190 $this->{$key} = $value;
191 }
192 }
193
194 /**
195 *Add payment method specific hooks.
196 */
197 public function add_hooks() {
198 add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array(
199 $this,
200 'process_admin_options'
201 ) );
202 add_filter( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
203
204 // Admin refund advisory for async payments
205 if ( is_admin() && current_user_can( 'edit_shop_orders' ) ) {
206 add_action( 'woocommerce_admin_order_data_after_order_details', array( $this, 'display_refund_advisory_for_async' ), 100 );
207 }
208 }
209
210 /**
211 * Enqueues payment method specific scripts.
212 *
213 * @return
214 */
215 public function enqueue_payment_scripts() {
216 return;
217 }
218
219 public function admin_enqueue_scripts( $hook_suffix ) {
220 $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
221 if ( 'woocommerce_page_wc-settings' !== $hook_suffix || 'checkout' !== $tab ) {
222 return;
223 }
224
225 $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : null;
226 if ( $this->id != $section ) {
227 return;
228 }
229
230 wp_enqueue_script(
231 'globalpayments-admin',
232 Plugin::get_url( '/assets/admin/js/globalpayments-admin.js' ),
233 array(
234 'wp-i18n' // include 'wp-i18n' for translation
235 ),
236 WC()->version,
237 true
238 );
239
240 // set script translation, this will look in plugin languages directory and look for .json translation file
241 wp_set_script_translations('globalpayments-admin', 'globalpayments-gateway-provider-for-woocommerce', WP_PLUGIN_DIR . '/'. basename( dirname( __FILE__ , 3 ) ) . '/languages');
242
243 wp_localize_script(
244 'globalpayments-admin',
245 'globalpayments_admin_params',
246 array(
247 'gateway_id' => $section,
248 )
249 );
250 wp_enqueue_style(
251 'globalpayments-admin',
252 Plugin::get_url( '/assets/admin/css/globalpayments-admin.css' ),
253 array(),
254 WC()->version
255 );
256 }
257
258 /**
259 * @inheritdoc
260 */
261 public function payment_fields() {
262 $this->enqueue_payment_scripts();
263 ?>
264
265 <div class="form-row form-row-wide globalpayments <?php echo esc_attr( $this->id ); ?>">
266 <div id="<?php echo esc_attr( $this->id ); ?>"></div>
267 </div>
268 <div class="clear"></div>
269
270 <?php
271 }
272
273 /**
274 * @inheritdoc
275 */
276 public function process_payment( $order_id ) {
277 $order = wc_get_order( $order_id );
278 try {
279 $request = $this->gateway->prepare_request(
280 $this->get_request_type(),
281 $order
282 );
283 $this->process_payment_before_gateway_request( $request, $order );
284 $gateway_response = $this->gateway->client->submit_request( $request );
285 $is_successful = $this->gateway->handle_response( $request, $gateway_response );
286 $this->process_payment_after_gateway_response( $gateway_response, $is_successful, $order );
287
288 return array(
289 'result' => $this->get_process_payment_result( $is_successful, $order ),
290 'redirect' => $this->get_process_payment_redirect( $is_successful, $order ),
291 );
292 } catch ( \Exception $e ) {
293 wc_get_logger()->error( $e->getMessage() );
294 if ( $e instanceof GatewayException ) {
295 throw new \Exception( esc_html( Utils::map_response_code_to_friendly_message() ) );
296 }
297 throw new \Exception( esc_html( $e->getMessage() ) );
298 }
299 }
300
301 /**
302 * @inheritdoc
303 */
304 public function process_refund( $order_id, $amount = null, $reason = '' ) {
305 return $this->gateway->process_refund( $order_id, $amount, $reason );
306 }
307
308 /**
309 * Get payment source
310 */
311 public function get_payment_source() {
312 return $this->payment_source;
313 }
314
315 protected function get_process_payment_result( $is_successful, $order ) {
316 return $is_successful ? 'success' : 'failure';
317 }
318
319 protected function get_process_payment_redirect( $is_successful, $order ) {
320 return $is_successful ? $this->get_return_url( $order ) : false;
321 }
322
323 /**
324 * init gateway.
325 */
326 protected function init_gateway() {
327 $this->gateway = new GpApiGateway( true );
328 }
329
330 /**
331 * Display refund advisory for async payment methods.
332 *
333 * @param \WC_Order $order
334 * @return void
335 */
336 public function display_refund_advisory_for_async( $order ): void {
337 // Prevent duplicate rendering - use static variable
338 static $already_rendered = array();
339
340 if ( isset( $already_rendered[ $order->get_id() ] ) ) {
341 return;
342 }
343
344 // Only show for specific async payment method IDs or when order notes indicate async payment
345 $async_payment_indicators = array( 'globalpayments_bankpayment', 'globalpayments_paypal' );
346 $order_payment_method = $order->get_payment_method();
347
348 // Check if it's a direct async payment method
349 $is_async_payment = in_array( $order_payment_method, $async_payment_indicators, true );
350
351 // Also check order notes for async payment keywords (for cases where gpapi is used but it's actually async)
352 if ( ! $is_async_payment && $order_payment_method === 'globalpayments_gpapi' ) {
353 $order_notes = wc_get_order_notes( array( 'order_id' => $order->get_id() ) );
354 foreach ( $order_notes as $note ) {
355 if ( stripos( $note->content, 'Open Banking' ) !== false ||
356 stripos( $note->content, 'PayPal' ) !== false ||
357 stripos( $note->content, 'Awaiting' ) !== false ) {
358 $is_async_payment = true;
359 break;
360 }
361 }
362 }
363
364 if ( ! $is_async_payment ) {
365 return;
366 }
367
368 // Only show for orders with transaction ID
369 $transaction_id = $order->get_transaction_id();
370 if ( empty( $transaction_id ) ) {
371 return;
372 }
373
374 $show_advisory = false;
375
376 // Check WooCommerce order status
377 $order_status = $order->get_status();
378 $pending_order_statuses = array( 'pending', 'on-hold', 'processing' );
379
380 if ( in_array( $order_status, $pending_order_statuses, true ) ) {
381 $show_advisory = true;
382 }
383
384 // Display advisory if conditions are met
385 if ( $show_advisory ) {
386 $already_rendered[ $order->get_id() ] = true;
387 $this->render_refund_advisory_html();
388 }
389 }
390
391 /**
392 * Render the HTML for refund advisory message with tooltip near refund button.
393 *
394 * @return void
395 */
396 protected function render_refund_advisory_html(): void {
397 /* translators: Tooltip shown on refund button for async payment methods */
398 $tooltip_message = esc_js( __( 'Payment confirmation for this method may take several days. Refunds are only available after a final payment status is received. Please wait for confirmation or contact support if the delay continues.', 'globalpayments-gateway-provider-for-woocommerce' ) );
399 ?>
400 <script type="text/javascript">
401 jQuery(document).ready(function($) {
402 function addRefundButtonTooltip() {
403 // Find refund button - try multiple selectors for compatibility
404 var $refundButton = $('.button.refund-items').first();
405 if (!$refundButton || $refundButton.length === 0) {
406 $refundButton = $('button.refund-items').first();
407 }
408 if (!$refundButton || $refundButton.length === 0) {
409 $refundButton = $('.wc-order-refund-items button').first();
410 }
411
412 if ($refundButton && $refundButton.length > 0) {
413 // Check if tooltip hasn't been added already
414 if (!$refundButton.attr('data-globalpayments-tooltip-added')) {
415 // Add title attribute to the button itself
416 $refundButton.attr('title', '<?php echo $tooltip_message; ?>');
417 $refundButton.attr('data-globalpayments-tooltip-added', 'true');
418
419 // Initialize WooCommerce tipTip on the button itself
420 if (typeof $.fn.tipTip === 'function') {
421 $refundButton.tipTip( {
422 'attribute': 'title',
423 'fadeIn': 50,
424 'fadeOut': 50,
425 'delay': 200
426 } );
427 }
428 return true;
429 }
430 }
431 return false;
432 }
433
434 // Try multiple times with delays
435 var attempts = 0;
436 var maxAttempts = 3;
437 var retryInterval = setInterval(function() {
438 if (addRefundButtonTooltip() || ++attempts >= maxAttempts) {
439 clearInterval(retryInterval);
440 }
441 }, 500);
442 });
443 </script>
444 <?php
445 }
446 }
447