Skip to content

Commit

Permalink
PayPal: Fixed VAT exempt & currency conversion problems
Browse files Browse the repository at this point in the history
(cherry picked from commit 3e026b0)
  • Loading branch information
Michael-Herzog committed May 14, 2024
1 parent 86f7e9b commit ac41c25
Showing 1 changed file with 32 additions and 14 deletions.
46 changes: 32 additions & 14 deletions src/Smartstore.Modules/Smartstore.PayPal/Client/PayPalHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
var batchContext = _productService.CreateProductBatchContext(cartProducts, null, customer, false);
var calculationOptions = _priceCalculationService.CreateDefaultOptions(false, customer, _currencyService.PrimaryCurrency, batchContext);

var isVatExempt = await _taxService.IsVatExemptAsync(customer);

foreach (var item in model.Items)
{
var cartItem = cart.Items.Where(x => x.Item.ProductId == item.ProductId).FirstOrDefault();
Expand All @@ -399,7 +401,7 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
var productName = item.ProductName?.Value?.Truncate(126);
var productDescription = item.ShortDesc?.Value?.Truncate(126);

purchaseUnitItems.Add(new PurchaseUnitItem
var purchaseUnitItem = new PurchaseUnitItem
{
UnitAmount = new MoneyMessage
{
Expand All @@ -410,14 +412,20 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
Description = productDescription,
Category = item.IsEsd ? ItemCategoryType.DigitalGoods : ItemCategoryType.PhysicalGoods,
Quantity = item.EnteredQuantity.ToString(),
Sku = item.Sku,
Tax = new MoneyMessage
Sku = item.Sku
};

if (!isVatExempt)
{
purchaseUnitItem.Tax = new MoneyMessage
{
Value = convertedUnitPriceTax.Amount.ToStringInvariant("F"),
CurrencyCode = currency.CurrencyCode
},
TaxRate = taxRate.Rate.ToStringInvariant("F")
});
};
purchaseUnitItem.TaxRate = taxRate.Rate.ToStringInvariant("F");
}

purchaseUnitItems.Add(purchaseUnitItem);
}

return purchaseUnitItems;
Expand All @@ -432,10 +440,11 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
var currency = _workContext.WorkingCurrency;

var purchaseUnitItems = await GetPurchaseUnitItemsAsync(cart, customer, currency);
var isVatExempt = await _taxService.IsVatExemptAsync(customer);

// Get subtotal
var cartSubTotalExclTax = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart, false);
var cartSubTotalinklTax = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart, true);
var cartSubTotalInklTax = await _orderCalculationService.GetShoppingCartSubtotalAsync(cart, true);
var subTotalConverted = _currencyService.ConvertFromPrimaryCurrency(cartSubTotalExclTax.SubtotalWithoutDiscount.Amount, currency);

// Get tax
Expand All @@ -452,7 +461,7 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
purchaseUnitItems.Each(x => itemTotal += x.UnitAmount.Value.Convert<decimal>() * x.Quantity.ToInt());

decimal itemTotalTax = 0;
purchaseUnitItems.Each(x => itemTotalTax += x.Tax.Value.Convert<decimal>() * x.Quantity.ToInt());
purchaseUnitItems.Each(x => itemTotalTax += x.Tax != null ? x.Tax.Value.Convert<decimal>() * x.Quantity.ToInt() : 0);

var purchaseUnit = new PurchaseUnit
{
Expand Down Expand Up @@ -492,22 +501,31 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar
orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryCurrency(cartTotal.DiscountAmount.Amount, currency);
}

decimal discountAmount = _roundingHelper.Round(orderTotalDiscountAmount.Amount + cartSubTotalinklTax.DiscountAmount.Amount);
var subTotalDiscountAmount = new Money();
if (cartSubTotalInklTax.DiscountAmount > decimal.Zero)
{
subTotalDiscountAmount = _currencyService.ConvertFromPrimaryCurrency(
isVatExempt ? cartSubTotalExclTax.DiscountAmount.Amount : cartSubTotalInklTax.DiscountAmount.Amount,
currency);
}

decimal discountAmount = _roundingHelper.Round(orderTotalDiscountAmount.Amount + subTotalDiscountAmount.Amount);

purchaseUnit.Amount.AmountBreakdown.Discount = new MoneyMessage
{
Value = discountAmount.ToStringInvariant("F"),
CurrencyCode = currency.CurrencyCode
};

// Get shipping cost
var shippingTotal = await _orderCalculationService.GetShoppingCartShippingTotalAsync(cart, true);
decimal shippingTotalAmount = 0;
var shippingTotal = await _orderCalculationService.GetShoppingCartShippingTotalAsync(cart, !isVatExempt);
var shippingTotalAmount = new Money();
if (shippingTotal.ShippingTotal != null)
{
shippingTotalAmount = _roundingHelper.Round(shippingTotal.ShippingTotal.Value.Amount);
shippingTotalAmount = _currencyService.ConvertFromPrimaryCurrency(_roundingHelper.Round(shippingTotal.ShippingTotal.Value.Amount), currency);
purchaseUnit.Amount.AmountBreakdown.Shipping = new MoneyMessage
{
Value = shippingTotal.ShippingTotal.Value.Amount.ToStringInvariant("F"),
Value = shippingTotalAmount.Amount.ToStringInvariant("F"),
CurrencyCode = currency.CurrencyCode
};
}
Expand All @@ -519,7 +537,7 @@ private async Task<List<PurchaseUnitItem>> GetPurchaseUnitItemsAsync(ShoppingCar

// TODO: (mh) (core) This is very hackish. PayPal was contacted and requested for a correct solution.
// Lets check for rounding issues.
var calculatedAmount = itemTotal + itemTotalTax + shippingTotalAmount - discountAmount;
var calculatedAmount = itemTotal + itemTotalTax + shippingTotalAmount.Amount - discountAmount;
var amountMismatch = calculatedAmount != purchaseUnit.Amount.Value.Convert<decimal>();
if (amountMismatch)
{
Expand Down

0 comments on commit ac41c25

Please sign in to comment.