using Microsoft.AspNetCore.Mvc; using Nop.Core; using Nop.Core.Domain.Orders; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Services.Catalog; using Nop.Services.Common; using Nop.Services.Customers; using Nop.Services.Directory; using Nop.Services.Orders; using Nop.Web.Framework; using Nop.Web.Framework.Controllers; using Nop.Web.Framework.Mvc.Filters; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers { [Area(AreaNames.ADMIN)] [AuthorizeAdmin] public class InnVoiceOrderController : BasePluginController { private readonly IOrderService _orderService; private readonly IWorkContext _workContext; private readonly IStoreContext _storeContext; private readonly ICustomerService _customerService; private readonly ICountryService _countryService; private readonly IProductService _productService; private readonly InnVoiceOrderService _innVoiceOrderService; private readonly FruitBankAttributeService _fruitBankAttributeService; private readonly IGenericAttributeService _genericAttributeService; private readonly FruitBankDbContext _dbContext; public InnVoiceOrderController( IOrderService orderService, IWorkContext workContext, IStoreContext storeContext, ICustomerService customerService, ICountryService countryService, IProductService productService, InnVoiceOrderService innVoiceOrderService, FruitBankAttributeService fruitBankAttributeService, IGenericAttributeService genericAttributeService, FruitBankDbContext dbContext) { _orderService = orderService; _workContext = workContext; _storeContext = storeContext; _customerService = customerService; _countryService = countryService; _productService = productService; _innVoiceOrderService = innVoiceOrderService; _fruitBankAttributeService = fruitBankAttributeService; _genericAttributeService = genericAttributeService; _dbContext = dbContext; } /// /// Create an order in InnVoice from a NopCommerce order /// [HttpPost] [IgnoreAntiforgeryToken] public async Task CreateOrder(int orderId) { try { // Validate and get order var order = await _orderService.GetOrderByIdAsync(orderId); var orderDto = await _dbContext.OrderDtos.GetByIdAsync(orderId, true); if (order == null) { return Json(new { success = false, message = "Order not found" }); } if (orderDto == null) { return Json(new { success = false, message = "OrderDTO not found" }); } if (orderDto.DateOfReceipt == null) { return Json(new { success = false, message = "Ki kell tölteni az átvétel idejét." }); } // Validate and get customer var customer = await _customerService.GetCustomerByIdAsync(orderDto.CustomerId); if (customer == null) { return Json(new { success = false, message = "Customer not found" }); } // Get and validate billing address var billingAddress = await _customerService.GetCustomerBillingAddressAsync(customer); if (billingAddress == null) { return Json(new { success = false, message = "Billing address not found" }); } var billingCountry = await _countryService.GetCountryByAddressAsync(billingAddress); var billingCountryCode = billingCountry?.TwoLetterIsoCode ?? "HU"; // Get shipping address (fallback to billing if not found) var shippingAddress = await _customerService.GetCustomerShippingAddressAsync(customer) ?? billingAddress; var shippingCountry = await _countryService.GetCountryByAddressAsync(shippingAddress); var shippingCountryCode = shippingCountry?.TwoLetterIsoCode ?? billingCountryCode; string megjegyzes = string.Empty; // Create order request var orderRequest = new OrderCreateRequest { VevoNev = customer.Company ?? string.Empty, VevoIrsz = billingAddress.ZipPostalCode ?? string.Empty, VevoTelep = billingAddress.City ?? string.Empty, VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(), VevoOrszag = billingCountryCode, VevoAdoszam = customer.VatNumber, MegrendelestombID = 1, MegrendelesKelte = ((DateTime)orderDto.DateOfReceipt).ToLocalTime(), Hatarido = DateTime.Now.AddDays(7), Devizanem = "Ft", // TODO: get real default - A. //FizetesiMod = order.PaymentMethodSystemName ?? "átutalás", FizetesiMod = "átutalás", //Email = customer.Email ?? string.Empty, Email = billingAddress.Email ?? customer.Email ?? string.Empty, Telefon = billingAddress.PhoneNumber ?? string.Empty, MegrendelesSzamStr = orderDto.Id.ToString(), Megjegyzes = $"" }; // Add shipping address details orderRequest.SzallNev = $"{shippingAddress.FirstName} {shippingAddress.LastName}".Trim(); orderRequest.SzallIrsz = shippingAddress.ZipPostalCode ?? string.Empty; orderRequest.SzallTelep = shippingAddress.City ?? string.Empty; orderRequest.SzallUtcaHsz = $"{shippingAddress.Address1} {shippingAddress.Address2}".Trim(); orderRequest.SzallOrszag = shippingCountryCode; // Get and validate order items var orderItems = await _dbContext.OrderItemDtos.GetAllByOrderId(order.Id, true).ToListAsync(); if (orderItems == null || orderItems.Count == 0) { return Json(new { success = false, message = "Order has no items" }); } // Add order items foreach (var item in orderItems) { var product = _dbContext.ProductDtos.GetById(item.ProductId); var productName = product?.Name ?? "Product"; if (item.IsMeasurable) { // For measurable products, quantity is weight stored in NetWeight orderRequest.AddItem(new InnVoiceOrderItem { TetelNev = productName, AfaSzoveg = "27%", // TODO: Configure VAT rate dynamically Brutto = true, EgysegAr = item.UnitPriceInclTax, Mennyiseg = item.NetWeight > 0 ? Convert.ToDecimal(item.NetWeight) : 0, MennyisegEgyseg = "kg", CikkSzam = string.Empty }); } else { orderRequest.AddItem(new InnVoiceOrderItem { TetelNev = productName, AfaSzoveg = "27%", // TODO: Configure VAT rate dynamically Brutto = true, EgysegAr = item.UnitPriceInclTax, Mennyiseg = item.Quantity, MennyisegEgyseg = "kt", CikkSzam = string.Empty }); } if(item.UnitPriceInclTax != product.Price) { megjegyzes += $"{productName} egységár módosítva: {Math.Round(product.Price, 2)} Ft -> {Math.Round(item.UnitPriceInclTax, 2)} Ft; \n"; megjegyzes += $"Kedvezmény: { ((1 - (item.UnitPriceInclTax / product.Price)) * 100).ToString() }%; \n"; } } orderRequest.Megjegyzes = megjegyzes; // Create order via API var response = await _innVoiceOrderService.CreateOrderAsync(orderRequest); if (response == null) { return Json(new { success = false, message = "No response from InnVoice API" }); } if (response.IsSuccess) { var currentStore = await _storeContext.GetCurrentStoreAsync(); var storeId = currentStore?.Id ?? 0; // Save InnVoice order details as attributes //await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync( // order.Id, // "InnVoiceOrderTechId", // response.TechId, // storeId //); await _genericAttributeService.SaveAttributeAsync( order, "InnVoiceOrderTechId", response.TechId, storeId ); await _genericAttributeService.SaveAttributeAsync( order, "InnVoiceOrderTableId", response.TableId?.ToString() ?? string.Empty, storeId ); await _genericAttributeService.SaveAttributeAsync( order, "InnVoiceOrderPrintLink", response.PrintUrl?.ToString() ?? string.Empty, storeId ); return Json(new { success = true, message = "Order created successfully in InnVoice", data = new { tableId = response.TableId, techId = response.TechId, printUrl = response.PrintUrl } }); } return Json(new { success = false, message = $"InnVoice API Error: {response.Message ?? "Unknown error"}" }); } catch (Exception ex) { // Log the exception here // _logger.LogError(ex, "Error creating order {OrderId} in InnVoice", orderId); return Json(new { success = false, message = $"Error: {ex.Message}" }); } } /// /// Get InnVoice order status for a NopCommerce order /// /// /// Get InnVoice order status for a NopCommerce order /// [HttpGet] public async Task GetOrderStatus(int orderId) { try { var order = await _orderService.GetOrderByIdAsync(orderId); if (order == null) return Json(new { success = false, message = "Order not found" }); var storeId = (await _storeContext.GetCurrentStoreAsync()).Id; // Get saved InnVoice order TechId var techId = await _genericAttributeService.GetAttributeAsync( order, "InnVoiceOrderTechId", storeId ); var printLink = await _genericAttributeService.GetAttributeAsync( order, "InnVoiceOrderPrintLink", storeId ); if (string.IsNullOrEmpty(techId)) { return Json(new { success = false, message = "No InnVoice order found for this order" }); } // Fetch the order details from InnVoice API using TechId var innVoiceOrders = await _innVoiceOrderService.GetOrderByTechIdAsync(techId); if (innVoiceOrders == null || innVoiceOrders.Count == 0) { return Json(new { success = false, message = "Order not found in InnVoice" }); } var innVoiceOrder = innVoiceOrders.FirstOrDefault(); return Json(new { success = true, data = new { tableId = innVoiceOrder.TableId, techId = innVoiceOrder.TechId, printUrl = printLink, customerName = innVoiceOrder.CustomerName, totalGross = innVoiceOrder.TotalGross, currency = innVoiceOrder.Currency, orderDate = innVoiceOrder.OrderDate } }); } catch (Exception ex) { return Json(new { success = false, message = $"Error: {ex.Message}" }); } } /// /// Create multiple orders in InnVoice from multiple NopCommerce orders /// [HttpPost] [IgnoreAntiforgeryToken] public async Task CreateMultipleOrders([FromBody] int[] orderIds) { try { if (orderIds == null || orderIds.Length == 0) return Json(new { success = false, message = "No order IDs provided" }); var orderRequests = new List(); foreach (var orderId in orderIds) { var order = await _orderService.GetOrderByIdAsync(orderId); if (order == null) continue; var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId); var billingAddress = await _customerService.GetCustomerBillingAddressAsync(customer); if (billingAddress == null) continue; var billingCountry = await _countryService.GetCountryByAddressAsync(billingAddress); var billingCountryCode = billingCountry?.TwoLetterIsoCode ?? "HU"; var orderRequest = new OrderCreateRequest { VevoNev = $"{billingAddress.FirstName} {billingAddress.LastName}", VevoIrsz = billingAddress.ZipPostalCode ?? "", VevoTelep = billingAddress.City ?? "", VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(), VevoOrszag = billingCountryCode, MegrendelestombID = 1, MegrendelesKelte = order.CreatedOnUtc.ToLocalTime(), Hatarido = DateTime.Now.AddDays(7), Devizanem = "Ft", FizetesiMod = order.PaymentMethodSystemName, Email = billingAddress.Email, Telefon = billingAddress.PhoneNumber, MegrendelesSzamStr = order.Id.ToString(), Megjegyzes = $"" }; // Add order items var orderItems = await _orderService.GetOrderItemsAsync(order.Id); foreach (var item in orderItems) { var product = await _productService.GetProductByIdAsync(item.ProductId); orderRequest.AddItem(new InnVoiceOrderItem { TetelNev = product?.Name ?? "Product", AfaSzoveg = "27%", Brutto = true, EgysegAr = item.UnitPriceInclTax, Mennyiseg = item.Quantity, MennyisegEgyseg = "db", CikkSzam = product?.Sku }); } orderRequests.Add(orderRequest); } if (orderRequests.Count == 0) return Json(new { success = false, message = "No valid orders to create" }); // Create orders via API var responses = await _innVoiceOrderService.CreateOrdersAsync(orderRequests); if (responses != null) { var successCount = responses.Count(r => r.IsSuccess); var failureCount = responses.Count - successCount; // Save TechIds for successful orders var storeId = (await _storeContext.GetCurrentStoreAsync()).Id; for (int i = 0; i < responses.Count && i < orderIds.Length; i++) { if (responses[i].IsSuccess) { var order = await _orderService.GetOrderByIdAsync(orderIds[i]); if (order != null) { await _genericAttributeService.SaveAttributeAsync( order, "InnVoiceOrderTechId", responses[i].TechId, storeId ); await _genericAttributeService.SaveAttributeAsync( order, "InnVoiceOrderTableId", responses[i].TableId?.ToString(), storeId ); } } } return Json(new { success = successCount > 0, message = $"Created {successCount} orders successfully. {failureCount} failed.", data = new { successCount, failureCount, responses = responses.Select(r => new { success = r.IsSuccess, tableId = r.TableId, techId = r.TechId, message = r.Message, printUrl = r.PrintUrl }) } }); } else { throw new Exception($"InvoiceOrderAPi invalid response"); } } catch (Exception ex) { return Json(new { success = false, message = $"Error: {ex.Message}" }); } } } }