Price calculation improvements, fixes, etc...

This commit is contained in:
Loretta 2025-10-24 15:47:45 +02:00
parent f9b302c5d9
commit 11b151a9ec
7 changed files with 232 additions and 124 deletions

View File

@ -160,7 +160,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
return RedirectToAction("List", "Order");
// store attributes in GenericAttribute table
await _genericAttributeService.SaveAttributeAsync(order, nameof(IMeasurable.IsMeasurable), model.IsMeasurable, _storeContext.GetCurrentStore().Id);
//await _genericAttributeService.SaveAttributeAsync(order, nameof(IMeasurable.IsMeasurable), model.IsMeasurable, _storeContext.GetCurrentStore().Id);
await _genericAttributeService.SaveAttributeAsync(order, nameof(IOrderDto.DateOfReceipt), model.DateOfReceipt, _storeContext.GetCurrentStore().Id);
_notificationService.SuccessNotification("Custom attributes saved successfully.");
@ -226,11 +226,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
//var productDtosById = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(op => op.Id)).ToDictionaryAsync(p => p.Id, prodDto => prodDto);
var store = _storeContext.GetCurrentStore();
var productDtosByOrderItemId = (await _dbContext.ProductDtos.GetByIdsAsync(orderProducts.Select(x => x.Id).ToArray())).ToDictionary(k => k.Id, v => v);
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
{
await _orderService.InsertOrderAsync(order);
order.CustomOrderNumber = order.Id.ToString();
await _orderService.UpdateOrderAsync(order);
order.OrderTotal = 0;
foreach (var item in orderProducts)
{
@ -239,48 +241,47 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
if (product == null || product.StockQuantity - item.Quantity < 0)
{
var errorText = $"product == null || product.StockQuantity - item.Quantity < 0; productId: {product?.Id}; product?.StockQuantity - item.Quantity: {product?.StockQuantity - item.Quantity}";
_logger.Error($"{errorText}");
throw new Exception($"{errorText}");
}
//var (_, finalUnitPrice, _, _) = await _priceCalculationService.GetFinalPriceAsync(product, customer, store, item.Price, 0, true, item.Quantity, null, null);
var productDto = productDtosByOrderItemId[item.Id];
var isMeasurable = productDto.IsMeasurable;
//var (presetPriceInclTax, _) = await _taxService.GetProductPriceAsync(product, finalPrice, true, customer);
//var (presetPriceExclTax, _) = await _taxService.GetProductPriceAsync(product, finalPrice, false, customer);
//model.UnitPriceExclTax = presetPriceExclTax;
//model.UnitPriceInclTax = presetPriceInclTax;
//model.Quantity = item.Quantity;
//model.SubTotalExclTax = presetPriceExclTax;
//model.SubTotalInclTax = presetPriceInclTax;
//if (productDtosById.TryGetValue(item.Id, out var productDto))
var orderItem = new OrderItem
{
var orderItem = new OrderItem
{
OrderId = order.Id,
ProductId = item.Id,
Quantity = item.Quantity,
UnitPriceInclTax = item.Price,
UnitPriceExclTax = item.Price,
PriceInclTax = item.Price * item.Quantity,
PriceExclTax = item.Price * item.Quantity,
OriginalProductCost = product.ProductCost,
AttributeDescription = string.Empty,
AttributesXml = string.Empty,
DiscountAmountInclTax = 0,
DiscountAmountExclTax = 0
};
await _orderService.InsertOrderItemAsync(orderItem);
OrderId = order.Id,
ProductId = item.Id,
Quantity = item.Quantity,
UnitPriceInclTax = item.Price,
UnitPriceExclTax = item.Price,
PriceInclTax = isMeasurable ? 0 : item.Price * item.Quantity,
PriceExclTax = isMeasurable ? 0 : item.Price * item.Quantity,
OriginalProductCost = product.ProductCost,
AttributeDescription = string.Empty,
AttributesXml = string.Empty,
DiscountAmountInclTax = 0,
DiscountAmountExclTax = 0
};
//await _productService.AddStockQuantityHistoryEntryAsync(product, -orderItem.Quantity, product.StockQuantity, 1);
await _productService.AdjustInventoryAsync(product, -orderItem.Quantity, orderItem.AttributesXml, "");
//await _productService.BookReservedInventoryAsync(product, 1, item.Quantity, "");
}
//else _logger.Error($"(productDtosById.TryGetValue(item.Id, out var product) == false); {item}");
order.OrderTotal += orderItem.PriceInclTax;
await _orderService.InsertOrderItemAsync(orderItem);
//await _productService.AddStockQuantityHistoryEntryAsync(product, -orderItem.Quantity, product.StockQuantity, 1);
await _productService.AdjustInventoryAsync(product, -orderItem.Quantity, orderItem.AttributesXml, "");
//await _productService.BookReservedInventoryAsync(product, 1, item.Quantity, "");
}
order.CustomOrderNumber = order.Id.ToString();
order.OrderSubtotalInclTax = order.OrderTotal;
order.OrderSubtotalExclTax = order.OrderTotal;
order.OrderSubTotalDiscountInclTax = order.OrderTotal;
order.OrderSubTotalDiscountExclTax = order.OrderTotal;
await _orderService.UpdateOrderAsync(order);
return true;
});

