Skip to content

Commit

Permalink
Introduce express checkout utilities class (#7926)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdmoore authored Dec 22, 2023
1 parent 693bb75 commit ce4dc97
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 391 deletions.
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 Helper instance.
*
* @var WC_Payments_Express_Checkout_Button_Helper
*/
private $express_checkout_helper;

/**
* 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_Helper $express_checkout_helper Express checkout helper.
*/
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_Helper $express_checkout_helper ) {
$this->gateway = $gateway;
$this->payment_request_button_handler = $payment_request_button_handler;
$this->platform_checkout_button_handler = $platform_checkout_button_handler;
$this->express_checkout_helper = $express_checkout_helper;

$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_helper, '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 Helper instance.
*
* @var WC_Payments_Express_Checkout_Button_Helper
*/
private $express_checkout_helper;

/**
* 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_Helper $express_checkout_helper Express checkout helper.
*/
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_Helper $express_checkout_helper ) {
$this->account = $account;
$this->gateway = $gateway;
$this->express_checkout_helper = $express_checkout_helper;
}

/**
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_helper->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_helper->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_helper->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_helper->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_helper->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_helper->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_helper->build_display_items( $itemized_display_items );
$data['result'] = 'success';
} catch ( Exception $e ) {
$data += $this->build_display_items( $itemized_display_items );
$data += $this->express_checkout_helper->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_helper->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_helper->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_helper->cart_prices_include_tax() ) {
// Only proceed when taxes are enabled, but not included.
return [];
}
Expand Down
Loading

0 comments on commit ce4dc97

Please sign in to comment.