Skip to content

Commit

Permalink
Updated WooPayments MultiCurrency integration with Product Add-Ons (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jimjasson authored Jul 29, 2024
1 parent 6fa6dd9 commit 2101d76
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 77 deletions.
4 changes: 4 additions & 0 deletions changelog/fix-issue-8911
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: update

Updated the integration between WooPayments Multi-Currency and Product Add-Ons.
139 changes: 94 additions & 45 deletions includes/multi-currency/Compatibility/WooCommerceProductAddOns.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,37 +110,64 @@ public function product_addons_params( array $params ): array {
*/
public function get_item_data( $addon_data, $addon, $cart_item ): array {
$price = isset( $cart_item['addons_price_before_calc'] ) ? $cart_item['addons_price_before_calc'] : $addon['price'];
$name = $addon['name'];

if ( 0.0 === $addon['price'] ) {
$name .= '';
} elseif ( 'percentage_based' === $addon['price_type'] && 0.0 === $price ) {
$name .= '';
} elseif ( 'custom_price' === $addon['field_type'] ) {
$name .= ' (' . wc_price( $addon['price'] ) . ')';
} elseif ( 'percentage_based' !== $addon['price_type'] && $addon['price'] && apply_filters( 'woocommerce_addons_add_price_to_name', '__return_true' ) ) {
// Get our converted and tax adjusted price to put in the add on name.
$price = $this->multi_currency->get_price( $addon['price'], 'product' );
if ( 'input_multiplier' === $addon['field_type'] ) {
// Quantity/multiplier add on needs to be split, calculated, then multiplied by input value.
$price = $this->multi_currency->get_price( $addon['price'] / $addon['value'], 'product' ) * $addon['value'];
$value = $addon['value'];

/*
* 'woocommerce_addons_add_cart_price_to_value'
*
* Use this filter to display the price next to each selected add-on option.
* By default, add-on prices show up only next to flat fee add-ons.
*
* @param boolean
*/
$add_price_to_value = apply_filters( 'woocommerce_addons_add_cart_price_to_value', false, $cart_item );

if ( 0.0 === (float) $addon['price'] ) {
$value .= '';
} elseif ( 'percentage_based' === $addon['price_type'] && 0.0 === (float) $price ) {
$value .= '';
} elseif ( 'custom_price' === $addon['field_type'] && $addon['price'] ) {
if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
$addon_price = wc_price( \WC_Product_Addons_Helper::get_product_addon_price_for_display( $addon['price'], $cart_item['data'] ) );
/* translators: %1$s custom addon price in cart */
$value .= sprintf( _x( ' (%1$s)', 'custom price addon price in cart', 'woocommerce-payments' ), $addon_price );
$addon['display'] = $value;
}
} elseif ( 'flat_fee' === $addon['price_type'] && $addon['price'] ) {
if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
$addon_price = $this->multi_currency->get_price( $addon['price'], 'product' );
if ( 'input_multiplier' === $addon['field_type'] ) {
// Quantity/multiplier add on needs to be split, calculated, then multiplied by input value.
$addon_price = $this->multi_currency->get_price( $addon['price'] / $addon['value'], 'product' ) * $addon['value'];
}
$addon_price = wc_price( \WC_Product_Addons_Helper::get_product_addon_price_for_display( $addon_price, $cart_item['data'] ) );
/* translators: %1$s flat fee addon price in order */
$value .= sprintf( _x( ' (+ %1$s)', 'flat fee addon price in cart', 'woocommerce-payments' ), $addon_price );
}
if ( class_exists( '\WC_Product_Addons_Helper' ) ) {
$price = \WC_Product_Addons_Helper::get_product_addon_price_for_display( $price, $cart_item['data'] );
$name .= ' (' . wc_price( $price ) . ')';
} elseif ( 'quantity_based' === $addon['price_type'] && $addon['price'] && $add_price_to_value ) {
if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
$addon_price = $this->multi_currency->get_price( $addon['price'], 'product' );
if ( 'input_multiplier' === $addon['field_type'] ) {
// Quantity/multiplier add on needs to be split, calculated, then multiplied by input value.
$addon_price = $this->multi_currency->get_price( $addon['price'] / $addon['value'], 'product' ) * $addon['value'];
}
$addon_price = wc_price( \WC_Product_Addons_Helper::get_product_addon_price_for_display( $addon_price, $cart_item['data'] ) );
/* translators: %1$s addon price in order */
$value .= sprintf( _x( ' (%1$s)', 'quantity based addon price in cart', 'woocommerce-payments' ), $addon_price );
}
} else {
} elseif ( 'percentage_based' === $addon['price_type'] && $addon['price'] && $add_price_to_value ) {
// Get the percentage cost in the currency in use, and set the meta data on the product that the value was converted.
$_product = wc_get_product( $cart_item['product_id'] );
$price = $this->multi_currency->get_price( $price, 'product' );
$_product->set_price( $price * ( $addon['price'] / 100 ) );
$_product->update_meta_data( self::ADDONS_CONVERTED_META_KEY, 1 );
$name .= ' (' . WC()->cart->get_product_price( $_product ) . ')';
/* translators: %1$s addon price in order */
$value .= sprintf( _x( ' (%1$s)', 'percentage based addon price in cart', 'woocommerce-payments' ), WC()->cart->get_product_price( $_product ) );
}

return [
'name' => $name,
'value' => $addon['value'],
'name' => $addon['name'],
'value' => $value,
'display' => isset( $addon['display'] ) ? $addon['display'] : '',
];
}
Expand All @@ -155,10 +182,14 @@ public function get_item_data( $addon_data, $addon, $cart_item ): array {
* @return array
*/
public function update_product_price( $updated_prices, $cart_item, $prices ): array {
$price = $this->multi_currency->get_price( $prices['price'], 'product' );
$regular_price = $this->multi_currency->get_price( $prices['regular_price'], 'product' );
$sale_price = $this->multi_currency->get_price( $prices['sale_price'], 'product' );
$quantity = $cart_item['quantity'];
$price = $this->multi_currency->get_price( $prices['price'], 'product' );
$regular_price = $this->multi_currency->get_price( $prices['regular_price'], 'product' );
$sale_price = $this->multi_currency->get_price( $prices['sale_price'], 'product' );
$flat_fees = 0;
$quantity = $cart_item['quantity'];
$price_before_addons = $price;
$regular_price_before_addons = $regular_price;
$sale_price_before_addons = $sale_price;

// TODO: Check compat with Smart Coupons.
// Compatibility with Smart Coupons self declared gift amount purchase.
Expand Down Expand Up @@ -191,14 +222,16 @@ public function update_product_price( $updated_prices, $cart_item, $prices ): ar

switch ( $addon['price_type'] ) {
case 'percentage_based':
$price += (float) ( $cart_item['data']->get_price( 'view' ) * ( $addon_price / 100 ) );
$regular_price += (float) ( $regular_price * ( $addon_price / 100 ) );
$sale_price += (float) ( $sale_price * ( $addon_price / 100 ) );
$price += (float) ( $price_before_addons * ( $addon_price / 100 ) );
$regular_price += (float) ( $regular_price_before_addons * ( $addon_price / 100 ) );
$sale_price += (float) ( $sale_price_before_addons * ( $addon_price / 100 ) );
break;
case 'flat_fee':
$price += (float) ( $addon_price / $quantity );
$regular_price += (float) ( $addon_price / $quantity );
$sale_price += (float) ( $addon_price / $quantity );
$flat_fee = $quantity > 0 ? (float) ( $addon_price / $quantity ) : 0;
$price += $flat_fee;
$regular_price += $flat_fee;
$sale_price += $flat_fee;
$flat_fees += $flat_fee;
break;
default:
$price += (float) $addon_price;
Expand All @@ -212,9 +245,10 @@ public function update_product_price( $updated_prices, $cart_item, $prices ): ar
$cart_item['data']->update_meta_data( self::ADDONS_CONVERTED_META_KEY, 1 );

return [
'price' => $price,
'regular_price' => $regular_price,
'sale_price' => $sale_price,
'price' => $price,
'regular_price' => $regular_price,
'sale_price' => $sale_price,
'addons_flat_fees_sum' => $flat_fees,
];
}

Expand All @@ -230,8 +264,17 @@ public function update_product_price( $updated_prices, $cart_item, $prices ): ar
*/
public function order_line_item_meta( array $meta_data, array $addon, \WC_Order_Item_Product $item, array $values ): array {

$add_price_to_value = apply_filters( 'woocommerce_addons_add_order_price_to_value', false, $item );

$value = $addon['value'];

// Pass the timestamp as the add-on value in order to save the timestamp to the DB.
if ( isset( $addon['timestamp'] ) ) {
$value = $addon['timestamp'];
}

// If there is an add-on price, add the price of the add-on to the label name.
if ( $addon['price'] && apply_filters( 'woocommerce_addons_add_price_to_name', true ) ) {
if ( $addon['price'] && $add_price_to_value ) {
$product = $item->get_product();

if ( 'percentage_based' === $addon['price_type'] && 0.0 !== (float) $product->get_price() ) {
Expand All @@ -247,24 +290,30 @@ public function order_line_item_meta( array $meta_data, array $addon, \WC_Order_
// Convert all others.
$addon_price = $this->multi_currency->get_price( $addon['price'], 'product' );
}
if ( class_exists( '\WC_Product_Addons_Helper' ) ) {
$price = html_entity_decode(
if ( class_exists( 'WC_Product_Addons_Helper' ) ) {
$price = html_entity_decode(
wp_strip_all_tags( wc_price( \WC_Product_Addons_Helper::get_product_addon_price_for_display( $addon_price, $values['data'] ) ) ),
ENT_QUOTES,
get_bloginfo( 'charset' )
);
$addon['name'] .= ' (' . $price . ')';
}
}

if ( 'custom_price' === $addon['field_type'] ) {
$addon['value'] = $addon['price'];
if ( 'flat_fee' === $addon['price_type'] && $addon['price'] && $add_price_to_value ) {
/* translators: %1$s flat fee addon price in order */
$value .= sprintf( _x( ' (+ %1$s)', 'flat fee addon price in order', 'woocommerce-payments' ), $price );
} elseif ( ( 'quantity_based' === $addon['price_type'] || 'percentage_based' === $addon['price_type'] ) && $addon['price'] && $add_price_to_value ) {
/* translators: %1$s addon price in order */
$value .= sprintf( _x( ' (%1$s)', 'addon price in order', 'woocommerce-payments' ), $price );
} elseif ( 'custom_price' === $addon['field_type'] ) {
/* translators: %1$s custom addon price in order */
$value = sprintf( _x( ' (%1$s)', 'custom addon price in order', 'woocommerce-payments' ), $price );
}

$meta_data['raw_price'] = $this->multi_currency->get_price( $addon['price'], 'product' );
}

return [
'key' => $addon['name'],
'value' => $addon['value'],
];
$meta_data['value'] = $value;
return $meta_data;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public function test_order_line_item_meta_returns_flat_fee_data_correctly() {
$this->mock_multi_currency->method( 'get_price' )->with( $price, 'product' )->willReturn( (float) $price * 2 );
$addon = [
'name' => 'checkboxes',
'value' => 'flat fee',
'value' => 'flat fee (+ $84.00)',
'price' => (float) $price,
'field_type' => 'checkbox',
'price_type' => 'flat_fee',
Expand All @@ -149,10 +149,10 @@ public function test_order_line_item_meta_returns_flat_fee_data_correctly() {
$item->save();

$expected = [
'key' => 'checkboxes ($84.00)',
'value' => 'flat fee',
'key' => 'checkboxes',
'value' => 'flat fee (+ $84.00)',
];
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [], $addon, $item, [ 'data' => '' ] ) );
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [ 'key' => 'checkboxes' ], $addon, $item, [ 'data' => '' ] ) );
}

public function test_order_line_item_meta_returns_percentage_data_correctly() {
Expand All @@ -171,10 +171,10 @@ public function test_order_line_item_meta_returns_percentage_data_correctly() {
$item->save();

$expected = [
'key' => 'checkboxes ($5.00)',
'key' => 'checkboxes',
'value' => 'percentage based',
];
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [], $addon, $item, [ 'data' => '' ] ) );
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [ 'key' => 'checkboxes' ], $addon, $item, [ 'data' => '' ] ) );
}

public function test_order_line_item_meta_returns_input_multiplier_data_correctly() {
Expand All @@ -195,18 +195,18 @@ public function test_order_line_item_meta_returns_input_multiplier_data_correctl
$item->save();

$expected = [
'key' => 'quantity ($42.00)',
'key' => 'quantity',
'value' => 2,
];
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [], $addon, $item, [ 'data' => '' ] ) );
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [ 'key' => 'quantity' ], $addon, $item, [ 'data' => '' ] ) );
}

