Refactor EKÁER mapping: unify company info, doc updates
- Introduced ICompanyInfoBase for standardized company/partner data; refactored PartnerBase and interfaces to implement it - Replaced EkaerMappingOptions with EkaerCompanyInfo; updated all usages, constructors, and tests - Refactored EKÁER mapping logic to use ICompanyInfoBase; improved normalization and address handling - Added regex/validation for plate numbers and country codes; new error codes - Added Currency to PartnerBase; updated grids to display it - Updated ProductDto doc for GTIN/VTSZ data model issue - Enabled validation in CargoTruck grid - Added DMODEL topic docs: TOPIC_CODES.md, DATAMODEL_ISSUES.md, README.md - Removed obsolete files and updated settings.local.json - General code and doc improvements for maintainability
This commit is contained in:
parent
2fb1151e5d
commit
0a1287ce67
|
|
@ -52,7 +52,9 @@
|
|||
"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(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/` |
|
||||
|
|
@ -8,20 +8,20 @@ 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 <see cref="EkaerMappingOptions"/>-t a DI szolgáltatja.
|
||||
/// <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 EkaerMappingOptions _options;
|
||||
private readonly EkaerCompanyInfo _company;
|
||||
|
||||
public FruitBankEkaerService(IShippingToEkaerMapper mapper, IEkaerSubmitService submitService, EkaerMappingOptions options)
|
||||
public FruitBankEkaerService(IShippingToEkaerMapper mapper, IEkaerSubmitService submitService, EkaerCompanyInfo company)
|
||||
{
|
||||
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||
_submitService = submitService ?? throw new ArgumentNullException(nameof(submitService));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_company = company ?? throw new ArgumentNullException(nameof(company));
|
||||
}
|
||||
|
||||
public Task<EkaerSubmitResult> SubmitShippingAsync(Shipping shipping, OperationType operation = OperationType.Create, CancellationToken cancellationToken = default)
|
||||
|
|
@ -29,7 +29,7 @@ public sealed class FruitBankEkaerService : IFruitBankEkaerService
|
|||
ArgumentNullException.ThrowIfNull(shipping);
|
||||
|
||||
// map (FruitBank.Common) → submit: validate → send (AyCode.Services)
|
||||
var operations = _mapper.MapShipping(shipping, _options, operation);
|
||||
var operations = _mapper.MapShipping(shipping, _company, operation);
|
||||
return _submitService.SubmitAsync(operations, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class ProductDto : MgProductDto, IProductDto
|
|||
/// 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>Nop.Plugin.Misc.AIPlugin/docs/EKAER/EKAER_ISSUES.md#mgfbankplug-ekaer-i-t3x8</c>.
|
||||
/// 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.")]
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
|
||||
namespace FruitBank.Common.Services.Ekaer;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ShippingToEkaerMapper"/> konfiguráció-függő bemenetei, amelyek NEM a <c>Shipping</c>-ből
|
||||
/// származnak: a bejelentő (FruitBank) mint címzett/destination cégadatai, a lerakodási hely (saját raktár),
|
||||
/// és a saját országkód a tradeType irány meghatározásához.
|
||||
/// </summary>
|
||||
/// <remarks>Ezek később a szerver-oldali plugin beállításaiból (settings) töltődnek — lásd a plugin <c>docs/EKAER/EKAER_TODO.md</c> #2.</remarks>
|
||||
public sealed class EkaerMappingOptions
|
||||
{
|
||||
/// <summary>A bejelentő (FruitBank) neve — a tradeCard <c>destinationName</c>-je bejövő relációban.</summary>
|
||||
public string? DestinationName { get; set; }
|
||||
|
||||
/// <summary>A bejelentő adószáma (<c>destinationVatNumber</c>). Pattern: <c>[0-9A-Z-]{1,15}</c>.</summary>
|
||||
public string? DestinationVatNumber { get; set; }
|
||||
|
||||
/// <summary>A bejelentő országkódja (2 betű). Alapértelmezés: <c>HU</c>.</summary>
|
||||
public string DestinationCountryCode { get; set; } = "HU";
|
||||
|
||||
/// <summary>A bejelentő címe egybeírva (<c>destinationAddress</c>, max 200).</summary>
|
||||
public string? DestinationAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A lerakodási / raktározási hely (a saját raktár). Magyar cím esetén a Name/VatNumber/Phone/Email
|
||||
/// kitöltése kötelező — ezért kész <see cref="LocationType"/>-ként adjuk át (a plugin-konfigból összeállítva).
|
||||
/// </summary>
|
||||
public LocationType? UnloadLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A bejelentő saját országkódja a tradeType meghatározásához: ha a feladó (beszállító) országa
|
||||
/// ezzel egyezik → <c>D</c> (belföld-belföld), egyébként → <c>I</c> (import). Alapértelmezés: <c>HU</c>.
|
||||
/// </summary>
|
||||
public string HomeCountryCode { get; set; } = "HU";
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Entities;
|
||||
|
||||
|
|
@ -8,19 +9,17 @@ namespace FruitBank.Common.Services.Ekaer;
|
|||
/// 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
|
||||
/// (<c>NavReportServiceBase</c> / <c>EkaerManageService</c>) felelőssége. A tényleges NAV-bejelentést
|
||||
/// a szerver-oldali (nopCommerce plugin) service végzi, amely ezt a leképezőt használja. A leképezés
|
||||
/// tisztázott pontjai és nyitott döntései a plugin <c>docs/EKAER/README.md</c> és <c>EKAER_TODO.md</c> fájljaiban.
|
||||
/// 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. A fuvarozó/jármű a Shipping szintjén, az eladó/tételek a dokumentum szintjén élnek.</param>
|
||||
/// <param name="options">A konfiguráció-függő adatok (destination cég, lerakodási hely, home country).</param>
|
||||
/// <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>
|
||||
/// <returns>Dokumentumonként egy <see cref="TradeCardOperationType"/>, a beérkezés sorrendjében indexelve.</returns>
|
||||
IReadOnlyList<TradeCardOperationType> MapShipping(Shipping shipping, EkaerMappingOptions options, OperationType operation = OperationType.Create);
|
||||
IReadOnlyList<TradeCardOperationType> MapShipping(Shipping shipping, EkaerCompanyInfo company, OperationType operation = OperationType.Create);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
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;
|
||||
|
|
@ -7,15 +10,19 @@ namespace FruitBank.Common.Services.Ekaer;
|
|||
|
||||
/// <inheritdoc cref="IShippingToEkaerMapper"/>
|
||||
/// <remarks>
|
||||
/// Tiszta (állapotmentes) leképező. A <c>TradeType</c>/<c>TradeReasonType</c> enumokat aliasszal hozzuk be,
|
||||
/// hogy elkerüljük a <c>Models.Common.TradeCardType</c> enum és a <c>Models.TradeCardType</c> osztály névütközését.
|
||||
/// 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
|
||||
{
|
||||
public IReadOnlyList<TradeCardOperationType> MapShipping(Shipping shipping, EkaerMappingOptions options, OperationType operation = OperationType.Create)
|
||||
/// <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(options);
|
||||
ArgumentNullException.ThrowIfNull(company);
|
||||
|
||||
var operations = new List<TradeCardOperationType>();
|
||||
var index = 0;
|
||||
|
|
@ -28,43 +35,43 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
{
|
||||
Index = index,
|
||||
Operation = operation,
|
||||
TradeCard = BuildTradeCard(shipping, document, options),
|
||||
TradeCard = BuildTradeCard(shipping, document, company),
|
||||
});
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
private static TradeCardType BuildTradeCard(Shipping shipping, ShippingDocument document, EkaerMappingOptions options)
|
||||
private static TradeCardType BuildTradeCard(Shipping shipping, ShippingDocument document, EkaerCompanyInfo company)
|
||||
{
|
||||
var seller = document.Partner; // a beszállító (feladó)
|
||||
var seller = document.Partner; // a beszállító (feladó) — ICompanyInfoBase
|
||||
|
||||
var tradeCard = new TradeCardType
|
||||
{
|
||||
TradeType = ResolveTradeType(seller, options),
|
||||
ModByCarrierEnabled = false, // mi jelentünk; a fuvarozó alapból nem módosíthatja a bejelentést
|
||||
TradeType = ResolveTradeType(seller),
|
||||
ModByCarrierEnabled = false, // mi jelentünk; a fuvarozó alapból nem módosíthat
|
||||
|
||||
// Feladó / eladó = a beszállító (ShippingDocument.Partner)
|
||||
// Feladó / eladó = a beszállító
|
||||
SellerName = seller?.Name,
|
||||
SellerVatNumber = NormalizeVatNumber(seller?.TaxId),
|
||||
SellerCountry = NormalizeCountryCode(seller?.CountryCode, 2),
|
||||
SellerAddress = BuildAddress(seller),
|
||||
SellerAddress = Truncate(seller?.FullAddress, 200),
|
||||
|
||||
// Címzett = a bejelentő (FruitBank) — bejövő relációban (lásd EKAER_TODO #1)
|
||||
DestinationName = options.DestinationName,
|
||||
DestinationVatNumber = NormalizeVatNumber(options.DestinationVatNumber),
|
||||
DestinationCountry = NormalizeCountryCode(options.DestinationCountryCode, 2),
|
||||
DestinationAddress = options.DestinationAddress,
|
||||
// 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ó (Carrier) nincs, csak szöveges név.
|
||||
// Fuvarozó (Shipping.CargoPartner). Regisztrált EKAER-azonosító nincs, csak szöveges név.
|
||||
CarrierText = shipping.CargoPartner?.Name,
|
||||
|
||||
// Lerakodási hely = saját raktár (konfigból); felrakodás = a beszállító telephelye.
|
||||
UnloadLocation = options.UnloadLocation,
|
||||
// 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), saját rendszámmal/országgal.
|
||||
// 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);
|
||||
|
||||
|
|
@ -73,11 +80,11 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bejövő (beszerzés) reláció: belföldi feladó → <c>D</c> (belföld-belföld), egyébként → <c>I</c> (import,
|
||||
/// közösségből belföldre). Az export (<c>E</c>) jelenleg nincs leképezve (lásd EKAER_TODO #1, #7).
|
||||
/// 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(Partner? seller, EkaerMappingOptions options)
|
||||
=> string.Equals(seller?.CountryCode, options.HomeCountryCode, StringComparison.OrdinalIgnoreCase)
|
||||
private static TradeType ResolveTradeType(ICompanyInfoBase? seller)
|
||||
=> string.Equals(seller?.CountryCode, HomeCountry, StringComparison.OrdinalIgnoreCase)
|
||||
? TradeType.D
|
||||
: TradeType.I;
|
||||
|
||||
|
|
@ -86,10 +93,10 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
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 (MGFBANKPLUG-EKAER-I-T3X8)
|
||||
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.
|
||||
// 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()
|
||||
|
|
@ -99,13 +106,12 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
};
|
||||
|
||||
/// <summary>
|
||||
/// Felrakodási hely a beszállító címéből. (Magyar feladónál a NAV kötelezővé teszi a Phone/Email-t,
|
||||
/// ami a <c>Partner</c> entitásban nincs — lásd EKAER_TODO #6.)
|
||||
/// 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(Partner? seller)
|
||||
private static LocationType? BuildLoadLocation(ICompanyInfoBase? seller)
|
||||
{
|
||||
if (seller == null) return null;
|
||||
|
||||
if (seller is null) return null;
|
||||
return new LocationType
|
||||
{
|
||||
Name = seller.Name,
|
||||
|
|
@ -117,21 +123,11 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>Egybeírt cím (<c>sellerAddress</c>/<c>destinationAddress</c>, max 200): "1234 Budapest Fő utca 1.".</summary>
|
||||
private static string? BuildAddress(PartnerBase? partner)
|
||||
{
|
||||
if (partner == null) return null;
|
||||
|
||||
var parts = new[] { partner.PostalCode, partner.City, partner.Street }.Where(p => !string.IsNullOrWhiteSpace(p));
|
||||
var address = string.Join(" ", parts).Trim(); return Truncate(string.IsNullOrWhiteSpace(address) ? null : address, 200);
|
||||
}
|
||||
|
||||
/// <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 == '-').ToArray());
|
||||
var cleaned = new string([.. value.ToUpperInvariant().Where(c => char.IsAsciiLetterOrDigit(c) || c == '-')]);
|
||||
return Truncate(EmptyToNull(cleaned), 15);
|
||||
}
|
||||
|
||||
|
|
@ -139,16 +135,14 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
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> — a kötőjel/szóköz NEM engedett, ezért eltávolítjuk.</summary>
|
||||
/// <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);
|
||||
}
|
||||
|
|
@ -157,12 +151,12 @@ public sealed class ShippingToEkaerMapper : IShippingToEkaerMapper
|
|||
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 == null ? null : value.Length <= maxLen ? value : value[..maxLen];
|
||||
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.
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using AyCode.Services.Nav.Ekaer;
|
||||
using AyCode.Services.Nav.Ekaer.Models;
|
||||
using FruitBank.Common.Dtos;
|
||||
using FruitBank.Common.Entities;
|
||||
|
|
@ -58,13 +59,14 @@ public sealed class ShippingToEkaerMapperTests
|
|||
return shipping;
|
||||
}
|
||||
|
||||
private static EkaerMappingOptions CreateOptions() => new()
|
||||
private static EkaerCompanyInfo CreateCompany() => new()
|
||||
{
|
||||
DestinationName = "FruitBank Kft",
|
||||
DestinationVatNumber = "98765432-2-41",
|
||||
DestinationCountryCode = "HU",
|
||||
DestinationAddress = "1102 Budapest Raktár utca 5",
|
||||
HomeCountryCode = "HU",
|
||||
Name = "FruitBank Kft",
|
||||
TaxId = "98765432-2-41",
|
||||
CountryCode = "HU",
|
||||
PostalCode = "1102",
|
||||
City = "Budapest",
|
||||
Street = "Raktar utca 5",
|
||||
UnloadLocation = new LocationType
|
||||
{
|
||||
Name = "FruitBank Raktár",
|
||||
|
|
@ -72,7 +74,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
Country = "HU",
|
||||
ZipCode = "1102",
|
||||
City = "Budapest",
|
||||
Street = "Raktár utca",
|
||||
Street = "Raktar utca",
|
||||
StreetNumber = "5",
|
||||
},
|
||||
};
|
||||
|
|
@ -90,7 +92,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
ShippingItems = [],
|
||||
});
|
||||
|
||||
var ops = Mapper.MapShipping(shipping, CreateOptions());
|
||||
var ops = Mapper.MapShipping(shipping, CreateCompany());
|
||||
|
||||
Assert.AreEqual(2, ops.Count, "dokumentumonként egy tradeCard");
|
||||
Assert.AreEqual(1, ops[0].Index);
|
||||
|
|
@ -101,14 +103,14 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_NullDocuments_ReturnsEmpty()
|
||||
{
|
||||
var ops = Mapper.MapShipping(new Shipping { ShippingDocuments = null }, CreateOptions());
|
||||
var ops = Mapper.MapShipping(new Shipping { ShippingDocuments = null }, CreateCompany());
|
||||
Assert.AreEqual(0, ops.Count);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_HonorsExplicitOperation()
|
||||
{
|
||||
var ops = Mapper.MapShipping(CreateShipping(), CreateOptions(), OperationType.Modify);
|
||||
var ops = Mapper.MapShipping(CreateShipping(), CreateCompany(), OperationType.Modify);
|
||||
Assert.AreEqual(OperationType.Modify, ops[0].Operation);
|
||||
}
|
||||
|
||||
|
|
@ -117,15 +119,15 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_DomesticSeller_TradeTypeDomestic()
|
||||
{
|
||||
var ops = Mapper.MapShipping(CreateShipping(sellerCountry: "HU"), CreateOptions());
|
||||
Assert.AreEqual(TradeType.D, ops[0].TradeCard.TradeType, "belföldi feladó → D");
|
||||
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"), CreateOptions());
|
||||
Assert.AreEqual(TradeType.I, ops[0].TradeCard.TradeType, "külföldi feladó → I (import)");
|
||||
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 ----------------------------------------------------
|
||||
|
|
@ -133,7 +135,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_MapsItemFields()
|
||||
{
|
||||
var item = Mapper.MapShipping(CreateShipping(), CreateOptions())[0].TradeCard.Items[0];
|
||||
var item = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard.Items[0];
|
||||
|
||||
Assert.AreEqual("08081010", item.ProductVtsz, "productVtsz = ProductDto.Gtin");
|
||||
Assert.AreEqual("Alma", item.ProductName);
|
||||
|
|
@ -147,29 +149,30 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_MapsSellerFromPartner()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), CreateOptions())[0].TradeCard;
|
||||
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");
|
||||
StringAssert.Contains(tradeCard.SellerAddress, "Budapest", "a sellerAddress a Partner FullAddress-éből jön");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_MapsDestinationAndUnloadFromOptions()
|
||||
public void MapShipping_MapsDestinationAndUnloadFromCompany()
|
||||
{
|
||||
var options = CreateOptions();
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), options)[0].TradeCard;
|
||||
var company = CreateCompany();
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), company)[0].TradeCard;
|
||||
|
||||
Assert.AreEqual("FruitBank Kft", tradeCard.DestinationName);
|
||||
Assert.AreEqual("HU", tradeCard.DestinationCountry);
|
||||
Assert.AreSame(options.UnloadLocation, tradeCard.UnloadLocation, "a lerakodási hely a konfigból jön");
|
||||
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(), CreateOptions())[0].TradeCard;
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(), CreateCompany())[0].TradeCard;
|
||||
Assert.AreEqual("Fuvaros Zrt", tradeCard.CarrierText);
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +181,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_NormalizesLicencePlate_RemovesHyphenAndUppercases()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(plate: "abc-123"), CreateOptions())[0].TradeCard;
|
||||
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);
|
||||
}
|
||||
|
|
@ -186,7 +189,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_WithTrailer_MapsVehicle2()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: true), CreateOptions())[0].TradeCard;
|
||||
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);
|
||||
|
|
@ -195,7 +198,7 @@ public sealed class ShippingToEkaerMapperTests
|
|||
[TestMethod]
|
||||
public void MapShipping_NoTrailer_Vehicle2Null()
|
||||
{
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: false), CreateOptions())[0].TradeCard;
|
||||
var tradeCard = Mapper.MapShipping(CreateShipping(withTrailer: false), CreateCompany())[0].TradeCard;
|
||||
Assert.IsNotNull(tradeCard.Vehicle);
|
||||
Assert.IsNull(tradeCard.Vehicle2, "nincs pótkocsi → nincs vehicle2");
|
||||
}
|
||||
|
|
@ -204,9 +207,9 @@ public sealed class ShippingToEkaerMapperTests
|
|||
|
||||
[TestMethod]
|
||||
public void MapShipping_NullShipping_Throws()
|
||||
=> Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(null!, CreateOptions()));
|
||||
=> Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(null!, CreateCompany()));
|
||||
|
||||
[TestMethod]
|
||||
public void MapShipping_NullOptions_Throws()
|
||||
public void MapShipping_NullCompany_Throws()
|
||||
=> Assert.ThrowsExactly<ArgumentNullException>(() => Mapper.MapShipping(CreateShipping(), null!));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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