Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 6 additions & 2 deletions modules/ppcp-store-sync/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use WooCommerce\PayPalCommerce\StoreSync\Inspector\InspectionFormHandler;
use WooCommerce\PayPalCommerce\StoreSync\Inspector\InspectionStatusPage;
use WooCommerce\PayPalCommerce\StoreSync\Helper\AgenticCheckoutProcessor;
use WooCommerce\PayPalCommerce\StoreSync\Helper\ShippingOptionsBuilder;
use WooCommerce\PayPalCommerce\StoreSync\Helper\PayPalOrderManager;
use WooCommerce\PayPalCommerce\StoreSync\Helper\AgenticCartBuilder;
use WooCommerce\PayPalCommerce\StoreSync\Helper\ProductManager;
Expand Down Expand Up @@ -142,7 +143,9 @@
$c->get( 'agentic.logger' )
);
},

'agentic.helper.shipping-options-builder' => static function (): ShippingOptionsBuilder {
return new ShippingOptionsBuilder();
},
'agentic.helper.checkout-processor' => static function ( ContainerInterface $c ): AgenticCheckoutProcessor {
return new AgenticCheckoutProcessor(
$c->get( 'agentic.helper.paypal-order-manager' ),
Expand Down Expand Up @@ -222,7 +225,8 @@
'agentic.response.factory' => static function ( ContainerInterface $c ): ResponseFactory {
return new ResponseFactory(
$c->get( 'agentic.helper.cart-builder' ),
$c->get( 'agentic.response.applied-coupons-builder' )
$c->get( 'agentic.response.applied-coupons-builder' ),
$c->get( 'agentic.helper.shipping-options-builder' )
);
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ private function build_minimum_spend( string $code, PayPalCart $cart, ?WC_Coupon
$currency = CartHelper::currency( $cart, get_woocommerce_currency() );

return array(
'minimum_required' => number_format( $minimum, 2, '.', '' ),
'current_subtotal' => number_format( $subtotal, 2, '.', '' ),
'shortage_amount' => number_format( $shortage, 2, '.', '' ),
'minimum_required' => CartHelper::format_decimal( $minimum ),
'current_subtotal' => CartHelper::format_decimal( $subtotal ),
'shortage_amount' => CartHelper::format_decimal( $shortage ),
'currency_code' => $currency,
);
}
Expand All @@ -219,8 +219,8 @@ private function build_maximum_spend( string $code, PayPalCart $cart, ?WC_Coupon
$currency = CartHelper::currency( $cart, get_woocommerce_currency() );

return array(
'maximum_allowed' => number_format( $maximum, 2, '.', '' ),
'current_subtotal' => number_format( $subtotal, 2, '.', '' ),
'maximum_allowed' => CartHelper::format_decimal( $maximum ),
'current_subtotal' => CartHelper::format_decimal( $subtotal ),
'currency_code' => $currency,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use WC_Discounts;
use WooCommerce\PayPalCommerce\StoreSync\Helper\ProductManager;
use WooCommerce\PayPalCommerce\StoreSync\Schema\PayPalCart;
use WooCommerce\PayPalCommerce\StoreSync\Helper\CartHelper;

/**
* Calculates discount amounts for coupons using WooCommerce's native discount calculation.
Expand Down Expand Up @@ -70,8 +71,7 @@ public function calculate_discount_amount( WC_Coupon $wc_coupon, PayPalCart $car
? array_sum( $totals[ $code ] )
: $totals[ $code ];

// The value from get_discounts_by_coupon() is already in regular decimal format.
return number_format( $discount_value, 2, '.', '' );
return CartHelper::format_decimal( $discount_value );
}

return '0.00';
Expand Down
12 changes: 7 additions & 5 deletions modules/ppcp-store-sync/src/Helper/CartHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,15 @@ static function ( float $cart_total, CartItem $item ): float {
}

/**
* Formats a price value to two decimal places.
* Formats a price value for an API response.
*
* @param float $value The price value to format.
* PayPal expects monetary values to be strings with two decimal places.
*
* @param int|float|string $value The price value to format.
* @return string The formatted price (e.g., "123.45").
*/
public static function format_decimal( float $value ): string {
return number_format( $value, 2, '.', '' );
public static function format_decimal( $value ): string {
return number_format( (float) $value, 2, '.', '' );
}

public static function full_customer_name( PayPalCart $cart, string $default = '' ): string {
Expand Down Expand Up @@ -195,7 +197,7 @@ public static function calculate_totals( WC_Cart $wc_cart, string $currency_code
public static function money( string $currency_code, float $value ): array {
return array(
'currency_code' => $currency_code,
'value' => number_format( $value, 2 ),
'value' => self::format_decimal( $value ),
);
}
}
14 changes: 1 addition & 13 deletions modules/ppcp-store-sync/src/Helper/PayPalOrderManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ private function build_items_for_patch( PayPalCart $cart ): array {
'quantity' => (string) $item->quantity(),
'unit_amount' => array(
'currency_code' => $currency,
'value' => $this->format_money( (float) $price->value() ),
'value' => CartHelper::format_decimal( $price->value() ),
),
);
}
Expand Down Expand Up @@ -406,16 +406,4 @@ public function capture_order( string $order_id ): ?array {
return null;
}
}

/**
* Format a money value for PayPal API.
*
* PayPal requires money values as strings with 2 decimal places.
*
* @param float $value The money value.
* @return string Formatted money value.
*/
private function format_money( float $value ): string {
return number_format( $value, 2, '.', '' );
}
}
89 changes: 89 additions & 0 deletions modules/ppcp-store-sync/src/Helper/ShippingOptionsBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php
/**
* Builds the available_shipping_options array for cart API responses.
*
* @package WooCommerce\PayPalCommerce\StoreSync\Helper
*/

declare( strict_types = 1 );

namespace WooCommerce\PayPalCommerce\StoreSync\Helper;

use WC_Cart;

class ShippingOptionsBuilder {

/**
* Build shipping options from the WC cart state post calculate_totals().
*
* Returns an empty array when no cart is available or no packages exist.
* Exactly one option in a non-empty result has is_selected = true.
*
* @param WC_Cart|null $wc_cart The WooCommerce cart.
* @return array
*/
public function build( ?WC_Cart $wc_cart ): array {
if ( null === $wc_cart ) {
return array();
}

$packages = WC()->shipping()->get_packages();

// Note: This plugin only supports a single package.
// Key constraint is the PayPal API that can receive one shipping address per order.
$package = $packages[0] ?? null;

if ( empty( $package ) ) {
return array();
}

$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );

$chosen_id = null;

// The CartResponse schema expects only one selected shipping option.
// If we have _any_ options, we pluck the first value as it's always present,
// even when the session incorrectly contains multiple chosen methods.
// We silently ignore cases where more than one option is chosen in the session.
if ( is_array( $chosen_methods ) && ! empty( $chosen_methods ) ) {
$chosen_id = $chosen_methods[0];
}

$currency = get_woocommerce_currency();
$options = array();
$all_rates = $package['rates'] ?? array();
$first_rate_id = null;

foreach ( $all_rates as $rate ) {
// Note: Rate IDs can repeat in different packages, e.g. "flat_rate:1" can apply
// to all packages. We do not care about this potential repeat ID, for 2 reasons:
// 1. The PayPal API only supports single-package orders.
// 2. The PayPalCart only supports a single shipping method.
$rate_id = $rate->get_id();

if ( null === $first_rate_id ) {
$first_rate_id = $rate_id;
}

$options[] = array(
'id' => $rate_id,
'label' => $rate->get_label(),
'amount' => CartHelper::format_decimal( $rate->get_cost() ),
'currency' => $currency,
'is_selected' => false,
);
}

if ( empty( $options ) ) {
return array();
}

$selected_id = $chosen_id ?? $first_rate_id;
foreach ( $options as &$option ) {
$option['is_selected'] = ( $option['id'] === $selected_id );
}
unset( $option );

return $options;
}
}
3 changes: 2 additions & 1 deletion modules/ppcp-store-sync/src/Ingestion/ProductsPayload.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use WC_Product;
use WC_Product_Variation;
use WooCommerce\PayPalCommerce\StoreSync\Helper\CartHelper;

class ProductsPayload {
private string $merchant_store_url;
Expand Down Expand Up @@ -293,6 +294,6 @@ private function format_price( $price ): string {
return '';
}

return number_format( (float) $price, 2, '.', '' ) . ' ' . get_woocommerce_currency();
return CartHelper::format_decimal( $price ) . ' ' . get_woocommerce_currency();
}
}
Loading
Loading