public function test_order_line_item_meta_returns_custom_price_data_correctly() {
$price = 42;
$this->mock_multi_currency->method( 'get_price' )->with( $price, 'product' )->willReturn( (float) $price * 2 );
$addon = [
'name' => 'checkboxes',
'value' => 'custom price',
'name' => 'custom price',
'value' => (float) $price,
'price' => (float) $price,
'field_type' => 'custom_price',
'price_type' => '',
Expand All @@ -218,10 +218,10 @@ public function test_order_line_item_meta_returns_custom_price_data_correctly()
$item->save();

$expected = [
'key' => 'checkboxes ($42.00)',
'key' => 'checkboxes',
'value' => 42.0,
];
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [], $addon, $item, [ 'data' => '' ] ) );
$this->assertSame( $expected, $this->woocommerce_product_add_ons->order_line_item_meta( [ 'key' => 'checkboxes' ], $addon, $item, [ 'data' => '' ] ) );
}

public function test_update_product_price_returns_flat_fee_data_correctly() {
Expand All @@ -243,9 +243,10 @@ public function test_update_product_price_returns_flat_fee_data_correctly() {
'sale_price' => 0,
];
$expected = [
'price' => 78.0, // (10 * 1.5) + (42 * 1.5)
'regular_price' => 78.0,
'sale_price' => 63.0, // (0 * 1.5) + (42 * 1.5)
'price' => 78.0, // (10 * 1.5) + (42 * 1.5)
'regular_price' => 78.0,
'sale_price' => 63.0, // (0 * 1.5) + (42 * 1.5)
'addons_flat_fees_sum' => 63.0,
];

$this->mock_multi_currency
Expand Down Expand Up @@ -282,9 +283,10 @@ public function test_update_product_price_returns_percentage_data_correctly() {
'sale_price' => 0,
];
$expected = [
'price' => 22.5, // 10 * 1.5 * 1.5
'regular_price' => 22.5,
'sale_price' => 0.0,
'price' => 22.5, // 10 * 1.5 * 1.5
'regular_price' => 22.5,
'sale_price' => 0.0,
'addons_flat_fees_sum' => 0,
];

// Product is created with a price of 10, and update_product_price calls get_price, which is already converted.
Expand Down Expand Up @@ -322,9 +324,10 @@ public function test_update_product_price_returns_custom_price_data_correctly()
'sale_price' => 0,
];
$expected = [
'price' => 57.0, // (10 * 1.5) + 42
'regular_price' => 57.0,
'sale_price' => 42.0,
'price' => 57.0, // (10 * 1.5) + 42
'regular_price' => 57.0,
'sale_price' => 42.0,
'addons_flat_fees_sum' => 0,
];

