221 lines
11 KiB
C#
221 lines
11 KiB
C#
using AyCode.Core.Loggers;
|
||
using AyCode.Entities;
|
||
using FruitBank.Common.Dtos;
|
||
using Mango.Nop.Core.Loggers;
|
||
using Nop.Core;
|
||
using Nop.Core.Caching;
|
||
using Nop.Core.Domain.Catalog;
|
||
using Nop.Core.Domain.Customers;
|
||
using Nop.Core.Domain.Directory;
|
||
using Nop.Core.Domain.Discounts;
|
||
using Nop.Core.Domain.Orders;
|
||
using Nop.Core.Domain.Stores;
|
||
using Nop.Data;
|
||
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
||
using Nop.Services.Catalog;
|
||
using Nop.Services.Customers;
|
||
using Nop.Services.Directory;
|
||
using Nop.Services.Discounts;
|
||
using Nop.Services.Localization;
|
||
|
||
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
|
||
|
||
public class CustomPriceCalculationService : PriceCalculationService
|
||
{
|
||
private FruitBankDbContext _dbContext;
|
||
private readonly IProductAttributeService _productAttributeService;
|
||
private readonly ISpecificationAttributeService _specificationAttributeService;
|
||
private readonly ILocalizationService _localizationService;
|
||
private readonly IStoreContext _storeContext;
|
||
private ILogger _logger;
|
||
|
||
public CustomPriceCalculationService(
|
||
FruitBankDbContext dbContext,
|
||
// inject all base deps
|
||
CatalogSettings catalogSettings,
|
||
CurrencySettings currencySettings,
|
||
ICategoryService categoryService,
|
||
ICurrencyService currencyService,
|
||
IManufacturerService manufacturerService,
|
||
IProductAttributeParser productAttributeParser,
|
||
IProductAttributeService productAttributeService,
|
||
ISpecificationAttributeService specificationAttributeService,
|
||
IProductService productService,
|
||
ICustomerService customerService,
|
||
IDiscountService discountService,
|
||
IDiscountPluginManager discountPluginManager,
|
||
ILocalizationService localizationService,
|
||
IStaticCacheManager cacheManager,
|
||
IWorkContext workContext,
|
||
IEnumerable<IAcLogWriterBase> logWriters,
|
||
IStoreContext storeContext)
|
||
: base(catalogSettings, currencySettings, categoryService, currencyService, customerService, discountService, manufacturerService,
|
||
productAttributeParser, productService,
|
||
cacheManager)
|
||
{
|
||
_logger = new Logger<CustomPriceCalculationService>(logWriters.ToArray());
|
||
|
||
_dbContext = dbContext;
|
||
// assign all base deps to local private vars if needed
|
||
_productAttributeService = productAttributeService;
|
||
_specificationAttributeService = specificationAttributeService;
|
||
_localizationService = localizationService;
|
||
_storeContext = storeContext;
|
||
}
|
||
|
||
public static decimal CalculateOrderItemFinalPrice(bool isMeasurable, decimal unitPrice, int quantity, double netWeight)
|
||
=> decimal.Round(unitPrice * (isMeasurable ? (decimal)netWeight: quantity), 0);
|
||
|
||
private static (decimal finalPriceInclTax, decimal finalPriceExclTax) CalculateOrderItemFinalPrices(int quantity, decimal unitPriceInclTax, decimal unitPriceExclTax, bool isMeasurable, double netWeight)
|
||
{
|
||
var finalPriceInclTax = CalculateOrderItemFinalPrice(isMeasurable, unitPriceInclTax, quantity, netWeight);
|
||
var finalPriceExclTax = CalculateOrderItemFinalPrice(isMeasurable, unitPriceExclTax, quantity, netWeight);
|
||
|
||
return (finalPriceInclTax, finalPriceExclTax);
|
||
}
|
||
|
||
public async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItem orderItem, OrderItemDto? orderItemDtoHelper = null)
|
||
{
|
||
orderItemDtoHelper ??= await _dbContext.OrderItemDtos.GetByIdAsync(orderItem.Id, true);
|
||
return await CheckAndUpdateOrderItemFinalPricesAsync(orderItem, orderItemDtoHelper.IsMeasurable, orderItemDtoHelper.NetWeight);
|
||
}
|
||
|
||
//public async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItemDto orderItemDto)
|
||
//{
|
||
// var orderItem = await _dbContext.OrderItems.GetByIdAsync(orderItemDto.Id);
|
||
// return await CheckAndUpdateOrderItemFinalPricesAsync(orderItem, orderItemDto.IsMeasurable, orderItemDto.NetWeight);
|
||
//}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="orderItem"></param>
|
||
/// <param name="isMeasurable"></param>
|
||
/// /// <param name="netWeight"></param>
|
||
/// <returns>true if has changes</returns>
|
||
public async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItem orderItem, bool isMeasurable, double netWeight)
|
||
{
|
||
_logger.Info($"orderItem.Id: {orderItem.Id}");
|
||
|
||
if (orderItem.UnitPriceInclTax == 0 || orderItem.UnitPriceExclTax == 0)
|
||
{
|
||
var orderDto = await _dbContext.OrderDtos.GetByIdAsync(orderItem.OrderId, false);
|
||
var customer = await _dbContext.Customers.GetByIdAsync(orderDto.CustomerId);
|
||
var product = await _dbContext.Products.GetByIdAsync(orderItem.ProductId);
|
||
var pr = await GetFinalPriceAsync(product, customer, _storeContext.GetCurrentStore(), null, 0, true, 1, null, null);
|
||
orderItem.UnitPriceInclTax = pr.finalPrice;
|
||
orderItem.UnitPriceExclTax = pr.finalPrice / (decimal)1.27;
|
||
}
|
||
|
||
var finalPrices = CalculateOrderItemFinalPrices(orderItem.Quantity, orderItem.UnitPriceInclTax, orderItem.UnitPriceExclTax, isMeasurable, netWeight);
|
||
|
||
if (finalPrices.finalPriceInclTax == orderItem.PriceInclTax && finalPrices.finalPriceExclTax == orderItem.PriceExclTax) return false;
|
||
|
||
_logger.Info($"orderItem.PriceInclTax({orderItem.PriceInclTax}) != finalPriceInclTax({finalPrices.finalPriceInclTax}) || " +
|
||
$"orderItem.PriceExclTax({orderItem.PriceExclTax}) != finalPriceExclTax({finalPrices.finalPriceExclTax})");
|
||
|
||
orderItem.PriceInclTax = finalPrices.finalPriceInclTax;
|
||
orderItem.PriceExclTax = finalPrices.finalPriceExclTax;
|
||
|
||
await _dbContext.OrderItems.UpdateAsync(orderItem, false);
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="order"></param>
|
||
/// <returns>true if has changes</returns>
|
||
public async Task<bool> CheckAndUpdateOrderTotalPrice(Order order)
|
||
{
|
||
var prevOrderTotal = order.OrderTotal;
|
||
|
||
var orderItemDtosById = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id).ToDictionaryAsync(k => k.Id, v => v);
|
||
var orderItems = await _dbContext.OrderItems.GetByIdsAsync(orderItemDtosById.Keys.ToList());
|
||
|
||
order.OrderTotal = 0;
|
||
|
||
foreach (var orderItem in orderItems)
|
||
{
|
||
var orderItemDto = orderItemDtosById[orderItem.Id];
|
||
|
||
await CheckAndUpdateOrderItemFinalPricesAsync(orderItem, orderItemDto.IsMeasurable, orderItemDto.NetWeight);
|
||
order.OrderTotal += orderItem.PriceInclTax;
|
||
}
|
||
|
||
if (order.OrderTotal == prevOrderTotal) return false;
|
||
|
||
_logger.Info($"order.OrderTotal({order.OrderTotal}) == prevOrderTotal({prevOrderTotal})");
|
||
|
||
order.OrderSubtotalInclTax = order.OrderTotal;
|
||
order.OrderSubtotalExclTax = (order.OrderTotal / (decimal)1.27);
|
||
|
||
//mivel csak csekkolunk, de nem adunk vissza semmilyen kedvezményt, így a subtotal discount értékek kiszámolááshoz meg kell hívni megint a calculate final price-t
|
||
decimal orderSubTotalDiscountInclTax = 0;
|
||
decimal orderSubTotalDiscountExclTax = 0;
|
||
var store = await _storeContext.GetCurrentStoreAsync();
|
||
|
||
foreach (var orderItem in orderItems)
|
||
{
|
||
var orderItemDto = orderItemDtosById[orderItem.Id];
|
||
var product = await _dbContext.Products.GetByIdAsync(orderItem.ProductId);
|
||
var customer = await _dbContext.Customers.GetByIdAsync(order.CustomerId);
|
||
var itemPrice = await GetFinalPriceAsync(product, customer, store, 0, true, orderItemDto.Quantity);
|
||
orderSubTotalDiscountInclTax += itemPrice.appliedDiscountAmount;
|
||
orderSubTotalDiscountExclTax += itemPrice.appliedDiscountAmount / (decimal)1.27;
|
||
}
|
||
|
||
|
||
order.OrderSubTotalDiscountInclTax = orderSubTotalDiscountInclTax;
|
||
order.OrderSubTotalDiscountExclTax = orderSubTotalDiscountExclTax;
|
||
|
||
await _dbContext.Orders.UpdateAsync(order, false);
|
||
return true;
|
||
}
|
||
|
||
//public override async Task<(decimal priceWithoutDiscounts, decimal finalPrice, decimal appliedDiscountAmount, List<Discount> appliedDiscounts)> GetFinalPriceAsync(
|
||
// Product product, Customer customer, Store store, decimal? overriddenProductPrice, decimal additionalCharge = 0, bool includeDiscounts = true,
|
||
// int quantity = 1, DateTime? rentalStartDate = null, DateTime? rentalEndDate = null)
|
||
public override async Task<(decimal priceWithoutDiscounts, decimal finalPrice, decimal appliedDiscountAmount, List<Discount> appliedDiscounts)> GetFinalPriceAsync
|
||
(Product product, Customer customer, Store store, decimal? overriddenProductPrice, decimal additionalCharge, bool includeDiscounts, int quantity,
|
||
DateTime? rentalStartDate, DateTime? rentalEndDate)
|
||
{
|
||
var productDto = await _dbContext.ProductDtos.GetByIdAsync(product.Id, true);
|
||
|
||
|
||
var finalPrice = await base.GetFinalPriceAsync(product, customer, store, overriddenProductPrice, additionalCharge, includeDiscounts, quantity, rentalStartDate, rentalEndDate);
|
||
|
||
if (productDto.IsMeasurable)
|
||
{
|
||
// For measurable products the real price is weight × unit price, determined only after
|
||
// physical weighing. Until then we expose 0 so the cart and checkout total are honest.
|
||
// The actual PriceInclTax / PriceExclTax on OrderItem is set by
|
||
// CheckAndUpdateOrderItemFinalPricesAsync after the order is weighed.
|
||
//return (0m, 0m, 0m, new System.Collections.Generic.List<Nop.Core.Domain.Discounts.Discount>());
|
||
|
||
//finalPrice.priceWithoutDiscounts = 0;
|
||
//return (0, finalPrice.finalPrice, finalPrice.appliedDiscountAmount, []);
|
||
return finalPrice;
|
||
//return (overriddenProductPrice.GetValueOrDefault(0), overriddenProductPrice.GetValueOrDefault(0), 0m, []);
|
||
}
|
||
//var productAttributeMappings = await _specificationAttributeService.GetProductSpecificationAttributesAsync(product.Id);
|
||
////Product Attributes
|
||
//foreach (var pam in productAttributeMappings)
|
||
//{
|
||
// //get option
|
||
// var attributeOtion = await _specificationAttributeService.GetSpecificationAttributeOptionByIdAsync(pam.SpecificationAttributeOptionId);
|
||
|
||
// //get attribute
|
||
// var attribute = await _specificationAttributeService.GetSpecificationAttributeByIdAsync(attributeOtion.SpecificationAttributeId);
|
||
|
||
// // you can check for specific attribute by its name or id
|
||
// if (attribute.Name == "Needs to be measured for price")
|
||
// {
|
||
// return (0m, 0m, 0m, []);
|
||
// }
|
||
//}
|
||
|
||
return finalPrice;
|
||
}
|
||
}
|