491 lines
22 KiB
Markdown
491 lines
22 KiB
Markdown
# HANDEL04 — Relacje i generowanie dokumentów
|
||
|
||
> Wspólne fakty o typie, podstawowe typy i szablon wzorca: [../handel.md](../handel.md).
|
||
|
||
Rozdział opisuje **publiczny tor przekształceń dokumentów handlowych**: generowanie dokumentów
|
||
podrzędnych z nadrzędnych (zamówienie → faktura → dokument magazynowy), wiązanie i rozwiązywanie
|
||
powiązań oraz odczyt łańcucha relacji i stanu pokrycia zamówienia.
|
||
|
||
> **Punkt wejścia — `IRelacjeService`.** Cała logika relacji handlowych jest udostępniona dodatkom
|
||
> zewnętrznym **wyłącznie** przez serwis `Soneta.Handel.RelacjeDokumentow.Api.IRelacjeService`
|
||
> (scope: `Session`). Workery wykonawcze (`PowiazDokumentyWorker`, `UsunPowiazanieDokumentowWorker`,
|
||
> akcje menu „Relacje”) są **internal** — nie instancjonuj ich z dodatku. Pobranie serwisu:
|
||
>
|
||
> ```csharp
|
||
> using Microsoft.Extensions.DependencyInjection; // GetRequiredService
|
||
> using Soneta.Handel.RelacjeDokumentow.Api; // IRelacjeService, HandlerSet
|
||
>
|
||
> var rel = session.GetRequiredService<IRelacjeService>(); // rzuca, gdy serwisu brak
|
||
> // albo: var rel = session.GetService<IRelacjeService>(); // zwraca null, gdy brak
|
||
> ```
|
||
>
|
||
> **Reguły wspólne dla całego rozdziału:**
|
||
> - Dokumenty **nadrzędne muszą być zatwierdzone** (`dok.Stan = StanDokumentuHandlowego.Zatwierdzony`)
|
||
> — z bufora relacja nie powstanie.
|
||
> - Wywołanie metody serwisu (`NowyPodrzedny*`, `Dolacz*`) jest operacją modyfikującą — musi działać
|
||
> **w otwartej transakcji edycyjnej** (`session.Logout(editMode: true)`), a po zamknięciu transakcji
|
||
> zatwierdź zmiany przez `session.Save()`.
|
||
> - Wynik to `DokumentHandlowy[]` — tablica utworzonych/dołączonych dokumentów podrzędnych.
|
||
> - `Context` (zaznaczenie / parametry UI) i `HandlerSet` (callbacki rozstrzygające) są **opcjonalne**.
|
||
> Jeśli definicja relacji wymaga rozstrzygnięcia (np. wyboru dostaw, magazynu, pozycji) i **nie
|
||
> dostarczysz odpowiedniego callbacka**, platforma rzuci `NotImplementedException`.
|
||
|
||
### HandlerSet — callbacki rozstrzygające
|
||
|
||
`HandlerSet` to zbiór delegatów wołanych przez silnik relacji, gdy przekształcenie wymaga decyzji,
|
||
którą w UI podejmuje użytkownik. W trybie programowym (dodatek, test, worker bez UI) musisz je
|
||
dostarczyć sam — inaczej `NotImplementedException`. Najważniejsze:
|
||
|
||
| Callback | Typ | Kiedy potrzebny |
|
||
|---|---|---|
|
||
| `WybierzMagazynCallback` | `Func<Context, Magazyn>` | definicja relacji ma `WyborPozycji = WybórMagazynu` — wskaż magazyn docelowy |
|
||
| `WybierzMagazynDocelowyCallback` | `Func<DokumentDocelowy, Magazyn>` | wybór magazynu dla dokumentu docelowego (domyślnie `d.MagazynDo`) |
|
||
| `WybierzPozycjeCallback` | `Action<DokumentDocelowy>` | definicja ma `WyborPozycji = WybórPozycji` — zaznacz pozycje (domyślnie `PrzeliczPozycje()`) |
|
||
| `WybierzDostawyCallback` | `Action<DostawaWorker>` | wskazanie partii/dostaw przy rozchodzie (gdy `WskazaniePartii` wymuszone) |
|
||
| `WybierzDokumentyZaliczkoweCallback` | `Action<DokumentDocelowy>` | faktura z zaliczkami |
|
||
| `UstawParametryFakturowania` | `Action<DefRelacjiCyklicznaFakturowanieParams>` | fakturowanie cykliczne |
|
||
|
||
Domyślnie `WybierzPozycjeCallback` przepisuje wszystkie pozycje (`PrzeliczPozycje()`). Callbacki bez
|
||
sensownej wartości domyślnej (`WybierzMagazynCallback`, `WybierzDostawyCallback`,
|
||
`WybierzDokumentyZaliczkoweCallback`) rzucają `NotImplementedException`, dopóki ich nie nadpiszesz.
|
||
|
||
---
|
||
|
||
### HANDEL-W17 — Generowanie faktury z zamówienia (ZO → FV)
|
||
|
||
**Cel:** z zatwierdzonego zamówienia (odbiorcy `ZO` lub do dostawcy `ZD`) wygenerować pojedynczy
|
||
dokument podrzędny o wskazanym symbolu (np. fakturę `FV`). Relacja **jeden nadrzędny → jeden
|
||
podrzędny** (indywidualna).
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Wejście | Symbol podrzędnego | Uwaga |
|
||
|---|---|---|---|
|
||
| ZO → FV | jedno zamówienie odbiorcy | `"FV"` | klasyczna realizacja sprzedaży |
|
||
| ZD → ZK (FZ) | zamówienie do dostawcy | `"ZK"` / `"FZ"` | zakup; może wymagać `WybierzMagazynCallback` |
|
||
| FA → WZ pojedynczo | jedna faktura | `"WZ"` | wydanie magazynowe do faktury (patrz HANDEL-W21) |
|
||
| Wszystkie pozycje | bez `HandlerSet` lub `WybierzPozycjeCallback` = przepisz wszystko | — | gdy definicja relacji ma `BrakOkna` |
|
||
| Wybrane pozycje | `WybierzPozycjeCallback` zaznacza podzbiór | — | gdy definicja ma `WybórPozycji` |
|
||
|
||
**Pola i typy:**
|
||
`IRelacjeService.NowyPodrzednyIndywidualny(DokumentHandlowy[] nadrzedne, string symbolPodrzednego,
|
||
Context context = null, HandlerSet handlers = null) → DokumentHandlowy[]`.
|
||
Wynik ma `Length == nadrzedne.Length` (każdy nadrzędny dostaje własny podrzędny).
|
||
Pozycja podrzędnego: `poz.Dostawa` (wskazana partia/dostawa, gdy dotyczy).
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Soneta.Handel;
|
||
using Soneta.Handel.RelacjeDokumentow.Api;
|
||
|
||
var rel = session.GetRequiredService<IRelacjeService>();
|
||
|
||
// zamowienie jest już zatwierdzone (StanDokumentuHandlowego.Zatwierdzony)
|
||
DokumentHandlowy[] faktury;
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
faktury = rel.NowyPodrzednyIndywidualny(
|
||
new[] { zamowienie },
|
||
"FV"); // bez HandlerSet — gdy relacja nie wymaga rozstrzygnięć
|
||
t.Commit(); // CommitUI() w workerze/extenderze
|
||
}
|
||
session.Save();
|
||
|
||
DokumentHandlowy faktura = faktury[0]; // jeden nadrzędny → jeden podrzędny
|
||
```
|
||
|
||
Wariant z wyborem pozycji (przepisz tylko pozycje danego towaru):
|
||
|
||
```csharp
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
var wynik = rel.NowyPodrzednyIndywidualny(
|
||
new[] { zamowienie }, "FV",
|
||
handlers: new HandlerSet
|
||
{
|
||
WybierzPozycjeCallback = docelowy =>
|
||
{
|
||
// docelowy: DokumentDocelowy — zaznacz pozycje do przeniesienia
|
||
docelowy.PrzeliczPozycje(); // domyślnie: wszystkie
|
||
}
|
||
});
|
||
t.Commit();
|
||
}
|
||
session.Save();
|
||
```
|
||
|
||
**Pułapki:**
|
||
- Dokument nadrzędny **musi być zatwierdzony** — z bufora `NowyPodrzedny*` nie zadziała.
|
||
- Gdy definicja relacji wymaga rozstrzygnięcia (magazyn, dostawy, pozycje), a `HandlerSet` go nie
|
||
dostarcza → `NotImplementedException`. Zacznij od wywołania bez `HandlerSet`; jeśli rzuca, dodaj
|
||
konkretny callback (patrz tabela powyżej).
|
||
- Symbol podrzędnego musi odpowiadać **istniejącej definicji relacji** wychodzącej z definicji
|
||
nadrzędnego (konfiguracja `DefRelacji` na `DefDokHandlowego`). Brak pasującej relacji → pusty wynik
|
||
lub wyjątek.
|
||
- Cała operacja w **jednej** transakcji + `Save()`. Mieszane sesje rekordów → użyj `session.Get(...)`.
|
||
|
||
---
|
||
|
||
### HANDEL-W18 — Zbiorczy dokument magazynowy z wielu faktur (wiele FA → 1 WZ/PZ)
|
||
|
||
**Cel:** z wielu zatwierdzonych faktur utworzyć **jeden** zbiorczy dokument podrzędny (np. jeden
|
||
dokument magazynowy `WZ`/`PZ` zbierający pozycje wszystkich faktur). Relacja **wiele nadrzędnych →
|
||
jeden podrzędny** (zbiorcza).
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Wejście | Symbol | Wynik |
|
||
|---|---|---|---|
|
||
| Wiele FA → 1 WZ | tablica faktur sprzedaży | `"WZ"` | 1 wydanie zbiorcze |
|
||
| Wiele FZ → 1 PZ | tablica faktur zakupu | `"PZ"` | 1 przyjęcie zbiorcze |
|
||
| Wiele ZO → 1 FV | zbiorcza faktura z zamówień | `"FV"` | 1 faktura zbiorcza |
|
||
|
||
**Pola i typy:**
|
||
`IRelacjeService.NowyPodrzednyZbiorczy(DokumentHandlowy[] nadrzedne, string symbolPodrzednego,
|
||
Context context = null, HandlerSet handlers = null) → DokumentHandlowy[]`.
|
||
W przeciwieństwie do HANDEL-W17 zwraca zwykle tablicę **jednoelementową** (jeden dokument zbiorczy).
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
var rel = session.GetRequiredService<IRelacjeService>();
|
||
|
||
// faktury: DokumentHandlowy[] — wszystkie zatwierdzone, zgodne (ten sam kontrahent/magazyn wg konfiguracji)
|
||
DokumentHandlowy wz;
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
var wynik = rel.NowyPodrzednyZbiorczy(faktury, "WZ");
|
||
wz = wynik[0]; // jeden zbiorczy dokument magazynowy
|
||
t.Commit();
|
||
}
|
||
session.Save();
|
||
```
|
||
|
||
**Pułapki:**
|
||
- Dokumenty zbiorcze powstają tylko z dokumentów **zgodnych** (wymóg ten sam kontrahent / magazyn /
|
||
waluta — zależnie od definicji relacji zbiorczej). Niezgodne wejście → wyjątek lub pominięcie.
|
||
- Wszystkie nadrzędne muszą być **zatwierdzone**.
|
||
- Tak jak w HANDEL-W17 — brak wymaganego callbacka w `HandlerSet` → `NotImplementedException`.
|
||
- Nie zakładaj `Length == nadrzedne.Length` — tu wynik jest **agregatem** (zwykle 1 dokument).
|
||
|
||
---
|
||
|
||
### HANDEL-W19 — Zbiorcza faktura z wielu dokumentów magazynowych (wiele WZ → 1 FA)
|
||
|
||
**Cel:** „odwrotny” kierunek HANDEL-W18 — z wielu zatwierdzonych dokumentów magazynowych (np. `WZ`)
|
||
utworzyć **jedną** zbiorczą fakturę sprzedaży.
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Wejście | Symbol | Uwaga |
|
||
|---|---|---|---|
|
||
| Wiele WZ → 1 FV | wydania magazynowe | `"FV"` | fakturowanie zbiorcze rozchodów |
|
||
| Wiele PZ → 1 FZ | przyjęcia magazynowe | `"FZ"` | zbiorczy zakup |
|
||
|
||
**Pola i typy:** ta sama metoda `NowyPodrzednyZbiorczy(...)` co w HANDEL-W18 — różni się tylko kierunkiem
|
||
(nadrzędne = dokumenty magazynowe, symbol podrzędnego = faktura).
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
var rel = session.GetRequiredService<IRelacjeService>();
|
||
|
||
// wydania: DokumentHandlowy[] — zatwierdzone WZ tego samego kontrahenta
|
||
DokumentHandlowy fakturaZbiorcza;
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
fakturaZbiorcza = rel.NowyPodrzednyZbiorczy(wydania, "FV")[0];
|
||
t.Commit();
|
||
}
|
||
session.Save();
|
||
```
|
||
|
||
**Pułapki:**
|
||
- Kierunek relacji (magazynowy → handlowy) musi być skonfigurowany jako `DefRelacji` na definicji
|
||
dokumentu magazynowego. Brak relacji → pusty wynik.
|
||
- Dokumenty magazynowe muszą być **zatwierdzone** i zgodne (kontrahent / waluta).
|
||
- Walidator stanu ujemnego nie dotyczy tej operacji (rozchód już się dokonał na WZ), ale faktura
|
||
przejmie wartości z dokumentów źródłowych — nie modyfikuj pozycji ręcznie po przekształceniu, jeśli
|
||
ma zachować zgodność z magazynem.
|
||
|
||
---
|
||
|
||
### HANDEL-W20 — Wyszukiwanie dokumentów powiązanych (odczyt pól kalkulowanych)
|
||
|
||
**Cel:** odczytać dokumenty powiązane bez ręcznego przeszukiwania relacji — przez pola kalkulowane na
|
||
`DokumentHandlowy`. Działa w obie strony: dla faktury → jej dokumenty magazynowe, dla magazynowego →
|
||
jego faktury.
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Pole kalkulowane | Typ | Zwraca |
|
||
|---|---|---|---|
|
||
| Magazynowe dla faktury | `dok.DokumentyMagazynowe` | `DokumentHandlowy[]` | WZ/PZ powiązane z fakturą |
|
||
| Główny dok. magazynowy | `dok.DokumentMagazynowyGłówny` | `DokumentHandlowy` | pierwszy/główny magazynowy |
|
||
| Faktury dla magazynowego | `dok.DokumentyHandlowe` | `DokumentHandlowy[]` | faktury powiązane z WZ/PZ/ZO/ofertą |
|
||
|
||
**Pola i typy:** wszystkie trzy to **właściwości kalkulowane (read-only)** na `DokumentHandlowy`.
|
||
`DokumentyMagazynowe` dla dokumentu, który **sam jest magazynowy** (`TypPartii.Magazynowy` itd.),
|
||
zwraca `{ this }`. Analogicznie `DokumentyHandlowe` dla samego dokumentu handlowego zwraca `{ this }`.
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
// 1. Dla faktury — jej dokumenty magazynowe (wydania/przyjęcia)
|
||
foreach (DokumentHandlowy mag in faktura.DokumentyMagazynowe)
|
||
{
|
||
// mag.Numer, mag.Magazyn, mag.Pozycje ...
|
||
}
|
||
|
||
// główny dokument magazynowy (gdy potrzebny jeden)
|
||
DokumentHandlowy glowny = faktura.DokumentMagazynowyGłówny;
|
||
|
||
// 2. Dla dokumentu magazynowego — faktury, które go „obsługują”
|
||
foreach (DokumentHandlowy fa in wz.DokumentyHandlowe)
|
||
{
|
||
// fa.Numer, fa.Suma ...
|
||
}
|
||
```
|
||
|
||
**Pułapki:**
|
||
- To pola **kalkulowane** — czytaj, nie ustawiaj. Każde odwołanie uruchamia wyszukiwanie po relacjach,
|
||
więc **nie wołaj ich w pętli** dla tysięcy rekordów — buforuj wynik w zmiennej lokalnej.
|
||
- Zwracają **tablicę** (może być pusta), nie `null` — bezpiecznie iterować, ale sprawdzaj `.Length`
|
||
przed `[0]`.
|
||
- Pola respektują **prawa dostępu** — dokumenty bez prawa odczytu są pomijane (wynik może być węższy
|
||
niż faktyczny łańcuch relacji).
|
||
|
||
---
|
||
|
||
### HANDEL-W21 — Generowanie dokumentu magazynowego z faktury (FA → WZ pojedynczo)
|
||
|
||
**Cel:** do pojedynczej zatwierdzonej faktury wygenerować odpowiadający dokument magazynowy
|
||
(np. wydanie `WZ`). To wariant indywidualny (HANDEL-W17), tylko z innym symbolem docelowym.
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Wejście | Symbol | Uwaga |
|
||
|---|---|---|---|
|
||
| FV → WZ | faktura sprzedaży | `"WZ"` | wydanie z magazynu |
|
||
| FZ → PZ | faktura zakupu | `"PZ"` | przyjęcie do magazynu |
|
||
| Z wyborem partii | + `WybierzDostawyCallback` | — | gdy `WskazaniePartii` wymuszone na definicji WZ |
|
||
|
||
**Pola i typy:** `IRelacjeService.NowyPodrzednyIndywidualny(...)` — jak HANDEL-W17. Pozycje magazynowe mają
|
||
`poz.Dostawa` (wskazana partia/dostawa).
|
||
|
||
**Snippet (z wyborem partii — wymusza `HandlerSet`):**
|
||
|
||
```csharp
|
||
using Soneta.Magazyny;
|
||
|
||
var rel = session.GetRequiredService<IRelacjeService>();
|
||
|
||
DokumentHandlowy wz;
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
var wynik = rel.NowyPodrzednyIndywidualny(
|
||
new[] { faktura }, "WZ",
|
||
handlers: new HandlerSet
|
||
{
|
||
WybierzDostawyCallback = dostawaWorker =>
|
||
{
|
||
// dla każdej pozycji wskaż pobierane zasoby/partie
|
||
foreach (var poz in dostawaWorker.GetListPozycja())
|
||
{
|
||
dostawaWorker.Pozycja = poz;
|
||
foreach (Zasob z in dostawaWorker.Zasoby.Cast<Zasob>())
|
||
{
|
||
using var tz = z.Session.Logout(editMode: true);
|
||
// ... oznacz zasób jako pobrany (Pobrano = true)
|
||
tz.Commit();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
wz = wynik[0];
|
||
t.Commit();
|
||
}
|
||
session.Save();
|
||
```
|
||
|
||
**Pułapki:**
|
||
- Gdy definicja `WZ` ma `WskazaniePartii = WymuszonyDodawanie`, **musisz** dostarczyć
|
||
`WybierzDostawyCallback` — inaczej `NotImplementedException`.
|
||
- Rozchód wymaga wcześniejszego **zapisanego** przyjęcia towaru (`StanUjemnyVerifier` w Demo). Magazyn
|
||
księguje się dopiero po `Session.Save()` — samo `Commit`/`CommitUI` nie tworzy obrotów/zasobów.
|
||
- Po wygenerowaniu WZ odczytaj go zwrotnie przez `faktura.DokumentyMagazynowe` (HANDEL-W20).
|
||
|
||
---
|
||
|
||
### HANDEL-W22 — Kopiowanie faktury klientowi (`KopiujKlientowiFaktureWorker`)
|
||
|
||
**Cel:** skopiować zatwierdzone faktury sprzedaży klienta jako dokumenty zakupu **do bazy klienta**
|
||
(scenariusz biura rachunkowego pracującego na wielu bazach). Worker **publiczny**.
|
||
|
||
**Dostępność:** `Soneta.EI.KopiujKlientowiFaktureWorker` jest **public** (rejestracja
|
||
`[assembly: Worker(typeof(KopiujKlientowiFaktureWorker), typeof(DokHandlowe))]`). Akcja menu
|
||
„Kopiuj klientowi...”. **Widoczna tylko** gdy bieżąca baza jest *master* w konfiguracji „Praca na
|
||
wielu bazach” **i** licencja to `Biuro Rachunkowe` (`IsVisibleKopiuj`). Bez tej konfiguracji
|
||
nie zadziała (nie znajdzie bazy klienta).
|
||
|
||
**Pola i typy:**
|
||
- `[Context] DokumentHandlowy[] Dokumenty` — kopiowane faktury (brane są tylko `Zatwierdzony`).
|
||
- `[Context] Params Prms` — parametry; `Params : ContextBase`:
|
||
- `DefinicjaDokumentu Definicja` — definicja dokumentu zakupu w bazie klienta (lista z
|
||
`DefDokumentow.WgTypu[TypDokumentu.ZakupEwidencja]`);
|
||
- `bool PrzygotujPrzelewy` (domyślnie `true`) — czy generować przelewy dla zobowiązań.
|
||
- `object Kopiuj()` — akcja `[Action("Kopiuj klientowi...", Mode = SingleSession | Progress)]`;
|
||
zwraca komunikat tekstowy, szczegóły pisze do logu.
|
||
|
||
**Snippet (programowe użycie workera z `Params`):**
|
||
|
||
```csharp
|
||
using Soneta.EI;
|
||
|
||
// dokumenty: zaznaczone faktury sprzedaży (worker bierze tylko zatwierdzone)
|
||
var prms = new KopiujKlientowiFaktureWorker.Params(context)
|
||
{
|
||
Definicja = /* DefinicjaDokumentu zakupu */,
|
||
PrzygotujPrzelewy = true,
|
||
};
|
||
|
||
var worker = new KopiujKlientowiFaktureWorker
|
||
{
|
||
Dokumenty = dokumenty,
|
||
Prms = prms,
|
||
};
|
||
|
||
object komunikat = worker.Kopiuj(); // tworzy dokumenty w bazie klienta; Save robi worker wewnętrznie
|
||
```
|
||
|
||
**Pułapki:**
|
||
- Worker działa **na wielu bazach** (`DBItemContext`) — sam otwiera/zamyka transakcje i `Save()`
|
||
w bazie klienta. Nie opakowuj wywołania w zewnętrzną transakcję na bazie master.
|
||
- Kopiowane są **tylko faktury zatwierdzone**; dokumenty z zobowiązaniem (nie należnością) są
|
||
**pomijane** (zakup wymaga należności po stronie sprzedaży).
|
||
- W bazie klienta tworzony jest automatycznie kontrahent „biuro” (wg NIP z pieczątki firmy), jeśli go
|
||
brak. Brakujący sposób zapłaty w bazie klienta → dokument pominięty (log).
|
||
- Wymaga licencji `Biuro Rachunkowe` i roli master — w innym układzie akcja jest niewidoczna.
|
||
- Do zwykłego „kopiuj dokument w tej samej bazie” ten worker **nie służy** — to specjalizowany scenariusz
|
||
wielobazowy.
|
||
|
||
---
|
||
|
||
### HANDEL-W23 — Ręczne wiązanie i rozwiązywanie powiązań
|
||
|
||
**Cel:** **dołączyć** istniejący dokument do innego jako podrzędny/nadrzędny (bez generowania nowego)
|
||
oraz rozwiązać błędnie utworzone powiązanie. Tor publiczny = `IRelacjeService.Dolacz*`.
|
||
|
||
> **Uwaga o dostępności:** workery wykonawcze `PowiazDokumentyWorker` i
|
||
> `UsunPowiazanieDokumentowWorker` są **internal** — nie używaj ich z dodatku. Wiązanie realizuj przez
|
||
> `IRelacjeService.DolaczPodrzednyIndywidualny` / `DolaczNadrzedny`. **Programowego, publicznego API do
|
||
> *rozwiązywania* powiązań brak** — rozwiązywanie powiązań jest dostępne tylko interaktywnie (menu
|
||
> „Relacje” w aplikacji), bo odpowiedni worker jest internal. To ograniczenie publicznego kontraktu.
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Metoda | `relationName` |
|
||
|---|---|---|
|
||
| Dołącz podrzędny do nadrzędnego | `DolaczPodrzednyIndywidualny(documents, relationName)` | nazwa definicji relacji wychodzącej (np. `"Faktura"`) |
|
||
| Dołącz dokument do nadrzędnego | `DolaczNadrzedny(documents, relationName)` | nazwa relacji od strony nadrzędnego (np. `"Zamówienie"`) |
|
||
| Rozwiązanie powiązania | — | **tylko interaktywnie** (worker internal) |
|
||
|
||
**Pola i typy:**
|
||
```csharp
|
||
DokumentHandlowy[] DolaczPodrzednyIndywidualny(
|
||
DokumentHandlowy[] documents, string relationName,
|
||
Context context = null, HandlerSet handlers = null);
|
||
DokumentHandlowy[] DolaczNadrzedny(
|
||
DokumentHandlowy[] documents, string relationName,
|
||
Context context = null, HandlerSet handlers = null);
|
||
```
|
||
`relationName` to **nazwa definicji relacji** (`DefRelacji`), nie symbol dokumentu — np. `"Zamówienie"`,
|
||
`"Faktura"`, `"Korekta wydania magazynowego 2"`.
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
var rel = session.GetRequiredService<IRelacjeService>();
|
||
|
||
// Dołącz fakturę do istniejącego zamówienia jako nadrzędnego (relacja "Zamówienie")
|
||
using (var t = session.Logout(editMode: true))
|
||
{
|
||
var powiazane = rel.DolaczNadrzedny(new[] { faktura }, "Zamówienie");
|
||
t.Commit();
|
||
}
|
||
session.Save();
|
||
```
|
||
|
||
**Pułapki:**
|
||
- `relationName` musi dokładnie pasować do **nazwy `DefRelacji`** skonfigurowanej w bazie (wielkość
|
||
liter / spacje istotne) — niepasująca nazwa daje pusty/`null` wynik w tablicy.
|
||
- `Dolacz*` przetwarza dokumenty **pojedynczo** (`Array.ConvertAll`) — wynik na pozycji `i` może być
|
||
`null`, jeśli dołączenie konkretnego dokumentu się nie powiodło. Sprawdzaj elementy wyniku.
|
||
- Dokumenty muszą być **zatwierdzone** i wzajemnie zgodne (kontrahent / pozycje).
|
||
- **Rozwiązywanie** powiązań programowo z dodatku **niedostępne** — zaplanuj operację jako działanie
|
||
użytkownika w aplikacji (menu „Relacje”).
|
||
|
||
---
|
||
|
||
### HANDEL-W24 — Odczyt łańcucha powiązań i stan pokrycia zamówienia
|
||
|
||
**Cel:** prześledzić łańcuch relacji (oferta → zamówienie → faktura → dokument magazynowy) oraz
|
||
odczytać **stan pokrycia/realizacji zamówienia** (czy zamówienie zostało zrealizowane fakturami).
|
||
|
||
**Warianty:**
|
||
|
||
| Wariant | Mechanizm | Typ wyniku |
|
||
|---|---|---|
|
||
| W górę łańcucha (faktury dla magazynowego/zamówienia) | `dok.DokumentyHandlowe` (HANDEL-W20) | `DokumentHandlowy[]` |
|
||
| W dół łańcucha (magazynowe dla faktury) | `dok.DokumentyMagazynowe` (HANDEL-W20) | `DokumentHandlowy[]` |
|
||
| Stan pokrycia zamówienia (odczyt) | `StanPokryciaZamówieniaWorker.StanPokrycia` | enum `StanPokryciaZamówienia` |
|
||
|
||
**Pola i typy:**
|
||
- Odczyt stanu pokrycia: worker **public** `Soneta.Handel.StanPokryciaZamówieniaWorker`
|
||
(`[Context] DokumentHandlowy Dokument`) → property `StanPokrycia : StanPokryciaZamówienia`.
|
||
- Enum `Soneta.Handel.StanPokryciaZamówienia`: `Brak = 0`, `Częściowe = 1`, `Pełne = 2`,
|
||
`NiePodlega = 3`, `Niezweryfikowane = 4`.
|
||
- **Ważne:** worker tylko **odczytuje** wcześniej wyliczony stan (z cache na `Login`). Samo
|
||
przeliczenie uruchamia akcja menu „Sprawdź pokrycie” (`StanPokryciaZamowienWorker`, `[HandelAction]`)
|
||
— wywołuje ją użytkownik; dopóki nie zostanie odpalona, `StanPokrycia` zwraca `Niezweryfikowane`.
|
||
|
||
**Snippet:**
|
||
|
||
```csharp
|
||
using Soneta.Handel;
|
||
|
||
// Odczyt stanu pokrycia pojedynczego zamówienia (po wcześniejszym „Sprawdź pokrycie”):
|
||
var w = new StanPokryciaZamówieniaWorker { Dokument = zamowienie };
|
||
StanPokryciaZamówienia stan = w.StanPokrycia;
|
||
|
||
bool zrealizowane = stan == StanPokryciaZamówienia.Pełne;
|
||
|
||
// Łańcuch relacji w dół: zamówienie -> faktury -> ich dokumenty magazynowe
|
||
foreach (DokumentHandlowy fa in zamowienie.DokumentyHandlowe) // faktury zamówienia
|
||
foreach (DokumentHandlowy mag in fa.DokumentyMagazynowe) // wydania faktury
|
||
{
|
||
// mag.Numer, mag.Magazyn ...
|
||
}
|
||
```
|
||
|
||
**Pułapki:**
|
||
- `StanPokryciaZamówieniaWorker.StanPokrycia` zwraca `Niezweryfikowane`, dopóki w sesji/loginie nie
|
||
wykonano przeliczenia (akcja „Sprawdź pokrycie”). **Programowego, publicznego wyzwalacza
|
||
przeliczenia brak** — `StanPokryciaZamówień.Przelicz()` jest wywoływane przez internal akcję menu.
|
||
Z dodatku traktuj `StanPokrycia` jako **odczyt** stanu policzonego interaktywnie.
|
||
- Pola `DokumentyHandlowe`/`DokumentyMagazynowe` respektują prawa dostępu i są kalkulowane — buforuj
|
||
wynik, nie wołaj w gęstych pętlach (HANDEL-W20).
|
||
- Stan `NiePodlega` oznacza dokument, którego pokrycie nie dotyczy (np. nie jest zamówieniem) —
|
||
rozróżniaj go od `Brak` (zamówienie bez realizacji).
|
||
|
||
---
|
||
|
||
> **Powiązane sekcje:** tworzenie/stan dokumentu (sekcja 1–2), korekty (`IRelacjeService.NowaKorekta`,
|
||
> `NowaKorektaZbiorcza` — analogiczne do HANDEL-W17/HANDEL-W18, symbol korekty opcjonalny), magazyn i partie
|
||
> (`dok.Zasoby`, `dok.Obroty`, `GrupaDostaw`).
|
||
|
||
---
|
||
|