View File

@ -345,6 +345,14 @@
Width = "80"
}
};
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.IsMeasurable))
{
Title = T("Admin.Orders.Fields.IsMeasurable").Text,
Width = "100",
Render = new RenderCustom("renderColumnIsMeasurable"),
ClassName = NopColumnClassDefaults.CenterAll
});
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.IsMeasured))
{
Title = T("Admin.Orders.Fields.IsMeasured").Text,
@ -352,6 +360,7 @@
Render = new RenderCustom("renderColumnIsMeasurable"),
ClassName = NopColumnClassDefaults.CenterAll
});
gridModel.ColumnCollection.Add(new ColumnProperty(nameof(IOrderDto.DateOfReceipt))
{
Title = T("Admin.Orders.Fields.PickupDate").Text,

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Common;
@ -20,12 +21,15 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Components
private readonly FruitBankAttributeService _fruitBankAttributeService;
private readonly IWorkContext _workContext;
private readonly IStoreContext _storeContext;
private FruitBankDbContext _dbContext;
public OrderAttributesViewComponent(FruitBankAttributeService fruitBankAttributeService, IWorkContext workContext, IStoreContext storeContext)
public OrderAttributesViewComponent(FruitBankDbContext dbContext, FruitBankAttributeService fruitBankAttributeService, IWorkContext workContext, IStoreContext storeContext)
{
_workContext = workContext;
_storeContext = storeContext;
_fruitBankAttributeService = fruitBankAttributeService;
_dbContext= dbContext;
}
public async Task<IViewComponentResult> InvokeAsync(string widgetZone, object additionalData)
@ -36,19 +40,23 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Components
if (model.OrderId > 0)
{
var orderPickupAttributeValue = await _fruitBankAttributeService.GetGenericAttributeValueAsync<Order, DateTime?>(model.OrderId, nameof(IOrderDto.DateOfReceipt));
var orderMeasurableAttributeValue = await _fruitBankAttributeService.GetGenericAttributeValueAsync<Order, bool>(model.OrderId, nameof(IMeasurable.IsMeasurable));
var orderDto = await _dbContext.OrderDtos.GetByIdAsync(model.OrderId, true);
model.IsMeasurable = orderMeasurableAttributeValue;
if(orderPickupAttributeValue.HasValue && orderPickupAttributeValue.Value != DateTime.MinValue)
{
model.DateOfReceipt = orderPickupAttributeValue;
}
else
{
model.DateOfReceipt = null;
}
model.IsMeasurable = orderDto.IsMeasurable;
model.DateOfReceipt = orderDto.DateOfReceipt;
//var orderPickupAttributeValue = await _fruitBankAttributeService.GetGenericAttributeValueAsync<Order, DateTime?>(model.OrderId, nameof(IOrderDto.DateOfReceipt));
//if (orderPickupAttributeValue.HasValue && orderPickupAttributeValue.Value != DateTime.MinValue)
//{
// model.DateOfReceipt = orderPickupAttributeValue;
//}
//else
//{
// model.DateOfReceipt = null;
//}
}
return View("~/Plugins/Misc.FruitBankPlugin/Views/OrderAttributes.cshtml", model);
}
}

