Merge
This commit is contained in:
commit
b2af6b0bdc
|
|
@ -3,6 +3,7 @@ using AyCode.Core.Loggers;
|
||||||
using AyCode.Services.Server.SignalRs;
|
using AyCode.Services.Server.SignalRs;
|
||||||
using AyCode.Services.SignalRs;
|
using AyCode.Services.SignalRs;
|
||||||
using AyCode.Utils.Extensions;
|
using AyCode.Utils.Extensions;
|
||||||
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
using FluentMigrator.Runner.Generators.Base;
|
using FluentMigrator.Runner.Generators.Base;
|
||||||
using FruitBank.Common.Dtos;
|
using FruitBank.Common.Dtos;
|
||||||
using FruitBank.Common.Entities;
|
using FruitBank.Common.Entities;
|
||||||
|
|
@ -18,10 +19,12 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Nop.Core;
|
using Nop.Core;
|
||||||
|
using Nop.Core.Domain.Catalog;
|
||||||
using Nop.Core.Domain.Customers;
|
using Nop.Core.Domain.Customers;
|
||||||
using Nop.Core.Domain.Orders;
|
using Nop.Core.Domain.Orders;
|
||||||
using Nop.Core.Domain.Payments;
|
using Nop.Core.Domain.Payments;
|
||||||
using Nop.Core.Domain.Shipping;
|
using Nop.Core.Domain.Shipping;
|
||||||
|
using Nop.Core.Domain.Stores;
|
||||||
using Nop.Core.Domain.Tax;
|
using Nop.Core.Domain.Tax;
|
||||||
using Nop.Core.Events;
|
using Nop.Core.Events;
|
||||||
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order;
|
using Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Order;
|
||||||
|
|
@ -50,8 +53,10 @@ using Nop.Web.Framework.Controllers;
|
||||||
using Nop.Web.Framework.Mvc.Filters;
|
using Nop.Web.Framework.Mvc.Filters;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
using static Nop.Services.Security.StandardPermission;
|
||||||
|
|
||||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
{
|
{
|
||||||
|
|
@ -513,101 +518,164 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
ShippingAddressId = customer.ShippingAddressId,
|
ShippingAddressId = customer.ShippingAddressId,
|
||||||
PaymentMethodSystemName = "Payments.CheckMoneyOrder", // Default payment method
|
PaymentMethodSystemName = "Payments.CheckMoneyOrder", // Default payment method
|
||||||
CustomerCurrencyCode = "HUF", // TODO: GET Default currency - A.
|
CustomerCurrencyCode = "HUF", // TODO: GET Default currency - A.
|
||||||
|
|
||||||
|
OrderTotal = 0,
|
||||||
|
OrderSubtotalInclTax = 0,
|
||||||
|
OrderSubtotalExclTax = 0,
|
||||||
|
OrderSubTotalDiscountInclTax = 0,
|
||||||
|
OrderSubTotalDiscountExclTax = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
//var productDtosById = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(op => op.Id)).ToDictionaryAsync(p => p.Id, prodDto => prodDto);
|
//var productDtosById = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(op => op.Id)).ToDictionaryAsync(p => p.Id, prodDto => prodDto);
|
||||||
var store = _storeContext.GetCurrentStore();
|
var store = await _storeContext.GetCurrentStoreAsync();
|
||||||
var productDtosByOrderItemId = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(x => x.Id).ToArray()).ToDictionaryAsync(k => k.Id, v => v);
|
var admin = await _workContext.GetCurrentCustomerAsync();
|
||||||
|
|
||||||
var adminCustomer = await _workContext.GetCurrentCustomerAsync();
|
|
||||||
|
|
||||||
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
||||||
{
|
{
|
||||||
await _orderService.InsertOrderAsync(order);
|
await _orderService.InsertOrderAsync(order);
|
||||||
|
|
||||||
order.OrderTotal = 0;
|
|
||||||
|
|
||||||
foreach (var item in orderProducts)
|
|
||||||
{
|
|
||||||
var product = await _productService.GetProductByIdAsync(item.Id);
|
|
||||||
if (product == null)
|
|
||||||
{
|
|
||||||
var errorText = $"product == null; productId: {item.Id};";
|
|
||||||
|
|
||||||
_logger.Error($"{errorText}");
|
|
||||||
throw new Exception($"{errorText}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var productDto = productDtosByOrderItemId[item.Id];
|
|
||||||
var isMeasurable = productDto.IsMeasurable;
|
|
||||||
|
|
||||||
if ((product.StockQuantity + productDto.IncomingQuantity) - item.Quantity < 0)
|
|
||||||
{
|
|
||||||
var errorText = $"((product.StockQuantity + productDto.IncomingQuantity) - item.Quantity < 0); productId: {product.Id}; (product.StockQuantity + productDto.IncomingQuantity) - item.Quantity: {(product.StockQuantity + productDto.IncomingQuantity) - item.Quantity}";
|
|
||||||
|
|
||||||
_logger.Error($"{errorText}");
|
|
||||||
throw new Exception($"{errorText}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var valami = await _priceCalculationService.GetFinalPriceAsync(product, customer, store, includeDiscounts: true);
|
|
||||||
var unitPrice = valami.finalPrice;
|
|
||||||
|
|
||||||
// Calculate tax
|
|
||||||
var (unitPriceInclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPrice, true, customer);
|
|
||||||
var (unitPriceExclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPrice, false, customer);
|
|
||||||
|
|
||||||
|
|
||||||
var orderItem = new OrderItem
|
|
||||||
{
|
|
||||||
OrderId = order.Id,
|
|
||||||
ProductId = item.Id,
|
|
||||||
Quantity = item.Quantity,
|
|
||||||
|
|
||||||
UnitPriceInclTax = unitPriceInclTaxValue,
|
|
||||||
UnitPriceExclTax = unitPriceExclTaxValue,
|
|
||||||
|
|
||||||
PriceInclTax = isMeasurable ? 0 : unitPriceInclTaxValue * item.Quantity,
|
|
||||||
PriceExclTax = isMeasurable ? 0 : unitPriceExclTaxValue * item.Quantity,
|
|
||||||
|
|
||||||
OriginalProductCost = await _priceCalculationService.GetProductCostAsync(product, null),
|
|
||||||
|
|
||||||
AttributeDescription = string.Empty,
|
|
||||||
AttributesXml = string.Empty,
|
|
||||||
DiscountAmountInclTax = 0,
|
|
||||||
DiscountAmountExclTax = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
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, $"Rendelés létrehozva: #{order.Id}, rendelés tétel: #{orderItem.Id}, Felhasználó: #{adminCustomer.Id}");
|
|
||||||
//await _productService.BookReservedInventoryAsync(product, 1, item.Quantity, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
order.CustomOrderNumber = order.Id.ToString();
|
order.CustomOrderNumber = order.Id.ToString();
|
||||||
|
|
||||||
order.OrderSubtotalInclTax = order.OrderTotal;
|
await AddOrderItemsThenUpdateOrder(order, orderProducts, true, customer, store, admin);
|
||||||
order.OrderSubtotalExclTax = order.OrderTotal;
|
|
||||||
order.OrderSubTotalDiscountInclTax = order.OrderTotal;
|
|
||||||
order.OrderSubTotalDiscountExclTax = order.OrderTotal;
|
|
||||||
|
|
||||||
await _orderService.UpdateOrderAsync(order);
|
|
||||||
|
|
||||||
//var orderDto = await _dbContext.OrderDtos.GetByIdAsync(order.Id, true);
|
|
||||||
//await _sendToClient.SendMeasuringNotification("Módosult a rendelés, mérjétek újra!", orderDto);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (transactionSuccess) return RedirectToAction("Edit", "Order", new { id = order.Id });
|
if (transactionSuccess)
|
||||||
|
{
|
||||||
|
//var orderDto = await _dbContext.OrderDtos.GetByIdAsync(order.Id, true);
|
||||||
|
//await _sendToClient.SendMeasuringNotification("Módosult a rendelés, mérjétek újra!", orderDto);
|
||||||
|
|
||||||
|
return RedirectToAction("Edit", "Order", new { id = order.Id });
|
||||||
|
}
|
||||||
|
|
||||||
_logger.Error($"(transactionSuccess == false)");
|
_logger.Error($"(transactionSuccess == false)");
|
||||||
return RedirectToAction("Error", new { id = order.Id });
|
return RedirectToAction("Error", new { id = order.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OrderProductItem
|
private async Task AddOrderItemsThenUpdateOrder<TOrderProductItem>(Order order, IReadOnlyList<TOrderProductItem> orderProductItems, bool unitPricesIncludeDiscounts, Customer customer = null, Store store = null, Customer admin = null)
|
||||||
|
where TOrderProductItem : IOrderProductItemBase
|
||||||
{
|
{
|
||||||
|
store ??= await _storeContext.GetCurrentStoreAsync();
|
||||||
|
admin ??= await _workContext.GetCurrentCustomerAsync();
|
||||||
|
customer ??= await _workContext.GetCurrentCustomerAsync();
|
||||||
|
|
||||||
|
var helperProductDtosByOrderItemId = await _dbContext.ProductDtos.GetAllByIds(orderProductItems.Select(x => x.Id).ToArray()).ToDictionaryAsync(k => k.Id, v => v);
|
||||||
|
|
||||||
|
foreach (var orderProductItem in orderProductItems)
|
||||||
|
{
|
||||||
|
var product = await _productService.GetProductByIdAsync(orderProductItem.Id);
|
||||||
|
if (product == null)
|
||||||
|
{
|
||||||
|
_logger.Warning($"Product with ID {orderProductItem.Id} not found");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//var errorText = $"product == null; productId: {item.Id};";
|
||||||
|
|
||||||
|
//_logger.Error($"{errorText}");
|
||||||
|
//throw new Exception($"{errorText}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//var stockQuantity = await _productService.GetTotalStockQuantityAsync(product);
|
||||||
|
var productDto = helperProductDtosByOrderItemId[orderProductItem.Id];
|
||||||
|
var isMeasurable = productDto.IsMeasurable;
|
||||||
|
|
||||||
|
if ((product.StockQuantity + productDto.IncomingQuantity) - orderProductItem.Quantity < 0)
|
||||||
|
{
|
||||||
|
//errorMessage = $"Nem elérhető készleten!";
|
||||||
|
var errorText = $"((product.StockQuantity + productDto.IncomingQuantity) - item.Quantity < 0); productId: {product.Id}; (product.StockQuantity + productDto.IncomingQuantity) - item.Quantity: {(product.StockQuantity + productDto.IncomingQuantity) - orderProductItem.Quantity}";
|
||||||
|
|
||||||
|
_logger.Error($"{errorText}");
|
||||||
|
throw new Exception($"{errorText}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var orderItem = await CreateOrderItem(product, order, orderProductItem, isMeasurable, unitPricesIncludeDiscounts, customer, store);
|
||||||
|
|
||||||
|
await _orderService.InsertOrderItemAsync(orderItem);
|
||||||
|
await _productService.AdjustInventoryAsync(product, -orderItem.Quantity, orderItem.AttributesXml, string.Format(await _localizationService.GetResourceAsync("Admin.StockQuantityHistory.Messages.PlaceOrder"), order.Id));
|
||||||
|
|
||||||
|
var priceCalculation = await _priceCalculationService.GetFinalPriceAsync(product, customer, store, includeDiscounts: false);
|
||||||
|
var unitPriceInclTaxValue = priceCalculation.finalPrice;
|
||||||
|
|
||||||
|
var (unitPriceExclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPriceInclTaxValue, false, customer);
|
||||||
|
|
||||||
|
order.OrderSubtotalInclTax += unitPriceInclTaxValue * orderItem.Quantity;
|
||||||
|
order.OrderSubtotalExclTax += unitPriceExclTaxValue * orderItem.Quantity;
|
||||||
|
|
||||||
|
order.OrderSubTotalDiscountInclTax += order.OrderSubtotalInclTax - orderItem.PriceInclTax;
|
||||||
|
order.OrderSubTotalDiscountExclTax += order.OrderSubtotalExclTax - orderItem.PriceExclTax;
|
||||||
|
|
||||||
|
//order.OrderTax
|
||||||
|
//order.TaxRates
|
||||||
|
|
||||||
|
order.OrderTotal += orderItem.PriceInclTax + order.OrderShippingInclTax + order.PaymentMethodAdditionalFeeInclTax;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _orderService.UpdateOrderAsync(order);
|
||||||
|
|
||||||
|
await InsertOrderNoteAsync(order.Id, false, $"Products added {orderProductItems.Count} item to order by {admin.FirstName} {admin.LastName}, (CustomerId: {admin.Id})");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<OrderItem> CreateOrderItem<TOrderProductItem>(Product product, Order order, TOrderProductItem orderProductItem, bool isMeasurable, bool unitPricesIncludeDiscounts, Customer customer = null, Store store = null)
|
||||||
|
where TOrderProductItem : IOrderProductItemBase
|
||||||
|
{
|
||||||
|
if (product.Id != orderProductItem.Id)
|
||||||
|
throw new Exception($"CustomOrderController->CreateOrderItem; (product.Id != orderProductItem.Id)");
|
||||||
|
|
||||||
|
store ??= await _storeContext.GetCurrentStoreAsync();
|
||||||
|
customer ??= await _workContext.GetCurrentCustomerAsync();
|
||||||
|
|
||||||
|
var priceCalculation = await _priceCalculationService.GetFinalPriceAsync(product, customer, store, includeDiscounts: unitPricesIncludeDiscounts);
|
||||||
|
var unitPriceInclTaxValue = priceCalculation.finalPrice;
|
||||||
|
|
||||||
|
// Calculate tax
|
||||||
|
//var (unitPriceInclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPrice, true, customer);
|
||||||
|
var (unitPriceExclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPriceInclTaxValue, false, customer);
|
||||||
|
|
||||||
|
return new OrderItem
|
||||||
|
{
|
||||||
|
OrderId = order.Id,
|
||||||
|
ProductId = orderProductItem.Id,
|
||||||
|
Quantity = orderProductItem.Quantity,
|
||||||
|
|
||||||
|
OrderItemGuid = Guid.NewGuid(),
|
||||||
|
|
||||||
|
UnitPriceInclTax = unitPriceInclTaxValue,
|
||||||
|
UnitPriceExclTax = unitPriceExclTaxValue,
|
||||||
|
|
||||||
|
PriceInclTax = isMeasurable ? 0 : unitPriceInclTaxValue * orderProductItem.Quantity,
|
||||||
|
PriceExclTax = isMeasurable ? 0 : unitPriceExclTaxValue * orderProductItem.Quantity,
|
||||||
|
|
||||||
|
OriginalProductCost = await _priceCalculationService.GetProductCostAsync(product, null),
|
||||||
|
|
||||||
|
AttributeDescription = string.Empty,
|
||||||
|
AttributesXml = string.Empty,
|
||||||
|
|
||||||
|
DiscountAmountInclTax = decimal.Zero,
|
||||||
|
DiscountAmountExclTax = decimal.Zero,
|
||||||
|
|
||||||
|
DownloadCount = 0,
|
||||||
|
IsDownloadActivated = false,
|
||||||
|
LicenseDownloadId = 0,
|
||||||
|
ItemWeight = product.Weight * orderProductItem.Quantity,
|
||||||
|
RentalStartDateUtc = null,
|
||||||
|
RentalEndDateUtc = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IOrderProductItemBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ProductId
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OrderProductItem : IOrderProductItemBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ProductId
|
||||||
|
/// </summary>
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Sku { get; set; }
|
public string Sku { get; set; }
|
||||||
|
|
@ -616,10 +684,24 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{nameof(OrderProductItem)} [Id: {Id}; Name: {Name}; Sku: {Sku}; Quantity: {Quantity}; Price: {Price}]";
|
return $"{nameof(OrderProductItem)} [ProductId: {Id}; Name: {Name}; Sku: {Sku}; Quantity: {Quantity}; Price: {Price}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AddProductModel : OrderProductItem
|
||||||
|
{
|
||||||
|
///// <summary>
|
||||||
|
///// ProductId
|
||||||
|
///// </summary>
|
||||||
|
//public int Id { get; set; }
|
||||||
|
//public string Name { get; set; }
|
||||||
|
//public string Sku { get; set; }
|
||||||
|
//public int Quantity { get; set; }
|
||||||
|
//public decimal Price { get; set; }
|
||||||
|
public int StockQuantity { get; set; }
|
||||||
|
public int IncomingQuantity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
//private static OrderItem CreateOrderItem(ProductToAuctionMapping productToAuction, Order order, decimal orderTotal)
|
//private static OrderItem CreateOrderItem(ProductToAuctionMapping productToAuction, Order order, decimal orderTotal)
|
||||||
//{
|
//{
|
||||||
// return new OrderItem
|
// return new OrderItem
|
||||||
|
|
@ -662,17 +744,23 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
// };
|
// };
|
||||||
//}
|
//}
|
||||||
|
|
||||||
private static OrderNote CreateOrderNote(Order order, string note)
|
private static OrderNote CreateOrderNote(int orderId, bool displayToCustomer, string note)
|
||||||
{
|
{
|
||||||
return new OrderNote
|
return new OrderNote
|
||||||
{
|
{
|
||||||
CreatedOnUtc = order.CreatedOnUtc,
|
CreatedOnUtc = DateTime.UtcNow,//order.CreatedOnUtc,
|
||||||
DisplayToCustomer = true,
|
DisplayToCustomer = displayToCustomer,
|
||||||
OrderId = order.Id,
|
OrderId = orderId,
|
||||||
Note = note
|
Note = note
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task InsertOrderNoteAsync(int orderId, bool displayToCustomer, string note)
|
||||||
|
{
|
||||||
|
var orderNote = CreateOrderNote(orderId, displayToCustomer, note);
|
||||||
|
return _orderService.InsertOrderNoteAsync(orderNote);
|
||||||
|
}
|
||||||
|
|
||||||
private static string SerializeCustomValuesToXml(Dictionary<string, object> sourceDictionary)
|
private static string SerializeCustomValuesToXml(Dictionary<string, object> sourceDictionary)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(sourceDictionary);
|
ArgumentNullException.ThrowIfNull(sourceDictionary);
|
||||||
|
|
@ -1205,162 +1293,45 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
_logger.Info($"AddProductToOrder - OrderId: {orderId}, ProductsJson: {productsJson}");
|
_logger.Info($"AddProductToOrder - OrderId: {orderId}, ProductsJson: {productsJson}");
|
||||||
|
|
||||||
if (!await _permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_CREATE_EDIT_DELETE))
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_CREATE_EDIT_DELETE))
|
||||||
{
|
|
||||||
return Json(new { success = false, message = "Access denied" });
|
return Json(new { success = false, message = "Access denied" });
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(productsJson))
|
if (string.IsNullOrEmpty(productsJson))
|
||||||
{
|
|
||||||
return Json(new { success = false, message = "No products data received" });
|
return Json(new { success = false, message = "No products data received" });
|
||||||
}
|
|
||||||
|
|
||||||
var order = await _orderService.GetOrderByIdAsync(orderId);
|
var order = await _orderService.GetOrderByIdAsync(orderId);
|
||||||
|
|
||||||
if (order == null || order.Deleted)
|
if (order == null || order.Deleted)
|
||||||
{
|
|
||||||
return Json(new { success = false, message = "Order not found" });
|
return Json(new { success = false, message = "Order not found" });
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize products
|
// Deserialize products
|
||||||
var products = JsonConvert.DeserializeObject<List<AddProductModel>>(productsJson);
|
var products = productsJson.JsonTo<List<AddProductModel>>(); //JsonConvert.DeserializeObject<List<AddProductModel>>(productsJson);
|
||||||
|
|
||||||
if (products == null || !products.Any())
|
if (products == null || products.Count == 0)
|
||||||
{
|
|
||||||
return Json(new { success = false, message = "No products to add" });
|
return Json(new { success = false, message = "No products to add" });
|
||||||
}
|
|
||||||
|
|
||||||
var productDtosByOrderItemId = await _dbContext.ProductDtos.GetAllByIds(products.Select(x => x.Id).ToArray()).ToDictionaryAsync(k => k.Id, v => v);
|
|
||||||
|
|
||||||
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
|
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
|
||||||
var store = await _storeContext.GetCurrentStoreAsync();
|
var store = await _storeContext.GetCurrentStoreAsync();
|
||||||
var admin = await _workContext.GetCurrentCustomerAsync();
|
var admin = await _workContext.GetCurrentCustomerAsync();
|
||||||
|
|
||||||
string errorMessage = "";
|
string errorMessage = "";
|
||||||
|
|
||||||
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
|
||||||
{
|
{
|
||||||
// Add each product to the order
|
await AddOrderItemsThenUpdateOrder(order, products, true, customer, store, admin);
|
||||||
foreach (var productModel in products)
|
|
||||||
{
|
|
||||||
var product = await _productService.GetProductByIdAsync(productModel.Id);
|
|
||||||
if (product == null)
|
|
||||||
{
|
|
||||||
_logger.Warning($"Product with ID {productModel.Id} not found");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate stock
|
|
||||||
//var stockQuantity = await _productService.GetTotalStockQuantityAsync(product);
|
|
||||||
var productDto = productDtosByOrderItemId[productModel.Id];
|
|
||||||
var isMeasurable = productDto.IsMeasurable;
|
|
||||||
|
|
||||||
//if (stockQuantity < productModel.Quantity)
|
|
||||||
//{
|
|
||||||
// return Json(new
|
|
||||||
// {
|
|
||||||
// success = false,
|
|
||||||
// message = $"Product '{product.Name}' has insufficient stock. Available: {stockQuantity}, Requested: {productModel.Quantity}"
|
|
||||||
// });
|
|
||||||
//}
|
|
||||||
|
|
||||||
if ((product.StockQuantity + productDto.IncomingQuantity) - productModel.Quantity < 0)
|
|
||||||
{
|
|
||||||
errorMessage = $"Nem elérhető készleten!";
|
|
||||||
var errorText = $"((product.StockQuantity + productDto.IncomingQuantity) - item.Quantity < 0); productId: {product.Id}; (product.StockQuantity + productDto.IncomingQuantity) - item.Quantity: {(product.StockQuantity + productDto.IncomingQuantity) - productModel.Quantity}";
|
|
||||||
_logger.Error($"{errorText}");
|
|
||||||
throw new Exception($"{errorText}");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get or calculate price
|
|
||||||
//var unitPrice = productModel.Price > 0
|
|
||||||
// ? productModel.Price
|
|
||||||
// : (await _priceCalculationService.GetFinalPriceAsync(product, customer, store)).finalPrice;
|
|
||||||
|
|
||||||
|
|
||||||
var valami = await _priceCalculationService.GetFinalPriceAsync(product, customer, store, includeDiscounts: true);
|
|
||||||
var unitPrice = valami.finalPrice;
|
|
||||||
|
|
||||||
// Calculate tax
|
|
||||||
var (unitPriceInclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPrice, true, customer);
|
|
||||||
var (unitPriceExclTaxValue, _) = await _taxService.GetProductPriceAsync(product, unitPrice, false, customer);
|
|
||||||
|
|
||||||
// Create order item
|
|
||||||
var orderItem = new OrderItem
|
|
||||||
{
|
|
||||||
OrderItemGuid = Guid.NewGuid(),
|
|
||||||
OrderId = order.Id,
|
|
||||||
ProductId = product.Id,
|
|
||||||
Quantity = productModel.Quantity,
|
|
||||||
|
|
||||||
UnitPriceInclTax = unitPriceInclTaxValue,
|
|
||||||
UnitPriceExclTax = unitPriceExclTaxValue,
|
|
||||||
|
|
||||||
PriceInclTax = isMeasurable ? 0 : unitPriceInclTaxValue * productModel.Quantity,
|
|
||||||
PriceExclTax = isMeasurable ? 0 : unitPriceExclTaxValue * productModel.Quantity,
|
|
||||||
|
|
||||||
OriginalProductCost = await _priceCalculationService.GetProductCostAsync(product, null),
|
|
||||||
|
|
||||||
//UnitPriceInclTax = unitPriceInclTaxValue,
|
|
||||||
//UnitPriceExclTax = unitPriceExclTaxValue,
|
|
||||||
//PriceInclTax = unitPriceInclTaxValue * productModel.Quantity,
|
|
||||||
//PriceExclTax = unitPriceExclTaxValue * productModel.Quantity,
|
|
||||||
//OriginalProductCost = await _priceCalculationService.GetProductCostAsync(product, null),
|
|
||||||
|
|
||||||
DiscountAmountInclTax = decimal.Zero,
|
|
||||||
DiscountAmountExclTax = decimal.Zero,
|
|
||||||
DownloadCount = 0,
|
|
||||||
IsDownloadActivated = false,
|
|
||||||
LicenseDownloadId = 0,
|
|
||||||
ItemWeight = product.Weight * productModel.Quantity,
|
|
||||||
RentalStartDateUtc = null,
|
|
||||||
RentalEndDateUtc = null
|
|
||||||
};
|
|
||||||
|
|
||||||
await _orderService.InsertOrderItemAsync(orderItem);
|
|
||||||
|
|
||||||
// Adjust inventory
|
|
||||||
await _productService.AdjustInventoryAsync(
|
|
||||||
product,
|
|
||||||
-productModel.Quantity,
|
|
||||||
orderItem.AttributesXml,
|
|
||||||
string.Format(await _localizationService.GetResourceAsync("Admin.StockQuantityHistory.Messages.PlaceOrder"), order.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update order totals
|
|
||||||
var orderSubtotalInclTax = decimal.Zero;
|
|
||||||
var orderSubtotalExclTax = decimal.Zero;
|
|
||||||
|
|
||||||
var orderItems = await _orderService.GetOrderItemsAsync(order.Id);
|
|
||||||
foreach (var item in orderItems)
|
|
||||||
{
|
|
||||||
orderSubtotalInclTax += item.PriceInclTax;
|
|
||||||
orderSubtotalExclTax += item.PriceExclTax;
|
|
||||||
}
|
|
||||||
|
|
||||||
order.OrderSubtotalInclTax = orderSubtotalInclTax;
|
|
||||||
order.OrderSubtotalExclTax = orderSubtotalExclTax;
|
|
||||||
order.OrderTotal = orderSubtotalInclTax + order.OrderShippingInclTax + order.PaymentMethodAdditionalFeeInclTax - order.OrderDiscount;
|
|
||||||
|
|
||||||
await _orderService.UpdateOrderAsync(order);
|
|
||||||
|
|
||||||
// Add order note
|
|
||||||
await _orderService.InsertOrderNoteAsync(new OrderNote
|
|
||||||
{
|
|
||||||
OrderId = order.Id,
|
|
||||||
Note = $"Products added to order by {admin.FirstName} {admin.LastName}, (Id: {admin.Id})",
|
|
||||||
DisplayToCustomer = false,
|
|
||||||
CreatedOnUtc = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(transactionSuccess)
|
if (transactionSuccess)
|
||||||
{
|
{
|
||||||
_logger.Info($"Successfully added {products.Count} products to order {orderId}");
|
_logger.Info($"Successfully added {products.Count} products to order {orderId}");
|
||||||
|
|
||||||
|
//var orderDto = await _dbContext.OrderDtos.GetByIdAsync(order.Id, true);
|
||||||
|
//await _sendToClient.SendMeasuringNotification("Módosult a rendelés, mérjétek újra!", orderDto);
|
||||||
|
|
||||||
return Json(new { success = true, message = "Products added successfully" });
|
return Json(new { success = true, message = "Products added successfully" });
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
return Json(new { success = false, message = errorMessage });
|
return Json(new { success = false, message = errorMessage });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1370,20 +1341,6 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
return Json(new { success = false, message = $"Error: {ex.Message}" });
|
return Json(new { success = false, message = $"Error: {ex.Message}" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper model for deserialization
|
|
||||||
public class AddProductModel
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Sku { get; set; }
|
|
||||||
public int Quantity { get; set; }
|
|
||||||
public decimal Price { get; set; }
|
|
||||||
public int StockQuantity { get; set; }
|
|
||||||
public int IncomingQuantity { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers;
|
||||||
public class CustomOrderSignalREndpoint(FruitBankDbContext ctx, SignalRSendToClientService sendToClient, IPriceCalculationService customPriceCalculationService,IEventPublisher eventPublisher, IWorkContext workContext, IEnumerable<IAcLogWriterBase> logWriters)
|
public class CustomOrderSignalREndpoint(FruitBankDbContext ctx, SignalRSendToClientService sendToClient, IPriceCalculationService customPriceCalculationService,IEventPublisher eventPublisher, IWorkContext workContext, IEnumerable<IAcLogWriterBase> logWriters)
|
||||||
: ICustomOrderSignalREndpointServer
|
: ICustomOrderSignalREndpointServer
|
||||||
{
|
{
|
||||||
|
private const int FromOrderDays = -14;
|
||||||
private readonly ILogger _logger = new Logger<CustomOrderSignalREndpoint>(logWriters.ToArray());
|
private readonly ILogger _logger = new Logger<CustomOrderSignalREndpoint>(logWriters.ToArray());
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetAllOrderDtos)]
|
[SignalR(SignalRTags.GetAllOrderDtos)]
|
||||||
public async Task<List<OrderDto>> GetAllOrderDtos()
|
public async Task<List<OrderDto>> GetAllOrderDtos()
|
||||||
{
|
{
|
||||||
return await ctx.OrderDtos.GetAll(true).ToListAsync();
|
var fromDateUtc = DateTime.UtcNow.Date.AddDays(FromOrderDays);
|
||||||
|
return await ctx.OrderDtos.GetAll(true).Where(o => o.CreatedOnUtc > fromDateUtc).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetOrderDtoById)]
|
[SignalR(SignalRTags.GetOrderDtoById)]
|
||||||
|
|
@ -73,11 +75,11 @@ public class CustomOrderSignalREndpoint(FruitBankDbContext ctx, SignalRSendToCli
|
||||||
return await ctx.OrderItemDtos.GetByIdAsync(orderItemId, true);
|
return await ctx.OrderItemDtos.GetByIdAsync(orderItemId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetAllOrderItemDtos)]
|
[SignalR(SignalRTags.GetAllOrderItemDtos)]
|
||||||
public async Task<List<OrderItemDto>> GetAllOrderItemDtos()
|
public async Task<List<OrderItemDto>> GetAllOrderItemDtos()
|
||||||
{
|
{
|
||||||
return await ctx.OrderItemDtos.GetAll(true).ToListAsync();
|
var fromDateUtc = DateTime.UtcNow.Date.AddDays(FromOrderDays);
|
||||||
|
return await ctx.OrderItemDtos.GetAll(true).Where(oi => oi.OrderDto.CreatedOnUtc > fromDateUtc).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetAllOrderItemDtoByOrderId)]
|
[SignalR(SignalRTags.GetAllOrderItemDtoByOrderId)]
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,17 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
||||||
return await ctx.Shippings.GetByIdAsync(id, true);
|
return await ctx.Shippings.GetByIdAsync(id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SignalR(SignalRTags.AddShipping)]
|
||||||
|
public async Task<Shipping> AddShipping(Shipping shipping)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(shipping);
|
||||||
|
|
||||||
|
_logger.Detail($"AddShipping invoked; id: {shipping.Id}");
|
||||||
|
|
||||||
|
await ctx.Shippings.InsertAsync(shipping);
|
||||||
|
return await ctx.Shippings.GetByIdAsync(shipping.Id, true);
|
||||||
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.UpdateShipping)]
|
[SignalR(SignalRTags.UpdateShipping)]
|
||||||
public async Task<Shipping> UpdateShipping(Shipping shipping)
|
public async Task<Shipping> UpdateShipping(Shipping shipping)
|
||||||
{
|
{
|
||||||
|
|
@ -123,7 +134,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
||||||
_logger.Detail($"UpdateShipping invoked; id: {shipping.Id}");
|
_logger.Detail($"UpdateShipping invoked; id: {shipping.Id}");
|
||||||
|
|
||||||
await ctx.Shippings.UpdateAsync(shipping);
|
await ctx.Shippings.UpdateAsync(shipping);
|
||||||
return await ctx.Shippings.GetByIdAsync(shipping.Id, shipping.ShippingDocuments != null);
|
return await ctx.Shippings.GetByIdAsync(shipping.Id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetShippingItems)]
|
[SignalR(SignalRTags.GetShippingItems)]
|
||||||
|
|
@ -142,6 +153,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
||||||
return await ctx.ShippingItems.GetAllByShippingDocumentIdAsync(shippingDocumentId, true).ToListAsync();
|
return await ctx.ShippingItems.GetAllByShippingDocumentIdAsync(shippingDocumentId, true).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SignalR(SignalRTags.GetShippingItemsByShippingId)]
|
||||||
|
public async Task<List<ShippingItem>> GetShippingItemsByShippingId(int shippingId)
|
||||||
|
{
|
||||||
|
_logger.Detail($"GetShippingItemsByShippingId invoked");
|
||||||
|
|
||||||
|
return await ctx.ShippingItems.GetAllByShippingIdAsync(shippingId, true).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.GetShippingItemById)]
|
[SignalR(SignalRTags.GetShippingItemById)]
|
||||||
public async Task<ShippingItem> GetShippingItemById(int id)
|
public async Task<ShippingItem> GetShippingItemById(int id)
|
||||||
{
|
{
|
||||||
|
|
@ -253,6 +272,28 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
|
||||||
return await ctx.ShippingDocuments.GetByIdAsync(id, true);
|
return await ctx.ShippingDocuments.GetByIdAsync(id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SignalR(SignalRTags.GetShippingDocumentsByShippingId)]
|
||||||
|
public async Task<List<ShippingDocument>> GetShippingDocumentsByShippingId(int shippingId)
|
||||||
|
{
|
||||||
|
_logger.Detail($"GetShippingDocumentsByShippingId invoked; shippingId: {shippingId}");
|
||||||
|
|
||||||
|
return await ctx.ShippingDocuments.GetAllByShippingIdAsync(shippingId, true).ToListAsync();
|
||||||
|
}
|
||||||
|
[SignalR(SignalRTags.GetShippingDocumentsByProductId)]
|
||||||
|
public async Task<List<ShippingDocument>> GetShippingDocumentsByProductId(int productId)
|
||||||
|
{
|
||||||
|
_logger.Detail($"GetShippingDocumentsByProductId invoked; productId: {productId}");
|
||||||
|
|
||||||
|
return await ctx.ShippingDocuments.GetAllByProductIdAsync(productId, true).ToListAsync();
|
||||||
|
}
|
||||||
|
[SignalR(SignalRTags.GetShippingDocumentsByPartnerId)]
|
||||||
|
public async Task<List<ShippingDocument>> GetShippingDocumentsByPartnerId(int partnerId)
|
||||||
|
{
|
||||||
|
_logger.Detail($"GetShippingDocumentsByPartnerId invoked; partnerId: {partnerId}");
|
||||||
|
|
||||||
|
return await ctx.ShippingDocuments.GetAllByPartnerIdAsync(partnerId, true).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
[SignalR(SignalRTags.AddShippingDocument)]
|
[SignalR(SignalRTags.AddShippingDocument)]
|
||||||
public async Task<ShippingDocument> AddShippingDocument(ShippingDocument shippingDocument)
|
public async Task<ShippingDocument> AddShippingDocument(ShippingDocument shippingDocument)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,15 @@ public class ShippingDocumentDbTable : MgDbTableBase<ShippingDocument>
|
||||||
|
|
||||||
public Task<ShippingDocument> GetByIdAsync(int id, bool loadRelations)
|
public Task<ShippingDocument> GetByIdAsync(int id, bool loadRelations)
|
||||||
=> GetAll(loadRelations).FirstOrDefaultAsync(sd => sd.Id == id);
|
=> GetAll(loadRelations).FirstOrDefaultAsync(sd => sd.Id == id);
|
||||||
|
|
||||||
|
public IQueryable<ShippingDocument> GetAllByShippingIdAsync(int shippingId, bool loadRelations)
|
||||||
|
=> GetAll(loadRelations).Where(sd => sd.ShippingId == shippingId);
|
||||||
|
|
||||||
|
public IQueryable<ShippingDocument> GetAllByProductIdAsync(int productId, bool loadRelations)
|
||||||
|
=> GetAll(loadRelations).Where(sd => sd.ShippingItems.Any(si => si.ProductId == productId));
|
||||||
|
|
||||||
|
public IQueryable<ShippingDocument> GetAllByPartnerIdAsync(int partnerId, bool loadRelations)
|
||||||
|
=> GetAll(loadRelations).Where(sd => sd.PartnerId == partnerId);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +59,9 @@ public class ShippingItemDbTable : MgDbTableBase<ShippingItem>
|
||||||
public IQueryable<ShippingItem> GetAllByShippingDocumentIdAsync(int shippingDocumentId, bool loadRelations)
|
public IQueryable<ShippingItem> GetAllByShippingDocumentIdAsync(int shippingDocumentId, bool loadRelations)
|
||||||
=> GetAll(loadRelations).Where(si => si.ShippingDocumentId == shippingDocumentId);
|
=> GetAll(loadRelations).Where(si => si.ShippingDocumentId == shippingDocumentId);
|
||||||
|
|
||||||
|
public IQueryable<ShippingItem> GetAllByShippingIdAsync(int shippingId, bool loadRelations)
|
||||||
|
=> GetAll(loadRelations).Where(si => si.ShippingDocument.ShippingId == shippingId);
|
||||||
|
|
||||||
private static void PrepareValues(ShippingItem shippingItem)
|
private static void PrepareValues(ShippingItem shippingItem)
|
||||||
{
|
{
|
||||||
if (shippingItem.MeasuringCount < 1) shippingItem.MeasuringCount = 1;
|
if (shippingItem.MeasuringCount < 1) shippingItem.MeasuringCount = 1;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue