PluginProbe
WooCommerce Square / 4.4.0
WooCommerce Square v4.4.0
5.5.0 5.4.3 5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 All 132 releases
woocommerce-square / includes / Gateway.php
Gateway.php
1,428 lines 43.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WooCommerce Square
4 *
5 * This source file is subject to the GNU General Public License v3.0
6 * that is bundled with this package in the file license.txt.
7 * It is also available through the world-wide-web at this URL:
8 * http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
9 * If you did not receive a copy of the license and are unable to
10 * obtain it through the world-wide-web, please send an email
11 * to license@woocommerce.com so we can send you a copy immediately.
12 *
13 * DISCLAIMER
14 *
15 * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16 * versions in the future. If you wish to customize WooCommerce Square for your
17 * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18 *
19 * @author WooCommerce
20 * @copyright Copyright: (c) 2019, Automattic, Inc.
21 * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
22 */
23
24 namespace WooCommerce\Square;
25
26 defined( 'ABSPATH' ) || exit;
27
28 use WooCommerce\Square\Gateway\Card_Handler;
29 use WooCommerce\Square\Gateway\Customer_Helper;
30 use WooCommerce\Square\Gateway\Payment_Form;
31 use WooCommerce\Square\Handlers\Product;
32 use WooCommerce\Square\Utilities\Money_Utility;
33 use WooCommerce\Square\Gateway\Digital_Wallet;
34 use WooCommerce\Square\Framework\PaymentGateway\Payment_Gateway_Direct;
35 use WooCommerce\Square\Framework\PaymentGateway\Payment_Gateway_Helper;
36 use WooCommerce\Square\Framework\PaymentGateway\Payment_Gateway;
37 use WooCommerce\Square\Framework\Square_Helper;
38 use WooCommerce\Square\Gateway\Gift_Card;
39
40 /**
41 * The Square payment gateway class.
42 *
43 * @since 2.0.0
44 *
45 * @method Plugin get_plugin()
46 */
47 class Gateway extends Payment_Gateway_Direct {
48
49
50 /** @var Gateway\API API base instance */
51 private $api;
52
53 /**
54 * As per documentation, as of now, SCA is enabled only for UK merchants, but to be implemented for Europe.
55 * As other currencies get supported, add them here.
56 *
57 * @since 2.2.0
58 *
59 * @var array $sca_supported_currencies Currencies for which SCA(3DS) is supported
60 */
61 private $sca_supported_currencies = array( 'GBP', 'EUR' );
62
63 /**
64 * Square Payment Form instance
65 * Null by default.
66 *
67 * @since 2.2.3
68 *
69 */
70 private $payment_form = null;
71
72 /**
73 * Holds the instance of the Digital_Wallet class.
74 * @since 4.2.0
75 *
76 * @var null|Digital_Wallet
77 */
78 private $digital_wallet = null;
79
80 /**
81 * Holds the instance of the Gift_Card class.
82 * @since 4.2.0
83 *
84 * @var null|Gift_Card
85 */
86 private $gift_card = null;
87
88 /**
89 * Constructs the class.
90 *
91 * @since 2.0.0
92 */
93 public function __construct() {
94
95 parent::__construct(
96 Plugin::GATEWAY_ID,
97 wc_square(),
98 array(
99 'method_title' => __( 'Square', 'woocommerce-square' ),
100 'method_description' => __( 'Allow customers to use Square to securely pay with their credit cards', 'woocommerce-square' ),
101 'payment_type' => self::PAYMENT_TYPE_CREDIT_CARD,
102 'supports' => array(
103 self::FEATURE_PRODUCTS,
104 self::FEATURE_CARD_TYPES,
105 self::FEATURE_DETAILED_CUSTOMER_DECLINE_MESSAGES,
106 self::FEATURE_PAYMENT_FORM,
107 self::FEATURE_CREDIT_CARD_AUTHORIZATION,
108 self::FEATURE_CREDIT_CARD_CHARGE,
109 self::FEATURE_CREDIT_CARD_CHARGE_VIRTUAL,
110 self::FEATURE_CREDIT_CARD_CAPTURE,
111 self::FEATURE_REFUNDS,
112 self::FEATURE_VOIDS,
113 self::FEATURE_CUSTOMER_ID,
114 self::FEATURE_TOKENIZATION,
115 self::FEATURE_ADD_PAYMENT_METHOD,
116 self::FEATURE_TOKEN_EDITOR,
117 ),
118 )
119 );
120
121 $this->view_transaction_url = 'https://squareup.com/dashboard/sales/transactions/%s';
122
123 // log accept.js requests and responses
124 add_action( 'wp_ajax_wc_' . $this->get_id() . '_log_js_data', array( $this, 'log_js_data' ) );
125 add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_log_js_data', array( $this, 'log_js_data' ) );
126
127 add_action( 'wp_ajax_wc_' . $this->get_id() . '_get_token_by_id', array( $this, 'get_token_by_id' ) );
128 add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_get_token_by_id', array( $this, 'get_token_by_id' ) );
129
130 // store the Square item variation ID to order items
131 add_action( 'woocommerce_new_order_item', array( $this, 'store_new_order_item_square_meta' ), 10, 3 );
132
133 // restore refunded Square inventory
134 add_action( 'woocommerce_order_refunded', array( $this, 'restore_refunded_inventory' ), 10, 2 );
135
136 // AJAX Checkout validation handler.
137 add_action( 'wc_ajax_' . $this->get_id() . '_checkout_handler', array( $this, 'wc_ajax_square_checkout_handler' ) );
138
139 // Filter gateways depending on cart contents.
140 add_action( 'woocommerce_available_payment_gateways', array( $this, 'filter_available_gateways' ) );
141
142 // Display error messages depending on cart contents.
143 add_action( 'woocommerce_no_available_payment_methods_message', array( $this, 'filter_no_payment_gatways_message' ) );
144
145 // AJAX handler for get order amount
146 add_action( 'wp_ajax_wc_' . $this->get_id() . '_get_order_amount', array( $this, 'get_order_amount' ) );
147 add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_get_order_amount', array( $this, 'get_order_amount' ) );
148
149 // Init Square digital wallets.
150 $this->digital_wallet = new Digital_Wallet( $this );
151
152 // Init Square gift card.
153 $this->gift_card = new Gift_Card( $this );
154 }
155
156 /**
157 * Ajax callback to return payment token by token ID.
158 *
159 * @since 4.2.0
160 */
161 public function get_token_by_id() {
162 $nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : false;
163
164 if ( ! wp_verify_nonce( $nonce, 'payment_token_nonce' ) ) {
165 wp_send_json_error( esc_html__( 'Nonce verification failed.', 'woocommerce-square' ) );
166 }
167
168 $token_id = isset( $_GET['token_id'] ) ? absint( wp_unslash( $_GET['token_id'] ) ) : false;
169
170 if ( ! $token_id ) {
171 wp_send_json_error( esc_html__( 'Token ID missing.', 'woocommerce-square' ) );
172 }
173
174 $token_obj = \WC_Payment_Tokens::get( $token_id );
175
176 if ( is_null( $token_obj ) ) {
177 wp_send_json_error( esc_html__( 'No payment token exists for this ID.', 'woocommerce-square' ) );
178 }
179
180 wp_send_json_success( $token_obj->get_token() );
181 }
182
183
184 /**
185 * Logs any data sent by the payment form JS via AJAX.
186 *
187 * @since 2.0.0
188 */
189 public function log_js_data() {
190
191 check_ajax_referer( 'wc_' . $this->get_id() . '_log_js_data', 'security' );
192
193 $message = sprintf( "Square.js %1\$s:\n ", ! empty( $_REQUEST['type'] ) ? ucfirst( wc_clean( $_REQUEST['type'] ) ) : 'Request' );
194
195 // add the data
196 if ( ! empty( $_REQUEST['data'] ) ) {
197 $message .= print_r( wc_clean( $_REQUEST['data'] ), true );
198 }
199
200 $this->get_plugin()->log( $message, $this->get_id() );
201 }
202
203
204 /**
205 * Stores the Square item variation ID to order items when added to orders.
206 *
207 * @internal
208 *
209 * @since 2.0.0
210 *
211 * @param int $item_id order item ID
212 * @param \WC_Order_Item $item order item object
213 * @param int $order_id order ID
214 */
215 public function store_new_order_item_square_meta( $item_id, $item, $order_id ) {
216
217 if ( ! $item instanceof \WC_Order_Item_Product ) {
218 return;
219 }
220
221 $product = $item->get_product();
222
223 if ( ! $product instanceof \WC_Product ) {
224 return;
225 }
226
227 if ( ! Product::is_synced_with_square( $product ) ) {
228 return;
229 }
230
231 if ( $square_id = $product->get_meta( Product::SQUARE_VARIATION_ID_META_KEY ) ) {
232 $item->update_meta_data( Product::SQUARE_VARIATION_ID_META_KEY, $square_id );
233 }
234
235 $item->save_meta_data();
236 }
237
238 /**
239 * Overrides enqueue of the gateway-specific assets if present, including JS, CSS, and
240 * localized script params
241 *
242 * @since 2.1.7
243 */
244 protected function enqueue_payment_form_assets() {
245 // bail if *not* on add payment method page or checkout page.
246 if ( ! ( is_add_payment_method_page() || is_checkout() ) ) {
247 return;
248 }
249
250 parent::enqueue_payment_form_assets();
251 }
252
253 /**
254 * Enqueues the gateway JS.
255 *
256 * @since 2.0.0
257 */
258 protected function enqueue_gateway_assets() {
259
260 $is_payment_form_or_checkout = is_add_payment_method_page() || is_checkout() || ( function_exists( 'has_block' ) && has_block( 'woocommerce/checkout' ) );
261 $is_digital_wallet_page = 'yes' === $this->get_option( 'enable_digital_wallets', 'yes' ) && ( is_product() || is_cart() );
262
263 // bail if *not* on add payment method page or checkout page or not on the product or cart when digital wallets are enabled
264 if ( ! ( $is_payment_form_or_checkout || $is_digital_wallet_page ) ) {
265 return;
266 }
267
268 if ( $this->get_plugin()->get_settings_handler()->is_sandbox() ) {
269 $url = 'https://sandbox.web.squarecdn.com/v1/square.js';
270 } else {
271 $url = 'https://web.squarecdn.com/v1/square.js';
272 }
273
274 wp_enqueue_script( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-payment-form', $url, array(), Plugin::VERSION );
275
276 parent::enqueue_gateway_assets();
277
278 // Render PaymentForm JS
279 $this->get_payment_form_instance()->render_js();
280 }
281
282
283 /**
284 * Validates the entered payment fields.
285 *
286 * @since 2.0.0
287 *
288 * @return bool
289 */
290 public function validate_fields() {
291
292 $is_valid = true;
293
294 if ( $this->is_gift_card_applied() ) {
295 return $is_valid;
296 }
297
298 try {
299
300 if ( '' === Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-buyer-verification-token' ) ) {
301 throw new \Exception( '3D Secure Verification Token is missing' );
302 }
303
304 if ( Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-token' ) ) {
305 return $is_valid;
306 }
307
308 if ( ! Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' ) ) {
309 throw new \Exception( 'Payment nonce is missing' );
310 }
311 } catch ( \Exception $exception ) {
312
313 $is_valid = false;
314
315 Square_Helper::wc_add_notice( __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ), 'error' );
316
317 $this->add_debug_message( $exception->getMessage(), 'error' );
318 }
319
320 return $is_valid;
321 }
322
323
324 /**
325 * Gets the order object with payment information added.
326 *
327 * @since 2.0.0
328 *
329 * @param int|\WC_Order $order_id order ID or object
330 * @return \WC_Order
331 */
332 public function get_order( $order_id ) {
333
334 $order = parent::get_order( $order_id );
335
336 $order->payment->verification_token = Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-buyer-verification-token' );
337
338 $order->payment->nonce = new \stdClass();
339
340 if ( empty( $order->payment->token ) ) {
341
342 $order->payment->nonce->credit_card = Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' );
343
344 $order->payment->card_type = Payment_Gateway_Helper::normalize_card_type( Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-card-type' ) );
345 $order->payment->account_number = $order->payment->last_four = substr( Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-last-four' ), -4 );
346 $order->payment->exp_month = Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-exp-month' );
347 $order->payment->exp_year = Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-exp-year' );
348 $order->payment->postcode = Square_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-postcode' );
349 }
350
351 if ( $this->is_gift_card_applied() ) {
352 $order->payment->nonce->gift_card = Square_Helper::get_post( 'square-gift-card-payment-nonce' );
353 }
354
355 $order->square_customer_id = $order->customer_id;
356 $order->square_order_id = $this->get_order_meta( $order, 'square_order_id' );
357 $order->square_version = $this->get_order_meta( $order, 'square_version' );
358
359 // look up in the index for guest customers
360 if ( ! $order->get_user_id() ) {
361
362 $indexed_customers = Customer_Helper::get_customers_by_email( $order->get_billing_email() );
363
364 // only use an indexed customer ID if there was a single one returned, otherwise we can't know which to use
365 if ( ! empty( $indexed_customers ) && count( $indexed_customers ) === 1 ) {
366 $order->square_customer_id = $order->customer_id = $indexed_customers[0];
367 }
368 }
369
370 // if no previous customer could be found, always create a new customer
371 if ( empty( $order->square_customer_id ) ) {
372
373 try {
374
375 $response = $this->get_api()->create_customer( $order );
376
377 $order->square_customer_id = $order->customer_id = $response->get_customer_id(); // set $customer_id since we know this customer can be associated with this user
378
379 // store the guests customers in our index to avoid future duplicates
380 if ( ! $order->get_user_id() ) {
381 Customer_Helper::add_customer( $order->square_customer_id, $order->get_billing_email() );
382 }
383 } catch ( \Exception $exception ) {
384
385 // log the error, but continue with payment
386 if ( $this->debug_log() ) {
387 $this->get_plugin()->log( $exception->getMessage(), $this->get_id() );
388 }
389 }
390 }
391
392 return $order;
393 }
394
395
396 /**
397 * Do the transaction.
398 *
399 * @since 2.0.0
400 *
401 * @param WC_Order_Square $order
402 * @return bool
403 * @throws \Exception
404 */
405 protected function do_transaction( $order ) {
406
407 // if there is no associated Square order ID, create one
408 if ( empty( $order->square_order_id ) ) {
409
410 try {
411
412 $location_id = $this->get_plugin()->get_settings_handler()->get_location_id();
413 $response = $this->get_api()->create_order( $location_id, $order );
414
415 $this->maybe_save_gift_card_order_details( $response, $order );
416
417 $order->square_order_id = $response->getId();
418
419 // adjust order by difference between WooCommerce and Square order totals
420 $wc_total = Money_Utility::amount_to_cents( $order->get_total() );
421 $square_total = $response->getTotalMoney()->getAmount();
422 $delta_total = $wc_total - $square_total;
423
424 if ( abs( $delta_total ) > 0 ) {
425 $response = $this->get_api()->adjust_order( $location_id, $order, $response->getVersion(), $delta_total );
426
427 // since a downward adjustment causes (downward) tax recomputation, perform an additional (untaxed) upward adjustment if necessary
428 $square_total = $response->getTotalMoney()->getAmount();
429 $delta_total = $wc_total - $square_total;
430
431 if ( $delta_total > 0 ) {
432 $response = $this->get_api()->adjust_order( $location_id, $order, $response->getVersion(), $delta_total );
433 }
434 }
435
436 // reset the payment total to the total calculated by Square to prevent errors
437 $order->payment_total = Square_Helper::number_format( Money_Utility::cents_to_float( $response->getTotalMoney()->getAmount() ) );
438
439 } catch ( \Exception $exception ) {
440
441 // log the error, but continue with payment
442 if ( $this->debug_log() ) {
443 $this->get_plugin()->log( $exception->getMessage(), $this->get_id() );
444 }
445 }
446 }
447
448 return parent::do_transaction( $order );
449 }
450
451
452 /**
453 * Stores gift card details as order meta.
454 *
455 * @since 4.2.0
456 *
457 * @param \Square\Models\Order $square_order
458 * @param \WC_Order $order
459 */
460 public function maybe_save_gift_card_order_details( $square_order, $order ) {
461 $line_items = $square_order->getLineItems();
462
463 /** @var \Square\Models\OrderLineItem */
464 foreach ( $line_items as $line_item ) {
465 if ( \Square\Models\OrderLineItemItemType::GIFT_CARD !== $line_item->getItemType() ) {
466 continue;
467 }
468
469 $gift_card_line_item_id = $line_item->getUid();
470 $gift_card_amount = Square_Helper::number_format(
471 Money_Utility::cents_to_float(
472 $line_item->getTotalMoney()->getAmount()
473 )
474 );
475
476 $this->update_order_meta( $order, 'gift_card_line_item_id', $gift_card_line_item_id );
477 $this->update_order_meta( $order, 'gift_card_balance', $gift_card_amount );
478 $this->update_order_meta( $order, 'is_gift_card_purchased', 'yes' );
479 }
480 }
481
482
483 /**
484 * Adds transaction data to the order.
485 *
486 * @since 2.0.0
487 *
488 * @param \WC_Order $order order object
489 * @param \WooCommerce\Square\Gateway\API\Responses\Charge $response API response object
490 */
491 public function add_payment_gateway_transaction_data( $order, $response ) {
492
493 $location_id = $response->get_location_id() ? $response->get_location_id() : $this->get_plugin()->get_settings_handler()->get_location_id();
494
495 if ( $location_id ) {
496 $this->update_order_meta( $order, 'square_location_id', $location_id );
497 }
498
499 if ( $response->get_square_order_id() ) {
500 $this->update_order_meta( $order, 'square_order_id', $response->get_square_order_id() );
501 }
502
503 // store the plugin version on the order
504 $this->update_order_meta( $order, 'square_version', Plugin::VERSION );
505 }
506
507
508 /**
509 * Gets an order with capture data attached.
510 *
511 * @since 2.0.0
512 *
513 * @param int|\WC_Order $order order object
514 * @param null|float $amount amount to capture
515 * @return \WC_Order
516 */
517 public function get_order_for_capture( $order, $amount = null ) {
518
519 $order = parent::get_order_for_capture( $order, $amount );
520
521 $order->capture->location_id = $this->get_order_meta( $order, 'square_location_id' );
522 $order->square_version = $this->get_order_meta( $order, 'square_version' );
523
524 return $order;
525 }
526
527
528 /**
529 * Gets an order with refund data attached.
530 *
531 * @since 2.0.0
532 *
533 * @param int|\WC_Order $order order object
534 * @param float $amount amount to refund
535 * @param string $reason response for the refund
536 *
537 * @return \WC_Order|\WP_Error
538 */
539 protected function get_order_for_refund( $order, $amount, $reason ) {
540
541 $order = parent::get_order_for_refund( $order, $amount, $reason );
542 $order->square_version = $this->get_order_meta( $order, 'square_version' );
543
544 if ( $transaction_date = $this->get_order_meta( $order, 'trans_date' ) ) {
545 // refunds with the Refunds API can be made up to 1 year after payment and up to 120 days with the Transactions API
546 $max_refund_time = version_compare( $order->square_version, '2.2', '>=' ) ? '+1 year' : '+120 days';
547
548 // throw an error if the payment cannot be refunded
549 if ( current_time( 'timestamp' ) >= strtotime( $max_refund_time, strtotime( $transaction_date ) ) ) {
550 /* translators: %s maximum refund date. */
551 return new \WP_Error( 'wc_square_refund_age_exceeded', sprintf( __( 'Refunds must be made within %s of the original payment date.', 'woocommerce-square' ), '+1 year' === $max_refund_time ? 'a year' : '120 days' ) );
552 }
553 }
554
555 $order->refund->location_id = $this->get_order_meta( $order, 'square_location_id' );
556 $order->refund->tender_id = $this->get_order_meta( $order, 'authorization_code' );
557
558 if ( ! $order->refund->tender_id ) {
559
560 try {
561 $response = version_compare( $order->square_version, '2.2', '>=' ) ? $this->get_api()->get_payment( $order->refund->trans_id ) : $this->get_api()->get_transaction( $order->refund->trans_id, $order->refund->location_id );
562
563 if ( ! $response->get_authorization_code() ) {
564 throw new \Exception( 'Tender missing' );
565 }
566
567 $this->update_order_meta( $order, 'authorization_code', $response->get_authorization_code() );
568 $this->update_order_meta( $order, 'square_location_id', $response->get_location_id() );
569
570 $order->refund->location_id = $response->get_location_id();
571 $order->refund->tender_id = $response->get_authorization_code();
572
573 } catch ( \Exception $exception ) {
574
575 return new \WP_Error( 'wc_square_refund_tender_missing', __( 'Could not find original transaction tender. Please refund this transaction from your Square dashboard.', 'woocommerce-square' ) );
576 }
577 }
578
579 return $order;
580 }
581
582
583 /**
584 * Restores refunded Square inventory.
585 *
586 * @internal
587 *
588 * @since 2.0.0
589 *
590 * @param int $order_id order ID
591 * @param int $refund_id refund ID
592 */
593 public function restore_refunded_inventory( $order_id, $refund_id ) {
594 $inventory_adjustments = array();
595
596 // no handling if inventory sync is disabled
597 if ( ! $this->get_plugin()->get_settings_handler()->is_inventory_sync_enabled() ) {
598 return;
599 }
600
601 $order = wc_get_order( $order_id );
602
603 // check that the order was paid using our gateway
604 if ( ! $order instanceof \WC_Order || $order->get_payment_method() !== $this->get_id() ) {
605 return;
606 }
607
608 // don't refund items if the "Restock refunded items" option is unchecked - maintains backwards compatibility if this function is called outside of the `woocommerce_order_refunded` do_action
609 if ( isset( $_POST['restock_refunded_items'] ) ) {
610 // Validate the user has permissions to process this request.
611 if ( ! check_ajax_referer( 'order-item', 'security', false ) || ! current_user_can( 'edit_shop_orders' ) ) {
612 return;
613 }
614
615 if ( 'false' === $_POST['restock_refunded_items'] ) {
616 return;
617 }
618 }
619
620 $refund = wc_get_order( $refund_id );
621
622 if ( $refund instanceof \WC_Order_Refund ) {
623
624 foreach ( $refund->get_items() as $item ) {
625 if ( $item->is_type( 'line_item' ) ) {
626 $product = $item->get_product();
627
628 if ( $product ) {
629 $inventory_adjustment = Product::get_inventory_change_adjustment_type( $product, absint( $item->get_quantity() ) );
630
631 if ( ! empty( $inventory_adjustment ) ) {
632 $inventory_adjustments[] = $inventory_adjustment;
633 }
634 }
635 }
636 }
637 }
638
639 if ( ! empty( $inventory_adjustments ) ) {
640 wc_square()->get_api()->batch_change_inventory(
641 wc_square()->get_idempotency_key( $refund_id . '_' . time() . '_change_inventory' ),
642 $inventory_adjustments
643 );
644 }
645 }
646
647
648 /**
649 * Gets a mock order for adding a new payment method.
650 *
651 * @since 2.0.0
652 *
653 * @return \WC_Order
654 */
655 protected function get_order_for_add_payment_method() {
656
657 $order = parent::get_order_for_add_payment_method();
658
659 // if the customer doesn't have a postcode yet, use the value returned by Square JS
660 if ( ! $order->get_billing_postcode() && $postcode = Square_Helper::get_post( 'wc-square-credit-card-payment-postcode' ) ) {
661 $order->set_billing_postcode( $postcode );
662 }
663
664 return $order;
665 }
666
667
668 /**
669 * Builds the payment tokens handler instance.
670 *
671 * @since 2.0.0
672 *
673 * @return Card_Handler
674 */
675 public function build_payment_tokens_handler() {
676
677 return new Card_Handler( $this );
678 }
679
680 /**
681 * Returns the gift card object.
682 *
683 * @since 4.2.0
684 *
685 * @return Gift_Card;
686 */
687 public function get_gift_card_handler() {
688 return $this->gift_card;
689 }
690
691 /**
692 * Returns the gift card object.
693 *
694 * @since 4.2.0
695 *
696 * @return Digital_Wallet;
697 */
698 public function get_digital_wallet_handler() {
699 return $this->digital_wallet;
700 }
701
702
703 /** Admin methods *************************************************************************************************/
704
705
706 /**
707 * Initialize payment gateway settings fields
708 *
709 * @since 2.3.0
710 * @see WC_Settings_API::init_form_fields()
711 */
712 public function init_form_fields() {
713
714 // common top form fields
715 $this->form_fields = array(
716 'enabled' => array(
717 'title' => esc_html__( 'Enable / Disable', 'woocommerce-square' ),
718 'label' => esc_html__( 'Enable this gateway', 'woocommerce-square' ),
719 'type' => 'checkbox',
720 'default' => 'no',
721 ),
722
723 'title' => array(
724 'title' => esc_html__( 'Title', 'woocommerce-square' ),
725 'type' => 'text',
726 'desc_tip' => esc_html__( 'Payment method title that the customer will see during checkout.', 'woocommerce-square' ),
727 'default' => $this->get_default_title(),
728 ),
729
730 'description' => array(
731 'title' => esc_html__( 'Description', 'woocommerce-square' ),
732 'type' => 'textarea',
733 'desc_tip' => esc_html__( 'Payment method description that the customer will see during checkout.', 'woocommerce-square' ),
734 'default' => $this->get_default_description(),
735 ),
736
737 );
738
739 // both credit card authorization & charge supported
740 if ( $this->supports_credit_card_authorization() && $this->supports_credit_card_charge() ) {
741 $this->form_fields = $this->add_authorization_charge_form_fields( $this->form_fields );
742 }
743
744 // card types support
745 if ( $this->supports_card_types() ) {
746 $this->form_fields = $this->add_card_types_form_fields( $this->form_fields );
747 }
748
749 // tokenization support
750 if ( $this->supports_tokenization() ) {
751 $this->form_fields = $this->add_tokenization_form_fields( $this->form_fields );
752 }
753
754 // Square digital wallet (Apple Pay and Google Pay settings)
755 if ( $this->is_digital_wallet_available() ) {
756 $this->form_fields = $this->add_digital_wallets_form_fields( $this->form_fields );
757 }
758
759 $this->form_fields = $this->add_gift_cards_form_fields( $this->form_fields );
760
761 $this->form_fields['advanced_settings_title'] = array(
762 'title' => esc_html__( 'Advanced Settings', 'woocommerce-square' ),
763 'type' => 'title',
764 );
765
766 // add "detailed customer decline messages" option if the feature is supported
767 if ( $this->supports( self::FEATURE_DETAILED_CUSTOMER_DECLINE_MESSAGES ) ) {
768 $this->form_fields['enable_customer_decline_messages'] = array(
769 'title' => esc_html__( 'Detailed Decline Messages', 'woocommerce-square' ),
770 'type' => 'checkbox',
771 'label' => esc_html__( 'Check to enable detailed decline messages to the customer during checkout when possible, rather than a generic decline message.', 'woocommerce-square' ),
772 'default' => 'no',
773 );
774 }
775
776 // debug mode
777 $this->form_fields['debug_mode'] = array(
778 'title' => esc_html__( 'Debug Mode', 'woocommerce-square' ),
779 'type' => 'select',
780 'class' => 'wc-enhanced-select',
781 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
782 'desc' => sprintf( esc_html__( 'Show Detailed Error Messages and API requests/responses on the checkout page and/or save them to the %1$sdebug log%2$s', 'woocommerce-square' ), '<a href="' . Square_Helper::get_wc_log_file_url( $this->get_id() ) . '">', '</a>' ),
783 'default' => self::DEBUG_MODE_OFF,
784 'options' => array(
785 self::DEBUG_MODE_OFF => esc_html__( 'Off', 'woocommerce-square' ),
786 self::DEBUG_MODE_CHECKOUT => esc_html__( 'Show on Checkout Page', 'woocommerce-square' ),
787 self::DEBUG_MODE_LOG => esc_html__( 'Save to Log', 'woocommerce-square' ),
788 /* translators: show debugging information on both checkout page and in the log */
789 self::DEBUG_MODE_BOTH => esc_html__( 'Both', 'woocommerce-square' ),
790 ),
791 );
792
793 // if there is more than just the production environment available
794 if ( count( $this->get_environments() ) > 1 ) {
795 $this->form_fields = $this->add_environment_form_fields( $this->form_fields );
796 }
797
798 /**
799 * Payment Gateway Form Fields Filter.
800 *
801 * Actors can use this to add, remove, or tweak gateway form fields
802 *
803 * @since 4.0.0
804 * @param array $form_fields array of form fields in format required by WC_Settings_API
805 * @param Payment_Gateway $this gateway instance
806 */
807 $this->form_fields = apply_filters( 'wc_payment_gateway_' . $this->get_id() . '_form_fields', $this->form_fields, $this );
808 }
809
810 /**
811 * Adds the tokenization form fields to the gateway settings.
812 *
813 * Overridden to change the setting name to "Customer Profiles."
814 *
815 * @since 2.0.0
816 *
817 * @param array $form_fields existing fields
818 * @return array
819 */
820 protected function add_tokenization_form_fields( $form_fields ) {
821
822 $form_fields = parent::add_tokenization_form_fields( $form_fields );
823
824 if ( ! empty( $form_fields['tokenization'] ) ) {
825 $form_fields['tokenization']['title'] = __( 'Customer Profiles', 'woocommerce-square' );
826 $form_fields['tokenization']['label'] = __( 'Check to enable tokenization and allow customers to securely save their payment details for future checkout.', 'woocommerce-square' );
827 }
828
829 return $form_fields;
830 }
831
832
833 /**
834 * Clear the CSC field settings, as CSC is always required by Square.
835 *
836 * @since 2.0.0
837 *
838 * @param array $form_fields
839 * @return array
840 */
841 protected function add_csc_form_fields( $form_fields ) {
842
843 return $form_fields;
844 }
845
846
847 /**
848 * Adds the Card Types setting field.
849 *
850 * This adds UnionPay card type option and activates it by default
851 *
852 * @since 2.0.0
853 *
854 * @param array $form_fields
855 * @return array
856 */
857 protected function add_card_types_form_fields( $form_fields ) {
858
859 $form_fields = parent::add_card_types_form_fields( $form_fields );
860
861 if ( isset( $form_fields['card_types']['default'] ) ) {
862
863 if ( ! isset( $form_fields['card_types']['options']['UNIONPAY'] ) ) {
864 $form_fields['card_types']['options']['UNIONPAY'] = __( 'UnionPay', 'woocommerce-square' );
865 }
866
867 if ( ! in_array( 'UNIONPAY', $form_fields['card_types']['default'], true ) ) {
868 $form_fields['card_types']['default'][] = 'UNIONPAY';
869 }
870 }
871
872 return $form_fields;
873 }
874
875 /**
876 * Adds the Digital Wallet setting fields.
877 *
878 * @since 2.3.0
879 *
880 * @param array $form_fields
881 * @return array
882 */
883 protected function add_digital_wallets_form_fields( $form_fields ) {
884 $form_fields['digital_wallet_settings'] = array(
885 'title' => esc_html__( 'Digital Wallet Settings', 'woocommerce-square' ),
886 'description' => esc_html__( 'Take payments on your store with Apple Pay and Google Pay.', 'woocommerce-square' ),
887 'type' => 'title',
888 );
889
890 $form_fields['enable_digital_wallets'] = array(
891 'title' => esc_html__( 'Enable / Disable', 'woocommerce-square' ),
892 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
893 'description' => sprintf( esc_html__( 'Allow customers to pay with Apple Pay or Google Pay from your Product, Cart and Checkout pages. Read more about the availablity of digital wallets in our %1$sdocumentation%2$s.', 'woocommerce-square' ), '<a href="https://docs.woocommerce.com/document/woocommerce-square/">', '</a>' ),
894 'type' => 'checkbox',
895 'default' => 'yes',
896 'label' => esc_html__( 'Enable digital wallets', 'woocommerce-square' ),
897 );
898
899 $form_fields['digital_wallets_button_type'] = array(
900 'title' => esc_html__( 'Button Type', 'woocommerce-square' ),
901 'description' => esc_html__( 'This setting only applies to the Apple Pay button. When Google Pay is available, the Google Pay button will always have the "Buy with" button text.', 'woocommerce-square' ),
902 'desc_tip' => esc_html__( 'Select which text is displayed on the digital wallet buttons.', 'woocommerce-square' ),
903 'type' => 'select',
904 'default' => 'buy',
905 'class' => 'wc-enhanced-select wc-square-digital-wallet-options',
906 'options' => array(
907 'buy' => 'Buy Now',
908 'donate' => 'Donate',
909 'plain' => 'No Text',
910 ),
911 );
912
913 $form_fields['digital_wallets_apple_pay_button_color'] = array(
914 'title' => esc_html__( 'Apple Pay Button Color', 'woocommerce-square' ),
915 'desc_tip' => esc_html__( 'Select the color of the Apple Pay button.', 'woocommerce-square' ),
916 'type' => 'select',
917 'default' => 'black',
918 'class' => 'wc-enhanced-select wc-square-digital-wallet-options',
919 'options' => array(
920 'black' => 'Black',
921 'white' => 'White',
922 'white-outline' => 'White with outline',
923 ),
924 );
925
926 $form_fields['digital_wallets_google_pay_button_color'] = array(
927 'title' => esc_html__( 'Google Pay Button Color', 'woocommerce-square' ),
928 'desc_tip' => esc_html__( 'Select the color of the Google Pay button.', 'woocommerce-square' ),
929 'type' => 'select',
930 'default' => 'black',
931 'class' => 'wc-enhanced-select wc-square-digital-wallet-options',
932 'options' => array(
933 'black' => 'Black',
934 'white' => 'White',
935 ),
936 );
937
938 $form_fields['digital_wallets_hide_button_options'] = array(
939 'title' => esc_html__( 'Hide Digital Wallet Buttons', 'woocommerce-square' ),
940 'desc_tip' => esc_html__( 'Select any digital wallet buttons you don\'t want to be displayed on your store.', 'woocommerce-square' ),
941 'type' => 'multiselect',
942 'default' => '',
943 'class' => 'wc-enhanced-select wc-square-digital-wallet-options',
944 'options' => array(
945 'apple' => 'Apple Pay',
946 'google' => 'Google Pay',
947 ),
948 );
949
950 return $form_fields;
951 }
952
953 /**
954 * Adds the Gift Cards setting fields.
955 *
956 * @since 3.7.0
957 *
958 * @param array $form_fields
959 * @return array
960 */
961 public function add_gift_cards_form_fields( $form_fields ) {
962 $form_fields['gift_card_settings'] = array(
963 'title' => esc_html__( 'Gift Card settings', 'woocommerce-square' ),
964 'description' => esc_html__( 'Take payments on your store with a Gift Card.', 'woocommerce-square' ),
965 'type' => 'title',
966 );
967
968 $form_fields['enable_gift_cards'] = array(
969 'title' => esc_html__( 'Enable / Disable', 'woocommerce-square' ),
970 'description' => esc_html__( 'Allow customers to pay with a gift card.', 'woocommerce-square' ),
971 'type' => 'checkbox',
972 'default' => '',
973 'label' => esc_html__( 'Enable Gift Cards', 'woocommerce-square' ),
974 );
975
976 return $form_fields;
977 }
978
979 /** Conditional methods *******************************************************************************************/
980
981
982 /**
983 * Determines if the gateway is available.
984 *
985 * @since 2.0.0
986 *
987 * @return bool
988 */
989 public function is_available() {
990
991 return parent::is_available() && $this->get_plugin()->get_settings_handler()->is_connected() && $this->get_plugin()->get_settings_handler()->get_location_id();
992 }
993
994
995 /**
996 * Determines whether the CSC field is enabled.
997 *
998 * This is always required by the Square payment form JS.
999 *
1000 * @since 2.0.0
1001 *
1002 * @return bool
1003 */
1004 public function csc_enabled() {
1005
1006 return true;
1007 }
1008
1009
1010 /**
1011 * Determines whether new payment customers/tokens should be created before processing a payment.
1012 *
1013 * Square requires we create a new customer & customer card before referencing that customer in a transaction.
1014 *
1015 * @since 2.0.0
1016 *
1017 * @return bool
1018 */
1019 public function tokenize_before_sale() {
1020
1021 return true;
1022 }
1023
1024
1025 /**
1026 * Determines if 3d secure is enabled.
1027 *
1028 * @since 2.1.0
1029 * @deprecated 3.3.0 Square automatically detects whether SCA is required, so we do not need this function.
1030 *
1031 * @return bool
1032 */
1033 public function is_3d_secure_enabled() {
1034
1035 _deprecated_function( __FUNCTION__, '3.3.0' );
1036
1037 $base_currency = get_woocommerce_currency();
1038
1039 $sca_enabled_currencies = in_array( $base_currency, $this->sca_supported_currencies, true );
1040
1041 /**
1042 * Filters whether or not 3d Secure should be enabled.
1043 *
1044 * @since 2.1.0
1045 *
1046 * @param bool $enabled
1047 * @param Gateway $gateway_instance
1048 */
1049 return apply_filters( 'wc_square_is_3d_secure_enabled', $sca_enabled_currencies, $this );
1050 }
1051
1052 /**
1053 * Determines if digital wallets are available.
1054 *
1055 * @since 2.3
1056 * @return bool
1057 */
1058 public function is_digital_wallet_available() {
1059 $is_available = false;
1060 $base_location = wc_get_base_location();
1061 $supported_countries = array( 'US', 'GB', 'CA', 'IE', 'FR', 'ES', 'AU' );
1062 $is_currency_supported = in_array( get_woocommerce_currency(), array( 'USD', 'GBP', 'CAD', 'EUR', 'AUD' ), true );
1063 $is_country_supported = ( ! empty( $base_location['country'] ) && in_array( $base_location['country'], $supported_countries, true ) );
1064
1065 if ( ( wc_site_is_https() || wc_square()->get_settings_handler()->is_sandbox() ) && $is_currency_supported && $is_country_supported ) {
1066 $is_available = true;
1067 }
1068
1069 return $is_available;
1070 }
1071
1072 /** Getter methods ************************************************************************************************/
1073
1074
1075 /**
1076 * Gets order meta.
1077 *
1078 * Overridden to handle any missing transaction ID meta from v1.
1079 *
1080 * @since 2.0.0
1081 *
1082 * @param \WC_Order|int $order order object or ID
1083 * @param string $key meta key
1084 * @return mixed
1085 */
1086 public function get_order_meta( $order, $key ) {
1087
1088 if ( is_numeric( $order ) ) {
1089 $order = wc_get_order( $order );
1090 }
1091
1092 // migrate any missing transaction IDs
1093 if ( $order && 'trans_id' === $key && ! parent::get_order_meta( $order, $key ) && $order->get_transaction_id() ) {
1094 $this->update_order_meta( $order, 'trans_id', $order->get_transaction_id() );
1095 }
1096
1097 return parent::get_order_meta( $order, $key );
1098 }
1099
1100
1101 /**
1102 * Gets the authorization -> capture time window.
1103 *
1104 * Square limits captures to 6 days.
1105 *
1106 * @since 2.0.0
1107 *
1108 * @return int
1109 */
1110 public function get_authorization_time_window() {
1111
1112 return 144;
1113 }
1114
1115
1116 /**
1117 * Gets the payment form handler instance.
1118 *
1119 * @since 2.0.0
1120 *
1121 * @return Payment_Form
1122 */
1123 public function get_payment_form_instance() {
1124
1125 if ( empty( $this->payment_form ) ) {
1126 $this->payment_form = new Payment_Form( $this );
1127 }
1128
1129 return $this->payment_form;
1130 }
1131
1132
1133 /**
1134 * Gets the API instance.
1135 *
1136 * @since 2.0.0
1137 *
1138 * @return Gateway\API
1139 */
1140 public function get_api() {
1141
1142 if ( ! $this->api ) {
1143 $settings = $this->get_plugin()->get_settings_handler();
1144 $this->api = new Gateway\API( $settings->get_access_token(), $settings->get_location_id(), $settings->is_sandbox() );
1145 }
1146
1147 return $this->api;
1148 }
1149
1150
1151 /**
1152 * Gets the gateway settings fields.
1153 *
1154 * @since 2.0.0
1155 *
1156 * @return array
1157 */
1158 protected function get_method_form_fields() {
1159
1160 return array();
1161 }
1162
1163
1164 /**
1165 * Gets a user's stored customer ID.
1166 *
1167 * Overridden to avoid auto-creating customer IDs, as Square generates them.
1168 *
1169 * @since 2.0.0
1170 *
1171 * @param int $user_id user ID
1172 * @param array $args arguments
1173 * @return string
1174 */
1175 public function get_customer_id( $user_id, $args = array() ) {
1176
1177 // Square generates customer IDs
1178 $args['autocreate'] = false;
1179
1180 return parent::get_customer_id( $user_id, $args );
1181 }
1182
1183
1184 /**
1185 * Gets a guest's customer ID.
1186 *
1187 * @since 2.0.0
1188 *
1189 * @param \WC_Order $order order object
1190 * @return string|bool
1191 */
1192 public function get_guest_customer_id( \WC_Order $order ) {
1193
1194 // is there a customer id already tied to this order?
1195 $customer_id = $this->get_order_meta( $order, 'customer_id' );
1196
1197 if ( $customer_id ) {
1198 return $customer_id;
1199 }
1200
1201 return false;
1202 }
1203
1204
1205 /**
1206 * Gets the configured environment ID.
1207 *
1208 * Square doesn't really support a sandbox, so we don't show a setting for this.
1209 *
1210 * @since 2.0.0
1211 *
1212 * @return string
1213 */
1214 public function get_environment() {
1215
1216 return self::ENVIRONMENT_PRODUCTION;
1217 }
1218
1219 /**
1220 * Gets the configured application ID.
1221 *
1222 * @since 2.0.0
1223 *
1224 * @return string
1225 */
1226 public function get_application_id() {
1227
1228 $square_application_id = 'sq0idp-wGVapF8sNt9PLrdj5znuKA';
1229
1230 if ( $this->get_plugin()->get_settings_handler()->is_sandbox() ) {
1231 $square_application_id = $this->get_plugin()->get_settings_handler()->get_option( 'sandbox_application_id' );
1232 }
1233
1234 /**
1235 * Filters the configured application ID.
1236 *
1237 * @since 2.0.0
1238 *
1239 * @param string $application_id application ID
1240 */
1241 return apply_filters( 'wc_square_application_id', $square_application_id );
1242 }
1243
1244 /**
1245 * AJAX WooCommerce checkout validation handler
1246 *
1247 * Tap into woocommerce_after_checkout_validation hook
1248 * and return WooCommerce checkout validation errors
1249 *
1250 * @since 2.2
1251 */
1252 public function wc_ajax_square_checkout_handler() {
1253 // Nonce verfication.
1254 if ( ! check_ajax_referer( 'wc_' . $this->get_id() . '_checkout_validate', 'wc_' . $this->get_id() . '_checkout_validate_nonce', false ) ) {
1255 return wp_send_json_error( __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ) );
1256 }
1257
1258 // Nonce successfully verified. Proceed with validation.
1259 add_action( 'woocommerce_after_checkout_validation', array( $this, 'wc_ajax_square_checkout_validate' ), 10, 2 );
1260 WC()->checkout->process_checkout();
1261 }
1262
1263 /**
1264 * Filters to show only the Square gateway when cart contains a Gift card product.
1265 *
1266 * @since 4.2.0
1267 *
1268 * @param array $gateways Array of payment gateways.
1269 * @return array
1270 */
1271 public function filter_available_gateways( $gateways ) {
1272 $allowed_gateways = array();
1273
1274 if ( ! Gift_Card::cart_contains_gift_card() ) {
1275 return $gateways;
1276 }
1277
1278 if ( array_key_exists( Plugin::GATEWAY_ID, $gateways ) ) {
1279 $allowed_gateways[ Plugin::GATEWAY_ID ] = $gateways[ Plugin::GATEWAY_ID ];
1280 }
1281
1282 return $allowed_gateways;
1283 }
1284
1285 /**
1286 * If no payment gateways are available and cart contains gift card, then show error message.
1287 *
1288 * @since 4.2.0
1289 *
1290 * @param string $text Error message.
1291 * @return string
1292 */
1293 public function filter_no_payment_gatways_message( $text ) {
1294 if ( ! Gift_Card::cart_contains_gift_card() ) {
1295 return $text;
1296 }
1297
1298 return esc_html__( 'Your cart contains a Square Gift Card product which can only be purchased using the Square payment gateway.', 'woocommerce-square' );
1299 }
1300
1301 /**
1302 * Validate WooCommerce checkout data on Square JS AJAX call
1303 *
1304 * Returns validation errors (or success) as JSON and exits to prevent checkout
1305 *
1306 * @since 2.2
1307 *
1308 * @param array $data WooCommerce checkout POST data.
1309 * @param WP_Error $errors WooCommerce checkout errors.
1310 */
1311 public function wc_ajax_square_checkout_validate( $data, $errors = null ) {
1312 $error_messages = null;
1313 if ( ! is_null( $errors ) ) {
1314 $error_messages = $errors->get_error_messages();
1315 }
1316
1317 // Clear all existing notices.
1318 wc_clear_notices();
1319
1320 if ( empty( $error_messages ) ) {
1321 wp_send_json_success( 'validation_successful' );
1322 } else {
1323 wp_send_json_error( array( 'messages' => $error_messages ) );
1324 }
1325 exit;
1326 }
1327
1328 /**
1329 * Returns the $order object with a unique transaction ref member added
1330 *
1331 * @since 2.2.1
1332 * @param WC_Order $order the order object
1333 * @return WC_Order order object with member named unique_transaction_ref
1334 */
1335 protected function get_order_with_unique_transaction_ref( $order ) {
1336 $order_id = $order->get_id();
1337
1338 // generate a unique retry count
1339 if ( is_numeric( $this->get_order_meta( $order_id, 'retry_count' ) ) ) {
1340 $retry_count = $this->get_order_meta( $order_id, 'retry_count' );
1341 $retry_count++;
1342 } else {
1343 $retry_count = 0;
1344 }
1345
1346 // keep track of the retry count
1347 $this->update_order_meta( $order, 'retry_count', $retry_count );
1348
1349 $order->unique_transaction_ref = time() . '-' . $order_id . ( $retry_count >= 0 ? '-' . $retry_count : '' );
1350 return $order;
1351 }
1352
1353 /**
1354 * Returns the payment method image URL (if any) for the given $type, ie
1355 * if $type is 'amex' a URL to the american express card icon will be
1356 * returned. If $type is 'echeck', a URL to the echeck icon will be
1357 * returned.
1358 *
1359 * @since 3.4.0
1360 * @param string $type the payment method cc type or name
1361 * @return string the image URL or null
1362 */
1363 public function get_payment_method_image_url( $type ) {
1364
1365 $image_type = strtolower( $type );
1366
1367 if ( 'card' === $type ) {
1368 $image_type = 'cc-plain';
1369 }
1370
1371 /**
1372 * Payment Gateway Fallback to PNG Filter.
1373 *
1374 * Allow actors to enable the use of PNGs over SVGs for payment icon images.
1375 *
1376 * @since 3.4.0
1377 * @param bool $use_svg true by default, false to use PNGs
1378 */
1379 $image_extension = apply_filters( 'wc_payment_gateway_' . $this->get_plugin()->get_id() . '_use_svg', true ) ? '.svg' : '.png';
1380
1381 // first, is the card image available within the plugin?
1382 if ( is_readable( $this->get_plugin()->get_plugin_path() . '/assets/images/card-' . $image_type . $image_extension ) ) {
1383 return \WC_HTTPS::force_https_url( $this->get_plugin()->get_plugin_url() . '/assets/images/card-' . $image_type . $image_extension );
1384 }
1385
1386 // Fall back to framework image URL.
1387 return parent::get_payment_method_image_url( $type );
1388 }
1389
1390 /**
1391 * Mark an order as refunded. This should only be used when the full order
1392 * amount has been refunded.
1393 *
1394 * @since 3.2.0
1395 *
1396 * @param \WC_Order $order order object
1397 */
1398 public function mark_order_as_refunded( $order ) {
1399
1400 /* translators: Placeholders: %s - payment gateway title (such as Authorize.net, Braintree, etc) */
1401 $order_note = sprintf( esc_html__( '%s Order completely refunded.', 'woocommerce-square' ), $this->get_method_title() );
1402
1403 // Add order note and continue with WC refund process.
1404 $order->add_order_note( $order_note );
1405 }
1406
1407 /**
1408 * Get order amount via AJAX.
1409 *
1410 * @since 4.1.0
1411 */
1412 public function get_order_amount() {
1413 check_ajax_referer( 'wc_' . $this->get_id() . '_get_order_amount', 'security' );
1414 $total_amount = '';
1415 $is_pay_order = isset( $_POST['is_pay_order'] ) && 'true' === sanitize_key( $_POST['is_pay_order'] );
1416 if ( $is_pay_order ) {
1417 $order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
1418 $order = wc_get_order( $order_id );
1419 if ( $order ) {
1420 $total_amount = $order->get_total();
1421 }
1422 } else {
1423 $total_amount = WC()->cart->total;
1424 }
1425 wp_send_json_success( $total_amount );
1426 }
1427 }
1428