View File

@ -433,6 +433,9 @@ public class FruitBankDbContext : MgDbContextBase,
if (!orderItemDto.IsMeasurable) continue;
var finalPriceInclTax = decimal.Round(orderItemDto.UnitPriceInclTax * orderItemDto.Quantity, 0);
var finalPriceExclTax = decimal.Round(orderItemDto.UnitPriceExclTax * orderItemDto.Quantity, 0);
var gaNetWeight = CommonHelper.To<double>(orderItemDto.GenericAttributes.FirstOrDefault(x => x.Key == nameof(IMeasuringNetWeight.NetWeight))?.Value ?? "0");
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<OrderItem, double>

View File

@ -34,7 +34,7 @@ public class OrderDtoDbTable : MgDtoDbTableBase<OrderDto, Order>
=> GetAll(loadRelations).Where(o => o.OrderStatusId == (int)orderStatus);
public IQueryable<OrderDto> GetAllForMeasuring(bool loadRelations = true)
=> GetAllByOrderStatus(OrderStatus.Pending, loadRelations).Where(o => o.DateOfReceipt != null);
=> GetAllByOrderStatus(OrderStatus.Pending, loadRelations).Where(o => o.GenericAttributes.Any(ga => ga.Key == nameof(OrderDto.DateOfReceipt)));
public IQueryable<OrderDto> GetAllByIds(IEnumerable<int> orderIds, bool loadRelations = true) => GetAll(loadRelations).Where(o => orderIds.Contains(o.Id));
}

View File

