Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce express checkout utilities class #7926

Merged
merged 7 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/7588-express-checkout-utilities
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

Introduce WC_Payments_Express_Checkout_Button_Utils class.
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,26 @@ class WC_Payments_Express_Checkout_Button_Display_Handler {
*/
private $platform_checkout_button_handler;

/**
* Express Checkout Utilities instance.
*
* @var WC_Payments_Express_Checkout_Button_Utils
*/
private $express_checkout_utils;

/**
* Initialize class actions.
*
* @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
* @param WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler Payment request button handler.
* @param WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler Platform checkout button handler.
* @param WC_Payments_Express_Checkout_Button_Utils $express_checkout_utils Express checkout utils.
*/
public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler, WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler ) {
public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Payment_Request_Button_Handler $payment_request_button_handler, WC_Payments_WooPay_Button_Handler $platform_checkout_button_handler, WC_Payments_Express_Checkout_Button_Utils $express_checkout_utils ) {
$this->gateway = $gateway;
$this->payment_request_button_handler = $payment_request_button_handler;
$this->platform_checkout_button_handler = $platform_checkout_button_handler;
$this->express_checkout_utils = $express_checkout_utils;

$this->platform_checkout_button_handler->init();
$this->payment_request_button_handler->init();
Expand All @@ -54,6 +63,8 @@ public function __construct( WC_Payment_Gateway_WCPay $gateway, WC_Payments_Paym
$is_payment_request_enabled = 'yes' === $this->gateway->get_option( 'payment_request' );

if ( $is_woopay_enabled || $is_payment_request_enabled ) {
add_action( 'wc_ajax_wcpay_add_to_cart', [ $this->express_checkout_utils, 'ajax_add_to_cart' ] );

add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'display_express_checkout_buttons' ], 1 );
add_action( 'woocommerce_proceed_to_checkout', [ $this, 'display_express_checkout_buttons' ], 21 );
add_action( 'woocommerce_checkout_before_customer_details', [ $this, 'display_express_checkout_buttons' ], 1 );
Expand Down
216 changes: 25 additions & 191 deletions includes/class-wc-payments-payment-request-button-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,24 @@ class WC_Payments_Payment_Request_Button_Handler {
*/
private $gateway;

/**
* Express Checkout Utilities instance.
*
* @var WC_Payments_Express_Checkout_Button_Utils
*/
private $express_checkout_utils;

/**
* Initialize class actions.
*
* @param WC_Payments_Account $account Account information.
* @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
* @param WC_Payments_Account $account Account information.
* @param WC_Payment_Gateway_WCPay $gateway WCPay gateway.
* @param WC_Payments_Express_Checkout_Button_Utils $express_checkout_utils Express checkout utils.
*/
public function __construct( WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway ) {
$this->account = $account;
$this->gateway = $gateway;
public function __construct( WC_Payments_Account $account, WC_Payment_Gateway_WCPay $gateway, WC_Payments_Express_Checkout_Button_Utils $express_checkout_utils ) {
$this->account = $account;
$this->gateway = $gateway;
$this->express_checkout_utils = $express_checkout_utils;
}

/**
Expand Down Expand Up @@ -78,7 +87,6 @@ public function init() {
add_action( 'wc_ajax_wcpay_get_shipping_options', [ $this, 'ajax_get_shipping_options' ] );
add_action( 'wc_ajax_wcpay_update_shipping_method', [ $this, 'ajax_update_shipping_method' ] );
add_action( 'wc_ajax_wcpay_create_order', [ $this, 'ajax_create_order' ] );
add_action( 'wc_ajax_wcpay_add_to_cart', [ $this, 'ajax_add_to_cart' ] );
add_action( 'wc_ajax_wcpay_get_selected_product_data', [ $this, 'ajax_get_selected_product_data' ] );
add_action( 'wc_ajax_wcpay_pay_for_order', [ $this, 'ajax_pay_for_order' ] );

Expand Down Expand Up @@ -134,17 +142,6 @@ public function is_account_creation_possible() {
);
}

/**
* Gets total label.
*
* @return string
*/
public function get_total_label() {
// Get statement descriptor from API/cached account data.
$statement_descriptor = $this->account->get_statement_descriptor();
return str_replace( "'", '', $statement_descriptor ) . apply_filters( 'wcpay_payment_request_total_label_suffix', ' (via WooCommerce)' );
}

/**
* Sets the WC customer session if one is not set.
* This is needed so nonces can be verified by AJAX Request.
Expand Down Expand Up @@ -211,7 +208,7 @@ public function get_button_height() {
*/
public function get_product_price( $product ) {
// If prices should include tax, using tax inclusive price.
if ( $this->cart_prices_include_tax() ) {
if ( $this->express_checkout_utils->cart_prices_include_tax() ) {
$base_price = wc_get_price_including_tax( $product );
} else {
$base_price = wc_get_price_excluding_tax( $product );
Expand Down Expand Up @@ -319,7 +316,7 @@ public function get_product_data() {

$data['displayItems'] = $items;
$data['total'] = [
'label' => apply_filters( 'wcpay_payment_request_total_label', $this->get_total_label() ),
'label' => apply_filters( 'wcpay_payment_request_total_label', $this->express_checkout_utils->get_total_label() ),
'amount' => WC_Payments_Utils::prepare_amount( $price + $total_tax, $currency ),
'pending' => true,
];
Expand Down Expand Up @@ -382,7 +379,7 @@ public function display_pay_for_order_page_html( $order ) {
$data['displayItems'] = $items;
$data['needs_shipping'] = false; // This should be already entered/prepared.
$data['total'] = [
'label' => apply_filters( 'wcpay_payment_request_total_label', $this->get_total_label() ),
'label' => apply_filters( 'wcpay_payment_request_total_label', $this->express_checkout_utils->get_total_label() ),
'amount' => WC_Payments_Utils::prepare_amount( $order->get_total(), $currency ),
'pending' => true,
];
Expand All @@ -400,7 +397,7 @@ public function get_cart_data() {
return false;
}

return $this->build_display_items();
return $this->express_checkout_utils->build_display_items();
}

/**
Expand Down Expand Up @@ -802,7 +799,7 @@ public function scripts() {
'is_pay_for_order' => $this->is_pay_for_order_page(),
'has_block' => has_block( 'woocommerce/cart' ) || has_block( 'woocommerce/checkout' ),
'product' => $this->get_product_data(),
'total_label' => $this->get_total_label(),
'total_label' => $this->express_checkout_utils->get_total_label(),
];

WC_Payments::register_script_with_dependencies( 'WCPAY_PAYMENT_REQUEST', 'dist/payment-request', [ 'jquery', 'stripe' ] );
Expand Down Expand Up @@ -890,7 +887,7 @@ public function ajax_get_cart_details() {

WC()->cart->calculate_totals();

wp_send_json( array_merge( $this->build_display_items(), [ 'needs_shipping' => WC()->cart->needs_shipping() ] ) );
wp_send_json( array_merge( $this->express_checkout_utils->build_display_items(), [ 'needs_shipping' => WC()->cart->needs_shipping() ] ) );
}

/**
Expand Down Expand Up @@ -986,10 +983,10 @@ public function get_shipping_options( $shipping_address, $itemized_display_items

WC()->cart->calculate_totals();

$data += $this->build_display_items( $itemized_display_items );
$data += $this->express_checkout_utils->build_display_items( $itemized_display_items );
$data['result'] = 'success';
} catch ( Exception $e ) {
$data += $this->build_display_items( $itemized_display_items );
$data += $this->express_checkout_utils->build_display_items( $itemized_display_items );
$data['result'] = 'invalid_shipping_address';
}

Expand All @@ -1015,7 +1012,7 @@ public function ajax_update_shipping_method() {
$should_show_itemized_view = ! isset( $product_view_options['is_product_page'] ) ? true : filter_var( $product_view_options['is_product_page'], FILTER_VALIDATE_BOOLEAN );

$data = [];
$data += $this->build_display_items( $should_show_itemized_view );
$data += $this->express_checkout_utils->build_display_items( $should_show_itemized_view );
$data['result'] = 'success';

wp_send_json( $data );
Expand Down Expand Up @@ -1121,7 +1118,7 @@ public function ajax_get_selected_product_data() {

$data['displayItems'] = $items;
$data['total'] = [
'label' => $this->get_total_label(),
'label' => $this->express_checkout_utils->get_total_label(),
'amount' => WC_Payments_Utils::prepare_amount( $total + $total_tax, $currency ),
'pending' => true,
];
Expand All @@ -1139,62 +1136,6 @@ public function ajax_get_selected_product_data() {
}
}

/**
* Adds the current product to the cart. Used on product detail page.
*/
public function ajax_add_to_cart() {
check_ajax_referer( 'wcpay-add-to-cart', 'security' );

if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
define( 'WOOCOMMERCE_CART', true );
}

WC()->shipping->reset_shipping();

$product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : false;
$product = wc_get_product( $product_id );

if ( ! $product ) {
wp_send_json(
[
'error' => [
'code' => 'invalid_product_id',
'message' => __( 'Invalid product id', 'woocommerce-payments' ),
],
],
404
);
return;
}

$qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
$product_type = $product->get_type();

// First empty the cart to prevent wrong calculation.
WC()->cart->empty_cart();

if ( ( 'variable' === $product_type || 'variable-subscription' === $product_type ) && isset( $_POST['attributes'] ) ) {
$attributes = wc_clean( wp_unslash( $_POST['attributes'] ) );

$data_store = WC_Data_Store::load( 'product' );
$variation_id = $data_store->find_matching_product_variation( $product, $attributes );

WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
}

if ( in_array( $product_type, [ 'simple', 'variation', 'subscription', 'subscription_variation' ], true ) ) {
WC()->cart->add_to_cart( $product->get_id(), $qty );
}

WC()->cart->calculate_totals();

$data = [];
$data += $this->build_display_items();
$data['result'] = 'success';

wp_send_json( $data );
}

/**
* Handles payment requests on the Pay for Order page.
*
Expand Down Expand Up @@ -1510,16 +1451,6 @@ protected function calculate_shipping( $address = [] ) {
WC()->shipping->calculate_shipping( $packages );
}

/**
* Whether tax should be displayed on separate line in cart.
* returns true if tax is disabled or display of tax in checkout is set to inclusive.
*
* @return boolean
*/
private function cart_prices_include_tax() {
return ! wc_tax_enabled() || 'incl' === get_option( 'woocommerce_tax_display_cart' );
}

/**
* Builds the shipping methods to pass to Payment Request
*
Expand All @@ -1544,103 +1475,6 @@ protected function build_shipping_methods( $shipping_methods ) {
return $shipping;
}

/**
* Builds the line items to pass to Payment Request
*
* @param boolean $itemized_display_items Indicates whether to show subtotals or itemized views.
*/
public function build_display_items( $itemized_display_items = false ) {
if ( ! defined( 'WOOCOMMERCE_CART' ) ) {
define( 'WOOCOMMERCE_CART', true );
}

$items = [];
$subtotal = 0;
$discounts = 0;
$currency = get_woocommerce_currency();

// Default show only subtotal instead of itemization.
if ( ! apply_filters( 'wcpay_payment_request_hide_itemization', true ) || $itemized_display_items ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$amount = $cart_item['line_subtotal'];
$subtotal += $cart_item['line_subtotal'];
$quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';

$product_name = $cart_item['data']->get_name();

$item_tax = $this->cart_prices_include_tax() ? ( $cart_item['line_subtotal_tax'] ?? 0 ) : 0;

$item = [
'label' => $product_name . $quantity_label,
'amount' => WC_Payments_Utils::prepare_amount( $amount + $item_tax, $currency ),
];

$items[] = $item;
}
}

if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
$discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), WC()->cart->dp );
} else {
$applied_coupons = array_values( WC()->cart->get_coupon_discount_totals() );

foreach ( $applied_coupons as $amount ) {
$discounts += (float) $amount;
}
}

$discounts = wc_format_decimal( $discounts, WC()->cart->dp );
$tax = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp );
$shipping = wc_format_decimal( WC()->cart->shipping_total, WC()->cart->dp );
$items_total = wc_format_decimal( WC()->cart->cart_contents_total, WC()->cart->dp ) + $discounts;
$order_total = version_compare( WC_VERSION, '3.2', '<' ) ? wc_format_decimal( $items_total + $tax + $shipping - $discounts, WC()->cart->dp ) : WC()->cart->get_total( '' );

if ( ! $this->cart_prices_include_tax() ) {
$items[] = [
'label' => esc_html( __( 'Tax', 'woocommerce-payments' ) ),
'amount' => WC_Payments_Utils::prepare_amount( $tax, $currency ),
];
}

if ( WC()->cart->needs_shipping() ) {
$shipping_tax = $this->cart_prices_include_tax() ? WC()->cart->shipping_tax_total : 0;
$items[] = [
'label' => esc_html( __( 'Shipping', 'woocommerce-payments' ) ),
'amount' => WC_Payments_Utils::prepare_amount( $shipping + $shipping_tax, $currency ),
];
}

if ( WC()->cart->has_discount() ) {
$items[] = [
'label' => esc_html( __( 'Discount', 'woocommerce-payments' ) ),
'amount' => WC_Payments_Utils::prepare_amount( $discounts, $currency ),
];
}

if ( version_compare( WC_VERSION, '3.2', '<' ) ) {
$cart_fees = WC()->cart->fees;
} else {
$cart_fees = WC()->cart->get_fees();
}

// Include fees and taxes as display items.
foreach ( $cart_fees as $key => $fee ) {
$items[] = [
'label' => $fee->name,
'amount' => WC_Payments_Utils::prepare_amount( $fee->amount, $currency ),
];
}

return [
'displayItems' => $items,
'total' => [
'label' => $this->get_total_label(),
'amount' => max( 0, apply_filters( 'wcpay_calculated_total', WC_Payments_Utils::prepare_amount( $order_total, $currency ), $order_total, WC()->cart ) ),
'pending' => false,
],
];
}

/**
* Calculates whether Apple Pay is enabled for this store.
* The option value is not stored in the database, and is calculated
Expand Down Expand Up @@ -1715,7 +1549,7 @@ public function get_login_confirmation_settings() {
* @return array An array of final taxes.
*/
private function get_taxes_like_cart( $product, $price ) {
if ( ! wc_tax_enabled() || $this->cart_prices_include_tax() ) {
if ( ! wc_tax_enabled() || $this->express_checkout_utils->cart_prices_include_tax() ) {
// Only proceed when taxes are enabled, but not included.
return [];
}
Expand Down
Loading
Loading