456 lines
22 KiB
C#
456 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using gehGassi.Common;
|
|
using gehGassi.Core.Interfaces;
|
|
using gehGassi.Domain.Common;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace gehGassi.Core.Services
|
|
{
|
|
/// <summary>
|
|
/// Service der die Preise eines Produktes berechnet
|
|
/// </summary>
|
|
public class ShopCalculationService : IShopCalculationService
|
|
{
|
|
private readonly IProductService _productService;
|
|
private readonly ICustomerService _customerService;
|
|
private readonly IOptions<ShopOptions> _shopOptions;
|
|
private readonly IOptions<VatValidationSettings> _vatValidationSettings;
|
|
private readonly ITaxRateService _taxRateService;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="productService">Instanz eines IProductService</param>
|
|
/// <param name="customerService">Instanz eines ICustomerService</param>
|
|
/// <param name="shopOptions">Instanz von ShopOptions</param>
|
|
/// <param name="vatValidationSettings">Instanz von VatValidationSettings</param>
|
|
/// <param name="taxRateService">Instanz eines ITaxRateService</param>
|
|
public ShopCalculationService(IProductService productService, ICustomerService customerService, IOptions<ShopOptions> shopOptions, IOptions<VatValidationSettings> vatValidationSettings, ITaxRateService taxRateService)
|
|
{
|
|
_productService = productService;
|
|
_customerService = customerService;
|
|
_shopOptions = shopOptions;
|
|
_vatValidationSettings = vatValidationSettings;
|
|
_taxRateService = taxRateService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet den Preis einer Produktes für einen Kunden.
|
|
/// Berücksichtigt die Länder- und Kundeneinstellungen
|
|
/// </summary>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="quantity">Anzahl - Stück</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> CalculatePriceAsync(int productId, long customerId, int quantity)
|
|
{
|
|
var customer = await _customerService.GetAsync(customerId);
|
|
var result = await CalculatePriceAsync(productId, customerId, customer.Address.CountryCode, quantity);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet den Preis einer Produktes für einen Kunden.
|
|
/// Berücksichtigt die Länder- und Kundeneinstellungen
|
|
/// </summary>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="billingCountry">Iso2 Land für die Rechnung</param>
|
|
/// <param name="quantity">Anzahl - Stück</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> CalculatePriceAsync(int productId, long customerId, string billingCountry, int quantity)
|
|
{
|
|
var result = new PriceCalculation
|
|
{
|
|
TaxRate = 0,
|
|
TaxValue = 0
|
|
};
|
|
|
|
var product = await _productService.GetAsync(productId);
|
|
var customer = await _customerService.GetAsync(customerId);
|
|
var productCountry = await _productService.GetCountryAsync(productId, billingCountry);
|
|
|
|
result.Price = product.Price;
|
|
result.Price2 = product.Price2;
|
|
result.OldPrice = product.OldPrice;
|
|
result.OldPrice2 = product.OldPrice2;
|
|
|
|
if (productCountry != null)
|
|
{
|
|
result.Price = productCountry.Price;
|
|
result.Price2 = productCountry.Price2;
|
|
result.OldPrice = productCountry.OldPrice;
|
|
result.OldPrice2 = productCountry.OldPrice2;
|
|
}
|
|
|
|
decimal markup = 0m;
|
|
switch (product.ProductType)
|
|
{
|
|
case ProductType.Physical:
|
|
break;
|
|
case ProductType.Download:
|
|
break;
|
|
case ProductType.Listing:
|
|
markup = customer.MarkupListing;
|
|
break;
|
|
case ProductType.Advertisement:
|
|
markup = customer.MarkupAdvertisement;
|
|
break;
|
|
case ProductType.Pin:
|
|
markup = customer.MarkupPin;
|
|
break;
|
|
case ProductType.Banner:
|
|
markup = customer.MarkupBanner;
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
if (markup != 0)
|
|
{
|
|
result.Price += ((result.Price * markup) / 100);
|
|
result.OldPrice += ((result.OldPrice * markup) / 100);
|
|
result.Price2 += ((result.Price2 * markup) / 100);
|
|
result.OldPrice2 += ((result.OldPrice2 * markup) / 100);
|
|
}
|
|
|
|
result.Quantity = quantity;
|
|
result.Total = (result.Price + result.Price2) * quantity;
|
|
result.TotalOld = (result.OldPrice + result.OldPrice2) * quantity;
|
|
|
|
result.PriceGross = result.Price;
|
|
result.OldPriceGross = result.OldPrice;
|
|
result.Price2Gross = result.Price2;
|
|
result.OldPrice2Gross = result.OldPrice2;
|
|
result.TotalGross = result.Total;
|
|
result.TotalOldGross = result.TotalOld;
|
|
|
|
if (!product.IsTaxExempt)
|
|
{
|
|
//EU-Ausnahme. Gilt wenn Land in der EU und ungleich Quellland und Kunde ist Firma
|
|
var isEuCountry = _vatValidationSettings.Value.Countries.Contains(billingCountry);
|
|
var isNoTaxCountry = _vatValidationSettings.Value.NoTaxCountries.Contains(billingCountry);
|
|
var isSameAsSource = _shopOptions.Value.SourceCountry == billingCountry;
|
|
|
|
if ((!isEuCountry && !isNoTaxCountry) || isSameAsSource)
|
|
{
|
|
var taxRate = await _taxRateService.GetAsync(product.TaxRateId);
|
|
result.PriceGross = result.Price + ((result.Price * taxRate.Value) / 100);
|
|
result.OldPriceGross = result.OldPrice + ((result.OldPrice * taxRate.Value) / 100);
|
|
result.Price2Gross = result.Price2 + ((result.Price2 * taxRate.Value) / 100);
|
|
result.OldPrice2Gross = result.OldPrice2 + ((result.OldPrice2 * taxRate.Value) / 100);
|
|
|
|
result.PriceGross = Math.Round(result.PriceGross, 2, MidpointRounding.AwayFromZero);
|
|
result.OldPriceGross = Math.Round(result.OldPriceGross, 2, MidpointRounding.AwayFromZero);
|
|
result.Price2Gross = Math.Round(result.Price2Gross, 2, MidpointRounding.AwayFromZero);
|
|
result.OldPrice2Gross = Math.Round(result.OldPrice2Gross, 2, MidpointRounding.AwayFromZero);
|
|
|
|
result.TotalGross = (result.PriceGross + result.Price2Gross) * quantity;
|
|
result.TotalOldGross = (result.OldPriceGross + result.OldPrice2Gross) * quantity;
|
|
|
|
result.TaxRate = taxRate.Value;
|
|
}
|
|
}
|
|
|
|
result.TaxValue = result.TotalGross - result.Total;
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet den Preis einer Produktes für einen Kunden.
|
|
/// Berücksichtigt die Länder- und Kundeneinstellungen
|
|
/// </summary>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="billingCountry">Iso2 Land für die Rechnung</param>
|
|
/// <param name="quantity">Anzahl - Stück</param>
|
|
/// <param name="budget">Budget für Banner</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> CalculatePriceBannerAsync(int productId, long customerId, string billingCountry, int quantity, decimal budget)
|
|
{
|
|
var result = new PriceCalculation
|
|
{
|
|
TaxRate = 0,
|
|
TaxValue = 0
|
|
};
|
|
|
|
var product = await _productService.GetAsync(productId);
|
|
var customer = await _customerService.GetAsync(customerId);
|
|
var productCountry = await _productService.GetCountryAsync(productId, billingCountry);
|
|
|
|
result.Price = budget;
|
|
result.Price2 = 0m;
|
|
result.OldPrice = 0m;
|
|
result.OldPrice2 = 0m;
|
|
|
|
result.Quantity = quantity;
|
|
result.Total = (result.Price + result.Price2) * quantity;
|
|
result.TotalOld = (result.OldPrice + result.OldPrice2) * quantity;
|
|
|
|
result.PriceGross = result.Price;
|
|
result.OldPriceGross = result.OldPrice;
|
|
result.Price2Gross = result.Price2;
|
|
result.OldPrice2Gross = result.OldPrice2;
|
|
result.TotalGross = result.Total;
|
|
result.TotalOldGross = result.TotalOld;
|
|
|
|
if (!product.IsTaxExempt)
|
|
{
|
|
//EU-Ausnahme. Gilt wenn Land in der EU und ungleich Quellland und Kunde ist Firma
|
|
var isEuCountry = _vatValidationSettings.Value.Countries.Contains(billingCountry);
|
|
var isNoTaxCountry = _vatValidationSettings.Value.NoTaxCountries.Contains(billingCountry);
|
|
var isSameAsSource = _shopOptions.Value.SourceCountry == billingCountry;
|
|
|
|
if ((!isEuCountry && !isNoTaxCountry) || isSameAsSource)
|
|
{
|
|
var taxRate = await _taxRateService.GetAsync(product.TaxRateId);
|
|
var grossFactor = 1 + (taxRate.Value / 100);
|
|
result.Price = decimal.Round(result.PriceGross / grossFactor, 4, MidpointRounding.AwayFromZero);
|
|
|
|
result.Total = (result.Price + result.Price2) * quantity;
|
|
|
|
result.TaxRate = taxRate.Value;
|
|
}
|
|
}
|
|
|
|
result.TaxValue = result.TotalGross - result.Total;
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet den Preis einer Produktes für einen Kunden.
|
|
/// Berücksichtigt die Länder- und Kundeneinstellungen
|
|
/// </summary>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="priceType">Preistype</param>
|
|
/// <param name="priceAliquotType">Typ der aliquoten Berechnung</param>
|
|
/// <param name="startDate">Startdatum</param>
|
|
/// <param name="endDate">Enddatum</param>
|
|
/// <param name="quantity">Anzahl - Stück</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> CalculatePriceAsync(int productId, long customerId, PriceType priceType, PriceAliquotType priceAliquotType, DateTimeOffset startDate, DateTimeOffset endDate, int quantity)
|
|
{
|
|
var customer = await _customerService.GetAsync(customerId);
|
|
var result = await CalculatePriceAsync(productId, customerId, priceType, priceAliquotType, startDate, endDate, customer.Address.CountryCode, quantity);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet den Preis einer Produktes für einen Kunden.
|
|
/// Berücksichtigt die Länder- und Kundeneinstellungen
|
|
/// </summary>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="priceType">Preistype</param>
|
|
/// <param name="priceAliquotType">Typ der aliquoten Berechnung</param>
|
|
/// <param name="startDate">Startdatum</param>
|
|
/// <param name="endDate">Enddatum</param>
|
|
/// <param name="billingCountry">Iso2 Land für die Rechnung</param>
|
|
/// <param name="quantity">Anzahl - Stück</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> CalculatePriceAsync(int productId, long customerId, PriceType priceType, PriceAliquotType priceAliquotType, DateTimeOffset startDate, DateTimeOffset endDate, string billingCountry, int quantity)
|
|
{
|
|
var result = new PriceCalculation
|
|
{
|
|
TaxRate = 0,
|
|
TaxValue = 0
|
|
};
|
|
|
|
var product = await _productService.GetAsync(productId);
|
|
var customer = await _customerService.GetAsync(customerId);
|
|
var productCountry = await _productService.GetCountryAsync(productId, billingCountry);
|
|
|
|
result.Price = product.Price;
|
|
result.Price2 = product.Price2;
|
|
result.OldPrice = product.OldPrice;
|
|
result.OldPrice2 = product.OldPrice2;
|
|
|
|
if (productCountry != null)
|
|
{
|
|
result.Price = productCountry.Price;
|
|
result.Price2 = productCountry.Price2;
|
|
result.OldPrice = productCountry.OldPrice;
|
|
result.OldPrice2 = productCountry.OldPrice2;
|
|
}
|
|
|
|
decimal markup = 0m;
|
|
switch (product.ProductType)
|
|
{
|
|
case ProductType.Physical:
|
|
break;
|
|
case ProductType.Download:
|
|
break;
|
|
case ProductType.Listing:
|
|
markup = customer.MarkupListing;
|
|
break;
|
|
case ProductType.Advertisement:
|
|
markup = customer.MarkupAdvertisement;
|
|
break;
|
|
case ProductType.Pin:
|
|
markup = customer.MarkupPin;
|
|
break;
|
|
case ProductType.Banner:
|
|
markup = customer.MarkupBanner;
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
if (markup != 0)
|
|
{
|
|
result.Price += ((result.Price * markup) / 100);
|
|
result.OldPrice += ((result.OldPrice * markup) / 100);
|
|
result.Price2 += ((result.Price2 * markup) / 100);
|
|
result.OldPrice2 += ((result.OldPrice2 * markup) / 100);
|
|
}
|
|
|
|
if (priceAliquotType == PriceAliquotType.Month && priceType == PriceType.Year)
|
|
{
|
|
result.Price /= 12;
|
|
result.Price2 /= 12;
|
|
result.OldPrice /= 12;
|
|
result.OldPrice2 /= 12;
|
|
|
|
var months = (((endDate.Year - startDate.Year) * 12) + endDate.Month - startDate.Month) + 1;
|
|
result.Price *= months;
|
|
result.Price2 *= months;
|
|
result.OldPrice *= months;
|
|
result.OldPrice2 *= months;
|
|
}
|
|
|
|
if (priceAliquotType == PriceAliquotType.Day && priceType == PriceType.Month)
|
|
{
|
|
var totalDays = DateTime.DaysInMonth(endDate.Year, endDate.Month);
|
|
result.Price /= totalDays;
|
|
result.Price2 /= totalDays;
|
|
result.OldPrice /= totalDays;
|
|
result.OldPrice2 /= totalDays;
|
|
|
|
var days = (int)(endDate - startDate).TotalDays + 1;
|
|
result.Price *= days;
|
|
result.Price2 *= days;
|
|
result.OldPrice *= days;
|
|
result.OldPrice2 *= days;
|
|
}
|
|
|
|
if (priceType == PriceType.Day)
|
|
{
|
|
var days = (int)(endDate - startDate).TotalDays;
|
|
result.Price *= days;
|
|
result.Price2 *= days;
|
|
result.OldPrice *= days;
|
|
result.OldPrice2 *= days;
|
|
}
|
|
|
|
result.Quantity = quantity;
|
|
result.Total = (result.Price + result.Price2) * quantity;
|
|
result.TotalOld = (result.OldPrice + result.OldPrice2) * quantity;
|
|
|
|
result.PriceGross = result.Price;
|
|
result.OldPriceGross = result.OldPrice;
|
|
result.Price2Gross = result.Price2;
|
|
result.OldPrice2Gross = result.OldPrice2;
|
|
result.TotalGross = result.Total;
|
|
result.TotalOldGross = result.TotalOld;
|
|
|
|
if (!product.IsTaxExempt)
|
|
{
|
|
//EU-Ausnahme. Gilt wenn Land in der EU und ungleich Quellland und Kunde ist Firma
|
|
var isEuCountry = _vatValidationSettings.Value.Countries.Contains(billingCountry);
|
|
var isNoTaxCountry = _vatValidationSettings.Value.NoTaxCountries.Contains(billingCountry);
|
|
var isSameAsSource = _shopOptions.Value.SourceCountry == billingCountry;
|
|
|
|
if ((!isEuCountry && !isNoTaxCountry) || isSameAsSource)
|
|
{
|
|
var taxRate = await _taxRateService.GetAsync(product.TaxRateId);
|
|
result.PriceGross = result.Price + ((result.Price * taxRate.Value) / 100);
|
|
result.OldPriceGross = result.OldPrice + ((result.OldPrice * taxRate.Value) / 100);
|
|
result.Price2Gross = result.Price2 + ((result.Price2 * taxRate.Value) / 100);
|
|
result.OldPrice2Gross = result.OldPrice2 + ((result.OldPrice2 * taxRate.Value) / 100);
|
|
|
|
result.PriceGross = Math.Round(result.PriceGross, 2, MidpointRounding.AwayFromZero);
|
|
result.OldPriceGross = Math.Round(result.OldPriceGross, 2, MidpointRounding.AwayFromZero);
|
|
result.Price2Gross = Math.Round(result.Price2Gross, 2, MidpointRounding.AwayFromZero);
|
|
result.OldPrice2Gross = Math.Round(result.OldPrice2Gross, 2, MidpointRounding.AwayFromZero);
|
|
|
|
result.TotalGross = (result.PriceGross + result.Price2Gross) * quantity;
|
|
result.TotalOldGross = (result.OldPriceGross + result.OldPrice2Gross) * quantity;
|
|
|
|
result.TaxRate = taxRate.Value;
|
|
}
|
|
}
|
|
|
|
result.TaxValue = result.TotalGross - result.Total;
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aufschlagen von X Prozent auf eine Preis-Kalkulation
|
|
/// </summary>
|
|
/// <param name="priceCalculation">Preis-Kalkulation</param>
|
|
/// <param name="markup">Aufschlag in Prozent</param>
|
|
/// <param name="productId">Id des Produktes</param>
|
|
/// <param name="billingCountry">Iso2 Land für die Rechnung</param>
|
|
/// <returns>Preis-Kalkulation</returns>
|
|
public async Task<PriceCalculation> AddMarkupAsync(PriceCalculation priceCalculation, decimal markup, int productId, string billingCountry)
|
|
{
|
|
var product = await _productService.GetAsync(productId);
|
|
var productCountry = await _productService.GetCountryAsync(productId, billingCountry);
|
|
|
|
priceCalculation.Price += ((priceCalculation.Price * markup) / 100);
|
|
priceCalculation.OldPrice += ((priceCalculation.OldPrice * markup) / 100);
|
|
priceCalculation.Price2 += ((priceCalculation.Price2 * markup) / 100);
|
|
priceCalculation.OldPrice2 += ((priceCalculation.OldPrice2 * markup) / 100);
|
|
|
|
priceCalculation.Total = (priceCalculation.Price + priceCalculation.Price2) * priceCalculation.Quantity;
|
|
priceCalculation.TotalOld = (priceCalculation.OldPrice + priceCalculation.OldPrice2) * priceCalculation.Quantity;
|
|
|
|
priceCalculation.PriceGross = priceCalculation.Price;
|
|
priceCalculation.OldPriceGross = priceCalculation.OldPrice;
|
|
priceCalculation.Price2Gross = priceCalculation.Price2;
|
|
priceCalculation.OldPrice2Gross = priceCalculation.OldPrice2;
|
|
priceCalculation.TotalGross = priceCalculation.Total;
|
|
priceCalculation.TotalOldGross = priceCalculation.TotalOld;
|
|
|
|
if (!product.IsTaxExempt)
|
|
{
|
|
//EU-Ausnahme. Gilt wenn Land in der EU und ungleich Quellland und Kunde ist Firma
|
|
var isEuCountry = _vatValidationSettings.Value.Countries.Contains(billingCountry);
|
|
var isNoTaxCountry = _vatValidationSettings.Value.NoTaxCountries.Contains(billingCountry);
|
|
var isSameAsSource = _shopOptions.Value.SourceCountry == billingCountry;
|
|
|
|
if ((!isEuCountry && !isNoTaxCountry) || isSameAsSource)
|
|
{
|
|
var taxRate = await _taxRateService.GetAsync(product.TaxRateId);
|
|
priceCalculation.PriceGross = priceCalculation.Price + ((priceCalculation.Price * taxRate.Value) / 100);
|
|
priceCalculation.OldPriceGross = priceCalculation.OldPrice + ((priceCalculation.OldPrice * taxRate.Value) / 100);
|
|
priceCalculation.Price2Gross = priceCalculation.Price2 + ((priceCalculation.Price2 * taxRate.Value) / 100);
|
|
priceCalculation.OldPrice2Gross = priceCalculation.OldPrice2 + ((priceCalculation.OldPrice2 * taxRate.Value) / 100);
|
|
|
|
priceCalculation.PriceGross = Math.Round(priceCalculation.PriceGross, 2, MidpointRounding.AwayFromZero);
|
|
priceCalculation.OldPriceGross = Math.Round(priceCalculation.OldPriceGross, 2, MidpointRounding.AwayFromZero);
|
|
priceCalculation.Price2Gross = Math.Round(priceCalculation.Price2Gross, 2, MidpointRounding.AwayFromZero);
|
|
priceCalculation.OldPrice2Gross = Math.Round(priceCalculation.OldPrice2Gross, 2, MidpointRounding.AwayFromZero);
|
|
|
|
priceCalculation.TotalGross = (priceCalculation.PriceGross + priceCalculation.Price2Gross) * priceCalculation.Quantity;
|
|
priceCalculation.TotalOldGross = (priceCalculation.OldPriceGross + priceCalculation.OldPrice2Gross) * priceCalculation.Quantity;
|
|
|
|
priceCalculation.TaxRate = taxRate.Value;
|
|
}
|
|
}
|
|
|
|
priceCalculation.TaxValue = priceCalculation.TotalGross - priceCalculation.Total;
|
|
|
|
return priceCalculation;
|
|
}
|
|
}
|
|
}
|