This commit is contained in:
Adam 2025-10-20 17:51:01 +02:00
parent 89aa10e07b
commit f5b27f8c18
9 changed files with 1884 additions and 535 deletions

View File

@ -5,6 +5,7 @@ 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;
@ -176,7 +177,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
var order = new Order
{
OrderGuid = Guid.NewGuid(),
CustomOrderNumber = "",
CustomOrderNumber = null,
CustomerId = customerId,
CustomerLanguageId = customer.LanguageId ?? 1,
CustomerTaxDisplayType = TaxDisplayType.IncludingTax,
@ -217,7 +218,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
DiscountAmountInclTax = 0,
DiscountAmountExclTax = 0
};
//var valami = product.GenericAttributes.GetValueOrNull<bool>(nameof(IOrderDto.DateOfReceipt)); TEST - A.
await _orderService.InsertOrderItemAsync(orderItem);
}
else _logger.Error($"(productDtosById.TryGetValue(item.Id, out var product) == false); {item}");
@ -226,7 +227,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
return true;
});
if (transactionSuccess) return RedirectToAction("Edit", new { id = order.Id });
if (transactionSuccess) return RedirectToAction("Edit", "Order", new { id = order.Id });
_logger.Error($"(transactionSuccess == false)");
return RedirectToAction("Error", new { id = order.Id });

View File

@ -0,0 +1,397 @@
using Microsoft.AspNetCore.Mvc;
using Nop.Core;
using Nop.Core.Domain.Orders;
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 IGenericAttributeService _genericAttributeService;
public InnVoiceOrderController(
IOrderService orderService,
IWorkContext workContext,
IStoreContext storeContext,
ICustomerService customerService,
ICountryService countryService,
IProductService productService,
InnVoiceOrderService innVoiceOrderService,
IGenericAttributeService genericAttributeService)
{
_orderService = orderService;
_workContext = workContext;
_storeContext = storeContext;
_customerService = customerService;
_countryService = countryService;
_productService = productService;
_innVoiceOrderService = innVoiceOrderService;
_genericAttributeService = genericAttributeService;
}
/// <summary>
/// Create an order in InnVoice from a NopCommerce order
/// </summary>
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> CreateOrder(int orderId)
{
try
{
var order = await _orderService.GetOrderByIdAsync(orderId);
if (order == null)
return Json(new { success = false, message = "Order not found" });
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
// Get 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
var shippingAddress = await _customerService.GetCustomerShippingAddressAsync(customer);
var shippingCountry = shippingAddress != null
? await _countryService.GetCountryByAddressAsync(shippingAddress)
: null;
var shippingCountryCode = shippingCountry?.TwoLetterIsoCode ?? billingCountryCode;
// Create order request
var orderRequest = new OrderCreateRequest
{
VevoNev = $"{billingAddress.FirstName} {billingAddress.LastName}",
VevoIrsz = billingAddress.ZipPostalCode ?? "",
VevoTelep = billingAddress.City ?? "",
VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(),
VevoOrszag = billingCountryCode,
VevoAdoszam = billingAddress.Company, // Or a custom field for tax number
MegrendelestombID = 1, // Configure this based on your setup
MegrendelesKelte = order.CreatedOnUtc.ToLocalTime(),
Hatarido = DateTime.Now.AddDays(7), // 7 days delivery time
Devizanem = order.CustomerCurrencyCode,
FizetesiMod = order.PaymentMethodSystemName,
Email = billingAddress.Email,
Telefon = billingAddress.PhoneNumber,
MegrendelesSzamStr = order.Id.ToString()
};
// Add shipping address if different
if (shippingAddress != null)
{
orderRequest.SzallNev = $"{shippingAddress.FirstName} {shippingAddress.LastName}";
orderRequest.SzallIrsz = shippingAddress.ZipPostalCode ?? "";
orderRequest.SzallTelep = shippingAddress.City ?? "";
orderRequest.SzallUtcaHsz = $"{shippingAddress.Address1} {shippingAddress.Address2}".Trim();
orderRequest.SzallOrszag = shippingCountryCode;
}
// 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%", // Configure VAT rate as needed
Brutto = true,
EgysegAr = item.UnitPriceInclTax,
Mennyiseg = item.Quantity,
MennyisegEgyseg = "db",
CikkSzam = product?.Sku
});
}
// Create order via API
var response = await _innVoiceOrderService.CreateOrderAsync(orderRequest);
if (response.IsSuccess)
{
// Save the TechId, TableId, and PrintUrl to the order for future reference
await _genericAttributeService.SaveAttributeAsync(
order,
"InnVoiceOrderTechId",
response.TechId,
(await _storeContext.GetCurrentStoreAsync()).Id
);
await _genericAttributeService.SaveAttributeAsync(
order,
"InnVoiceOrderTableId",
response.TableId?.ToString(),
(await _storeContext.GetCurrentStoreAsync()).Id
);
await _genericAttributeService.SaveAttributeAsync(
order,
"InnVoiceOrderPrintLink",
response.PrintUrl?.ToString(),
(await _storeContext.GetCurrentStoreAsync()).Id
);
return Json(new
{
success = true,
message = "Order created successfully in InnVoice",
data = new
{
tableId = response.TableId,
techId = response.TechId,
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}"
});
}
}
/// <summary>
/// Get InnVoice order status for a NopCommerce order
/// </summary>
/// <summary>
/// Get InnVoice order status for a NopCommerce order
/// </summary>
[HttpGet]
public async Task<IActionResult> 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<string>(
order,
"InnVoiceOrderTechId",
storeId
);
var printLink = await _genericAttributeService.GetAttributeAsync<string>(
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}"
});
}
}
/// <summary>
/// Create multiple orders in InnVoice from multiple NopCommerce orders
/// </summary>
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> 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<OrderCreateRequest>();
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 = order.CustomerCurrencyCode,
FizetesiMod = order.PaymentMethodSystemName,
Email = billingAddress.Email,
Telefon = billingAddress.PhoneNumber,
MegrendelesSzamStr = order.Id.ToString()
};
// 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);
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
})
}
});
}
catch (Exception ex)
{
return Json(new
{
success = false,
message = $"Error: {ex.Message}"
});
}
}
}
}

View File

@ -1,28 +1,219 @@
using Microsoft.AspNetCore.Mvc;
using Nop.Web.Areas.Admin.Controllers;
using Nop.Web.Framework.Mvc.Filters;

using Microsoft.AspNetCore.Mvc;
using Nop.Core;
using Nop.Core.Domain.Orders;
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.Services.Security;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Mvc.Filters;
namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
{
[Area(AreaNames.ADMIN)]
[AuthorizeAdmin]
public class InvoiceController : BaseAdminController
[AuthorizeAdmin]
//[AutoValidateAntiforgeryToken]
public class InvoiceController : BasePluginController
{
private readonly IPermissionService _permissionService;
private readonly IOrderService _orderService;
private readonly IWorkContext _workContext;
private readonly IStoreContext _storeContext;
private readonly ICustomerService _customerService;
private readonly ICountryService _countryService;
private readonly IStateProvinceService _stateProvinceService;
// Add your InnVoice API service
private readonly InnVoiceApiService _innVoiceApiService;
private readonly IProductService _productService;
private readonly FruitBankAttributeService _fruitBankAttributeService;
public InvoiceController(IPermissionService permissionService)
public InvoiceController(
IOrderService orderService,
IWorkContext workContext,
IStoreContext storeContext,
ICustomerService customerService,
ICountryService countryService,
IStateProvinceService stateProvinceService,
InnVoiceApiService innVoiceApiService,
IProductService productService,
FruitBankAttributeService fruitBankAttributeService)
{
_permissionService = permissionService;
_orderService = orderService;
_workContext = workContext;
_storeContext = storeContext;
_customerService = customerService;
_countryService = countryService;
_stateProvinceService = stateProvinceService;
_innVoiceApiService = innVoiceApiService;
_productService = productService;
_fruitBankAttributeService = fruitBankAttributeService;
}
public async Task<IActionResult> List()
[HttpPost]
public async Task<IActionResult> CreateInvoice(int orderId)
{
if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL))
return AccessDeniedView();
try
{
var order = await _orderService.GetOrderByIdAsync(orderId);
if (order == null)
return Json(new { success = false, message = "Order not found" });
return View("~/Plugins/Misc.FruitBankPlugin/Areas/Admin/Views/Invoice/List.cshtml");
var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId);
var billingAddress = await _customerService.GetCustomerBillingAddressAsync(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 = true,
Email = billingAddress.Email,
MegrendelesSzamStr = order.CustomOrderNumber,
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
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Order, string>(orderId, nameof(InvoiceCreateResponse.TechId), response.TechId);
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
{
// Get the invoice from InnVoice using the saved TechId
var techId = await _fruitBankAttributeService.GetGenericAttributeValueAsync<Order, string>(
orderId,
nameof(InvoiceCreateResponse.TechId),
_storeContext.GetCurrentStore().Id
);
if (string.IsNullOrEmpty(techId))
{
return Json(new
{
success = false,
message = "No invoice TechId found for this order"
});
}
var invoices = await _innVoiceApiService.GetInvoiceByTechIdAsync(techId);
if (invoices != null && invoices.Count > 0)
{
var invoice = invoices.FirstOrDefault();
return Json(new
{
success = true,
data = new
{
tableId = invoice.TableId,
invoiceNumber = invoice.InvoiceNumberFormatted, // or invoice.InvoiceNumber
sorszam = invoice.InvoiceNumberFormatted,
printUrl = invoice.PrintUrl,
customerName = invoice.CustomerName,
totalGross = invoice.TotalGross,
currency = invoice.Currency,
isProforma = invoice.IsProforma,
isDraft = invoice.IsDraft
}
});
}
return Json(new
{
success = false,
message = "No invoice found for this order"
});
}
catch (Exception ex)
{
return Json(new
{
success = false,
message = $"Error: {ex.Message}"
});
}
}
}
}

