@@ -57,12 +57,22 @@ function ( array $item ): Item {
5757 $ product = $ item ['data ' ];
5858 $ cart_item_key = $ item ['key ' ] ?? null ;
5959
60- $ quantity = (int ) $ item ['quantity ' ];
61- $ image = wp_get_attachment_image_src ( (int ) $ product ->get_image_id (), 'full ' );
60+ $ wc_quantity = (float ) $ item ['quantity ' ];
61+ /**
62+ * PayPal requires an integer quantity of at least 1. WooCommerce allows
63+ * fractional quantities (e.g. 0.3, via plugins like Measurement Price
64+ * Calculator), which would otherwise truncate to 0 and be rejected by
65+ * the PayPal API. Normalize such lines to a single unit priced at the
66+ * full line subtotal, instead of truncating the quantity to 0.
67+ */
68+ $ is_fractional_unit = $ wc_quantity > 0 && $ wc_quantity < 1 ;
69+ $ quantity = $ is_fractional_unit ? 1 : (int ) $ wc_quantity ;
70+ $ image = wp_get_attachment_image_src ( (int ) $ product ->get_image_id (), 'full ' );
6271
63- $ price = (float ) $ item ['line_subtotal ' ] / (float ) $ item ['quantity ' ];
64- $ line_tax = isset ( $ item ['line_tax ' ] ) ? (float ) $ item ['line_tax ' ] : 0.0 ;
65- $ unit_tax = $ quantity > 0 ? $ line_tax / (float ) $ quantity : 0.0 ;
72+ $ line_subtotal = (float ) $ item ['line_subtotal ' ];
73+ $ price = $ is_fractional_unit ? $ line_subtotal : $ line_subtotal / $ wc_quantity ;
74+ $ line_tax = isset ( $ item ['line_tax ' ] ) ? (float ) $ item ['line_tax ' ] : 0.0 ;
75+ $ unit_tax = $ is_fractional_unit ? $ line_tax : ( $ quantity > 0 ? $ line_tax / (float ) $ quantity : 0.0 );
6676
6777 return new Item (
6878 $ this ->prepare_item_string ( $ product ->get_name () ),
@@ -137,14 +147,23 @@ function ( \WC_Order_Item_Fee $item ) use ( $order ): Item {
137147 * @return Item
138148 */
139149 private function from_wc_order_line_item ( \WC_Order_Item_Product $ item , \WC_Order $ order ): Item {
140- $ product = $ item ->get_product ();
141- $ currency = $ order ->get_currency ();
142- $ quantity = (int ) $ item ->get_quantity ();
143- $ price_without_tax = (float ) $ order ->get_item_subtotal ( $ item , false );
150+ $ product = $ item ->get_product ();
151+ $ currency = $ order ->get_currency ();
152+ $ wc_quantity = (float ) $ item ->get_quantity ();
153+ /**
154+ * PayPal requires an integer quantity of at least 1. WooCommerce allows
155+ * fractional quantities (e.g. 0.3, via plugins like Measurement Price
156+ * Calculator), which would otherwise truncate to 0 and be rejected by
157+ * the PayPal API. Normalize such lines to a single unit priced at the
158+ * full line subtotal, instead of truncating the quantity to 0.
159+ */
160+ $ is_fractional_unit = $ wc_quantity > 0 && $ wc_quantity < 1 ;
161+ $ quantity = $ is_fractional_unit ? 1 : (int ) $ wc_quantity ;
162+ $ price_without_tax = $ is_fractional_unit ? (float ) $ item ->get_subtotal () : (float ) $ order ->get_item_subtotal ( $ item , false );
144163 $ price_without_tax_rounded = round ( $ price_without_tax , 2 );
145164 $ image = $ product instanceof WC_Product ? wp_get_attachment_image_src ( (int ) $ product ->get_image_id (), 'full ' ) : '' ;
146165 $ line_tax = (float ) $ item ->get_total_tax ();
147- $ unit_tax = $ quantity > 0 ? $ line_tax / (float ) $ quantity : 0.0 ;
166+ $ unit_tax = $ is_fractional_unit ? $ line_tax : ( $ quantity > 0 ? $ line_tax / (float ) $ quantity : 0.0 ) ;
148167
149168 return new Item (
150169 $ this ->prepare_item_string ( $ item ->get_name () ),
0 commit comments