@ -11,18 +11,19 @@ using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Events;
using Mango.Nop.Core.Extensions;
using Nop.Core.Domain.Orders;
using Nop.Services.Catalog;
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.EventConsumers;
public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IEnumerable<IAcLogWriterBase> logWriters) :
MgEventConsumerBase(ctx, httpContextAcc, logWriters),
public class FruitBankEventConsumer :
MgEventConsumerBase,
IConsumer<EntityDeletedEvent<Shipping>>,
IConsumer<EntityInsertedEvent<ShippingItem>>,
IConsumer<EntityUpdatedEvent<ShippingItem>>,
IConsumer<EntityInsertedEvent<ShippingItem>>,
IConsumer<EntityUpdatedEvent<ShippingItem>>,
IConsumer<EntityDeletedEvent<ShippingItem>>,
IConsumer<EntityInsertedEvent<ShippingDocument>>,
IConsumer<EntityUpdatedEvent<ShippingDocument>>,
IConsumer<EntityDeletedEvent<ShippingDocument>>,
IConsumer<EntityInsertedEvent<ShippingDocument>>,
IConsumer<EntityUpdatedEvent<ShippingDocument>>,
IConsumer<EntityDeletedEvent<ShippingDocument>>,
IConsumer<EntityInsertedEvent<ShippingItemPallet>>,
IConsumer<EntityUpdatedEvent<ShippingItemPallet>>,
IConsumer<EntityDeletedEvent<ShippingItemPallet>>,
@ -30,6 +31,20 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
IConsumer<EntityInsertedEvent<OrderItem>>,
IConsumer<EntityUpdatedEvent<OrderItem>>
{
private CustomPriceCalculationService _customPriceCalculationService;
private readonly FruitBankDbContext _ctx;
private readonly FruitBankAttributeService _fruitBankAttributeService;
public FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, IPriceCalculationService customPriceCalculationService, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IEnumerable<IAcLogWriterBase> logWriters) : base(ctx, httpContextAcc, logWriters)
{
_ctx = ctx;
_fruitBankAttributeService = fruitBankAttributeService;
_customPriceCalculationService = customPriceCalculationService as CustomPriceCalculationService;
}
public override async Task HandleEventAsync(EntityUpdatedEvent<Product> eventMessage)
{
var product = await CheckAndUpdateProductManageInventoryMethodToManageStock(eventMessage.Entity);
@ -40,14 +55,14 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
if (saveProductCustomAttributesResult is { IsMeasurableChanged: true, IsMeasurable: not null })
{
var shippingItems = await ctx.ShippingItems.Table
var shippingItems = await _ctx.ShippingItems.Table
.Where(si => si.ProductId == product.Id && !si.IsMeasured && si.IsMeasurable != saveProductCustomAttributesResult.IsMeasurable.Value)
.ToListAsync();
if (shippingItems.Count > 0)
{
foreach (var shippingItem in shippingItems) shippingItem.IsMeasurable = saveProductCustomAttributesResult.IsMeasurable.Value;
await ctx.ShippingItems.UpdateAsync(shippingItems, false);
await _ctx.ShippingItems.UpdateAsync(shippingItems, false);
}
}
@ -68,7 +83,7 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
/// <param name="product"></param>
/// <returns>IsMeasureable</returns>
/// <exception cref="Exception"></exception>
private async Task<(bool IsMeasurableChanged, bool? IsMeasurable)> SaveProductCustomAttributesAsync(Product product)
{
if (product == null) return (false, null);
@ -85,7 +100,7 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
try
{
var productDto = product.Id > 0 ? await ctx.ProductDtos.GetByIdAsync(product.Id, false) : null;
var productDto = product.Id > 0 ? await _ctx.ProductDtos.GetByIdAsync(product.Id, false) : null;
//IsMeasurable
isMeasurable = form[nameof(IMeasurable.IsMeasurable)].ToString().Contains("true");
@ -93,7 +108,7 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
if (productDtoIsMeasurable == null || productDtoIsMeasurable.Value != isMeasurable.Value)
{
await fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, bool>(product.Id, nameof(IMeasurable.IsMeasurable), isMeasurable.Value);
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, bool>(product.Id, nameof(IMeasurable.IsMeasurable), isMeasurable.Value);
isMeasurableChanged = true;
}
@ -102,21 +117,21 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
var productDtoNetWeight = productDto?.GenericAttributes.GetValueOrNull<double>(nameof(IMeasuringNetWeight.NetWeight));
if (productDtoNetWeight == null || double.Round(productDtoNetWeight.Value, 1) != netWeight)
await fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, double>(product.Id, nameof(IMeasuringNetWeight.NetWeight), netWeight);
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, double>(product.Id, nameof(IMeasuringNetWeight.NetWeight), netWeight);
//Tára
var tare = double.Round(CommonHelper.To<double>(form[nameof(ITare.Tare)].ToString()), 1);
if (tare < 0) throw new Exception($"FruitBankEventConsumer->SaveProductCustomAttributesAsync(); (tare < 0); productId: {product.Id}; tare: {tare}");
if (productDto == null || productDto.Tare != tare)
await fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, double>(product.Id, nameof(ITare.Tare), tare);
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, double>(product.Id, nameof(ITare.Tare), tare);
//IncomingQuantity
var incomingQuantity = CommonHelper.To<int>(form[nameof(IIncomingQuantity.IncomingQuantity)].ToString());
if (incomingQuantity < 0) throw new Exception($"FruitBankEventConsumer->SaveProductCustomAttributesAsync(); (incomingQuantity < 0); productId: {product.Id}; incomingQuantity: {incomingQuantity}");
if (productDto == null || productDto.IncomingQuantity != incomingQuantity)
await fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, int>(product.Id, nameof(IIncomingQuantity.IncomingQuantity), incomingQuantity);
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, int>(product.Id, nameof(IIncomingQuantity.IncomingQuantity), incomingQuantity);
}
catch (Exception ex)
{
@ -151,8 +166,8 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
private async Task UpdateShippingItemMeasuringValuesAsync(ShippingItemPallet shippingItemPallet)
{
var shippingItem = await ctx.ShippingItems.GetByIdAsync(shippingItemPallet.ShippingItemId, false);
await ctx.UpdateShippingItemAsync(shippingItem);
var shippingItem = await _ctx.ShippingItems.GetByIdAsync(shippingItemPallet.ShippingItemId, false);
await _ctx.UpdateShippingItemAsync(shippingItem);
}
public async Task HandleEventAsync(EntityInsertedEvent<ShippingItem> eventMessage)
@ -183,13 +198,13 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
private async Task UpdateShippingDocumentIsAllMeasuredAsync(ShippingItem shippingItem)
{
//TODO: where: && IsMeasurable!!!! - J.
var isAllShippingItemMeasured = ctx.ShippingItems.GetAll(false).Where(si => si.ShippingDocumentId == shippingItem.ShippingDocumentId).All(si => si.IsMeasured);
var shippingDocument = await ctx.ShippingDocuments.GetByIdAsync(shippingItem.ShippingDocumentId);
var isAllShippingItemMeasured = _ctx.ShippingItems.GetAll(false).Where(si => si.ShippingDocumentId == shippingItem.ShippingDocumentId).All(si => si.IsMeasured);
var shippingDocument = await _ctx.ShippingDocuments.GetByIdAsync(shippingItem.ShippingDocumentId);
if (shippingDocument != null && shippingDocument.IsAllMeasured != isAllShippingItemMeasured)
{
shippingDocument.IsAllMeasured = isAllShippingItemMeasured;
await ctx.ShippingDocuments.UpdateAsync(shippingDocument);
await _ctx.ShippingDocuments.UpdateAsync(shippingDocument);
}
}
@ -209,13 +224,13 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
private async Task UpdateShippingIsAllMeasuredAsync(ShippingDocument shippingDocument)
{
var isAllShippingDocumentMeasured = ctx.ShippingDocuments.GetAll(false).Where(si => si.ShippingId == shippingDocument.ShippingId).All(si => si.IsAllMeasured);
var shipping = await ctx.Shippings.GetByIdAsync(shippingDocument.ShippingId);
var isAllShippingDocumentMeasured = _ctx.ShippingDocuments.GetAll(false).Where(si => si.ShippingId == shippingDocument.ShippingId).All(si => si.IsAllMeasured);
var shipping = await _ctx.Shippings.GetByIdAsync(shippingDocument.ShippingId);
if (shipping != null && shipping.IsAllMeasured != isAllShippingDocumentMeasured)
{
shipping.IsAllMeasured = isAllShippingDocumentMeasured;
await ctx.Shippings.UpdateAsync(shipping);
await _ctx.Shippings.UpdateAsync(shipping);
}
}
@ -227,46 +242,43 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAcc, FruitBa
{
Logger.Info($"HandleEventAsync->EntityDeletedEvent<Shipping>; id: {eventMessage.Entity.Id}");
await ctx.ShippingDocuments.DeleteAsync(sd => sd.ShippingId == eventMessage.Entity.Id, true);
await _ctx.ShippingDocuments.DeleteAsync(sd => sd.ShippingId == eventMessage.Entity.Id, true);
}
public async Task HandleEventAsync(EntityDeletedEvent<ShippingDocument> eventMessage)
{
Logger.Info($"HandleEventAsync->EntityDeletedEvent<ShippingDocument>; id: {eventMessage.Entity.Id}");
await ctx.ShippingItems.DeleteAsync(si => si.ShippingDocumentId == eventMessage.Entity.Id, true);
await _ctx.ShippingItems.DeleteAsync(si => si.ShippingDocumentId == eventMessage.Entity.Id, true);
}
public async Task HandleEventAsync(EntityDeletedEvent<ShippingItem> eventMessage)
{
Logger.Info($"HandleEventAsync->EntityDeletedEvent<ShippingItem>; id: {eventMessage.Entity.Id}");
await ctx.ShippingItemPallets.DeleteAsync(sp => sp.ShippingItemId == eventMessage.Entity.Id, false);
await _ctx.ShippingItemPallets.DeleteAsync(sp => sp.ShippingItemId == eventMessage.Entity.Id, false);
}
public async Task HandleEventAsync(EntityUpdatedEvent<OrderItem> eventMessage) => await CheckAndUpdateOrderItemFinalPrices(eventMessage.Entity);
public async Task HandleEventAsync(EntityInsertedEvent<OrderItem> eventMessage) => await CheckAndUpdateOrderItemFinalPrices(eventMessage.Entity);
private async Task CheckAndUpdateOrderItemFinalPrices(OrderItem orderItem)
public async Task HandleEventAsync(EntityUpdatedEvent<OrderItem> eventMessage)
{
Logger.Info($"HandleEventAsync->CheckAndUpdateOrderItemFinalPrices; orderItem.Id: {orderItem.Id}");
var finalPriceInclTax = decimal.Round(orderItem.UnitPriceInclTax * orderItem.Quantity, 0);
var finalPriceExclTax = decimal.Round(orderItem.UnitPriceExclTax * orderItem.Quantity, 0);
if (orderItem.PriceInclTax != finalPriceInclTax || orderItem.PriceExclTax != finalPriceExclTax)
//await _customPriceCalculationService.CheckAndUpdateOrderItemFinalPricesAsync(eventMessage.Entity);
if (await _customPriceCalculationService.CheckAndUpdateOrderItemFinalPricesAsync(eventMessage.Entity))
{
Logger.Error($"HandleEventAsync->CheckAndUpdateOrderItemFinalPrices; " +
$"orderItem.PriceInclTax({orderItem.PriceInclTax}) != finalPriceInclTax({finalPriceInclTax}) || " +
$"orderItem.PriceExclTax({orderItem.PriceExclTax}) != finalPriceExclTax({finalPriceExclTax})");
orderItem.PriceInclTax = finalPriceInclTax;
orderItem.PriceExclTax = finalPriceExclTax;
await ctx.OrderItems.UpdateAsync(orderItem, false);
var order = await _ctx.Orders.GetByIdAsync(eventMessage.Entity.OrderId);
await _customPriceCalculationService.CheckAndUpdateOrderTotalPrice(order);
}
}
#endregion Delete
}
public async Task HandleEventAsync(EntityInsertedEvent<OrderItem> eventMessage)
{
//await _customPriceCalculationService.CheckAndUpdateOrderItemFinalPricesAsync(eventMessage.Entity);
if (await _customPriceCalculationService.CheckAndUpdateOrderItemFinalPricesAsync(eventMessage.Entity))
{
var order = await _ctx.Orders.GetByIdAsync(eventMessage.Entity.OrderId);
await _customPriceCalculationService.CheckAndUpdateOrderTotalPrice(order);
}
}
}
#endregion Delete

View File

@ -1,29 +1,35 @@
using Nop.Core.Caching;
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;
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;
using Nop.Services.Logging;
using Nop.Core.Domain.Directory;
using Nop.Services.Directory;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Stores;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
public class CustomPriceCalculationService : PriceCalculationService
{
private readonly IRepository<Product> _productRepository;
private FruitBankDbContext _dbContext;
private readonly IProductAttributeService _productAttributeService;
private readonly ISpecificationAttributeService _specificationAttributeService;
private readonly ILocalizationService _localizationService;
private ILogger _logger;
public CustomPriceCalculationService(
IRepository<Product> productRepository,
FruitBankDbContext dbContext,
// inject all base deps
CatalogSettings catalogSettings,
CurrencySettings currencySettings,
@ -40,41 +46,110 @@ public class CustomPriceCalculationService : PriceCalculationService
ILocalizationService localizationService,
IStaticCacheManager cacheManager,
IWorkContext workContext,
ILogger logger)
IEnumerable<IAcLogWriterBase> logWriters)
: base(catalogSettings, currencySettings, categoryService, currencyService, customerService, discountService, manufacturerService,
productAttributeParser, productService,
cacheManager)
{
_productRepository = productRepository;
_logger = new Logger(logWriters.ToArray());
_dbContext = dbContext;
// assign all base deps to local private vars if needed
_productAttributeService = productAttributeService;
_specificationAttributeService = specificationAttributeService;
_localizationService = localizationService;
}
public decimal CalculateOrderItemFinalPrice(OrderItemDto orderItemDto, decimal unitPrice, int quantity)
=> decimal.Round(unitPrice * (orderItemDto.IsMeasurable ? (decimal)orderItemDto.NetWeight : quantity), 0);
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 async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItem orderItem)
{
var orderItemDto = await _dbContext.OrderItemDtos.GetByIdAsync(orderItem.Id, true);
return await CheckAndUpdateOrderItemFinalPricesAsync(orderItem, orderItemDto);
}
public async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItemDto orderItemDto)
{
var orderItem = await _dbContext.OrderItems.GetByIdAsync(orderItemDto.Id);
return await CheckAndUpdateOrderItemFinalPricesAsync(orderItem, orderItemDto);
}
public async Task<bool> CheckAndUpdateOrderItemFinalPricesAsync(OrderItem orderItem, OrderItemDto orderItemDto)
{
_logger.Info($"CustomPriceCalculationService->CheckAndUpdateOrderItemFinalPricesAsync; orderItem.Id: {orderItem.Id}");
var productAttributeMappings = await _specificationAttributeService.GetProductSpecificationAttributesAsync(product.Id);
//Product Attributes
foreach (var pam in productAttributeMappings)
var finalPriceInclTax = CalculateOrderItemFinalPrice(orderItemDto, orderItem.UnitPriceInclTax, orderItem.Quantity);
var finalPriceExclTax = CalculateOrderItemFinalPrice(orderItemDto, orderItem.UnitPriceExclTax, orderItem.Quantity);
if (orderItem.PriceInclTax == finalPriceInclTax && orderItem.PriceExclTax == finalPriceExclTax) return false;
_logger.Error($"CustomPriceCalculationService->CheckAndUpdateOrderItemFinalPricesAsync; " +
$"orderItem.PriceInclTax({orderItem.PriceInclTax}) != finalPriceInclTax({finalPriceInclTax}) || " +
$"orderItem.PriceExclTax({orderItem.PriceExclTax}) != finalPriceExclTax({finalPriceExclTax})");
orderItem.PriceInclTax = finalPriceInclTax;
orderItem.PriceExclTax = finalPriceExclTax;
await _dbContext.OrderItems.UpdateAsync(orderItem, false);
return true;
}
public async Task CheckAndUpdateOrderTotalPrice(Order order)
{
var prevOrderTotal = order.OrderTotal;
var orderItemDtos = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id).ToListAsync();
order.OrderTotal = 0;
foreach (var itemDto in orderItemDtos)
{
//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, []);
}
await CheckAndUpdateOrderItemFinalPricesAsync(itemDto);
order.OrderTotal += itemDto.PriceInclTax;
}
if (order.OrderTotal == prevOrderTotal) return;
_logger.Error($"HandleEventAsync->CheckAndUpdateOrderItemFinalPrices; order.OrderTotal({order.OrderTotal}) == prevOrderTotal({prevOrderTotal})");
order.OrderSubtotalInclTax = order.OrderTotal;
order.OrderSubtotalExclTax = order.OrderTotal;
order.OrderSubTotalDiscountInclTax = order.OrderTotal;
order.OrderSubTotalDiscountExclTax = order.OrderTotal;
await _dbContext.Orders.UpdateAsync(order);
}
//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);
if (productDto.IsMeasurable)
{
return (0, 0, 0m, []);
//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 await base.GetFinalPriceAsync(product, customer, store, overriddenProductPrice, additionalCharge, includeDiscounts, quantity, rentalStartDate, rentalEndDate);
}
}