diff --git a/docs/adr/0001-non-measurable-item-derived-weight.md b/docs/adr/0001-non-measurable-item-derived-weight.md new file mode 100644 index 00000000..6343b913 --- /dev/null +++ b/docs/adr/0001-non-measurable-item-derived-weight.md @@ -0,0 +1,47 @@ +# ADR 0001: Nem mérendő tétel súlya — derivált pallet-mérés a termék átlagsúlyából és tárájából + +## Status + +Proposed (2026-07-14) + +## Context + +- **Kiváltó:** az EKÁER kimenő bejelentésnél a `tradeCard.weight` nem mérendő tételnél 0, mert a nem mérendő pallet súlyai 0-k (domain #4). A NAV pozitív bruttót vár → **alul-jelentés**. +- Az `OrderItemDto.GrossWeight` copy-paste bug (nettót summázott) 2026-07-ben javítva, de a valódi hiány marad: **nem mérendő tételnek nincs súlya sehol**. +- **Időzítés:** most, mert az EKÁER kimenő beküldés élesedik (sandbox-auth után), és éles kimenő bejelentés helytelen súllyal menne ki. A kolléga a per-termék rekesz-`AverageWeight` megadását épp készíti — az adat-oldal adott lesz. +- **Scope IN:** a mérési súly-modell nem mérendő tételre (`OrderItemPallet` + a közös `MeasuringItemPalletBase` validáció); a kimenő mérés UI (tára/rekesz). **Scope OUT:** a per-termék `AverageWeight` felvitel (kolléga); a bejövő/leltár ág konkrét migrációja (követő döntés). + +## Decision + +A nem mérendő tétel is **teljes értékű, perzisztált pallet-mérést** kap: a kimenő mérésnél a **rekeszszám** (megvan) + **tára** (a productból default, a textbox `Visible=true`) + opcionális raklap alapján a pallet súlyai kiszámolódnak és **beíródnak** a palletbe — `NetWeight = ProductDto.AverageWeight (rekeszenkénti nettó) × rekeszszám`, `GrossWeight = Net + rekesz×tára + raklap`. Az `IsMeasurable` jelentése ezzel **„a súly forrása"** (kézi mérés vs. termék-átlagból derivált), nem „van-e súly". + +## Consequences + +**Positive:** +- A kimenő EKÁER-súly nem mérendő tételnél is valós (nem 0) → NAV-megfelelőség. +- A pallet marad az **egyetlen igazságforrás** (audit): a súly fizikailag benne van, nem számított nézet. +- Az `IsValidMeasuringValues` `!isMeasurable`-ága **kivehető** → a sok `IsMeasurable`-elágazás egységesül (a súly-validáció alakja azonos mindkét ágon). + +**Negative / kockázat (a három csapda):** +- **Közös bázis:** az `IsValidMeasuringValues(bool)` a `MeasuringItemPalletBase`-ben van → Shipping + StockTaking is hívja. `StockTakingDbContext:151` **dob** (`throw`), `FruitBankDbContext:245` gátol nem mérendő 0-súlyú palleten. A módosítás mindhárom hierarchiát érinti, nem csak az Order-ágat. +- **Visszamenőleges adat:** a régi, súly=0-s nem mérendő palletek egy egységesített szabály alatt „érvénytelenné" válnak → `SetOrderDtoToComplete` (`FruitBankDbContext:525`) + a „kész" színezés/összegzők visszaesnek a régi rendeléseknél. +- **Gomb-időzítés:** a mentés-gomb a memóriabeli palleten validál mentés ELŐTT (`PalletItemComponent:100`, `MeasuringIn.razor.cs:163`) → a derivált súlyt **élőben, kliens-oldalon** kell számolni (rekesz/tára beírásakor), nem mentéskor, különben a gomb sosem aktiválódik. + +**Follow-ups required:** +- Kolléga: per-termék `AverageWeight` (rekeszenkénti nettó) felvitel. +- **Nyitott döntés:** mindhárom ág egységesítése vs. `OrderItemPallet`-override (Csapda 1) — lásd az A' alternatívát. +- **Migrációs stratégia** a régi 0-súlyú nem mérendő palletekre (Csapda 2). +- Kimenő mérés UI: tára-textbox `Visible=true` + élő súly-számítás (Csapda 3). +- Doksi: `FruitBank.Common/docs/GLOSSARY.md` + `OrderItemPallet` ToonDescription („weights = 0.0" invariáns → derivált súly), plugin `docs/MEASUREMENT.md`. + +## Alternatives considered + +- **B — Read-time deriváció** (elvetve): a súlyt ne perzisztáld, hanem az `OrderItemDto.GrossWeight`/`NetWeight` getterben deriváld (nem mérendő → `AvgWeight × rekesz`), a pallet marad 0. + - *Reversibility:* olcsóbb (2 getter, `IsMeasurable`-guard), **nincs migráció, egyik csapda sem nyílik ki**. + - *Cons:* a pallet NEM igazságforrás (számított nézet), nincs tára/raklap-bontás, nem „egységes" — ezért elvetve az egységesség-cél (single source of truth) miatt. +- **A' — Order-only override** (nyitott implementációs fork, nem elvetett): csak `OrderItemPallet.IsValidMeasuringValues` override-ol, a bázis marad → Csapda 1 elkerülve, de a nem mérendő szemantika ágakonként eltér (az „egységes" cél sérül). Az implementációkor eldöntendő A (teljes egységesítés) vs. A'. + +## Related + +- **Related TODOs/Issues:** `MGFBANKPLUG-EKAER` K7Q2 **#7** (kimenő irány — a kimenő súly `OrderItemDto.GrossWeight`); az `OrderItemDto.GrossWeight` bug-fix (2026-07, pre-flight — nettó→bruttó summázás). +- **Related docs:** plugin `docs/MEASUREMENT.md`, `docs/EKAER/README.md`, `FruitBank.Common/docs/GLOSSARY.md`. diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 00000000..5e4f2e98 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,11 @@ +# Architecture Decision Records (ADR) + +Architektúra-szintű döntések durable rekordjai (Nygard-stílus): egy fájl = egy döntés, `NNNN-.md` néven. Minden ADR: kontextus → döntés → következmények → alternatívák. A `Status` a Nygard 4-értékű szótár: `Proposed` / `Accepted` / `Superseded by ADR-XXXX` / `Rejected` (ez KÜLÖN a `_ISSUES.md`/`_TODO.md` 3-értékű `Open`/`InProgress`/`Closed` szótárától). + +> Formátum + folyamat: `adr-author` skill (AyCode.Core `.github/skills/adr-author/`), sablon: `references/ADR_TEMPLATE.md`. + +## Index + +| ADR | Cím | Status | +|---|---|---| +| [0001](0001-non-measurable-item-derived-weight.md) | Nem mérendő tétel súlya — derivált pallet-mérés a termék átlagsúlyából és tárájából | Proposed (2026-07-14) |