View File

@ -81,6 +81,8 @@ public class PluginNopStartup : INopStartup
services.AddScoped<IConsumer<OrderPlacedEvent>, EventConsumer>();
services.AddScoped<IOrderMeasurementService, OrderMeasurementService>();
services.AddScoped<PendingMeasurementCheckoutFilter>();
services.AddScoped<InnVoiceApiService>();
services.AddScoped<InnVoiceOrderService>();
//services.AddScoped<OrderListModel, OrderListModelExtended>();
//services.AddScoped<OrderModel, OrderModelExtended>();

View File

@ -136,6 +136,11 @@ public class RouteProvider : IRouteProvider
name: "Plugin.FruitBank.Admin.Orders.CustomerSearchAutoComplete",
pattern: "Admin/CustomOrder/CustomerSearchAutoComplete",
defaults: new { controller = "CustomOrder", action = "CustomerSearchAutoComplete", area = AreaNames.ADMIN });
endpointRouteBuilder.MapControllerRoute(
name: "Plugin.FruitBank.Admin.Invoice.CreateInvoice",
pattern: "Admin/Invoice/CreateInvoice",
defaults: new { controller = "Invoice", action = "CreateInvoice", area = AreaNames.ADMIN });
}
/// <summary>

View File

@ -7,9 +7,6 @@
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<CopyRefAssembliesToPublishDirectory>true</CopyRefAssembliesToPublishDirectory>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Services\InnvoiceApiService.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="logo.jpg" />
@ -637,10 +634,6 @@
<Content Include="$(OutDir)\System.ServiceModel.Primitives.dll" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<None Include="Services\InnvoiceApiService.cs" />
</ItemGroup>
<!-- This target execute after "Build" target -->
<Target Name="NopTarget" AfterTargets="Build">
<MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(OutDir)" Targets="NopClear" />

View File

@ -0,0 +1,417 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Linq;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services
{
/// <summary>
/// Service for managing orders in InnVoice API
/// </summary>
public class InnVoiceOrderService
{
private readonly HttpClient _httpClient;
private readonly string _companyName;
private readonly string _username;
private readonly string _password;
private readonly string _baseUrl;
public InnVoiceOrderService(string companyName = "apiteszt", string username = "apiteszt", string password = "dsjfluio4324hjhjfdhkjskjh213kjgsd", string baseUrl = "https://api.innvoice.hu")
{
_companyName = companyName ?? throw new ArgumentNullException(nameof(companyName));
_username = username ?? throw new ArgumentNullException(nameof(username));
_password = password ?? throw new ArgumentNullException(nameof(password));
_baseUrl = baseUrl.TrimEnd('/');
_httpClient = new HttpClient();
SetupAuthentication();
}
private void SetupAuthentication()
{
var authToken = Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes($"{_username}:{_password}")
);
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken);
}
/// <summary>
/// Create one or more orders
/// </summary>
public async Task<List<OrderCreateResponse>> CreateOrdersAsync(List<OrderCreateRequest> orders)
{
var url = $"{_baseUrl}/{_companyName}/order";
var xml = BuildOrdersXml(orders);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", xml)
});
try
{
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return ParseOrderResponses(responseContent);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error creating orders: {ex.Message}", ex);
}
}
/// <summary>
/// Create a single order
/// </summary>
public async Task<OrderCreateResponse> CreateOrderAsync(OrderCreateRequest order)
{
var responses = await CreateOrdersAsync(new List<OrderCreateRequest> { order });
return responses.FirstOrDefault();
}
private string BuildOrdersXml(List<OrderCreateRequest> orders)
{
var ordersElement = new XElement("orders");
foreach (var order in orders)
{
var orderElement = new XElement("order");
orderElement.Add(new XElement("VevoNev", new XCData(order.VevoNev ?? "")));
orderElement.Add(new XElement("VevoIrsz", new XCData(order.VevoIrsz ?? "")));
orderElement.Add(new XElement("VevoTelep", new XCData(order.VevoTelep ?? "")));
orderElement.Add(new XElement("VevoUtcaHsz", new XCData(order.VevoUtcaHsz ?? "")));
if (!string.IsNullOrEmpty(order.VevoOrszag))
orderElement.Add(new XElement("VevoOrszag", new XCData(order.VevoOrszag)));
if (!string.IsNullOrEmpty(order.VevoAdoszam))
orderElement.Add(new XElement("VevoAdoszam", new XCData(order.VevoAdoszam)));
if (!string.IsNullOrEmpty(order.SzallNev))
orderElement.Add(new XElement("SzallNev", new XCData(order.SzallNev)));
if (!string.IsNullOrEmpty(order.SzallIrsz))
orderElement.Add(new XElement("SzallIrsz", new XCData(order.SzallIrsz)));
if (!string.IsNullOrEmpty(order.SzallTelep))
orderElement.Add(new XElement("SzallTelep", new XCData(order.SzallTelep)));
if (!string.IsNullOrEmpty(order.SzallUtcaHsz))
orderElement.Add(new XElement("SzallUtcaHsz", new XCData(order.SzallUtcaHsz)));
if (!string.IsNullOrEmpty(order.SzallOrszag))
orderElement.Add(new XElement("SzallOrszag", new XCData(order.SzallOrszag)));
orderElement.Add(new XElement("MegrendelestombID", new XCData(order.MegrendelestombID.ToString())));
orderElement.Add(new XElement("MegrendelesKelte", new XCData(order.MegrendelesKelte.ToString("yyyy.MM.dd."))));
orderElement.Add(new XElement("Hatarido", new XCData(order.Hatarido.ToString("yyyy.MM.dd."))));
orderElement.Add(new XElement("Devizanem", new XCData(order.Devizanem ?? "")));
if (!string.IsNullOrEmpty(order.FizetesiMod))
orderElement.Add(new XElement("FizetesiMod", new XCData(order.FizetesiMod)));
if (!string.IsNullOrEmpty(order.Megjegyzes))
orderElement.Add(new XElement("Megjegyzes", new XCData(order.Megjegyzes)));
if (!string.IsNullOrEmpty(order.Email))
orderElement.Add(new XElement("Email", new XCData(order.Email)));
if (!string.IsNullOrEmpty(order.Telefon))
orderElement.Add(new XElement("Telefon", new XCData(order.Telefon)));
if (!string.IsNullOrEmpty(order.MegrendelesSzamStr))
orderElement.Add(new XElement("MegrendelesSzamStr", new XCData(order.MegrendelesSzamStr)));
// Add items
foreach (var item in order.Items)
{
var tetelElement = new XElement("tetel");
tetelElement.Add(new XElement("TetelNev", item.TetelNev ?? ""));
tetelElement.Add(new XElement("AfaSzoveg", item.AfaSzoveg ?? ""));
tetelElement.Add(new XElement("Brutto", item.Brutto ? "1" : "0"));
tetelElement.Add(new XElement("EgysegAr", item.EgysegAr.ToString()));
tetelElement.Add(new XElement("Mennyiseg", item.Mennyiseg.ToString()));
tetelElement.Add(new XElement("MennyisegEgyseg", new XCData(item.MennyisegEgyseg ?? "")));
if (!string.IsNullOrEmpty(item.CikkSzam))
tetelElement.Add(new XElement("CikkSzam", new XCData(item.CikkSzam)));
orderElement.Add(tetelElement);
}
ordersElement.Add(orderElement);
}
return new XDeclaration("1.0", "UTF-8", null).ToString() + "\n" + ordersElement.ToString();
}
private List<OrderCreateResponse> ParseOrderResponses(string xml)
{
var responses = new List<OrderCreateResponse>();
try
{
var doc = XDocument.Parse(xml);
var orderElements = doc.Descendants("order");
foreach (var orderElement in orderElements)
{
var response = new OrderCreateResponse
{
ErrorCode = orderElement.Element("error")?.Value?.Trim(),
Message = orderElement.Element("message")?.Value?.Trim(),
TableId = int.TryParse(orderElement.Element("TABLE_ID")?.Value?.Trim(), out var tid) ? tid : (int?)null,
TechId = orderElement.Element("techid")?.Value?.Trim(),
PrintUrl = orderElement.Element("PrintUrl")?.Value?.Trim()
};
responses.Add(response);
}
}
catch (Exception ex)
{
throw new InnVoiceApiException($"Error parsing order response XML: {ex.Message}", ex);
}
return responses;
}
/// <summary>
/// Get order by technical ID
/// </summary>
public async Task<List<InnVoiceOrder>> GetOrderByTechIdAsync(string techId)
{
var url = $"{_baseUrl}/{_companyName}/order/techid/{Uri.EscapeDataString(techId)}";
return await GetOrdersFromUrlAsync(url);
}
/// <summary>
/// Get order by table ID
/// </summary>
public async Task<InnVoiceOrder> GetOrderByIdAsync(int tableId)
{
var url = $"{_baseUrl}/{_companyName}/order/id/{tableId}";
var orders = await GetOrdersFromUrlAsync(url);
return orders.Count > 0 ? orders[0] : null;
}
private async Task<List<InnVoiceOrder>> GetOrdersFromUrlAsync(string url)
{
try
{
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
// Parse XML response
return ParseOrdersFromXml(content);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error calling InnVoice API: {ex.Message}", ex);
}
catch (Exception ex)
{
throw new InnVoiceApiException($"Error parsing API response: {ex.Message}", ex);
}
}
private List<InnVoiceOrder> ParseOrdersFromXml(string xml)
{
var orders = new List<InnVoiceOrder>();
try
{
var doc = XDocument.Parse(xml);
var orderElements = doc.Descendants("order");
foreach (var orderElement in orderElements)
{
var order = new InnVoiceOrder
{
TableId = GetIntValue(orderElement, "TABLE_ID"),
VevoID = GetIntValue(orderElement, "VevoID"),
CustomerName = GetStringValue(orderElement, "VevoNev"),
CustomerZipCode = GetStringValue(orderElement, "VevoIrsz"),
CustomerCity = GetStringValue(orderElement, "VevoTelep"),
CustomerAddress = GetStringValue(orderElement, "VevoUtcaHsz"),
CustomerCountry = GetStringValue(orderElement, "VevoOrszag"),
CustomerTaxNumber = GetStringValue(orderElement, "VevoAdoszam"),
ShippingName = GetStringValue(orderElement, "SzallNev"),
ShippingZipCode = GetStringValue(orderElement, "SzallIrsz"),
ShippingCity = GetStringValue(orderElement, "SzallTelep"),
ShippingAddress = GetStringValue(orderElement, "SzallUtcaHsz"),
ShippingCountry = GetStringValue(orderElement, "SzallOrszag"),
OrderBookId = GetIntValue(orderElement, "MegrendelestombID"),
OrderDate = GetStringValue(orderElement, "MegrendelesKelte"),
DueDate = GetStringValue(orderElement, "Hatarido"),
Currency = GetStringValue(orderElement, "Devizanem"),
PaymentMethod = GetStringValue(orderElement, "FizetesiMod"),
Notes = GetStringValue(orderElement, "Megjegyzes"),
Email = GetStringValue(orderElement, "Email"),
Phone = GetStringValue(orderElement, "Telefon"),
ExternalOrderNumber = GetStringValue(orderElement, "MegrendelesSzamStr"),
TotalNet = GetDecimalValue(orderElement, "NettoErtek"),
TotalVAT = GetDecimalValue(orderElement, "AFAErtek"),
TotalGross = GetDecimalValue(orderElement, "BruttoErtek"),
TechId = GetStringValue(orderElement, "techid"),
PrintUrl = GetStringValue(orderElement, "PrintLink"),
UpdateTime = GetStringValue(orderElement, "_UpdateTime"),
QueryTime = GetStringValue(orderElement, "QueryTime")
};
// Parse line items
var itemElements = orderElement.Descendants("tetel");
foreach (var itemElement in itemElements)
{
order.Items.Add(new InnVoiceOrderLineItem
{
TableId = GetIntValue(itemElement, "TABLE_ID"),
ItemName = GetStringValue(itemElement, "TetelNev"),
ArticleNumber = GetStringValue(itemElement, "CikkSzam"),
VATText = GetStringValue(itemElement, "AfaSzoveg"),
VATRate = GetDecimalValue(itemElement, "AfaKulcs"),
IsGross = GetIntValue(itemElement, "Brutto") == 1,
UnitPrice = GetDecimalValue(itemElement, "EgysegAr"),
Quantity = GetDecimalValue(itemElement, "Mennyiseg"),
Unit = GetStringValue(itemElement, "MennyisegEgyseg")
});
}
orders.Add(order);
}
}
catch (Exception ex)
{
throw new InnVoiceApiException($"Error parsing XML: {ex.Message}", ex);
}
return orders;
}
private string GetStringValue(XElement element, string name)
{
return element.Element(name)?.Value?.Trim() ?? string.Empty;
}
private int GetIntValue(XElement element, string name)
{
var value = GetStringValue(element, name);
return int.TryParse(value, out var result) ? result : 0;
}
private decimal GetDecimalValue(XElement element, string name)
{
var value = GetStringValue(element, name);
return decimal.TryParse(value, out var result) ? result : 0m;
}
}
// Order Models
public class OrderCreateRequest
{
public string VevoNev { get; set; }
public string VevoIrsz { get; set; }
public string VevoTelep { get; set; }
public string VevoUtcaHsz { get; set; }
public string VevoOrszag { get; set; }
public string VevoAdoszam { get; set; }
public string SzallNev { get; set; }
public string SzallIrsz { get; set; }
public string SzallTelep { get; set; }
public string SzallUtcaHsz { get; set; }
public string SzallOrszag { get; set; }
public int MegrendelestombID { get; set; }
public DateTime MegrendelesKelte { get; set; }
public DateTime Hatarido { get; set; }
public string Devizanem { get; set; }
public string FizetesiMod { get; set; }
public string Megjegyzes { get; set; }
public string Email { get; set; }
public string Telefon { get; set; }
public string MegrendelesSzamStr { get; set; }
public List<InnVoiceOrderItem> Items { get; set; } = new List<InnVoiceOrderItem>();
public void AddItem(InnVoiceOrderItem item)
{
Items.Add(item);
}
}
public class InnVoiceOrderItem
{
public string TetelNev { get; set; }
public string AfaSzoveg { get; set; }
public bool Brutto { get; set; }
public decimal EgysegAr { get; set; }
public decimal Mennyiseg { get; set; }
public string MennyisegEgyseg { get; set; }
public string CikkSzam { get; set; }
}
public class OrderCreateResponse
{
public string ErrorCode { get; set; }
public string Message { get; set; }
public int? TableId { get; set; }
public string TechId { get; set; }
public string PrintUrl { get; set; }
public bool IsSuccess => ErrorCode == "200";
}
public class InnVoiceApiException : Exception
{
public InnVoiceApiException(string message) : base(message) { }
public InnVoiceApiException(string message, Exception innerException) : base(message, innerException) { }
}
// Order GET response models
public class InnVoiceOrder
{
public int TableId { get; set; }
public int VevoID { get; set; }
public string CustomerName { get; set; }
public string CustomerZipCode { get; set; }
public string CustomerCity { get; set; }
public string CustomerAddress { get; set; }
public string CustomerCountry { get; set; }
public string CustomerTaxNumber { get; set; }
public string ShippingName { get; set; }
public string ShippingZipCode { get; set; }
public string ShippingCity { get; set; }
public string ShippingAddress { get; set; }
public string ShippingCountry { get; set; }
public int OrderBookId { get; set; }
public string OrderDate { get; set; }
public string DueDate { get; set; }
public string Currency { get; set; }
public string PaymentMethod { get; set; }
public string Notes { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string ExternalOrderNumber { get; set; }
public decimal TotalNet { get; set; }
public decimal TotalVAT { get; set; }
public decimal TotalGross { get; set; }
public string TechId { get; set; }
public string PrintUrl { get; set; }
public string UpdateTime { get; set; }
public string QueryTime { get; set; }
public List<InnVoiceOrderLineItem> Items { get; set; } = new List<InnVoiceOrderLineItem>();
}
public class InnVoiceOrderLineItem
{
public int TableId { get; set; }
public string ItemName { get; set; }
public string ArticleNumber { get; set; }
public string VATText { get; set; }
public decimal VATRate { get; set; }
public bool IsGross { get; set; }
public decimal UnitPrice { get; set; }
public decimal Quantity { get; set; }
public string Unit { get; set; }
}
}