$this->mock_multi_currency
Expand Down Expand Up @@ -359,9 +362,10 @@ public function test_update_product_price_returns_multiplier_data_correctly() {
'sale_price' => 0,
];
$expected = [
'price' => 141.0, // (10 * 1.5) + ((42 * 1.5) * 2)
'regular_price' => 141.0,
'sale_price' => 126.0, // (0 * 1.5) + ((42 * 1.5) * 2)
'price' => 141.0, // (10 * 1.5) + ((42 * 1.5) * 2)
'regular_price' => 141.0,
'sale_price' => 126.0, // (0 * 1.5) + ((42 * 1.5) * 2)
'addons_flat_fees_sum' => 126.0,
];

$this->mock_multi_currency
Expand Down Expand Up @@ -440,9 +444,9 @@ public function test_get_item_data_returns_custom_price_data_correctly() {
'addons_price_before_calc' => 10,
];
$expected = [
'name' => 'Customer defined price (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'value' => '',
'display' => '',
'name' => 'Customer defined price',
'value' => ' (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'display' => ' (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
];

$this->assertSame( $expected, $this->woocommerce_product_add_ons->get_item_data( [], $addon, $cart_item ) );
Expand All @@ -464,8 +468,8 @@ public function test_get_item_data_returns_multiplier_price_data_correctly() {
'quantity' => 1,
];
$expected = [
'name' => 'Multiplier (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'value' => 2,
'name' => 'Multiplier',
'value' => '2 (+ <span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'display' => '',
];

Expand Down Expand Up @@ -500,8 +504,8 @@ public function test_get_item_data_returns_price_data_correctly() {
'quantity' => 1,
];
$expected = [
'name' => 'Checkbox (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'value' => 'Flat fee',
'name' => 'Checkbox',
'value' => 'Flat fee (+ <span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>42.00</bdi></span>)',
'display' => '',
];

Expand All @@ -526,7 +530,7 @@ public function test_get_item_data_returns_percentage_price_data_correctly() {
'addons_price_before_calc' => 10,
];
$expected = [
'name' => 'Checkbox (<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>5.00</bdi></span>)',
'name' => 'Checkbox',
'value' => 'Percentage',
'display' => '',
];
Expand Down

0 comments on commit 2101d76

Please sign in to comment.