EKÁER integration, product search, and schema updates
- Added EKÁER (NAV) service registrations and config to PluginNopStartup - Extended MgProductDto/IMgProductDto with Sku property - Raised min search term length to 3 in autocomplete endpoints - Increased ProductSearchAutoComplete maxResults to 300 - Refactored product search to filter by AvailableQuantity > 0 - Closed GTIN/VTSZ issue in EKAER_ISSUES.md, moved to data model topic - Added SCHEMA.md with Toon domain model, including Currency property for partners
This commit is contained in:
parent
d6c828262d
commit
6b105bb5ed
|
|
@ -969,8 +969,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
|
[CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)]
|
||||||
public virtual async Task<IActionResult> CustomerSearchAutoComplete(string term)
|
public virtual async Task<IActionResult> CustomerSearchAutoComplete(string term)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
|
if (string.IsNullOrWhiteSpace(term) || term.Length < 3) return Json(new List<object>());
|
||||||
return Json(new List<object>());
|
|
||||||
|
|
||||||
const int maxResults = 15;
|
const int maxResults = 15;
|
||||||
|
|
||||||
|
|
@ -1037,39 +1036,29 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
||||||
public virtual async Task<IActionResult> ProductSearchAutoComplete(string term)
|
public virtual async Task<IActionResult> ProductSearchAutoComplete(string term)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
|
if (string.IsNullOrWhiteSpace(term) || term.Length < 3) return Json(new List<object>());
|
||||||
return Json(new List<object>());
|
|
||||||
|
|
||||||
const int maxResults = 30;
|
const int maxResults = 300;
|
||||||
|
|
||||||
// Search products by name or SKU
|
// Search products by name or SKU
|
||||||
var products = await _productService.SearchProductsAsync(
|
var products = await _productService.SearchProductsAsync(keywords: term, pageIndex: 0, pageSize: maxResults);
|
||||||
keywords: term,
|
|
||||||
pageIndex: 0,
|
|
||||||
pageSize: maxResults);
|
|
||||||
|
|
||||||
var result = new List<object>();
|
var result = new List<object>();
|
||||||
var productDtosById = await _dbContext.ProductDtos.GetAllByIds(products.Select(p => p.Id)).ToDictionaryAsync(k => k.Id, v => v);
|
//var productDtosById = await _dbContext.ProductDtos.GetAllByIds(products.Select(p => p.Id)).Where(x => x.AvailableQuantity > 0).ToDictionaryAsync(k => k.Id, v => v);
|
||||||
|
var productDtos = await _dbContext.ProductDtos.GetAllByIds(products.Select(p => p.Id)).ToArrayAsync();
|
||||||
|
|
||||||
foreach (var product in products)
|
foreach (var productDto in productDtos.Where(x => x.AvailableQuantity > 0))
|
||||||
{
|
|
||||||
var productDto = productDtosById[product.Id];
|
|
||||||
if (productDto != null)
|
|
||||||
{
|
|
||||||
if (productDto.AvailableQuantity > 0)
|
|
||||||
{
|
{
|
||||||
result.Add(new
|
result.Add(new
|
||||||
{
|
{
|
||||||
label = $"{product.Name} [RENDELHETŐ: {productDto.AvailableQuantity} (R:{productDto.StockQuantity}/K:{productDto.IncomingQuantity})] [ÁR: {product.Price}]",
|
label = $"{productDto.Name} [RENDELHETŐ: {productDto.AvailableQuantity} (R:{productDto.StockQuantity}/K:{productDto.IncomingQuantity})] [ÁR: {productDto.Price}]",
|
||||||
value = product.Id,
|
value = productDto.Id,
|
||||||
sku = product.Sku,
|
sku = productDto.Sku,
|
||||||
price = product.Price,
|
price = productDto.Price,
|
||||||
stockQuantity = product.StockQuantity,
|
stockQuantity = productDto.StockQuantity,
|
||||||
availableQuantity = productDto.AvailableQuantity,
|
availableQuantity = productDto.AvailableQuantity,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json(result);
|
return Json(result);
|
||||||
}
|
}
|
||||||
|
|
@ -1078,8 +1067,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
||||||
public virtual async Task<IActionResult> PreOrderProductSearchAutoComplete(string term)
|
public virtual async Task<IActionResult> PreOrderProductSearchAutoComplete(string term)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
|
if (string.IsNullOrWhiteSpace(term) || term.Length < 3) return Json(new List<object>());
|
||||||
return Json(new List<object>());
|
|
||||||
|
|
||||||
const int maxResults = 30;
|
const int maxResults = 30;
|
||||||
var today = DateTime.UtcNow.Date;
|
var today = DateTime.UtcNow.Date;
|
||||||
|
|
@ -1151,8 +1139,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
|
||||||
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
[CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)]
|
||||||
public virtual async Task<IActionResult> ProductSearchUnfilteredAutoComplete(string term)
|
public virtual async Task<IActionResult> ProductSearchUnfilteredAutoComplete(string term)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(term) || term.Length < 2)
|
if (string.IsNullOrWhiteSpace(term) || term.Length < 3) return Json(new List<object>());
|
||||||
return Json(new List<object>());
|
|
||||||
|
|
||||||
const int maxResults = 30;
|
const int maxResults = 30;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@ using Nop.Web.Areas.Admin.Models.Catalog;
|
||||||
using Nop.Web.Areas.Admin.Models.Orders;
|
using Nop.Web.Areas.Admin.Models.Orders;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using Mango.Nop.Core.Loggers;
|
using Mango.Nop.Core.Loggers;
|
||||||
|
using AyCode.Services.Nav;
|
||||||
|
using AyCode.Services.Nav.Ekaer;
|
||||||
|
using FruitBank.Common.Services.Ekaer;
|
||||||
|
using FruitBank.Common.Server.Services.Ekaer;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
|
||||||
namespace Nop.Plugin.Misc.FruitBankPlugin.Infrastructure;
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Infrastructure;
|
||||||
|
|
||||||
|
|
@ -162,6 +167,44 @@ public class PluginNopStartup : INopStartup
|
||||||
services.AddScoped<FileStorageService>();
|
services.AddScoped<FileStorageService>();
|
||||||
services.AddScoped<ICustomerCreditService, CustomerCreditService>();
|
services.AddScoped<ICustomerCreditService, CustomerCreditService>();
|
||||||
|
|
||||||
|
// ── EKÁER (NAV közúti áruforgalom-bejelentés): map → validate → send ──────────
|
||||||
|
services.AddScoped<IShippingToEkaerMapper, ShippingToEkaerMapper>(); // FruitBank.Common — leképezés
|
||||||
|
services.AddScoped<IEkaerTradeCardValidator, EkaerTradeCardValidator>(); // AyCode.Services — NAV-validáció
|
||||||
|
services.AddScoped<IEkaerSubmitService, EkaerSubmitService>(); // AyCode.Services — validate→send
|
||||||
|
services.AddScoped<IFruitBankEkaerService, FruitBankEkaerService>(); // FruitBank.Common.Server — fogyasztó
|
||||||
|
|
||||||
|
services.AddHttpClient<EkaerManageService>() // AyCode.Services — NAV HTTP
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { SslProtocols = SslProtocols.Tls12 }); // a NAV TLS 1.2-t vár
|
||||||
|
|
||||||
|
// A NAV-fiók hitelesítő adatai + a saját telephely/raktár — konfigurációból (appsettings "Ekaer" szekció).
|
||||||
|
// ⚠️ Titkos kulcsok: secret store / appsettings, SOHA NEM a forráskódba.
|
||||||
|
services.AddSingleton<INavCredentials>(sp =>
|
||||||
|
{
|
||||||
|
var c = sp.GetRequiredService<IConfiguration>().GetSection("Ekaer:Credentials");
|
||||||
|
return new NavCredentials
|
||||||
|
{
|
||||||
|
User = c["User"] ?? "",
|
||||||
|
Password = c["Password"] ?? "",
|
||||||
|
SigningKey = c["SigningKey"] ?? "",
|
||||||
|
TaxNumber = c["TaxNumber"] ?? "",
|
||||||
|
BaseUrl = c["BaseUrl"] ?? "https://import-test-b.ekaer.nav.gov.hu", // TEST; PROD: https://import.ekaer.nav.gov.hu
|
||||||
|
};
|
||||||
|
});
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
{
|
||||||
|
var c = sp.GetRequiredService<IConfiguration>().GetSection("Ekaer:Company");
|
||||||
|
return new EkaerCompanyInfo
|
||||||
|
{
|
||||||
|
Name = c["Name"],
|
||||||
|
TaxId = c["TaxId"],
|
||||||
|
CountryCode = c["CountryCode"] ?? "HU", // a NAV EKÁER magyar
|
||||||
|
PostalCode = c["PostalCode"],
|
||||||
|
City = c["City"],
|
||||||
|
Street = c["Street"],
|
||||||
|
// UnloadLocation (saját telephely): magyar címnél a NAV Name/VatNumber/Phone/Email-t is kér — TODO configból összeállítani.
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
services.AddControllersWithViews(options =>
|
services.AddControllersWithViews(options =>
|
||||||
{
|
{
|
||||||
options.Filters.AddService<PendingMeasurementCheckoutFilter>();
|
options.Filters.AddService<PendingMeasurementCheckoutFilter>();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ Scope: a FruitBank EKÁER-bejelentés szerver-oldali / nopCommerce-integrációs
|
||||||
|
|
||||||
## MGFBANKPLUG-EKAER-I-T3X8: A `Product.Gtin` átmenetileg a VTSZ-t tárolja — szétválasztandó
|
## MGFBANKPLUG-EKAER-I-T3X8: A `Product.Gtin` átmenetileg a VTSZ-t tárolja — szétválasztandó
|
||||||
|
|
||||||
**Status:** Open · **Priority:** P3 · **Type:** I (adatmodell / átmeneti megoldás)
|
**Status:** Closed (2026-06-02) — superseded · **Priority:** P3 · **Type:** I (adatmodell / átmeneti megoldás)
|
||||||
|
|
||||||
|
### Resolution
|
||||||
|
**Áthelyezve** az általános adatmodell-topicba: **`FBANKAPP-DMODEL-I-P6X4`** (`FruitBank.Common/docs/DATAMODEL/DATAMODEL_ISSUES.md#fbankapp-dmodel-i-p6x4`). Indok: a GTIN/VTSZ szétválasztás **általános** adatmodell-kérdés, nem EKÁER-specifikus — az EKÁER csak felhasználója. A követés ott folytatódik; az alábbi leírás referencia.
|
||||||
|
|
||||||
Az EKÁER `tradeCardItem.productVtsz` (kötelező, 8 jegyű vámtarifaszám) forrása jelenleg a nopCommerce **`Product.Gtin`** oszlop (a `ProductDto.Gtin`-en keresztül). A GTIN és a VTSZ **fogalmilag különböző**:
|
Az EKÁER `tradeCardItem.productVtsz` (kötelező, 8 jegyű vámtarifaszám) forrása jelenleg a nopCommerce **`Product.Gtin`** oszlop (a `ProductDto.Gtin`-en keresztül). A GTIN és a VTSZ **fogalmilag különböző**:
|
||||||
- **GTIN** — globális kereskedelmi cikkszám (vonalkód-azonosító, EAN/UPC).
|
- **GTIN** — globális kereskedelmi cikkszám (vonalkód-azonosító, EAN/UPC).
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
# Domain Model Schema (Toon Format)
|
||||||
|
|
||||||
|
> Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview.
|
||||||
|
> Full domain model in Toon (Token-Oriented Object Notation) format — see `AyCode.Core/Serializers/Toons/README.md` (in AyCode.Core solution).
|
||||||
|
> This is the authoritative schema for entities, DTOs, and enums in the FruitBank domain.
|
||||||
|
> For behavioral documentation (workflows, lifecycles, event cascades) see `docs/DOMAIN_MODEL.md`.
|
||||||
|
|
||||||
@meta {
|
@meta {
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
format = "toon"
|
format = "toon"
|
||||||
|
|
@ -313,6 +320,8 @@
|
||||||
CountryCode: string
|
CountryCode: string
|
||||||
County: string
|
County: string
|
||||||
Created: DateTime
|
Created: DateTime
|
||||||
|
Currency: string
|
||||||
|
purpose: "ISO 4217 currency code the company trades and settles in with this partner (e.g. EUR, HUF). For supplier partners it is the source currency for converting shipping-item values to example: HUF in NAV EKÁER reporting."
|
||||||
Modified: DateTime
|
Modified: DateTime
|
||||||
Name: string
|
Name: string
|
||||||
PostalCode: string
|
PostalCode: string
|
||||||
|
|
@ -555,6 +564,8 @@
|
||||||
CountryCode: string
|
CountryCode: string
|
||||||
County: string
|
County: string
|
||||||
Created: DateTime
|
Created: DateTime
|
||||||
|
Currency: string
|
||||||
|
purpose: "ISO 4217 currency code the company trades and settles in with this partner (e.g. EUR, HUF). For supplier partners it is the source currency for converting shipping-item values to example: HUF in NAV EKÁER reporting."
|
||||||
Modified: DateTime
|
Modified: DateTime
|
||||||
Name: string
|
Name: string
|
||||||
PostalCode: string
|
PostalCode: string
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue