Compare commits
3 Commits
254ef5ef4c
...
0a1287ce67
| Author | SHA1 | Date |
|---|---|---|
|
|
0a1287ce67 | |
|
|
2fb1151e5d | |
|
|
b541405640 |
|
|
@ -12,7 +12,49 @@
|
|||
"Bash(do sed -i '1a using AyCode.Core.Serializers.Toons;\\\\n' \"$f\")",
|
||||
"Bash(done)",
|
||||
"Bash(rm \"C:/Users/Fullepi/.claude/projects/H--Applications-Mango-Source-FruitBankHybridApp/memory/feedback_framework_docs_no_consumer_types.md\")",
|
||||
"Bash(cd \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services.Server/bin/FruitBank\" && ls -la --time-style=full-iso Debug/net9.0/AyCode.Core.dll Release/net9.0/AyCode.Core.dll 2>&1)"
|
||||
"Bash(cd \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services.Server/bin/FruitBank\" && ls -la --time-style=full-iso Debug/net9.0/AyCode.Core.dll Release/net9.0/AyCode.Core.dll 2>&1)",
|
||||
"WebSearch",
|
||||
"Bash(dotnet --version)",
|
||||
"Bash(curl -sI -m 8 https://ekaer.nav.gov.hu/)",
|
||||
"Bash(echo \"---curl-exit:$?\")",
|
||||
"Bash(dotnet tool *)",
|
||||
"Read(//c/Users/Fullepi/Downloads/ekaer/Generated/AyCode.Services.Nav.Ekaer.Models//**)",
|
||||
"WebFetch(domain:github.com)",
|
||||
"Bash(curl -s -m 15 https://raw.githubusercontent.com/nav-gov-hu/Common/master/README.md)",
|
||||
"Bash(curl -s -m 15 \"https://api.github.com/repos/nav-gov-hu/Common/git/trees/master?recursive=1\")",
|
||||
"Bash(curl -s -m 15 \"https://api.github.com/repos/nav-gov-hu/Common\")",
|
||||
"Bash(curl -s -m 15 \"https://api.github.com/repos/nav-gov-hu/Common/git/trees/main?recursive=1\")",
|
||||
"Bash(sed -E 's/\"path\": *\"//;s/\"$//')",
|
||||
"Bash(curl -s -m 15 https://raw.githubusercontent.com/nav-gov-hu/Common/main/README_en.adoc)",
|
||||
"WebFetch(domain:ekaer.nav.gov.hu)",
|
||||
"Bash(curl -s -m 15 https://raw.githubusercontent.com/nav-gov-hu/Common/main/schemas/src/main/resources/xsd/hu/gov/nav/schemas/NTCA/2.0/common/authservice.xsd)",
|
||||
"Bash(echo \"=== Nav/docs \\(amit a user bemásolt\\) ===\" *)",
|
||||
"Bash(cp \"C:/Users/Fullepi/Downloads/ekaer/ekaermanagement.xsd\" \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/docs/\")",
|
||||
"Bash(cp \"C:/Users/Fullepi/Downloads/ekaer/common.xsd\" \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/docs/\")",
|
||||
"Bash(pdftotext -layout \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/docs/eKAERManagementService_2.2.pdf\" \"C:/Users/Fullepi/Downloads/ekaer/ekaer_2.2.txt\")",
|
||||
"Bash(sed -n '1,70p' \"C:/Users/Fullepi/Downloads/ekaer/ekaer_2.2.txt\")",
|
||||
"Bash(pdftotext -layout -enc UTF-8 H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/docs/eKAERManagementService_2.2.pdf C:/Users/Fullepi/Downloads/ekaer/ekaer_2.2.txt)",
|
||||
"Bash(cp C:/Users/Fullepi/Downloads/ekaer/Generated/AyCode.Services.Nav.Ekaer.Models/*.cs H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/Ekaer/Models/)",
|
||||
"Bash(echo '=== bemásolva: __CMDSUB_OUTPUT__')",
|
||||
"Bash(cp C:/Users/Fullepi/Downloads/ekaer/Generated2/AyCode.Services.Nav.Ekaer.Models/*.cs H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/Ekaer/Models/)",
|
||||
"Bash(cp C:/Users/Fullepi/Downloads/ekaer/Generated2/AyCode.Services.Nav.Ekaer.Models.Common/*.cs H:/Applications/Aycode/Source/AyCode.Core/AyCode.Services/Nav/Ekaer/Models/Common/)",
|
||||
"Bash(sha512sum)",
|
||||
"Bash(awk '{print toupper\\($1\\)}')",
|
||||
"Bash(git -C \"H:/Applications/Aycode/Source/AyCode.Core\" status --short)",
|
||||
"Bash(git -C \"H:/Applications/Mango/Source/FruitBankHybridApp\" status --short)",
|
||||
"Bash(git -C \"H:/Applications/Mango/Source/NopCommerce.Common\" status --short)",
|
||||
"Bash(Get-ChildItem -Path \"H:\\\\Applications\\\\Mango\\\\Source\\\\NopCommerce.Common\\\\4.70\\\\Plugins\\\\Nop.Plugin.Misc.AIPlugin\" -Directory)",
|
||||
"Bash(Select-Object Name)",
|
||||
"Bash(ICargo)",
|
||||
"Bash(IShipping\")",
|
||||
"Bash(ls -la \"H:\\\\Applications\\\\Mango\\\\Source\\\\NopCommerce.Common\\\\4.70\\\\Plugins\\\\Nop.Plugin.Misc.AIPlugin\" 2>/dev/null | head -30)",
|
||||
"PowerShell(ls \"H:\\\\Applications\\\\Mango\\\\Source\\\\FruitBankHybridApp\\\\FruitBank.Common\\\\Interfaces\\\\\" | where {$_.Name -match 'IPartner|ICargo|IShipping'} | select Name)",
|
||||
"Bash(find \"H:\\\\Applications\\\\FruitBankHybridApp\\\\FruitBank.Common\\\\Source\" -type f -name \"*Shipping*.cs\" 2>/dev/null | head -10)",
|
||||
"Bash(find \"H:\\\\Applications\\\\Aycode\\\\Source\\\\AyCode.Core\\\\AyCode.Services\" -type d | head -20)",
|
||||
"Bash(rm -f H:/Applications/Mango/Source/NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/Services/Ekaer/EkaerMappingOptions.cs H:/Applications/Mango/Source/NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/Services/Ekaer/IShippingToEkaerMapper.cs H:/Applications/Mango/Source/NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/Services/Ekaer/ShippingToEkaerMapper.cs)",
|
||||
"Bash(rmdir \"H:/Applications/Mango/Source/NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/Services/Ekaer\")",
|
||||
"Bash(rm -f \"H:/Applications/Mango/Source/NopCommerce.Common/4.70/Plugins/Nop.Plugin.Misc.AIPlugin/Infrastructure/NavCredentials.cs\" *)",
|
||||
"Bash(rm -f \"H:/Applications/Aycode/Source/AyCode.Core/AyCode.Entities/IPostalParty.cs\" *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# Topic Codes — FruitBankHybridApp (`FBANKAPP`)
|
||||
|
||||
Per-repo topic registry for the FruitBankHybridApp product, per the **per-repo extension convention** in `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`. Lists ONLY this repo's own topic codes; inherited (ACCORE / AyCode.Blazor / Mango.Nop) topics are reached through `@repo.own-dep-repos`.
|
||||
|
||||
**Foundational conventions are defined once at the framework layer — not restated here:**
|
||||
- ID format, type codes (`I`/`T`/`B`/`C`), ID rules, Status vocabulary, archival, registry-maintenance workflow → `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`
|
||||
- `<PREFIX>` (this repo = `FBANKAPP`, from the `@repo.prefix` in `.github/copilot-instructions.md`) + `<RAND>` spec → `AyCode.Core/.github/REPO_PREFIXES.md`
|
||||
|
||||
## This repo's own topic codes
|
||||
|
||||
| Code | Topic | Scope | Docs location |
|
||||
|----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|
|
||||
| `DMODEL` | DATA-MODEL | FruitBank entitások adatmodell-normalizálása: nopCommerce referencia-FK-k szabad string helyett (Country/Currency), azonosító-szétválasztások (GTIN/VTSZ), és hasonló átmeneti adatmodell-megoldások. **Általános** — nem funkció-specifikus (pl. nem EKÁER). | `FruitBank.Common/docs/DATAMODEL/` |
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Entities;
|
||||
using FruitBank.Common.Services.Ekaer;
|
||||
|
||||
namespace FruitBank.Common.Server.Services.Ekaer;
|
||||
|
||||
/// <inheritdoc cref="IFruitBankEkaerService"/>
|
||||
/// <remarks>
|
||||
/// A teljes lánc: <c>map</c> (<see cref="IShippingToEkaerMapper"/>, FruitBank.Common) →
|
||||
/// <c>validate → send</c> (<see cref="IEkaerSubmitService"/>, AyCode.Services). A NAV-fiók hitelesítő adatait
|
||||
/// (<c>INavCredentials</c>) és a saját cégadatokat (<see cref="EkaerCompanyInfo"/>) a DI szolgáltatja.
|
||||
/// </remarks>
|
||||
public sealed class FruitBankEkaerService : IFruitBankEkaerService
|
||||
{
|
||||
private readonly IShippingToEkaerMapper _mapper;
|
||||
private readonly IEkaerSubmitService _submitService;
|
||||
private readonly EkaerCompanyInfo _company;
|
||||
|
||||
public FruitBankEkaerService(IShippingToEkaerMapper mapper, IEkaerSubmitService submitService, EkaerCompanyInfo company)
|
||||
{
|
||||
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||
_submitService = submitService ?? throw new ArgumentNullException(nameof(submitService));
|
||||
_company = company ?? throw new ArgumentNullException(nameof(company));
|
||||
}
|
||||
|
||||
public Task<EkaerSubmitResult> SubmitShippingAsync(Shipping shipping, OperationType operation = OperationType.Create, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(shipping);
|
||||
|
||||
// map (FruitBank.Common) → submit: validate → send (AyCode.Services)
|
||||
var operations = _mapper.MapShipping(shipping, _company, operation);
|
||||
return _submitService.SubmitAsync(operations, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Entities;
|
||||
|
||||
namespace FruitBank.Common.Server.Services.Ekaer;
|
||||
|
||||
/// <summary>
|
||||
/// A FruitBank szerver-oldali EKÁER-fogyasztója: egy <see cref="Shipping"/>-et leképez EKÁER tradeCard-okra
|
||||
/// (a mapperrel), majd beküldi (az általános submit-orchestrátorral). Ez a vékony, projekt-specifikus réteg;
|
||||
/// az általános NAV/EKÁER logika (validátor, submit, manage) az <c>AyCode.Services</c>-ben él.
|
||||
/// </summary>
|
||||
public interface IFruitBankEkaerService
|
||||
{
|
||||
/// <summary>
|
||||
/// Leképezi és beküldi a szállítmányt. Az eredmény vagy validációs hibák (nem ment ki kérés),
|
||||
/// vagy a NAV-válasz — lásd <see cref="EkaerSubmitResult"/>.
|
||||
/// </summary>
|
||||
Task<EkaerSubmitResult> SubmitShippingAsync(Shipping shipping, OperationType operation = OperationType.Create, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -30,6 +30,16 @@ public class ProductDto : MgProductDto, IProductDto
|
|||
[Association(ThisKey = nameof(Id), OtherKey = nameof(GenericAttributeDto.EntityId), ExpressionPredicate = nameof(RelationWithGenericAttribute), CanBeNull = false)]
|
||||
public List<GenericAttributeDto> GenericAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A nopCommerce <c>Product.Gtin</c> oszlopa. <b>Átmenetileg az EKÁER VTSZ-t (vámtarifaszámot) tárolja</b> —
|
||||
/// a jövőbeli <c>ShippingToEkaerMapper</c> innen olvassa a <c>tradeCardItem.productVtsz</c> értékét.
|
||||
/// ⚠️ A GTIN ≠ VTSZ (a GTIN globális kereskedelmi cikkszám, a VTSZ vámtarifaszám). Külön mezőbe választandó —
|
||||
/// lásd <c>FruitBank.Common/docs/DATAMODEL/DATAMODEL_ISSUES.md#fbankapp-dmodel-i-p6x4</c>.
|
||||
/// </summary>
|
||||
[LinqToDB.Mapping.Column(nameof(Product.Gtin))]
|
||||
[ToonDescription(Purpose = "nopCommerce Gtin column — holds the EKÁER VTSZ (customs tariff number) used as the trade-card item productVtsz in NAV road-freight reporting.")]
|
||||
public string? Gtin { get; set; }
|
||||
|
||||
public ProductDto() :base()
|
||||
{ }
|
||||
public ProductDto(int productId) : base(productId)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using AyCode.Core.Serializers.Attributes;
|
||||
using AyCode.Core.Serializers.Toons;
|
||||
using AyCode.Core.Consts;
|
||||
using FruitBank.Common.Interfaces;
|
||||
using LinqToDB.Mapping;
|
||||
using Mango.Nop.Core.Entities;
|
||||
|
|
@ -17,10 +19,14 @@ public sealed class CargoTruck: MgEntityBase, ICargoTruck
|
|||
[ToonDescription(Purpose = "FK to the owning transport company (CargoPartner) — the carrier, not the goods supplier.")]
|
||||
public int CargoPartnerId { get; set; }
|
||||
|
||||
[Association(ThisKey = nameof(CargoPartnerId), OtherKey = nameof(CargoPartner.Id), CanBeNull = true)]
|
||||
[LinqToDB.Mapping.Association(ThisKey = nameof(CargoPartnerId), OtherKey = nameof(CargoPartner.Id), CanBeNull = true)]
|
||||
public CargoPartner CargoPartner { get; set; }
|
||||
|
||||
[RegularExpression(AcRegExpression.CountryCodeMax3Mask, ErrorMessage = "A jármű országkódja 1–3 nagybetű (pl. HU).")]
|
||||
public string CountryCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "A rendszám kötelező.")]
|
||||
[RegularExpression(AcRegExpression.PlateNumberMask, ErrorMessage = "A rendszám csak nagybetű és szám lehet, kötőjel/szóköz nélkül (pl. ABC123).")]
|
||||
public string LicencePlate { get; set; }
|
||||
|
||||
[ToonDescription(Purpose = "Discriminates the shared table: false = tractor/truck unit, true = trailer.")]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
using FruitBank.Common.Interfaces;
|
||||
using AyCode.Core.Serializers.Toons;
|
||||
using AyCode.Entities;
|
||||
using FruitBank.Common.Interfaces;
|
||||
using LinqToDB.Mapping;
|
||||
using Mango.Nop.Core.Entities;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using AyCode.Core.Interfaces;
|
||||
|
||||
namespace FruitBank.Common.Entities;
|
||||
|
||||
|
|
@ -11,6 +16,9 @@ public abstract class PartnerBase : MgEntityBase, IPartnerBase
|
|||
public string CertificationNumber { get; set; }
|
||||
|
||||
public string CountryCode { get; set; }
|
||||
|
||||
[ToonDescription(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.")]
|
||||
public string Currency { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string State { get; set; }
|
||||
|
|
@ -18,6 +26,10 @@ public abstract class PartnerBase : MgEntityBase, IPartnerBase
|
|||
public string City { get; set; }
|
||||
public string Street { get; set; }
|
||||
|
||||
[NotColumn, NotMapped, JsonIgnore, System.Text.Json.Serialization.JsonIgnore]
|
||||
[ToonDescription(Purpose = "The PostalCode + City + Street joined into a single-line postal address (non-empty parts).")]
|
||||
public string? FullAddress => this.ComposeFullAddress();
|
||||
|
||||
|
||||
[SkipValuesOnUpdate]
|
||||
public DateTime Created { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using AyCode.Interfaces.Entities;
|
||||
using AyCode.Core.Interfaces;
|
||||
using AyCode.Entities;
|
||||
using AyCode.Interfaces.Entities;
|
||||
using AyCode.Interfaces.TimeStampInfo;
|
||||
using FruitBank.Common.Entities;
|
||||
|
||||
|
|
@ -14,16 +16,11 @@ public interface IPartner : IPartnerBase
|
|||
List<ShippingDocument>? ShippingDocuments { get; set; }
|
||||
}
|
||||
|
||||
public interface IPartnerBase : IEntityInt, ITimeStampInfo
|
||||
public interface IPartnerBase : ICompanyInfoBase, IEntityInt, ITimeStampInfo
|
||||
{
|
||||
string Name { get; set; }
|
||||
string TaxId { get; set; }
|
||||
string CertificationNumber { get; set; }
|
||||
string CountryCode { get; set; }
|
||||
string PostalCode { get; set; }
|
||||
string Currency { get; set; }
|
||||
string Country { get; set; }
|
||||
string State { get; set; }
|
||||
string County { get; set; }
|
||||
string City { get; set; }
|
||||
string Street { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Entities;
|
||||
|
||||
namespace FruitBank.Common.Services.Ekaer;
|
||||
|
||||
/// <summary>
|
||||
/// FruitBank domain → NAV EKÁER tradeCard leképezés. Egy bejövő <see cref="Shipping"/>-ből
|
||||
/// EKÁER tradeCard műveleteket állít elő (dokumentumonként egyet).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A NAV-protokollt és az authentikációt NEM kezeli — az az <c>AyCode.Services.Nav</c> réteg felelőssége.
|
||||
/// A feladót (beszállító <c>Partner</c>) és a saját céget (<see cref="EkaerCompanyInfo"/>) egységesen,
|
||||
/// <see cref="AyCode.Entities.ICompanyInfoBase"/>-ként kezeli.
|
||||
/// </remarks>
|
||||
public interface IShippingToEkaerMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Leképezi a <paramref name="shipping"/> minden <c>ShippingDocument</c>-jét egy-egy EKÁER tradeCard műveletre.
|
||||
/// </summary>
|
||||
/// <param name="shipping">A bejövő szállítmány (fuvarozó/jármű a Shipping szintjén, eladó/tételek a dokumentum szintjén).</param>
|
||||
/// <param name="company">A bejelentő saját cégadatai (címzett bejövő relációban) + a lerakodási hely.</param>
|
||||
/// <param name="operation">A tradeCard művelet típusa. Alapértelmezés: <see cref="OperationType.Create"/>.</param>
|
||||
IReadOnlyList<TradeCardOperationType> MapShipping(Shipping shipping, EkaerCompanyInfo company, OperationType operation = OperationType.Create);
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
using AyCode.Core.Interfaces;
|
||||
using AyCode.Entities;
|
||||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Entities;
|
||||
using TradeReasonType = AyCode.Services.Nav.Ekaer.Models.Common.TradeReasonType;
|
||||
using TradeType = AyCode.Services.Nav.Ekaer.Models.Common.TradeType;
|
||||
|
||||
namespace FruitBank.Common.Services.Ekaer;
|
||||
|
||||
/// <inheritdoc cref="IShippingToEkaerMapper"/>
|
||||
/// <remarks>
|
||||
/// Tiszta (állapotmentes) leképező. A feladót és a saját céget egységesen <see cref="ICompanyInfoBase"/>-ként kezeli.
|
||||
/// A <c>TradeType</c>/<c>TradeReasonType</c> enumokat aliasszal hozzuk be a <c>Models.TradeCardType</c> osztály
|
||||
/// és a <c>Models.Common.TradeCardType</c> enum névütközése miatt.
|
||||
/// </remarks>
|
||||
public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
||||
{
|
||||
/// <summary>A NAV EKÁER magyar rendszer — a „belföld" mindig HU; minden más feladó-ország import.</summary>
|
||||
private const string HomeCountry = "HU";
|
||||
|
||||
public IReadOnlyList<TradeCardOperationType> MapShipping(Shipping shipping, EkaerCompanyInfo company, OperationType operation = OperationType.Create)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(shipping);
|
||||
ArgumentNullException.ThrowIfNull(company);
|
||||
|
||||
var operations = new List<TradeCardOperationType>();
|
||||
var index = 0;
|
||||
|
||||
// Granularitás: egy ShippingDocument → egy tradeCard (lásd EKAER_TODO #5).
|
||||
foreach (var document in shipping.ShippingDocuments ?? [])
|
||||
{
|
||||
index++;
|
||||
operations.Add(new TradeCardOperationType
|
||||
{
|
||||
Index = index,
|
||||
Operation = operation,
|
||||
TradeCard = BuildTradeCard(shipping, document, company),
|
||||
});
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
private static TradeCardType BuildTradeCard(Shipping shipping, ShippingDocument document, EkaerCompanyInfo company)
|
||||
{
|
||||
var seller = document.Partner; // a beszállító (feladó) — ICompanyInfoBase
|
||||
|
||||
var tradeCard = new TradeCardType
|
||||
{
|
||||
TradeType = ResolveTradeType(seller),
|
||||
ModByCarrierEnabled = false, // mi jelentünk; a fuvarozó alapból nem módosíthat
|
||||
|
||||
// Feladó / eladó = a beszállító
|
||||
SellerName = seller?.Name,
|
||||
SellerVatNumber = NormalizeVatNumber(seller?.TaxId),
|
||||
SellerCountry = NormalizeCountryCode(seller?.CountryCode, 2),
|
||||
SellerAddress = Truncate(seller?.FullAddress, 200),
|
||||
|
||||
// Címzett = a bejelentő saját cége (bejövő relációban)
|
||||
DestinationName = company.Name,
|
||||
DestinationVatNumber = NormalizeVatNumber(company.TaxId),
|
||||
DestinationCountry = NormalizeCountryCode(company.CountryCode, 2),
|
||||
DestinationAddress = Truncate(company.FullAddress, 200),
|
||||
|
||||
// Fuvarozó (Shipping.CargoPartner). Regisztrált EKAER-azonosító nincs, csak szöveges név.
|
||||
CarrierText = shipping.CargoPartner?.Name,
|
||||
|
||||
// Lerakodás = saját telephely (a cégadatból); felrakodás = a beszállító telephelye.
|
||||
UnloadLocation = company.UnloadLocation,
|
||||
LoadLocation = BuildLoadLocation(seller),
|
||||
};
|
||||
|
||||
// Vonó jármű + vontatmány: az EKÁER külön bejegyzésként kéri (vehicle / vehicle2).
|
||||
if (shipping.CargoTruck != null) tradeCard.Vehicle = BuildVehicle(shipping.CargoTruck);
|
||||
if (shipping.CargoTrailer != null) tradeCard.Vehicle2 = BuildVehicle(shipping.CargoTrailer);
|
||||
|
||||
foreach (var item in document.ShippingItems ?? []) tradeCard.Items.Add(BuildItem(item));
|
||||
return tradeCard;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Belföldi feladó (HU) → <c>D</c> (belföld-belföld), egyébként → <c>I</c> (import). A NAV EKÁER magyar,
|
||||
/// így a belföld mindig HU; az export (<c>E</c>) jelenleg nincs leképezve (lásd EKAER_TODO #1, #7).
|
||||
/// </summary>
|
||||
private static TradeType ResolveTradeType(ICompanyInfoBase? seller)
|
||||
=> string.Equals(seller?.CountryCode, HomeCountry, StringComparison.OrdinalIgnoreCase)
|
||||
? TradeType.D
|
||||
: TradeType.I;
|
||||
|
||||
private static TradeCardItemType BuildItem(ShippingItem item) => new()
|
||||
{
|
||||
ItemExternalId = item.Id.ToString(),
|
||||
// Bejövő áru = beszerzés → A. (Enum: S=értékesítés, A=beszerzés, W=bérmunka, O=egyéb.) Lásd EKAER_TODO #9.
|
||||
TradeReason = TradeReasonType.A,
|
||||
ProductVtsz = item.ProductDto?.Gtin, // VTSZ — átmenetileg a Gtin oszlopban (FBANKAPP-DMODEL-I-P6X4)
|
||||
ProductName = item.ProductName,
|
||||
Weight = (decimal)item.MeasuredGrossWeight, // bruttó tömeg kg-ban (lásd EKAER_TODO #4)
|
||||
// Value (HUF): a deviza/FX tisztázásáig NEM töltjük (a mező opcionális). Lásd EKAER_TODO #3, #10.
|
||||
};
|
||||
|
||||
private static BasicVehicleDetailType BuildVehicle(CargoTruck truck) => new()
|
||||
{
|
||||
PlateNumber = NormalizePlateNumber(truck.LicencePlate),
|
||||
Country = NormalizeCountryCode(truck.CountryCode, 3),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Felrakodási hely a beszállító adataiból. (Magyar feladónál a NAV a Phone/Email-t is kéri, ami az
|
||||
/// entitásban nincs — lásd EKAER_TODO #6.)
|
||||
/// </summary>
|
||||
private static LocationType? BuildLoadLocation(ICompanyInfoBase? seller)
|
||||
{
|
||||
if (seller is null) return null;
|
||||
return new LocationType
|
||||
{
|
||||
Name = seller.Name,
|
||||
VatNumber = NormalizeVatNumber(seller.TaxId),
|
||||
Country = NormalizeCountryCode(seller.CountryCode, 2),
|
||||
ZipCode = NormalizeZipCode(seller.PostalCode),
|
||||
City = seller.City,
|
||||
Street = seller.Street,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Adószám normalizálása. Pattern: <c>[0-9A-Z-]{1,15}</c>.</summary>
|
||||
private static string? NormalizeVatNumber(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return null;
|
||||
var cleaned = new string([.. value.ToUpperInvariant().Where(c => char.IsAsciiLetterOrDigit(c) || c == '-')]);
|
||||
return Truncate(EmptyToNull(cleaned), 15);
|
||||
}
|
||||
|
||||
/// <summary>Országkód normalizálása. Pattern: <c>[A-Z]{1,maxLen}</c> (seller/location: 2, jármű: 3).</summary>
|
||||
private static string? NormalizeCountryCode(string? value, int maxLen)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return null;
|
||||
var cleaned = new string([.. value.ToUpperInvariant().Where(char.IsAsciiLetter)]);
|
||||
return Truncate(EmptyToNull(cleaned), maxLen);
|
||||
}
|
||||
|
||||
/// <summary>Rendszám normalizálása. Pattern: <c>[A-Z0-9ÖŐÜŰ]{4,15}</c> — kötőjel/szóköz NEM engedett.</summary>
|
||||
private static string? NormalizePlateNumber(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return null;
|
||||
var cleaned = new string([.. value.ToUpperInvariant().Where(c => char.IsAsciiLetterOrDigit(c) || c is 'Ö' or 'Ő' or 'Ü' or 'Ű')]);
|
||||
return Truncate(EmptyToNull(cleaned), 15);
|
||||
}
|
||||
|
||||
/// <summary>Irányítószám normalizálása. Pattern: <c>[A-Z0-9 -]{2,10}</c> vagy üres.</summary>
|
||||
private static string? NormalizeZipCode(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return null;
|
||||
var cleaned = new string([.. value.ToUpperInvariant().Where(c => char.IsAsciiLetterOrDigit(c) || c is ' ' or '-')]);
|
||||
return Truncate(EmptyToNull(cleaned), 10);
|
||||
}
|
||||
|
||||
private static string? EmptyToNull(string? value) => string.IsNullOrEmpty(value) ? null : value;
|
||||
|
||||
private static string? Truncate(string? value, int maxLen)
|
||||
=> value is null ? null : value.Length <= maxLen ? value : value[..maxLen];
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# DATA-MODEL — Known Issues
|
||||
|
||||
> Companion to [`README.md`](README.md). Topic `DMODEL`, prefix `FBANKAPP` → entry IDs `FBANKAPP-DMODEL-I-<RAND>` (issue) / `-B-` (bug).
|
||||
> ID format, Status vocabulary, type codes, archival → `../../../.github/TOPIC_CODES.md` (→ framework registry).
|
||||
|
||||
Scope: a FruitBank entitások adatmodell-normalizálási teendői (nopCommerce referencia-FK-k, azonosító-szétválasztások).
|
||||
|
||||
## Active entries
|
||||
|
||||
## FBANKAPP-DMODEL-I-K3D9: A Partner-entitások nopCommerce referencia-mezői szabad string-ek, FK helyett
|
||||
|
||||
**Status:** Open · **Priority:** P3 · **Type:** I (adatmodell / normalizálás)
|
||||
|
||||
A `PartnerBase` (és így `Partner` / `CargoPartner`) + a `CargoTruck` a nopCommerce referencia-adatait **szabad string-ként** tárolja, ahelyett hogy a megfelelő nopCommerce tábla **Id-jára FK-zna**:
|
||||
|
||||
| Mező | Jelenlegi | Helyes (hosszú táv) |
|
||||
|---|---|---|
|
||||
| `CountryCode` (string) | szabad szöveg (pl. `"HU"`) | nopCommerce **`Country.Id`** FK; a megjelenített kód a `Country.TwoLetterIsoCode`-ból — `PartnerBase` + `CargoTruck` |
|
||||
| `Currency` (string) | szabad szöveg (pl. `"EUR"`) | nopCommerce **`Currency.Id`** FK; a megjelenített kód a `Currency.CurrencyCode`-ból — `PartnerBase` |
|
||||
|
||||
**Hatás:** működik (a string-eket kézzel töltjük), de **nincs hivatkozás-integritás**, és a kódok elgépelhetők / inkonzisztensek lehetnek. Az EKÁER-leképezés a string pontosságára támaszkodik (`seller`/`destination`/`vehicle` `Country`, és a value→HUF deviza forrás-pénzneme).
|
||||
|
||||
**Javítási irány:** FK-oszlop (`CountryId`, `CurrencyId`) + navigation a nopCommerce táblákra; a megjelenített/exportált kód a referencia-entitásból.
|
||||
|
||||
**Affected:**
|
||||
- `FruitBank.Common/Entities/PartnerBase.cs` → `CountryCode`, `Currency`
|
||||
- `FruitBank.Common/Entities/CargoTruck.cs` → `CountryCode`
|
||||
- felhasználó: `FruitBank.Common/Services/Ekaer/ShippingToEkaerMapper.cs` (a `*Country` + a deviza-konverzió pontossága)
|
||||
|
||||
## FBANKAPP-DMODEL-I-P6X4: A `Product.Gtin` átmenetileg a VTSZ-t tárolja — szétválasztandó
|
||||
|
||||
**Status:** Open · **Priority:** P3 · **Type:** I (adatmodell / átmeneti megoldás)
|
||||
|
||||
> **Supersedes** `MGFBANKPLUG-EKAER-I-T3X8` — áthelyezve az EKÁER-topicból ide, mert a GTIN/VTSZ szétválasztás **általános** adatmodell-kérdés (a GTIN globális termékazonosító, a VTSZ vámtarifaszám), nem EKÁER-specifikus.
|
||||
|
||||
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).
|
||||
- **VTSZ** — vámtarifaszám (a termék vám-/statisztikai besorolása).
|
||||
|
||||
Egy termékhez a kettő nem azonos; a `Gtin` oszlop VTSZ-ként való használata **átmeneti** megoldás az EKÁER-integráció beindításához.
|
||||
|
||||
**Hatás:** jelenleg nincs üzemszerű gond (a `Gtin` mező szabad, és a VTSZ-t tölthetjük bele). Hosszú távon viszont, ha a valódi GTIN-re is szükség lesz, a kettő ütközik.
|
||||
|
||||
**Javítási irány:** külön `Vtsz` mező/`GenericAttribute` a `Product`-on, és a `ShippingToEkaerMapper` onnan olvasson — a `Gtin` maradjon a valódi GTIN.
|
||||
|
||||
**Affected:**
|
||||
- `FruitBank.Common/Dtos/ProductDto.cs` → `Gtin` property (a `[Column(nameof(Product.Gtin))]` jelöléssel, summary-ban megjelölve)
|
||||
- `FruitBank.Common/Services/Ekaer/ShippingToEkaerMapper.cs` → a `productVtsz` forrása
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# DATA-MODEL — FruitBank adatmodell-normalizálás
|
||||
|
||||
Topic `DMODEL`, prefix `FBANKAPP` → entry ID-k `FBANKAPP-DMODEL-I-<RAND>` (issue) / `-T-` (TODO) / `-B-` (bug).
|
||||
ID-formátum, Status, type-kódok, archiválás → `../../../.github/TOPIC_CODES.md` (→ framework registry).
|
||||
|
||||
A FruitBank entitások (`Partner`, `CargoPartner`, `CargoTruck`, `ProductDto`) **adatmodell-átmenetiségei**: olyan mezők, amelyek hosszú távon a nopCommerce referencia-tábláira FK-znának, vagy külön mezőbe válnának — de jelenleg szabad string / átmeneti megoldás.
|
||||
|
||||
> Ezek **általános** adatmodell-kérdések, NEM funkció-specifikusak. Az EKÁER-, pre-order- stb. doksik csak **hivatkoznak** ide (nem duplikálják).
|
||||
|
||||
## Companion fájlok
|
||||
|
||||
- [`DATAMODEL_ISSUES.md`](DATAMODEL_ISSUES.md) — az aktív adatmodell-issue-k.
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Dtos;
|
||||
using FruitBank.Common.Entities;
|
||||
using FruitBank.Common.Services.Ekaer;
|
||||
using TradeReasonType = AyCode.Services.Nav.Ekaer.Models.Common.TradeReasonType;
|
||||
using TradeType = AyCode.Services.Nav.Ekaer.Models.Common.TradeType;
|
||||
|
||||
namespace FruitBankHybrid.Shared.Tests.Ekaer;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tesztek a <see cref="ShippingToEkaerMapper"/>-re — a FruitBank <c>Shipping</c> → NAV EKÁER tradeCard
|
||||
/// leképezésre. Tisztán memóriában felépített entitásokon fut (nincs hálózat/DB), determinisztikus.
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public sealed class ShippingToEkaerMapperTests
|
||||
{
|
||||
private static readonly ShippingToEkaerMapper Mapper = new();
|
||||
|
||||
// ---- Helpers ------------------------------------------------------------
|
||||
|
||||
private static Shipping CreateShipping(string sellerCountry = "HU", string plate = "ABC-123", bool withTrailer = true)
|
||||
{
|
||||
var item = new ShippingItem
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Alma",
|
||||
ProductDto = new ProductDto { Gtin = "08081010", Name = "Alma" },
|
||||
MeasuredGrossWeight = 123.5,
|
||||
MeasuredQuantity = 10,
|
||||
UnitPriceOnDocument = 5.0,
|
||||
};
|
||||
|
||||
var document = new ShippingDocument
|
||||
{
|
||||
Country = sellerCountry,
|
||||
Partner = new Partner
|
||||
{
|
||||
Name = "Beszállító Kft",
|
||||
TaxId = "12345678-2-42",
|
||||
CountryCode = sellerCountry,
|
||||
PostalCode = "1011",
|
||||
City = "Budapest",
|
||||
Street = "Fő utca 1",
|
||||
},
|
||||
ShippingItems = [item],
|
||||
};
|
||||
|
||||
var shipping = new Shipping
|
||||
{
|
||||
CargoPartner = new CargoPartner { Name = "Fuvaros Zrt", CountryCode = "HU" },
|
||||
CargoTruck = new CargoTruck { LicencePlate = plate, CountryCode = "HU", IsTrailer = false },
|
||||
ShippingDocuments = [document],
|
||||
};
|
||||
|
||||
if (withTrailer)
|
||||
shipping.CargoTrailer = new CargoTruck { LicencePlate = "XYZ-789", CountryCode = "HU", IsTrailer = true };
|
||||
|
||||
return shipping;
|
||||
}
|
||||
|
||||
private static EkaerCompanyInfo CreateCompany() => new()
|
||||
{
|
||||
Name = "FruitBank Kft",
|
||||
TaxId = "98765432-2-41",
|
||||
CountryCode = "HU",
|
||||
PostalCode = "1102",
|
||||
City = "Budapest",
|
||||
Street = "Raktar utca 5",
|
||||
UnloadLocation = new LocationType
|
||||
{
|
||||
Name = "FruitBank Raktár",
|
||||
VatNumber = "98765432-2-41",
|
||||
Country = "HU",
|
||||
ZipCode = "1102",
|
||||
City = "Budapest",
|
||||
Street = "Raktar utca",
|
||||
StreetNumber = "5",
|
||||
},
|
||||
};
|
||||
|
||||
// ---- Granularitás / index ----------------------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_ProducesOneOperationPerDocument_WithSequentialIndex()
|
||||
{
|
||||
var shipping = CreateShipping();
|
||||
shipping.ShippingDocuments!.Add(new ShippingDocument
|
||||
{
|
||||
Country = "HU",
|
||||
Partner = new Partner { Name = "Másik Beszállító", CountryCode = "HU" },
|
||||
ShippingItems = [],
|
||||
});
|
||||
|
||||
var ops = Mapper.MapShipping(shipping, CreateCompany());
|
||||
|
||||
Assert.AreEqual(2, ops.Count, "dokumentumonként egy tradeCard");
|
||||
Assert.AreEqual(1, ops[0].Index);
|
||||
Assert.AreEqual(2, ops[1].Index);
|
||||
Assert.AreEqual(OperationType.Create, ops[0].Operation, "alapértelmezett művelet: Create");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NullDocuments_ReturnsEmpty()
|
||||
{
|
||||
var ops = Mapper.MapShipping(new Shipping { ShippingDocuments = null }, CreateCompany());
|
||||
Assert.AreEqual(0, ops.Count);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_HonorsExplicitOperation()
|
||||
{
|
||||
var ops = Mapper.MapShipping(CreateShipping(), CreateCompany(), OperationType.Modify);
|
||||
Assert.AreEqual(OperationType.Modify, ops[0].Operation);
|
||||
}
|
||||
|
||||
// ---- tradeType irány ----------------------------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_DomesticSeller_TradeTypeDomestic()
|
||||
{
|
||||
var ops = Mapper.MapShipping(CreateShipping(sellerCountry: "HU"), CreateCompany());
|
||||
Assert.AreEqual(TradeType.D, ops[0].TradeCard.TradeType, "belföldi (HU) feladó → D");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_ForeignSeller_TradeTypeImport()
|
||||
{
|
||||
var ops = Mapper.MapShipping(CreateShipping(sellerCountry: "DE"), CreateCompany());
|
||||
Assert.AreEqual(TradeType.I, ops[0].TradeCard.TradeType, "nem-HU feladó → I (import) — a NAV EKÁER magyar");
|
||||
}
|
||||
|
||||
// ---- Tétel-leképezés ----------------------------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_MapsItemFields()
|
||||
{
|
||||
var item = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard.Items[0];
|
||||
|
||||
Assert.AreEqual("08081010", item.ProductVtsz, "productVtsz = ProductDto.Gtin");
|
||||
Assert.AreEqual("Alma", item.ProductName);
|
||||
Assert.AreEqual(123.5m, item.Weight, "weight = MeasuredGrossWeight (bruttó)");
|
||||
Assert.AreEqual(TradeReasonType.A, item.TradeReason, "bejövő áru = beszerzés = A");
|
||||
Assert.IsNull(item.Value, "a HUF érték a deviza tisztázásáig nincs kitöltve");
|
||||
}
|
||||
|
||||
// ---- Eladó (seller*) ----------------------------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_MapsSellerFromPartner()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard;
|
||||
|
||||
Assert.AreEqual("Beszállító Kft", tradeCard.SellerName);
|
||||
Assert.AreEqual("12345678-2-42", tradeCard.SellerVatNumber);
|
||||
Assert.AreEqual("HU", tradeCard.SellerCountry);
|
||||
StringAssert.Contains(tradeCard.SellerAddress, "Budapest", "a sellerAddress a Partner FullAddress-éből jön");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_MapsDestinationAndUnloadFromCompany()
|
||||
{
|
||||
var company = CreateCompany();
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), company)[0].TradeCard;
|
||||
|
||||
Assert.AreEqual("FruitBank Kft", tradeCard.DestinationName);
|
||||
Assert.AreEqual("HU", tradeCard.DestinationCountry);
|
||||
StringAssert.Contains(tradeCard.DestinationAddress, "Budapest", "a destinationAddress a company FullAddress-éből jön");
|
||||
Assert.AreSame(company.UnloadLocation, tradeCard.UnloadLocation, "a lerakodási hely a cégadatból jön");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_MapsCarrierTextFromCargoPartner()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard;
|
||||
Assert.AreEqual("Fuvaros Zrt", tradeCard.CarrierText);
|
||||
}
|
||||
|
||||
// ---- Járművek + rendszám-normalizálás ----------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NormalizesLicencePlate_RemovesHyphenAndUppercases()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(plate: "abc-123"), CreateCompany())[0].TradeCard;
|
||||
Assert.AreEqual("ABC123", tradeCard.Vehicle!.PlateNumber, "a NAV pattern nem enged kötőjelet, és nagybetűs");
|
||||
Assert.AreEqual("HU", tradeCard.Vehicle.Country);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_WithTrailer_MapsVehicle2()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: true), CreateCompany())[0].TradeCard;
|
||||
Assert.IsNotNull(tradeCard.Vehicle, "vonó jármű");
|
||||
Assert.IsNotNull(tradeCard.Vehicle2, "vontatmány");
|
||||
Assert.AreEqual("XYZ789", tradeCard.Vehicle2!.PlateNumber);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NoTrailer_Vehicle2Null()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: false), CreateCompany())[0].TradeCard;
|
||||
Assert.IsNotNull(tradeCard.Vehicle);
|
||||
Assert.IsNull(tradeCard.Vehicle2, "nincs pótkocsi → nincs vehicle2");
|
||||
}
|
||||
|
||||
// ---- Védőkorlátok -------------------------------------------------------
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NullShipping_Throws()
|
||||
=> Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(null!, CreateCompany()));
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NullCompany_Throws()
|
||||
=> Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(CreateShipping(), null!));
|
||||
}
|
||||
|
|
@ -35,12 +35,13 @@ public sealed class OrderClientTests
|
|||
[TestMethod]
|
||||
public async Task GetAllStockTakings()
|
||||
{
|
||||
var stockTakings = await _signalRClient.GetStockTakings(false);
|
||||
var stockTakings = await _signalRClient.GetStockTakings(true);
|
||||
|
||||
Assert.IsNotNull(stockTakings);
|
||||
Assert.IsTrue(stockTakings.Count != 0);
|
||||
Assert.IsNotEmpty(stockTakings);
|
||||
|
||||
Assert.IsTrue(stockTakings.All(o => o.StockTakingItems.All(oi => oi.Product != null && oi.Product.Id == oi.ProductId)));
|
||||
Assert.IsTrue(stockTakings.All(o => o.StockTakingItems != null));
|
||||
Assert.IsTrue(stockTakings.All(o => o.StockTakingItems!.All(oi => oi.Product != null && oi.Product.Id == oi.ProductId)));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
@ -49,9 +50,9 @@ public sealed class OrderClientTests
|
|||
var stockTakingItems = await _signalRClient.GetStockTakingItems();
|
||||
|
||||
Assert.IsNotNull(stockTakingItems);
|
||||
Assert.IsTrue(stockTakingItems.Count != 0);
|
||||
Assert.IsNotEmpty(stockTakingItems);
|
||||
|
||||
Assert.IsTrue(stockTakingItems.All(oi => oi.StockTaking != null && oi.Product != null && oi.Product.Id == oi.ProductId));
|
||||
Assert.IsTrue(stockTakingItems.All(oi => oi is { StockTaking: not null, Product: not null } && oi.Product.Id == oi.ProductId));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
<DxGridDataColumn FieldName="Name" />
|
||||
<DxGridDataColumn FieldName="TaxId" />
|
||||
<DxGridDataColumn FieldName="CertificationNumber" />
|
||||
<DxGridDataColumn FieldName="@nameof(CargoPartner.Currency)" />
|
||||
<DxGridDataColumn FieldName="@nameof(CargoPartner.CountryCode)" />
|
||||
<DxGridDataColumn FieldName="PostalCode" />
|
||||
<DxGridDataColumn FieldName="@nameof(CargoPartner.Country)" />
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
SignalRClient="FruitBankSignalRClient"
|
||||
Logger="_logger"
|
||||
CssClass="@GridCss"
|
||||
ValidationEnabled="false"
|
||||
ValidationEnabled="true"
|
||||
OnGridFocusedRowChanged="Grid_FocusedRowChanged">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Descending" ReadOnly="true" />
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
<DxGridDataColumn FieldName="Name" />
|
||||
<DxGridDataColumn FieldName="TaxId" />
|
||||
<DxGridDataColumn FieldName="CertificationNumber" />
|
||||
<DxGridDataColumn FieldName="@nameof(CargoPartner.Currency)" />
|
||||
<DxGridDataColumn FieldName="@nameof(Partner.CountryCode)" />
|
||||
<DxGridDataColumn FieldName="PostalCode" />
|
||||
<DxGridDataColumn FieldName="@nameof(Partner.Country)" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue