Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs

609 lines
26 KiB
C#

using AyCode.Core.Loggers;
using AyCode.Services.SignalRs;
using FruitBank.Common.Dtos;
using FruitBank.Common.Entities;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Server.Interfaces;
using FruitBank.Common.SignalRs;
using Mango.Nop.Core.Extensions;
using Mango.Nop.Core.Loggers;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Shipping;
using Nop.Core.Domain.Tax;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Factories;
using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Security;
using Nop.Web.Areas.Admin.Controllers;
using Nop.Web.Areas.Admin.Factories;
using Nop.Web.Areas.Admin.Models.Orders;
using Nop.Web.Framework;
using Nop.Web.Framework.Mvc.Filters;
using System.Text.Json.Serialization;
using System.Xml;
using System.Xml.Serialization;
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
{
[Area(AreaNames.ADMIN)]
[AuthorizeAdmin]
public class CustomOrderController : BaseAdminController, ICustomOrderSignalREndpointServer
{
private readonly FruitBankDbContext _dbContext;
private readonly IOrderService _orderService;
private readonly CustomOrderModelFactory _orderModelFactory;
private readonly ICustomOrderSignalREndpointServer _customOrderSignalREndpoint;
private readonly IPermissionService _permissionService;
private readonly IGenericAttributeService _genericAttributeService;
private readonly INotificationService _notificationService;
private readonly ICustomerService _customerService;
private readonly IProductService _productService;
private readonly IStoreContext _storeContext;
private readonly IWorkContext _workContext;
// ... other dependencies
private readonly ILogger _logger;
public CustomOrderController(FruitBankDbContext fruitBankDbContext, IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService, ICustomerService customerService, IProductService productService, IEnumerable<IAcLogWriterBase> logWriters, IStoreContext storeContext, IWorkContext workContext)
{
_logger = new Logger<CustomOrderController>(logWriters.ToArray());
_dbContext = fruitBankDbContext;
_orderService = orderService;
_orderModelFactory = orderModelFactory as CustomOrderModelFactory;
_customOrderSignalREndpoint = customOrderSignalREndpoint;
_permissionService = permissionService;
_genericAttributeService = genericAttributeService;
_notificationService = notificationService;
_customerService = customerService;
_productService = productService;
_storeContext = storeContext;
_workContext = workContext;
// ... initialize other deps
}
#region CustomOrderSignalREndpoint
[NonAction] public Task<List<OrderDto>> GetAllOrderDtos() => _customOrderSignalREndpoint.GetAllOrderDtos();
[NonAction]public Task<OrderDto> GetOrderDtoById(int orderId) => _customOrderSignalREndpoint.GetOrderDtoById(orderId);
[NonAction]public Task<List<OrderDto>> GetPendingOrderDtos() => _customOrderSignalREndpoint.GetPendingOrderDtos();
[NonAction] public Task<OrderDto> StartMeasuring(int orderId, int userId) => _customOrderSignalREndpoint.StartMeasuring(orderId, userId);
[NonAction]public Task<OrderDto> SetOrderStatusToComplete(int orderId, int revisorId) => _customOrderSignalREndpoint.SetOrderStatusToComplete(orderId, revisorId);
[NonAction] public Task<List<OrderDto>> GetAllOrderDtoByIds(int[] orderIds) => _customOrderSignalREndpoint.GetAllOrderDtoByIds(orderIds);
[NonAction] public Task<OrderItemPallet> AddOrUpdateMeasuredOrderItemPallet(OrderItemPallet orderItemPallet) => _customOrderSignalREndpoint.AddOrUpdateMeasuredOrderItemPallet(orderItemPallet);
#endregion CustomOrderSignalREndpoint
[CheckPermission(StandardPermission.Orders.ORDERS_VIEW)]
public virtual async Task<IActionResult> List(List<int> orderStatuses = null, List<int> paymentStatuses = null, List<int> shippingStatuses = null)
{
//prepare model
var model = await _orderModelFactory.PrepareOrderSearchModelAsync(new OrderSearchModel
{
OrderStatusIds = orderStatuses,
PaymentStatusIds = paymentStatuses,
ShippingStatusIds = shippingStatuses,
});
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/List.cshtml", model);
}
[HttpPost]
[CheckPermission(StandardPermission.Orders.ORDERS_VIEW)]
public async Task<IActionResult> OrderList(OrderSearchModel searchModel)
{
//prepare model
var orderListModel = await GetOrderListModelByFilter(searchModel);
//var orderListModel = new OrderListModel();
var valami = Json(orderListModel);
Console.WriteLine(valami);
return valami;
}
public async Task<OrderListModelExtended> GetOrderListModelByFilter(OrderSearchModel searchModel)
{
//return _customOrderService.
var orderListModel = await _orderModelFactory.PrepareOrderListModelExtendedAsync(searchModel);
_logger.Debug($"Total: {orderListModel.RecordsTotal}, Data Count: {orderListModel.Data.Count()}");
foreach (var item in orderListModel.Data.Take(3))
{
_logger.Debug($"Order: {item.Id}, {item.CustomOrderNumber}");
}
return orderListModel;
}
public virtual IActionResult Test()
{
// Your custom logic here
// This will use your custom List.cshtml view
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Order/Test.cshtml");
}
//[HttpPost]
//[CheckPermission(Nop.Services.Security.StandardPermission.Orders.ORDERS_VIEW)]
//public virtual async Task<IActionResult> OrderList(OrderSearchModel searchModel)
//{
// //prepare model
// var model = await _orderModelFactory.PrepareOrderListModelAsync(searchModel);
// return Json(model);
//}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SaveOrderAttributes(OrderAttributesModel model)
{
if (!ModelState.IsValid)
{
// reload order page with errors
return RedirectToAction("Edit", "Order", new { id = model.OrderId });
}
var order = await _orderService.GetOrderByIdAsync(model.OrderId);
if (order == null)
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(IOrderDto.DateOfReceipt), model.DateOfReceipt, _storeContext.GetCurrentStore().Id);
_notificationService.SuccessNotification("Custom attributes saved successfully.");
return RedirectToAction("Edit", "Order", new { id = model.OrderId });
}
[HttpPost]
//[CheckPermission(StandardPermission.Orders.ORDERS_CREATE)]
public virtual async Task<IActionResult> Create(int customerId, string orderProductsJson)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_CREATE_EDIT_DELETE))
return AccessDeniedView();
// Validate customer
var customer = await _customerService.GetCustomerByIdAsync(customerId);
if (customer == null) return RedirectToAction("List");
var billingAddress = await _customerService.GetCustomerBillingAddressAsync(customer);
if(billingAddress == null)
{
//let's see if he has any address at all
var addresses = await _customerService.GetAddressesByCustomerIdAsync(customer.Id);
if(addresses != null && addresses.Count > 0)
{
//set the first one as billing
billingAddress = addresses[0];
customer.BillingAddressId = billingAddress.Id;
await _customerService.UpdateCustomerAsync(customer);
}
else
{
//no address at all, cannot create order
_logger.Error($"Cannot create order for customer {customer.Id}, no billing address found.");
return RedirectToAction("List");
}
}
//var currency = await _workContext.GetWorkingCurrencyAsync();
//customer.CurrencyId = currency.Id;
// Parse products
var orderProducts = string.IsNullOrEmpty(orderProductsJson) ? [] : JsonConvert.DeserializeObject<List<OrderProductItem>>(orderProductsJson);
// Create order
var order = new Order
{
OrderGuid = Guid.NewGuid(),
CustomOrderNumber = "",
CustomerId = customerId,
CustomerLanguageId = customer.LanguageId ?? 1,
CustomerTaxDisplayType = TaxDisplayType.IncludingTax,
CustomerIp = string.Empty,
OrderStatus = OrderStatus.Pending,
PaymentStatus = PaymentStatus.Pending,
ShippingStatus = ShippingStatus.ShippingNotRequired,
CreatedOnUtc = DateTime.UtcNow,
BillingAddressId = customer.BillingAddressId ?? 0,
ShippingAddressId = customer.ShippingAddressId,
PaymentMethodSystemName = "Payments.CheckMoneyOrder", // Default payment method
CustomerCurrencyCode = "HUF", // TODO: GET Default currency - A.
};
//var productDtosById = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(op => op.Id)).ToDictionaryAsync(p => p.Id, prodDto => prodDto);
var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ =>
{
await _orderService.InsertOrderAsync(order);
order.CustomOrderNumber = order.Id.ToString();
await _orderService.UpdateOrderAsync(order);
foreach (var item in orderProducts)
{
var product = await _productService.GetProductByIdAsync(item.Id);
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}");
}
//if (productDtosById.TryGetValue(item.Id, out var productDto))
{
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);
//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}");
}
return true;
});
if (transactionSuccess) return RedirectToAction("Edit", "Order", new { id = order.Id });
_logger.Error($"(transactionSuccess == false)");
return RedirectToAction("Error", new { id = order.Id });
}
public class OrderProductItem
{
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 override string ToString()
{
return $"{nameof(OrderProductItem)} [Id: {Id}; Name: {Name}; Sku: {Sku}; Quantity: {Quantity}; Price: {Price}]";
}
}
//private static OrderItem CreateOrderItem(ProductToAuctionMapping productToAuction, Order order, decimal orderTotal)
//{
// return new OrderItem
// {
// ProductId = productToAuction.ProductId,
// OrderId = order.Id,
// OrderItemGuid = Guid.NewGuid(),
// PriceExclTax = orderTotal,
// PriceInclTax = orderTotal,
// UnitPriceExclTax = orderTotal,
// UnitPriceInclTax = orderTotal,
// Quantity = productToAuction.ProductAmount,
// };
//}
//private static Order CreateOrder(ProductToAuctionMapping productToAuction, decimal orderTotal, Customer customer, Address billingAddress, int storeId, Dictionary<string, object> customValues)
//{
// return new Order
// {
// BillingAddressId = billingAddress.Id,
// CreatedOnUtc = DateTime.UtcNow,
// CurrencyRate = 1,
// CustomOrderNumber = productToAuction.AuctionId + "/" + productToAuction.SortIndex,
// CustomValuesXml = SerializeCustomValuesToXml(customValues),
// CustomerCurrencyCode = "HUF",
// CustomerId = productToAuction.WinnerCustomerId,
// CustomerLanguageId = 2,
// CustomerTaxDisplayType = TaxDisplayType.IncludingTax,
// OrderGuid = Guid.NewGuid(),
// OrderStatus = OrderStatus.Pending,
// OrderTotal = orderTotal,
// PaymentStatus = PaymentStatus.Pending,
// PaymentMethodSystemName = "Payments.CheckMoneyOrder",
// ShippingStatus = ShippingStatus.ShippingNotRequired,
// StoreId = storeId,
// VatNumber = customer.VatNumber,
// CustomerIp = customer.LastIpAddress,
// OrderSubtotalExclTax = orderTotal,
// OrderSubtotalInclTax = orderTotal
// };
//}
private static OrderNote CreateOrderNote(Order order, string note)
{
return new OrderNote
{
CreatedOnUtc = order.CreatedOnUtc,
DisplayToCustomer = true,
OrderId = order.Id,
Note = note
};
}
private static string SerializeCustomValuesToXml(Dictionary<string, object> sourceDictionary)
{
ArgumentNullException.ThrowIfNull(sourceDictionary);
if (!sourceDictionary.Any())
return null;
var ds = new DictionarySerializer(sourceDictionary);
var xs = new XmlSerializer(typeof(DictionarySerializer));
using var textWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(textWriter))
{
xs.Serialize(xmlWriter, ds);
}
var result = textWriter.ToString();
return result;
}
[HttpGet] // Change from [HttpPost] to [HttpGet]
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
public virtual async Task<IActionResult> CustomerSearchAutoComplete(string term)
{
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
return Json(new List<object>());
const int maxResults = 15;
// Search by email (contains)
var customersByEmail = await _customerService.GetAllCustomersAsync(
email: term,
pageIndex: 0,
pageSize: maxResults);
// Search by first name (contains)
var customersByFirstName = await _customerService.GetAllCustomersAsync(
firstName: term,
pageIndex: 0,
pageSize: maxResults);
// Search by last name (contains)
var customersByLastName = await _customerService.GetAllCustomersAsync(
lastName: term,
pageIndex: 0,
pageSize: maxResults);
var customersByCompanyName = await _customerService.GetAllCustomersAsync(
company: term,
pageIndex: 0,
pageSize: maxResults);
// Combine and deduplicate results
var allCustomers = customersByEmail
.Union(customersByFirstName)
.Union(customersByLastName)
.Union(customersByCompanyName)
.DistinctBy(c => c.Id)
.Take(maxResults)
.ToList();
var result = new List<object>();
foreach (var customer in allCustomers)
{
var fullName = await _customerService.GetCustomerFullNameAsync(customer);
var company = customer.Company;
if (string.IsNullOrEmpty(fullName))
fullName = "[No name]";
if(string.IsNullOrEmpty(company))
company = "[No company]";
string fullText = $"{company} ({fullName}), {customer.Email}";
//var displayText = !string.IsNullOrEmpty(customer.Email)
// ? $"{customer.Email}, {customer.Company} ({fullName})"
// : fullName;
result.Add(new
{
label = fullText,
value = customer.Id
});
}
return Json(result);
}
[HttpGet]
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
public virtual async Task<IActionResult> ProductSearchAutoComplete(string term)
{
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
return Json(new List<object>());
const int maxResults = 15;
// Search products by name or SKU
var products = await _productService.SearchProductsAsync(
keywords: term,
pageIndex: 0,
pageSize: maxResults);
var result = new List<object>();
foreach (var product in products)
{
result.Add(new
{
label = $"{product.Name} [KÉSZLET: {product.StockQuantity}]",
value = product.Id,
sku = product.Sku,
price = product.Price,
stockQuantity = product.StockQuantity
});
}
return Json(result);
}
//[HttpPost]
//public async Task<IActionResult> CreateInvoice(int orderId)
//{
// try
// {
// var order = await _orderService.GetOrderByIdAsync(orderId);
// if (order == null)
// return Json(new { success = false, message = "Order not found" });
// var billingAddress = await _customerService.GetCustomerBillingAddressAsync(order.Customer);
// if (billingAddress == null)
// return Json(new { success = false, message = "Billing address not found" });
// var country = await _countryService.GetCountryByAddressAsync(billingAddress);
// var countryCode = country?.TwoLetterIsoCode ?? "HU";
// // Create invoice request
// var invoiceRequest = new InvoiceCreateRequest
// {
// VevoNev = $"{billingAddress.FirstName} {billingAddress.LastName}",
// VevoIrsz = billingAddress.ZipPostalCode ?? "",
// VevoTelep = billingAddress.City ?? "",
// VevoOrszag = countryCode,
// VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(),
// SzamlatombID = 1, // Configure this based on your setup
// SzamlaKelte = DateTime.Now,
// TeljesitesKelte = DateTime.Now,
// Hatarido = DateTime.Now.AddDays(15), // 15 days payment term
// Devizanem = order.CustomerCurrencyCode,
// FizetesiMod = order.PaymentMethodSystemName,
// Felretett = false,
// Proforma = false,
// Email = billingAddress.Email,
// Telefon = billingAddress.PhoneNumber
// };
// // Add order items
// var orderItems = await _orderService.GetOrderItemsAsync(order.Id);
// foreach (var item in orderItems)
// {
// var product = await _productService.GetProductByIdAsync(item.ProductId);
// invoiceRequest.AddItem(new InvoiceItem
// {
// TetelNev = product?.Name ?? "Product",
// AfaSzoveg = "27%", // Configure VAT rate as needed
// Brutto = true,
// EgysegAr = item.UnitPriceInclTax,
// Mennyiseg = item.Quantity,
// MennyisegEgyseg = "db",
// CikkSzam = product?.Sku
// });
// }
// // Create invoice via API
// var response = await _innVoiceApiService.CreateInvoiceAsync(invoiceRequest);
// if (response.IsSuccess)
// {
// // TODO: Save invoice details to your database for future reference
// // You might want to create a custom table to store:
// // - OrderId
// // - InnVoice TableId
// // - Invoice Number
// // - PDF URL
// // - Created Date
// return Json(new
// {
// success = true,
// message = "Invoice created successfully",
// data = new
// {
// tableId = response.TableId,
// invoiceNumber = response.Sorszam,
// sorszam = response.Sorszam,
// printUrl = response.PrintUrl
// }
// });
// }
// else
// {
// return Json(new
// {
// success = false,
// message = $"InnVoice API Error: {response.Message}"
// });
// }
// }
// catch (Exception ex)
// {
// return Json(new
// {
// success = false,
// message = $"Error: {ex.Message}"
// });
// }
//}
//[HttpGet]
//public async Task<IActionResult> GetInvoiceStatus(int orderId)
//{
// try
// {
// // TODO: Retrieve invoice details from your database
// // This is a placeholder - you need to implement actual storage/retrieval
// // Example: var invoiceData = await _yourInvoiceService.GetByOrderIdAsync(orderId);
// // if (invoiceData != null)
// // {
// // return Json(new
// // {
// // success = true,
// // data = new
// // {
// // tableId = invoiceData.TableId,
// // invoiceNumber = invoiceData.InvoiceNumber,
// // sorszam = invoiceData.InvoiceNumber,
// // printUrl = invoiceData.PrintUrl
// // }
// // });
// // }
// return Json(new
// {
// success = false,
// message = "No invoice found for this order"
// });
// }
// catch (Exception ex)
// {
// return Json(new
// {
// success = false,
// message = $"Error: {ex.Message}"
// });
// }
//}
}
}