View File

@ -1,4 +1,5 @@
using System;

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
@ -10,487 +11,627 @@ using System.Text;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services
{
/// <summary>
/// Service for interacting with InnVoice Invoice API
/// API Documentation: https://help.innvoice.hu/hc/hu/articles/360003142839
/// </summary>
public class InnVoiceApiService
{
private readonly HttpClient _httpClient;
private readonly string _companyName;
private readonly string _username;
private readonly string _password;
private readonly string _baseUrl;
/// <summary>
/// Service for interacting with InnVoice Invoice API
/// API Documentation: https://help.innvoice.hu/hc/hu/articles/360003142839
/// </summary>
public class InnVoiceApiService
{
private readonly HttpClient _httpClient;
private readonly string _companyName;
private readonly string _username;
private readonly string _password;
private readonly string _baseUrl;
public InnVoiceApiService(string companyName, string username, string password, string baseUrl = "https://api.innvoice.hu")
{
_companyName = companyName ?? throw new ArgumentNullException(nameof(companyName));
_username = username ?? throw new ArgumentNullException(nameof(username));
_password = password ?? throw new ArgumentNullException(nameof(password));
_baseUrl = baseUrl.TrimEnd('/');
public InnVoiceApiService(string companyName = "apiteszt", string username = "apiteszt", string password = "dsjfluio4324hjhjfdhkjskjh213kjgsd", string baseUrl = "https://api.innvoice.hu")
{
_companyName = companyName ?? throw new ArgumentNullException(nameof(companyName));
_username = username ?? throw new ArgumentNullException(nameof(username));
_password = password ?? throw new ArgumentNullException(nameof(password));
_baseUrl = baseUrl.TrimEnd('/');
_httpClient = new HttpClient();
SetupAuthentication();
}
_httpClient = new HttpClient();
SetupAuthentication();
}
private void SetupAuthentication()
{
var authToken = Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes($"{_username}:{_password}")
);
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken);
}
private void SetupAuthentication()
{
var authToken = Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes($"{_username}:{_password}")
);
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken);
}
/// <summary>
/// Get all invoices
/// Rate limit: 20 times per hour without ID parameter
/// </summary>
public async Task<List<Invoice>> GetAllInvoicesAsync()
{
var url = $"{_baseUrl}/{_companyName}/invoice";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get all invoices
/// Rate limit: 20 times per hour without ID parameter
/// </summary>
public async Task<List<Invoice>> GetAllInvoicesAsync()
{
var url = $"{_baseUrl}/{_companyName}/invoice";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoice by internal table ID
/// </summary>
public async Task<Invoice> GetInvoiceByIdAsync(int tableId)
{
var url = $"{_baseUrl}/{_companyName}/invoice/id/{tableId}";
var invoices = await GetInvoicesFromUrlAsync(url);
return invoices.Count > 0 ? invoices[0] : null;
}
/// <summary>
/// Get invoice by internal table ID
/// </summary>
public async Task<Invoice> GetInvoiceByIdAsync(int tableId)
{
var url = $"{_baseUrl}/{_companyName}/invoice/id/{tableId}";
var invoices = await GetInvoicesFromUrlAsync(url);
return invoices.Count > 0 ? invoices[0] : null;
}
/// <summary>
/// Get invoice by invoice number
/// </summary>
public async Task<List<Invoice>> GetInvoiceByNumberAsync(string invoiceNumber)
{
var url = $"{_baseUrl}/{_companyName}/invoice/invoicenumber/{Uri.EscapeDataString(invoiceNumber)}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoice by invoice number
/// </summary>
public async Task<List<Invoice>> GetInvoiceByNumberAsync(string invoiceNumber)
{
var url = $"{_baseUrl}/{_companyName}/invoice/invoicenumber/{Uri.EscapeDataString(invoiceNumber)}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by creation date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByCreationDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/created/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoice by invoice number
/// </summary>
public async Task<List<Invoice>> GetInvoiceByTechIdAsync(string techId)
{
//api.innvoice.hu/%regnev%/invoice/techid/%TECHID%
var url = $"{_baseUrl}/{_companyName}/invoice/techid/{Uri.EscapeDataString(techId)}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by fulfillment date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByFulfillmentDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/fulfillment/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by due date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByDueDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/duedate/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by creation date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByCreationDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/created/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by payment date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByPaymentDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/paymentdate/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by fulfillment date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByFulfillmentDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/fulfillment/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by customer tax number
/// </summary>
public async Task<List<Invoice>> GetInvoicesByCustomerTaxNumberAsync(string taxNumber)
{
var url = $"{_baseUrl}/{_companyName}/invoice/taxnumber/{Uri.EscapeDataString(taxNumber)}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by due date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByDueDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/duedate/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices modified since a specific timestamp
/// Format: YYYYMMDDHHmmss (year, month, day, hour, minute, second)
/// Recommended for tracking changes every 10 minutes
/// Rate limit: Full queries or queries older than current month limited to 10 times per 30 days
/// Recommended: Only use current month dates
/// </summary>
public async Task<List<Invoice>> GetInvoicesByUpdateTimeAsync(DateTime updateTime)
{
var timeStr = updateTime.ToString("yyyyMMddHHmmss");
var url = $"{_baseUrl}/{_companyName}/invoice/updatedtime/{timeStr}";
return await GetInvoicesFromUrlAsync(url);
}
/// <summary>
/// Get invoices by payment date
/// Format: YYYYMMDD
/// </summary>
public async Task<List<Invoice>> GetInvoicesByPaymentDateAsync(DateTime date)
{
var dateStr = date.ToString("yyyyMMdd");
var url = $"{_baseUrl}/{_companyName}/invoice/paymentdate/{dateStr}";
return await GetInvoicesFromUrlAsync(url);
}
private async Task<List<Invoice>> GetInvoicesFromUrlAsync(string url)
{
try
{
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
/// <summary>
/// Get invoices by customer tax number
/// </summary>
public async Task<List<Invoice>> GetInvoicesByCustomerTaxNumberAsync(string taxNumber)
{
var url = $"{_baseUrl}/{_companyName}/invoice/taxnumber/{Uri.EscapeDataString(taxNumber)}";
return await GetInvoicesFromUrlAsync(url);
}
var content = await response.Content.ReadAsStringAsync();
var invoices = JsonSerializer.Deserialize<List<Invoice>>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
/// <summary>
/// Get invoices modified since a specific timestamp
/// Format: YYYYMMDDHHmmss (year, month, day, hour, minute, second)
/// Recommended for tracking changes every 10 minutes
/// Rate limit: Full queries or queries older than current month limited to 10 times per 30 days
/// Recommended: Only use current month dates
/// </summary>
public async Task<List<Invoice>> GetInvoicesByUpdateTimeAsync(DateTime updateTime)
{
var timeStr = updateTime.ToString("yyyyMMddHHmmss");
var url = $"{_baseUrl}/{_companyName}/invoice/updatedtime/{timeStr}";
return await GetInvoicesFromUrlAsync(url);
}
return invoices ?? new List<Invoice>();
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error calling InnVoice API: {ex.Message}", ex);
}
catch (JsonException ex)
{
throw new InnVoiceApiException($"Error parsing API response: {ex.Message}", ex);
}
}
}
private async Task<List<Invoice>> GetInvoicesFromUrlAsync(string url)
{
try
{
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
// Models
public class Invoice
{
[JsonPropertyName("TABLE_ID")]
public int TableId { get; set; }
var content = await response.Content.ReadAsStringAsync();
[JsonPropertyName("InvoiceNumber")]
public string InvoiceNumber { get; set; }
// Parse XML response
return ParseInvoicesFromXml(content);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error calling InnVoice API: {ex.Message}", ex);
}
catch (Exception ex)
{
throw new InnVoiceApiException($"Error parsing API response: {ex.Message}", ex);
}
}
[JsonPropertyName("Created")]
public string Created { get; set; }
[JsonPropertyName("Fulfillment")]
public string Fulfillment { get; set; }
[JsonPropertyName("DueDate")]
public string DueDate { get; set; }
private List<Invoice> ParseInvoicesFromXml(string xml)
{
var invoices = new List<Invoice>();
[JsonPropertyName("PaymentDate")]
public string PaymentDate { get; set; }
try
{
var doc = XDocument.Parse(xml);
var invoiceElements = doc.Descendants("invoice");
[JsonPropertyName("CustomerName")]
public string CustomerName { get; set; }
foreach (var invoiceElement in invoiceElements)
{
var invoice = new Invoice
{
TableId = GetIntValue(invoiceElement, "TABLE_ID"),
VevoID = GetIntValue(invoiceElement, "VevoID"),
CustomerName = GetStringValue(invoiceElement, "VevoNev"),
CustomerZipCode = GetStringValue(invoiceElement, "VevoIrsz"),
CustomerCity = GetStringValue(invoiceElement, "VevoTelep"),
CustomerAddress = GetStringValue(invoiceElement, "VevoUtcaHsz"),
CustomerCountry = GetStringValue(invoiceElement, "VevoOrszag"),
CustomerTaxNumber = GetStringValue(invoiceElement, "VevoAdoszam"),
CustomerGroupTaxNumber = GetStringValue(invoiceElement, "VevoCsAdoszam"),
PaymentMethod = GetStringValue(invoiceElement, "FizetesiMod"),
FulfillmentDate = GetStringValue(invoiceElement, "TeljesitesKelte"),
InvoiceDate = GetStringValue(invoiceElement, "SzamlaKelte"),
DueDate = GetStringValue(invoiceElement, "Hatarido"),
Notes = GetStringValue(invoiceElement, "Megjegyzes"),
Currency = GetStringValue(invoiceElement, "Devizanem"),
IsDraft = GetIntValue(invoiceElement, "Felretett") == 1,
IsCancelled = GetIntValue(invoiceElement, "Storno") == 1,
IsAdvance = GetIntValue(invoiceElement, "Eloleg") == 1,
IsProforma = GetIntValue(invoiceElement, "Proforma") == 1,
TotalNet = GetDecimalValue(invoiceElement, "NettoErtek"),
TotalVAT = GetDecimalValue(invoiceElement, "AFAErtek"),
TotalGross = GetDecimalValue(invoiceElement, "BruttoErtek"),
OutstandingAmount = GetDecimalValue(invoiceElement, "Hatralek"),
OverdueAmount = GetDecimalValue(invoiceElement, "LejartHatralek"),
PaidAmount = GetDecimalValue(invoiceElement, "Befizetes"),
InvoiceNumber = GetStringValue(invoiceElement, "Sorszam"),
InvoiceNumberFormatted = GetStringValue(invoiceElement, "SorszamFormatted"),
InvoiceId = GetIntValue(invoiceElement, "SzamlaID"),
UniqueId = GetStringValue(invoiceElement, "_UniqueID"),
ExchangeRate = GetDecimalValue(invoiceElement, "Arfolyam"),
InvoiceBookId = GetIntValue(invoiceElement, "SzamlatombID"),
InvoiceBookName = GetStringValue(invoiceElement, "SzamlatombNev"),
IsElectronic = GetIntValue(invoiceElement, "Eszamla") == 1,
Phone = GetStringValue(invoiceElement, "Telefon"),
Email = GetStringValue(invoiceElement, "Email"),
UpdateTime = GetStringValue(invoiceElement, "_UpdateTime"),
QueryTime = GetStringValue(invoiceElement, "QueryTime"),
OrderNumber = GetStringValue(invoiceElement, "MegrendelesSzamStr"),
OrderDate = GetStringValue(invoiceElement, "MegrendelesIdopontStr"),
ShippingName = GetStringValue(invoiceElement, "SzallNev"),
ShippingZipCode = GetStringValue(invoiceElement, "SzallIrsz"),
ShippingCity = GetStringValue(invoiceElement, "SzallTelep"),
ShippingAddress = GetStringValue(invoiceElement, "SzallUtcaHsz"),
ShippingCountry = GetStringValue(invoiceElement, "SzallOrszag"),
PrintUrl = GetStringValue(invoiceElement, "PrintLink"),
InvoiceLink = GetStringValue(invoiceElement, "SzamlaLink"),
HealthFundName = GetStringValue(invoiceElement, "VevoEPNev"),
HealthFundCode = GetStringValue(invoiceElement, "VevoEPKod")
};
[JsonPropertyName("CustomerTaxNumber")]
public string CustomerTaxNumber { get; set; }
// Parse line items
var itemElements = invoiceElement.Descendants("tetel");
foreach (var itemElement in itemElements)
{
invoice.Items.Add(new InvoiceLineItem
{
TableId = GetIntValue(itemElement, "TABLE_ID"),
ItemName = GetStringValue(itemElement, "TetelNev"),
ArticleNumber = GetStringValue(itemElement, "CikkSzam"),
VTSZSZJ = GetStringValue(itemElement, "VTSZSZJ"),
VATText = GetStringValue(itemElement, "AfaSzoveg"),
VATRate = GetDecimalValue(itemElement, "AfaKulcs"),
IsGross = GetIntValue(itemElement, "Brutto") == 1,
UnitPrice = GetDecimalValue(itemElement, "EgysegAr"),
Quantity = GetDecimalValue(itemElement, "Mennyiseg"),
Unit = GetStringValue(itemElement, "MennyisegEgyseg"),
ProductId = GetIntValue(itemElement, "TermekID"),
DiscountAmount = GetDecimalValue(itemElement, "KedvezmenyOsszeg")
});
}
[JsonPropertyName("CustomerAddress")]
public string CustomerAddress { get; set; }
invoices.Add(invoice);
}
}
catch (Exception ex)
{
throw new InnVoiceApiException($"Error parsing XML: {ex.Message}", ex);
}
[JsonPropertyName("TotalNet")]
public decimal TotalNet { get; set; }
return invoices;
}
[JsonPropertyName("TotalGross")]
public decimal TotalGross { get; set; }
private string GetStringValue(XElement element, string name)
{
return element.Element(name)?.Value?.Trim() ?? string.Empty;
}
[JsonPropertyName("Currency")]
public string Currency { get; set; }
private int GetIntValue(XElement element, string name)
{
var value = GetStringValue(element, name);
return int.TryParse(value, out var result) ? result : 0;
}
[JsonPropertyName("Status")]
public string Status { get; set; }
private decimal GetDecimalValue(XElement element, string name)
{
var value = GetStringValue(element, name);
return decimal.TryParse(value, out var result) ? result : 0m;
}
[JsonPropertyName("InvoiceType")]
public string InvoiceType { get; set; }
[JsonPropertyName("PaymentMethod")]
public string PaymentMethod { get; set; }
// Add more properties as needed based on actual API response
}
public class InnVoiceApiException : Exception
{
public InnVoiceApiException(string message) : base(message) { }
public InnVoiceApiException(string message, Exception innerException) : base(message, innerException) { }
}
// Invoice Creation Models
public class InvoiceCreateRequest
{
public int VevoID { get; set; } = 0;
public string VevoNev { get; set; }
public string VevoIrsz { get; set; }
public string VevoOrszag { get; set; }
public string VevoTelep { get; set; }
public string VevoUtcaHsz { get; set; }
public string VevoEPNev { get; set; }
public string VevoEPKod { get; set; }
public string SzallNev { get; set; }
public string SzallIrsz { get; set; }
public string SzallTelep { get; set; }
public string SzallUtcaHsz { get; set; }
public string SzallOrszag { get; set; }
public int SzamlatombID { get; set; }
public DateTime SzamlaKelte { get; set; }
public DateTime TeljesitesKelte { get; set; }
public DateTime Hatarido { get; set; }
public string Devizanem { get; set; }
public string FizetesiMod { get; set; }
public string Megjegyzes { get; set; }
public string Nyelv1 { get; set; }
public string Nyelv2 { get; set; }
public decimal? Arfolyam { get; set; }
public string ArfolyamDeviza { get; set; }
public bool Fizetve { get; set; }
public bool Eszamla { get; set; }
public string VevoAdoszam { get; set; }
public string VevoCsAdoszam { get; set; }
public string Telefon { get; set; }
public string Email { get; set; }
public string MegrendelesSzamStr { get; set; }
public string MegrendelesIdopontStr { get; set; }
public bool Felretett { get; set; }
public bool Proforma { get; set; }
public bool AutomatikusAr { get; set; }
public bool Eloleg { get; set; }
public bool Sendmail { get; set; }
public string MailSubject { get; set; }
public string MailBody { get; set; }
public string Eredetiszamla { get; set; }
public List<InvoiceItem> Items { get; set; } = new List<InvoiceItem>();
public void AddItem(InvoiceItem item)
{
Items.Add(item);
}
public string ToXml()
{
var invoices = new XElement("invoices");
var invoice = new XElement("invoice");
if (VevoID > 0)
invoice.Add(new XElement("VevoID", new XCData(VevoID.ToString())));
invoice.Add(new XElement("VevoNev", new XCData(VevoNev ?? "")));
invoice.Add(new XElement("VevoIrsz", new XCData(VevoIrsz ?? "")));
invoice.Add(new XElement("VevoTelep", new XCData(VevoTelep ?? "")));
invoice.Add(new XElement("VevoOrszag", new XCData(VevoOrszag ?? "")));
invoice.Add(new XElement("VevoUtcaHsz", new XCData(VevoUtcaHsz ?? "")));
if (!string.IsNullOrEmpty(VevoEPNev))
invoice.Add(new XElement("VevoEPNev", new XCData(VevoEPNev)));
if (!string.IsNullOrEmpty(VevoEPKod))
invoice.Add(new XElement("VevoEPKod", new XCData(VevoEPKod)));
if (!string.IsNullOrEmpty(SzallNev))
invoice.Add(new XElement("SzallNev", new XCData(SzallNev)));
if (!string.IsNullOrEmpty(SzallIrsz))
invoice.Add(new XElement("SzallIrsz", new XCData(SzallIrsz)));
if (!string.IsNullOrEmpty(SzallTelep))
invoice.Add(new XElement("SzallTelep", new XCData(SzallTelep)));
if (!string.IsNullOrEmpty(SzallUtcaHsz))
invoice.Add(new XElement("SzallUtcaHsz", new XCData(SzallUtcaHsz)));
if (!string.IsNullOrEmpty(SzallOrszag))
invoice.Add(new XElement("SzallOrszag", new XCData(SzallOrszag)));
invoice.Add(new XElement("SzamlatombID", new XCData(SzamlatombID.ToString())));
invoice.Add(new XElement("SzamlaKelte", new XCData(SzamlaKelte.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("TeljesitesKelte", new XCData(TeljesitesKelte.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("Hatarido", new XCData(Hatarido.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("Devizanem", new XCData(Devizanem ?? "")));
invoice.Add(new XElement("FizetesiMod", new XCData(FizetesiMod ?? "")));
if (!string.IsNullOrEmpty(Megjegyzes))
invoice.Add(new XElement("Megjegyzes", new XCData(Megjegyzes)));
if (!string.IsNullOrEmpty(Nyelv1))
invoice.Add(new XElement("Nyelv1", new XCData(Nyelv1)));
if (!string.IsNullOrEmpty(Nyelv2))
invoice.Add(new XElement("Nyelv2", new XCData(Nyelv2)));
if (Arfolyam.HasValue)
invoice.Add(new XElement("Arfolyam", new XCData(Arfolyam.Value.ToString())));
if (!string.IsNullOrEmpty(ArfolyamDeviza))
invoice.Add(new XElement("ArfolyamDeviza", new XCData(ArfolyamDeviza)));
invoice.Add(new XElement("Fizetve", Fizetve ? "1" : "0"));
invoice.Add(new XElement("Eszamla", Eszamla ? "1" : "0"));
if (!string.IsNullOrEmpty(VevoAdoszam))
invoice.Add(new XElement("VevoAdoszam", new XCData(VevoAdoszam)));
if (!string.IsNullOrEmpty(VevoCsAdoszam))
invoice.Add(new XElement("VevoCsAdoszam", new XCData(VevoCsAdoszam)));
if (!string.IsNullOrEmpty(Telefon))
invoice.Add(new XElement("Telefon", new XCData(Telefon)));
if (!string.IsNullOrEmpty(Email))
invoice.Add(new XElement("Email", new XCData(Email)));
if (!string.IsNullOrEmpty(MegrendelesSzamStr))
invoice.Add(new XElement("MegrendelesSzamStr", new XCData(MegrendelesSzamStr)));
if (!string.IsNullOrEmpty(MegrendelesIdopontStr))
invoice.Add(new XElement("MegrendelesIdopontStr", new XCData(MegrendelesIdopontStr)));
invoice.Add(new XElement("Felretett", Felretett ? "1" : "0"));
invoice.Add(new XElement("Proforma", Proforma ? "1" : "0"));
if (AutomatikusAr)
invoice.Add(new XElement("AutomatikusAr", "1"));
if (Eloleg)
invoice.Add(new XElement("Eloleg", "1"));
if (Sendmail)
{
invoice.Add(new XElement("Sendmail", "1"));
if (!string.IsNullOrEmpty(MailSubject))
invoice.Add(new XElement("MailSubject", new XCData(MailSubject)));
if (!string.IsNullOrEmpty(MailBody))
invoice.Add(new XElement("MailBody", new XCData(MailBody)));
}
if (!string.IsNullOrEmpty(Eredetiszamla))
invoice.Add(new XElement("Eredetiszamla", new XCData(Eredetiszamla)));
// Add items
foreach (var item in Items)
{
var tetel = new XElement("tetel");
tetel.Add(new XElement("TetelNev", new XCData(item.TetelNev ?? "")));
tetel.Add(new XElement("AfaSzoveg", item.AfaSzoveg ?? ""));
tetel.Add(new XElement("Brutto", item.Brutto ? "1" : "0"));
tetel.Add(new XElement("EgysegAr", item.EgysegAr.ToString()));
tetel.Add(new XElement("Mennyiseg", item.Mennyiseg.ToString()));
tetel.Add(new XElement("MennyisegEgyseg", new XCData(item.MennyisegEgyseg ?? "")));
if (item.KedvezmenyOsszeg.HasValue)
tetel.Add(new XElement("KedvezmenyOsszeg", item.KedvezmenyOsszeg.Value.ToString()));
if (item.TermekID.HasValue)
tetel.Add(new XElement("TermekID", item.TermekID.Value.ToString()));
if (!string.IsNullOrEmpty(item.Megjegyzes))
tetel.Add(new XElement("Megjegyzes", new XCData(item.Megjegyzes)));
if (!string.IsNullOrEmpty(item.CikkSzam))
tetel.Add(new XElement("CikkSzam", new XCData(item.CikkSzam)));
if (!string.IsNullOrEmpty(item.VTSZSZJ))
tetel.Add(new XElement("VTSZSZJ", new XCData(item.VTSZSZJ)));
if (item.ElolegSzamlaTABLE_ID.HasValue)
tetel.Add(new XElement("ElolegSzamlaTABLE_ID", item.ElolegSzamlaTABLE_ID.Value.ToString()));
if (!string.IsNullOrEmpty(item.ElolegSzamlaSorszam))
tetel.Add(new XElement("ElolegSzamlaSorszam", new XCData(item.ElolegSzamlaSorszam)));
invoice.Add(tetel);
}
invoices.Add(invoice);
return new XDeclaration("1.0", "UTF-8", null).ToString() + "\n" + invoices.ToString();
}
}
public class InvoiceItem
{
public string TetelNev { get; set; }
public string AfaSzoveg { get; set; }
public bool Brutto { get; set; }
public decimal EgysegAr { get; set; }
public decimal Mennyiseg { get; set; }
public string MennyisegEgyseg { get; set; }
public decimal? KedvezmenyOsszeg { get; set; }
public int? TermekID { get; set; }
public string Megjegyzes { get; set; }
public string CikkSzam { get; set; }
public string VTSZSZJ { get; set; }
public int? ElolegSzamlaTABLE_ID { get; set; }
public string ElolegSzamlaSorszam { get; set; }
}
public class InvoiceCreateResponse
{
public string ErrorCode { get; set; }
public string Message { get; set; }
public int? TableId { get; set; }
public int? VevoID { get; set; }
public string TechId { get; set; }
public string Sorszam { get; set; }
public string PrintUrl { get; set; }
public bool IsSuccess => ErrorCode == "200";
public static InvoiceCreateResponse FromXml(string xml)
{
var doc = XDocument.Parse(xml);
var invoice = doc.Descendants("invoice").FirstOrDefault();
if (invoice == null)
{
throw new InnVoiceApiException("Invalid XML response format");
}
return new InvoiceCreateResponse
{
ErrorCode = invoice.Element("error")?.Value,
Message = invoice.Element("message")?.Value?.Trim(),
TableId = int.TryParse(invoice.Element("TABLE_ID")?.Value?.Trim(), out var tid) ? tid : (int?)null,
VevoID = int.TryParse(invoice.Element("VevoID")?.Value?.Trim(), out var vid) ? vid : (int?)null,
TechId = invoice.Element("techid")?.Value?.Trim(),
Sorszam = invoice.Element("Sorszam")?.Value?.Trim(),
PrintUrl = invoice.Element("PrintUrl")?.Value?.Trim()
};
}
}
/// <summary>
/// Create a new invoice
/// </summary>
public async Task<InvoiceCreateResponse> CreateInvoiceAsync(InvoiceCreateRequest request)
{
var url = $"{_baseUrl}/{_companyName}/invoice";
{
var url = $"{_baseUrl}/{_companyName}/invoice";
var xml = request.ToXml();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", xml)
});
var xml = request.ToXml();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", xml)
});
try
{
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
try
{
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return InvoiceCreateResponse.FromXml(responseContent);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error creating invoice: {ex.Message}", ex);
}
}
var responseContent = await response.Content.ReadAsStringAsync();
return InvoiceCreateResponse.FromXml(responseContent);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error creating invoice: {ex.Message}", ex);
}
}
/// <summary>
/// Update an existing invoice
/// </summary>
public async Task<InvoiceCreateResponse> UpdateInvoiceAsync(int tableId, InvoiceCreateRequest request)
{
// Set the VevoID if updating customer information
var url = $"{_baseUrl}/{_companyName}/invoice";
/// <summary>
/// Update an existing invoice
/// </summary>
public async Task<InvoiceCreateResponse> UpdateInvoiceAsync(int tableId, InvoiceCreateRequest request)
{
// Set the VevoID if updating customer information
var url = $"{_baseUrl}/{_companyName}/invoice";
var xml = request.ToXml();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", xml),
new KeyValuePair<string, string>("id", tableId.ToString())
});
var xml = request.ToXml();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", xml),
new KeyValuePair<string, string>("id", tableId.ToString())
});
try
{
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
try
{
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return InvoiceCreateResponse.FromXml(responseContent);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error updating invoice: {ex.Message}", ex);
}
}
var responseContent = await response.Content.ReadAsStringAsync();
return InvoiceCreateResponse.FromXml(responseContent);
}
catch (HttpRequestException ex)
{
throw new InnVoiceApiException($"Error updating invoice: {ex.Message}", ex);
}
}
}
// Models
public class Invoice
{
public int TableId { get; set; }
public int VevoID { get; set; }
public string CustomerName { get; set; }
public string CustomerZipCode { get; set; }
public string CustomerCity { get; set; }
public string CustomerAddress { get; set; }
public string CustomerCountry { get; set; }
public string CustomerTaxNumber { get; set; }
public string CustomerGroupTaxNumber { get; set; }
public string PaymentMethod { get; set; }
public string FulfillmentDate { get; set; }
public string InvoiceDate { get; set; }
public string DueDate { get; set; }
public string Notes { get; set; }
public string Currency { get; set; }
public bool IsDraft { get; set; }
public bool IsCancelled { get; set; }
public bool IsAdvance { get; set; }
public bool IsProforma { get; set; }
public decimal TotalNet { get; set; }
public decimal TotalVAT { get; set; }
public decimal TotalGross { get; set; }
public decimal OutstandingAmount { get; set; }
public decimal OverdueAmount { get; set; }
public decimal PaidAmount { get; set; }
public string InvoiceNumber { get; set; }
public string InvoiceNumberFormatted { get; set; }
public int InvoiceId { get; set; }
public string UniqueId { get; set; }
public decimal ExchangeRate { get; set; }
public int InvoiceBookId { get; set; }
public string InvoiceBookName { get; set; }
public bool IsElectronic { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string UpdateTime { get; set; }
public string QueryTime { get; set; }
public string OrderNumber { get; set; }
public string OrderDate { get; set; }
public string ShippingName { get; set; }
public string ShippingZipCode { get; set; }
public string ShippingCity { get; set; }
public string ShippingAddress { get; set; }
public string ShippingCountry { get; set; }
public string PrintUrl { get; set; }
public string InvoiceLink { get; set; }
public string HealthFundName { get; set; }
public string HealthFundCode { get; set; }
public List<InvoiceLineItem> Items { get; set; } = new List<InvoiceLineItem>();
}
public class InvoiceLineItem
{
public int TableId { get; set; }
public string ItemName { get; set; }
public string ArticleNumber { get; set; }
public string VTSZSZJ { get; set; }
public string VATText { get; set; }
public decimal VATRate { get; set; }
public bool IsGross { get; set; }
public decimal UnitPrice { get; set; }
public decimal Quantity { get; set; }
public string Unit { get; set; }
public int ProductId { get; set; }
public decimal DiscountAmount { get; set; }
}
// Invoice Creation Models
public class InvoiceCreateRequest
{
public int VevoID { get; set; } = 0;
public string VevoNev { get; set; }
public string VevoIrsz { get; set; }
public string VevoOrszag { get; set; }
public string VevoTelep { get; set; }
public string VevoUtcaHsz { get; set; }
public string VevoEPNev { get; set; }
public string VevoEPKod { get; set; }
public string SzallNev { get; set; }
public string SzallIrsz { get; set; }
public string SzallTelep { get; set; }
public string SzallUtcaHsz { get; set; }
public string SzallOrszag { get; set; }
public int SzamlatombID { get; set; }
public DateTime SzamlaKelte { get; set; }
public DateTime TeljesitesKelte { get; set; }
public DateTime Hatarido { get; set; }
public string Devizanem { get; set; }
public string FizetesiMod { get; set; }
public string Megjegyzes { get; set; }
public string Nyelv1 { get; set; }
public string Nyelv2 { get; set; }
public decimal? Arfolyam { get; set; }
public string ArfolyamDeviza { get; set; }
public bool Fizetve { get; set; }
public bool Eszamla { get; set; }
public string VevoAdoszam { get; set; }
public string VevoCsAdoszam { get; set; }
public string Telefon { get; set; }
public string Email { get; set; }
public string MegrendelesSzamStr { get; set; }
public string MegrendelesIdopontStr { get; set; }
public bool Felretett { get; set; }
public bool Proforma { get; set; }
public bool AutomatikusAr { get; set; }
public bool Eloleg { get; set; }
public bool Sendmail { get; set; }
public string MailSubject { get; set; }
public string MailBody { get; set; }
public string Eredetiszamla { get; set; }
public List<InvoiceItem> Items { get; set; } = new List<InvoiceItem>();
public void AddItem(InvoiceItem item)
{
Items.Add(item);
}
public string ToXml()
{
var invoices = new XElement("invoices");
var invoice = new XElement("invoice");
if (VevoID > 0)
invoice.Add(new XElement("VevoID", new XCData(VevoID.ToString())));
invoice.Add(new XElement("VevoNev", new XCData(VevoNev ?? "")));
invoice.Add(new XElement("VevoIrsz", new XCData(VevoIrsz ?? "")));
invoice.Add(new XElement("VevoTelep", new XCData(VevoTelep ?? "")));
invoice.Add(new XElement("VevoOrszag", new XCData(VevoOrszag ?? "")));
invoice.Add(new XElement("VevoUtcaHsz", new XCData(VevoUtcaHsz ?? "")));
if (!string.IsNullOrEmpty(VevoEPNev))
invoice.Add(new XElement("VevoEPNev", new XCData(VevoEPNev)));
if (!string.IsNullOrEmpty(VevoEPKod))
invoice.Add(new XElement("VevoEPKod", new XCData(VevoEPKod)));
if (!string.IsNullOrEmpty(SzallNev))
invoice.Add(new XElement("SzallNev", new XCData(SzallNev)));
if (!string.IsNullOrEmpty(SzallIrsz))
invoice.Add(new XElement("SzallIrsz", new XCData(SzallIrsz)));
if (!string.IsNullOrEmpty(SzallTelep))
invoice.Add(new XElement("SzallTelep", new XCData(SzallTelep)));
if (!string.IsNullOrEmpty(SzallUtcaHsz))
invoice.Add(new XElement("SzallUtcaHsz", new XCData(SzallUtcaHsz)));
if (!string.IsNullOrEmpty(SzallOrszag))
invoice.Add(new XElement("SzallOrszag", new XCData(SzallOrszag)));
invoice.Add(new XElement("SzamlatombID", new XCData(SzamlatombID.ToString())));
invoice.Add(new XElement("SzamlaKelte", new XCData(SzamlaKelte.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("TeljesitesKelte", new XCData(TeljesitesKelte.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("Hatarido", new XCData(Hatarido.ToString("yyyy.MM.dd."))));
invoice.Add(new XElement("Devizanem", new XCData(Devizanem ?? "")));
invoice.Add(new XElement("FizetesiMod", new XCData(FizetesiMod ?? "")));
if (!string.IsNullOrEmpty(Megjegyzes))
invoice.Add(new XElement("Megjegyzes", new XCData(Megjegyzes)));
if (!string.IsNullOrEmpty(Nyelv1))
invoice.Add(new XElement("Nyelv1", new XCData(Nyelv1)));
if (!string.IsNullOrEmpty(Nyelv2))
invoice.Add(new XElement("Nyelv2", new XCData(Nyelv2)));
if (Arfolyam.HasValue)
invoice.Add(new XElement("Arfolyam", new XCData(Arfolyam.Value.ToString())));
if (!string.IsNullOrEmpty(ArfolyamDeviza))
invoice.Add(new XElement("ArfolyamDeviza", new XCData(ArfolyamDeviza)));
invoice.Add(new XElement("Fizetve", Fizetve ? "1" : "0"));
invoice.Add(new XElement("Eszamla", Eszamla ? "1" : "0"));
if (!string.IsNullOrEmpty(VevoAdoszam))
invoice.Add(new XElement("VevoAdoszam", new XCData(VevoAdoszam)));
if (!string.IsNullOrEmpty(VevoCsAdoszam))
invoice.Add(new XElement("VevoCsAdoszam", new XCData(VevoCsAdoszam)));
if (!string.IsNullOrEmpty(Telefon))
invoice.Add(new XElement("Telefon", new XCData(Telefon)));
if (!string.IsNullOrEmpty(Email))
invoice.Add(new XElement("Email", new XCData(Email)));
if (!string.IsNullOrEmpty(MegrendelesSzamStr))
invoice.Add(new XElement("MegrendelesSzamStr", new XCData(MegrendelesSzamStr)));
if (!string.IsNullOrEmpty(MegrendelesIdopontStr))
invoice.Add(new XElement("MegrendelesIdopontStr", new XCData(MegrendelesIdopontStr)));
invoice.Add(new XElement("Felretett", Felretett ? "1" : "0"));
invoice.Add(new XElement("Proforma", Proforma ? "1" : "0"));
if (AutomatikusAr)
invoice.Add(new XElement("AutomatikusAr", "1"));
if (Eloleg)
invoice.Add(new XElement("Eloleg", "1"));
if (Sendmail)
{
invoice.Add(new XElement("Sendmail", "1"));
if (!string.IsNullOrEmpty(MailSubject))
invoice.Add(new XElement("MailSubject", new XCData(MailSubject)));
if (!string.IsNullOrEmpty(MailBody))
invoice.Add(new XElement("MailBody", new XCData(MailBody)));
}
if (!string.IsNullOrEmpty(Eredetiszamla))
invoice.Add(new XElement("Eredetiszamla", new XCData(Eredetiszamla)));
// Add items
foreach (var item in Items)
{
var tetel = new XElement("tetel");
tetel.Add(new XElement("TetelNev", new XCData(item.TetelNev ?? "")));
tetel.Add(new XElement("AfaSzoveg", item.AfaSzoveg ?? ""));
tetel.Add(new XElement("Brutto", item.Brutto ? "1" : "0"));
tetel.Add(new XElement("EgysegAr", item.EgysegAr.ToString()));
tetel.Add(new XElement("Mennyiseg", item.Mennyiseg.ToString()));
tetel.Add(new XElement("MennyisegEgyseg", new XCData(item.MennyisegEgyseg ?? "")));
if (item.KedvezmenyOsszeg.HasValue)
tetel.Add(new XElement("KedvezmenyOsszeg", item.KedvezmenyOsszeg.Value.ToString()));
if (item.TermekID.HasValue)
tetel.Add(new XElement("TermekID", item.TermekID.Value.ToString()));
if (!string.IsNullOrEmpty(item.Megjegyzes))
tetel.Add(new XElement("Megjegyzes", new XCData(item.Megjegyzes)));
if (!string.IsNullOrEmpty(item.CikkSzam))
tetel.Add(new XElement("CikkSzam", new XCData(item.CikkSzam)));
if (!string.IsNullOrEmpty(item.VTSZSZJ))
tetel.Add(new XElement("VTSZSZJ", new XCData(item.VTSZSZJ)));
if (item.ElolegSzamlaTABLE_ID.HasValue)
tetel.Add(new XElement("ElolegSzamlaTABLE_ID", item.ElolegSzamlaTABLE_ID.Value.ToString()));
if (!string.IsNullOrEmpty(item.ElolegSzamlaSorszam))
tetel.Add(new XElement("ElolegSzamlaSorszam", new XCData(item.ElolegSzamlaSorszam)));
invoice.Add(tetel);
}
invoices.Add(invoice);
return new XDeclaration("1.0", "UTF-8", null).ToString() + "\n" + invoices.ToString();
}
}
public class InvoiceItem
{
public string TetelNev { get; set; }
public string AfaSzoveg { get; set; }
public bool Brutto { get; set; }
public decimal EgysegAr { get; set; }
public decimal Mennyiseg { get; set; }
public string MennyisegEgyseg { get; set; }
public decimal? KedvezmenyOsszeg { get; set; }
public int? TermekID { get; set; }
public string Megjegyzes { get; set; }
public string CikkSzam { get; set; }
public string VTSZSZJ { get; set; }
public int? ElolegSzamlaTABLE_ID { get; set; }
public string ElolegSzamlaSorszam { get; set; }
}
public class InvoiceCreateResponse
{
public string ErrorCode { get; set; }
public string Message { get; set; }
public int? TableId { get; set; }
public int? VevoID { get; set; }
public string TechId { get; set; }
public string Sorszam { get; set; }
public string PrintUrl { get; set; }
public bool IsSuccess => ErrorCode == "200";
public static InvoiceCreateResponse FromXml(string xml)
{
var doc = XDocument.Parse(xml);
var invoice = doc.Descendants("invoice").FirstOrDefault();
if (invoice == null)
{
throw new InnVoiceApiException("Invalid XML response format");
}
return new InvoiceCreateResponse
{
ErrorCode = invoice.Element("error")?.Value,
Message = invoice.Element("message")?.Value?.Trim(),
TableId = int.TryParse(invoice.Element("TABLE_ID")?.Value?.Trim(), out var tid) ? tid : (int?)null,
VevoID = int.TryParse(invoice.Element("VevoID")?.Value?.Trim(), out var vid) ? vid : (int?)null,
TechId = invoice.Element("techid")?.Value?.Trim(),
Sorszam = invoice.Element("Sorszam")?.Value?.Trim(),
PrintUrl = invoice.Element("PrintUrl")?.Value?.Trim()
};
}
}
}

View File

@ -1,15 +1,44 @@
@using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders
@model OrderAttributesModel
<!-- InnVoice Invoice Section -->
<!-- InnVoice Management Section -->
<div class="card card-default mb-3">
<div class="card-header">
<i class="fas fa-file-invoice"></i>
InnVoice Invoice Management
InnVoice Management
</div>
<div class="card-body">
<!-- Order Subsection -->
<div class="form-group row">
<div class="col-md-12">
<div class="col-12 col-md-3">
<h5><i class="fas fa-shopping-cart"></i> Order</h5>
<div id="orderStatus" class="alert alert-info" style="display: none;">
<i class="fas fa-info-circle"></i> <span id="orderStatusMessage"></span>
</div>
<div id="orderDetails" style="display: none;">
<p><strong>Order Table ID:</strong> <span id="orderTableId"></span></p>
<p><strong>Order Tech ID:</strong> <span id="orderTechId"></span></p>
<p>
<a id="orderPdfLink" href="#" target="_blank" class="btn btn-sm btn-info">
<i class="fas fa-file-pdf"></i> View Order PDF
</a>
</p>
</div>
</div>
<div class="col-12 col-md-3 text-right">
<button type="button" id="createOrderBtn" class="btn btn-success">
<i class="fas fa-shopping-cart"></i> Create Order in InnVoice
</button>
<button type="button" id="checkOrderBtn" class="btn btn-secondary" style="display: none;">
<i class="fas fa-sync"></i> Refresh Order
</button>
</div>
<div class="col-12 col-md-3">
<h5><i class="fas fa-file-invoice-dollar"></i> Invoice</h5>
<div id="invoiceStatus" class="alert alert-info" style="display: none;">
<i class="fas fa-info-circle"></i> <span id="invoiceStatusMessage"></span>
</div>
@ -18,62 +47,66 @@
<p><strong>Table ID:</strong> <span id="invoiceTableId"></span></p>
<p>
<a id="invoicePdfLink" href="#" target="_blank" class="btn btn-sm btn-info">
<i class="fas fa-file-pdf"></i> View PDF
<i class="fas fa-file-pdf"></i> View Invoice PDF
</a>
</p>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-md-12 text-right">
<div class="col-12 col-md-3 text-right">
<button type="button" id="createInvoiceBtn" class="btn btn-success">
<i class="fas fa-file-invoice-dollar"></i> Create & Upload Invoice
<i class="fas fa-file-invoice-dollar"></i> Create Invoice
</button>
<button type="button" id="checkInvoiceBtn" class="btn btn-secondary" style="display: none;">
<i class="fas fa-sync"></i> Check Invoice Status
<i class="fas fa-sync"></i> Refresh Invoice
</button>
</div>
</div>
<div class="form-group row">
<div class="col-12">
<div class="form-group row">
<div class="col-md-3">
<nop-label asp-for="IsMeasurable" />
</div>
<div class="col-md-9">
<nop-editor asp-for="IsMeasurable" />
<span asp-validation-for="IsMeasurable"></span>
</div>
</div>
<div class="form-group row">
<div class="col-md-3">
<nop-label asp-for="DateOfReceipt" />
</div>
<div class="col-md-9">
<nop-editor asp-for="DateOfReceipt" />
<span asp-validation-for="DateOfReceipt"></span>
</div>
</div>
<div class="form-group row">
<div class="col-md-12 text-right">
<button type="button" id="saveAttributesBtn" class="btn btn-primary">
<i class="fa fa-save"></i> Save Attributes
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Custom Order Attributes Section -->
<div class="card card-default">
<div class="card-header">
<i class="fas fa-tags"></i>
Custom Order Attributes
</div>
<div class="card-body">
<div class="form-group row">
<div class="col-md-3">
<nop-label asp-for="IsMeasurable" />
</div>
<div class="col-md-9">
<nop-editor asp-for="IsMeasurable" />
<span asp-validation-for="IsMeasurable"></span>
</div>
</div>
<div class="form-group row">
<div class="col-md-3">
<nop-label asp-for="DateOfReceipt" />
</div>
<div class="col-md-9">
<nop-editor asp-for="DateOfReceipt" />
<span asp-validation-for="DateOfReceipt"></span>
</div>
</div>
<div class="form-group row">
<div class="col-md-12 text-right">
<button type="button" id="saveAttributesBtn" class="btn btn-primary">
<i class="fa fa-save"></i> Save Attributes
</button>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
var createOrderUrl = '/Admin/InnVoiceOrder/CreateOrder';
var getOrderStatusUrl = '/Admin/InnVoiceOrder/GetOrderStatus';
var createInvoiceUrl = '/Admin/Invoice/CreateInvoice';
var getInvoiceStatusUrl = '/Admin/Invoice/GetInvoiceStatus';
var orderExists = false;
var invoiceExists = false;
// Save Order Attributes
$("#saveAttributesBtn").click(function () {
$.ajax({
@ -94,8 +127,148 @@
});
});
// ========== ORDER MANAGEMENT ==========
// Create Order
$("#createOrderBtn").click(function (e) {
e.preventDefault();
e.stopPropagation();
var btn = $(this);
btn.prop("disabled", true).html('<i class="fas fa-spinner fa-spin"></i> Creating Order...');
showOrderStatus("Creating order in InnVoice, please wait...", "info");
$.ajax({
type: "POST",
url: createOrderUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
console.log("Order Response:", response);
btn.prop("disabled", false).html('<i class="fas fa-shopping-cart"></i> Create Order in InnVoice');
if (response.success) {
showOrderStatus("Order created successfully in InnVoice!", "success");
displayOrderDetails(response.data);
orderExists = true;
updateOrderButtons();
} else {
showOrderStatus("Error: " + (response.message || "Unknown error"), "danger");
}
},
error: function (xhr, status, error) {
console.error("Order AJAX Error:", xhr, status, error);
btn.prop("disabled", false).html('<i class="fas fa-shopping-cart"></i> Create Order in InnVoice');
var errorMessage = "Error creating order";
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage = xhr.responseJSON.message;
} else if (xhr.responseText) {
try {
var errorObj = JSON.parse(xhr.responseText);
errorMessage = errorObj.message || errorMessage;
} catch (e) {
errorMessage = "Error: " + xhr.status + " - " + xhr.statusText;
}
}
showOrderStatus(errorMessage, "danger");
}
});
return false;
});
// Check Order Status
$("#checkOrderBtn").click(function (e) {
e.preventDefault();
e.stopPropagation();
var btn = $(this);
btn.prop("disabled", true).html('<i class="fas fa-spinner fa-spin"></i> Checking...');
$.ajax({
type: "GET",
url: getOrderStatusUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Refresh Order');
if (response.success && response.data) {
displayOrderDetails(response.data);
showOrderStatus("Order details refreshed", "success");
} else {
showOrderStatus("No order found in InnVoice for this order", "warning");
}
},
error: function () {
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Refresh Order');
showOrderStatus("Error checking order status", "danger");
}
});
return false;
});
function showOrderStatus(message, type) {
var statusDiv = $("#orderStatus");
statusDiv.removeClass("alert-info alert-success alert-warning alert-danger")
.addClass("alert-" + type);
$("#orderStatusMessage").text(message);
statusDiv.show();
}
function displayOrderDetails(data) {
$("#orderTableId").text(data.tableId || "N/A");
$("#orderTechId").text(data.techId || "N/A");
if (data.printUrl) {
$("#orderPdfLink").attr("href", data.printUrl).show();
} else {
$("#orderPdfLink").hide();
}
$("#orderDetails").show();
}
function updateOrderButtons() {
if (orderExists) {
$("#createOrderBtn").hide();
$("#checkOrderBtn").show();
} else {
$("#createOrderBtn").show();
$("#checkOrderBtn").hide();
}
}
// Check if order exists on page load
$.ajax({
type: "GET",
url: getOrderStatusUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
if (response.success && response.data) {
displayOrderDetails(response.data);
orderExists = true;
updateOrderButtons();
}
},
error: function() {
// Silently fail on page load
orderExists = false;
updateOrderButtons();
}
});
// ========== INVOICE MANAGEMENT ==========
// Create Invoice
$("#createInvoiceBtn").click(function () {
$("#createInvoiceBtn").click(function (e) {
e.preventDefault();
e.stopPropagation();
var btn = $(this);
btn.prop("disabled", true).html('<i class="fas fa-spinner fa-spin"></i> Creating Invoice...');
@ -103,60 +276,74 @@
$.ajax({
type: "POST",
url: "@Url.Action("CreateInvoice", "InnVoice")",
data: {
orderId: "@Model.OrderId",
__RequestVerificationToken: $('input[name="__RequestVerificationToken"]').val()
},
url: createInvoiceUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
btn.prop("disabled", false).html('<i class="fas fa-file-invoice-dollar"></i> Create & Upload Invoice');
console.log("Invoice Response:", response);
btn.prop("disabled", false).html('<i class="fas fa-file-invoice-dollar"></i> Create Invoice');
if (response.success) {
showInvoiceStatus("Invoice created successfully!", "success");
displayInvoiceDetails(response.data);
$("#checkInvoiceBtn").show();
invoiceExists = true;
updateInvoiceButtons();
} else {
showInvoiceStatus("Error: " + response.message, "danger");
showInvoiceStatus("Error: " + (response.message || "Unknown error"), "danger");
}
},
error: function (xhr) {
btn.prop("disabled", false).html('<i class="fas fa-file-invoice-dollar"></i> Create & Upload Invoice');
error: function (xhr, status, error) {
console.error("Invoice AJAX Error:", xhr, status, error);
btn.prop("disabled", false).html('<i class="fas fa-file-invoice-dollar"></i> Create Invoice');
var errorMessage = "Error creating invoice";
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage = xhr.responseJSON.message;
} else if (xhr.responseText) {
try {
var errorObj = JSON.parse(xhr.responseText);
errorMessage = errorObj.message || errorMessage;
} catch (e) {
errorMessage = "Error: " + xhr.status + " - " + xhr.statusText;
}
}
showInvoiceStatus(errorMessage, "danger");
}
});
return false;
});
// Check Invoice Status
$("#checkInvoiceBtn").click(function () {
$("#checkInvoiceBtn").click(function (e) {
e.preventDefault();
e.stopPropagation();
var btn = $(this);
btn.prop("disabled", true).html('<i class="fas fa-spinner fa-spin"></i> Checking...');
$.ajax({
type: "GET",
url: "@Url.Action("GetInvoiceStatus", "InnVoice")",
data: {
orderId: "@Model.OrderId"
},
url: getInvoiceStatusUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Check Invoice Status');
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Refresh Invoice');
if (response.success && response.data) {
displayInvoiceDetails(response.data);
showInvoiceStatus("Invoice details loaded", "success");
showInvoiceStatus("Invoice details refreshed", "success");
} else {
showInvoiceStatus("No invoice found for this order", "warning");
}
},
error: function () {
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Check Invoice Status');
btn.prop("disabled", false).html('<i class="fas fa-sync"></i> Refresh Invoice');
showInvoiceStatus("Error checking invoice status", "danger");
}
});
return false;
});
function showInvoiceStatus(message, type) {
@ -180,19 +367,34 @@
$("#invoiceDetails").show();
}
function updateInvoiceButtons() {
if (invoiceExists) {
$("#createInvoiceBtn").hide();
$("#checkInvoiceBtn").show();
} else {
$("#createInvoiceBtn").show();
$("#checkInvoiceBtn").hide();
}
}
// Check if invoice exists on page load
$.ajax({
type: "GET",
url: "@Url.Action("GetInvoiceStatus", "InnVoice")",
data: {
orderId: "@Model.OrderId"
},
url: getInvoiceStatusUrl,
data: { orderId: @Model.OrderId },
dataType: 'json',
success: function (response) {
if (response.success && response.data) {
displayInvoiceDetails(response.data);
$("#checkInvoiceBtn").show();
invoiceExists = true;
updateInvoiceButtons();
}
},
error: function() {
// Silently fail on page load
invoiceExists = false;
updateInvoiceButtons();
}
});
});
</script>
</script>