@@ -273,6 +273,16 @@ private static Money PrepareMoney(decimal value, string currencyCode)
273273 } ;
274274 }
275275
276+ /// <summary>
277+ /// Convert money object to decimal value
278+ /// </summary>
279+ /// <param name="value">Amount value</param>
280+ /// <returns>Decimal value</returns>
281+ private static decimal ConvertMoney ( Money amount )
282+ {
283+ return decimal . TryParse ( amount ? . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var value ) ? value : decimal . Zero ;
284+ }
285+
276286 /// <summary>
277287 /// Prepare order context
278288 /// </summary>
@@ -384,8 +394,6 @@ private async Task<List<Item>> PrepareOrderItemsAsync(CartDetails details)
384394 var ( itemSubTotal , itemDiscount , _, _) = await _shoppingCartService . GetSubTotalAsync ( item , true ) ;
385395 var unitPrice = itemSubTotal / item . Quantity ;
386396 var ( unitPriceExclTax , _) = await _taxService . GetProductPriceAsync ( product , unitPrice , false , details . Customer ) ;
387- var ( unitPriceInclTax , _) = await _taxService . GetProductPriceAsync ( product , unitPrice , true , details . Customer ) ;
388- var itemTax = unitPriceInclTax - unitPriceExclTax ;
389397
390398 return new Item
391399 {
@@ -398,8 +406,7 @@ private async Task<List<Item>> PrepareOrderItemsAsync(CartDetails details)
398406 : CategoryType . PHYSICAL_GOODS . ToString ( ) . ToUpper ( ) ,
399407 Url = url ,
400408 ImageUrl = imageUrl ,
401- UnitAmount = PrepareMoney ( unitPriceExclTax , details . CurrencyCode ) ,
402- Tax = PrepareMoney ( itemTax , details . CurrencyCode )
409+ UnitAmount = PrepareMoney ( unitPriceExclTax , details . CurrencyCode )
403410 } ;
404411 } ) . ToListAsync ( ) ;
405412
@@ -412,16 +419,13 @@ private async Task<List<Item>> PrepareOrderItemsAsync(CartDetails details)
412419 await foreach ( var attributeValue in values )
413420 {
414421 var ( attributePriceExclTax , _) = await _taxService . GetCheckoutAttributePriceAsync ( attribute , attributeValue , false , details . Customer ) ;
415- var ( attributePriceInclTax , _) = await _taxService . GetCheckoutAttributePriceAsync ( attribute , attributeValue , true , details . Customer ) ;
416- var attributeTax = attributePriceInclTax - attributePriceExclTax ;
417422
418423 items . Add ( new ( )
419424 {
420425 Name = CommonHelper . EnsureMaximumLength ( attribute . Name , 127 ) ,
421426 Description = CommonHelper . EnsureMaximumLength ( $ "{ attribute . Name } - { attributeValue . Name } ", 127 ) ,
422427 Quantity = 1 . ToString ( ) ,
423- UnitAmount = PrepareMoney ( attributePriceExclTax , details . CurrencyCode ) ,
424- Tax = PrepareMoney ( attributeTax , details . CurrencyCode )
428+ UnitAmount = PrepareMoney ( attributePriceExclTax , details . CurrencyCode )
425429 } ) ;
426430 }
427431 }
@@ -442,6 +446,7 @@ private async Task<OrderMoney> PrepareOrderMoneyAsync(CartDetails details, List<
442446 {
443447 //in some rare cases we need an additional item to adjust the order total
444448 //this can happen due to complex discounts or a large order and related to rounding in calculations
449+ //PayPal uses two decimal places, while nopCommerce can use more complex types of rounding (configured for each currency separately)
445450 var adjustmentName = await _localizationService . GetResourceAsync ( "Plugins.Payments.PayPalCommerce.Order.Adjustment.Name" ) ;
446451 var adjustmentDescription = await _localizationService . GetResourceAsync ( "Plugins.Payments.PayPalCommerce.Order.Adjustment.Description" ) ;
447452 if ( items . FirstOrDefault ( item => adjustmentName . Equals ( item . Name ) && adjustmentDescription . Equals ( item . Description ) ) is Item adjustmentItem )
@@ -458,67 +463,52 @@ private async Task<OrderMoney> PrepareOrderMoneyAsync(CartDetails details, List<
458463 var ( _, _, subTotal , _, _) = await _orderTotalCalculationService . GetShoppingCartSubTotalAsync ( details . Cart , includingTax : false ) ;
459464 total = subTotal ;
460465 }
466+ var orderTotal = PrepareMoney ( total . Value , details . CurrencyCode ) ;
461467
462468 var ( shippingTotal , _, _) = await _orderTotalCalculationService . GetShoppingCartShippingTotalAsync ( details . Cart , includingTax : false ) ;
463- var ( shippingTotalWithTax , _, _) = await _orderTotalCalculationService . GetShoppingCartShippingTotalAsync ( details . Cart , includingTax : true ) ;
464-
465- var itemTotal = items
466- . Sum ( item => decimal . Parse ( item . UnitAmount ? . Value ?? "0" , NumberStyles . Any , CultureInfo . InvariantCulture ) * int . Parse ( item . Quantity ) ) ;
467- var itemAdjustment = decimal . Zero ;
469+ var orderShippingTotal = PrepareMoney ( shippingTotal ?? decimal . Zero , details . CurrencyCode ) ;
468470
469471 var ( taxTotal , _) = await _orderTotalCalculationService . GetTaxTotalAsync ( details . Cart , usePaymentMethodAdditionalFee : false ) ;
470- var itemTaxTotal = items
471- . Sum ( item => decimal . Parse ( item . Tax ? . Value ?? "0" , NumberStyles . Any , CultureInfo . InvariantCulture ) * int . Parse ( item . Quantity ) ) ;
472- var shippingTax = ( shippingTotalWithTax ?? 0 ) - ( shippingTotal ?? 0 ) ;
473- var taxAdjustment = taxTotal - itemTaxTotal - shippingTax ;
474- if ( taxAdjustment > decimal . Zero )
475- itemTotal += taxAdjustment ;
476- if ( taxAdjustment < decimal . Zero || shippingTax > decimal . Zero )
477- {
478- taxAdjustment = Math . Max ( taxAdjustment , decimal . Zero ) ;
479- foreach ( var item in items )
480- {
481- item . Tax = null ;
482- }
483- }
472+ var orderTaxTotal = PrepareMoney ( taxTotal , details . CurrencyCode ) ;
484473
485- var discountTotal = itemTotal + taxTotal + ( shippingTotal ?? decimal . Zero ) - total . Value ;
474+ var itemAdjustment = decimal . Zero ;
475+ var itemTotal = items . Sum ( item => ConvertMoney ( item . UnitAmount ) * int . Parse ( item . Quantity ) ) ;
476+ var discountTotal = itemTotal + ConvertMoney ( orderTaxTotal ) + ConvertMoney ( orderShippingTotal ) - ConvertMoney ( orderTotal ) ;
486477 if ( discountTotal < decimal . Zero )
487478 {
488479 itemAdjustment = - discountTotal ;
489480 itemTotal += itemAdjustment ;
490481 discountTotal = decimal . Zero ;
491482 }
483+ var orderItemTotal = PrepareMoney ( itemTotal , details . CurrencyCode ) ;
484+ var orderDiscount = PrepareMoney ( discountTotal , details . CurrencyCode ) ;
492485
493486 //set adjustment item if needed
494- if ( itemAdjustment > decimal . Zero || taxAdjustment > decimal . Zero )
487+ if ( itemAdjustment > decimal . Zero )
495488 {
496- var amount = PrepareMoney ( itemAdjustment + taxAdjustment , details . CurrencyCode ) ;
497- if ( decimal . TryParse ( amount . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var value ) && value > decimal . Zero )
489+ var unitAmount = PrepareMoney ( itemAdjustment , details . CurrencyCode ) ;
490+ if ( ConvertMoney ( unitAmount ) > decimal . Zero )
498491 {
499492 items . Add ( new ( )
500493 {
501494 Name = adjustmentName ,
502495 Description = adjustmentDescription ,
503496 Quantity = 1 . ToString ( ) ,
504- UnitAmount = amount ,
505- Tax = taxAdjustment > decimal . Zero && items . Any ( item => item ? . Tax is not null )
506- ? PrepareMoney ( taxAdjustment , details . CurrencyCode )
507- : null
497+ UnitAmount = unitAmount
508498 } ) ;
509499 }
510500 }
511501
512502 return new ( )
513503 {
514504 CurrencyCode = details . CurrencyCode ,
515- Value = PrepareMoney ( total . Value , details . CurrencyCode ) . Value ,
505+ Value = orderTotal . Value ,
516506 Breakdown = new ( )
517507 {
518- ItemTotal = PrepareMoney ( itemTotal , details . CurrencyCode ) ,
519- TaxTotal = PrepareMoney ( taxTotal , details . CurrencyCode ) ,
520- Shipping = PrepareMoney ( shippingTotal ?? decimal . Zero , details . CurrencyCode ) ,
521- Discount = PrepareMoney ( discountTotal , details . CurrencyCode )
508+ ItemTotal = orderItemTotal ,
509+ TaxTotal = orderTaxTotal ,
510+ Shipping = orderShippingTotal ,
511+ Discount = orderDiscount
522512 }
523513 } ;
524514 }
@@ -1767,9 +1757,7 @@ await _actionContextAccessor.ActionContext.HttpContext.Session
17671757 return false ;
17681758
17691759 //recalculate the total and update the items, since the shipping price may have changed
1770- var items = unit . Items ;
1771- if ( items . Any ( item => item ? . Tax is null ) )
1772- items = await PrepareOrderItemsAsync ( details ) ;
1760+ var items = await PrepareOrderItemsAsync ( details ) ;
17731761 var orderAmount = await PrepareOrderMoneyAsync ( details , items ) ;
17741762 var cardData = new CardData
17751763 {
@@ -1896,9 +1884,7 @@ await _genericAttributeService
18961884 } ;
18971885
18981886 //recalculate the total and update the items, since the amounts may have changed
1899- var items = unit . Items ;
1900- if ( items . Any ( item => item ? . Tax is null ) )
1901- items = await PrepareOrderItemsAsync ( details ) ;
1887+ var items = await PrepareOrderItemsAsync ( details ) ;
19021888 var orderAmount = await PrepareOrderMoneyAsync ( details , items ) ;
19031889 var cardData = new CardData
19041890 {
@@ -2042,8 +2028,7 @@ await _genericAttributeService.GetAttributeAsync<NopShippingOption>(customer,
20422028 //totals must match
20432029 var ( cartTotal , _, _, _, _, _) = await _orderTotalCalculationService
20442030 . GetShoppingCartTotalAsync ( cart , usePaymentMethodAdditionalFee : false ) ;
2045- decimal . TryParse ( unit . Amount ? . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var orderAmount ) ;
2046- var difference = Math . Abs ( orderAmount - Math . Round ( cartTotal ?? decimal . Zero , 2 ) ) ;
2031+ var difference = Math . Abs ( ConvertMoney ( unit . Amount ) - Math . Round ( cartTotal ?? decimal . Zero , 2 ) ) ;
20472032 if ( difference > decimal . Zero )
20482033 throw new NopException ( $ "Shopping cart total and approved order amount differ by { difference } ") ;
20492034
@@ -2902,8 +2887,7 @@ await _orderService.InsertOrderNoteAsync(new()
29022887 if ( ! _orderProcessingService . CanMarkOrderAsAuthorized ( nopOrder ) )
29032888 break ;
29042889
2905- decimal . TryParse ( authorization . Amount ? . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var authorizationAmount ) ;
2906- if ( authorizationAmount >= Math . Round ( nopOrder . OrderTotal , 2 ) )
2890+ if ( ConvertMoney ( authorization . Amount ) >= Math . Round ( nopOrder . OrderTotal , 2 ) )
29072891 await _orderProcessingService . MarkAsAuthorizedAsync ( nopOrder ) ;
29082892
29092893 break ;
@@ -2947,8 +2931,7 @@ await _orderService.InsertOrderNoteAsync(new()
29472931 if ( ! _orderProcessingService . CanMarkOrderAsPaid ( nopOrder ) )
29482932 break ;
29492933
2950- decimal . TryParse ( capture . Amount ? . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var captureAmount ) ;
2951- if ( captureAmount >= Math . Round ( nopOrder . OrderTotal , 2 ) )
2934+ if ( ConvertMoney ( capture . Amount ) >= Math . Round ( nopOrder . OrderTotal , 2 ) )
29522935 await _orderProcessingService . MarkOrderAsPaidAsync ( nopOrder ) ;
29532936
29542937 break ;
@@ -3039,8 +3022,7 @@ await _orderService.InsertOrderNoteAsync(new()
30393022 nopOrder . CaptureTransactionId = orderCapture . Id ;
30403023 nopOrder . CaptureTransactionResult = orderCapture . Status ;
30413024
3042- decimal . TryParse ( orderCapture . Amount ? . Value , NumberStyles . Any , CultureInfo . InvariantCulture , out var captureAmount ) ;
3043- if ( captureAmount >= Math . Round ( nopOrder . OrderTotal , 2 ) )
3025+ if ( ConvertMoney ( orderCapture . Amount ) >= Math . Round ( nopOrder . OrderTotal , 2 ) )
30443026 await _orderProcessingService . MarkOrderAsPaidAsync ( nopOrder ) ;
30453027
30463028 break ;
0 commit comments