18 KiB
HANDEL12 — Wydruki i raporty
Wspólne fakty o typie, podstawowe typy i szablon wzorca: ../handel.md.
Wydruk dokumentu handlowego (faktura, dokument magazynowy, paragon) oraz raporty
i zestawienia tworzy się przez serwis IReportService z modułu Soneta.Business.UI.
Serwis bierze wzorzec wydruku (*.repx / *.aspx / *.dotx), kontekst z danymi
(rekord, zaznaczenie, parametry) i zwraca gotowy dokument jako strumień (Stream) —
bez udziału interfejsu użytkownika. To jest jedyny mechanizm, którego dodatek zewnętrzny
powinien używać do programowego generowania wydruków (export do PDF, wysyłka e-mail,
archiwizacja). Klasa ReportResult opisuje co i jak wydrukować.
Dostęp do serwisu (publiczny kontrakt):
using Microsoft.Extensions.DependencyInjection; // GetRequiredService using Soneta.Business.UI; // IReportService, ReportResult, ReportFormats, ReportTargets var raporty = session.GetRequiredService<IReportService>();
Metody IReportService (publiczne):
| Metoda | Zwraca | Zastosowanie |
|---|---|---|
Stream GenerateReport(ReportResult rr) |
strumień (PDF/XLSX/PNG/…) | generowanie wydruku binarnego do strumienia/pliku/e-maila |
string GenerateReportStr(ReportResult rr) |
string | wydruk tekstowy (HTML, TXT) |
void PrintReport(ReportResult rr, bool archive = false, string archivePath = "") |
— | wydruk na drukarkę (sprzęt), opcjonalna archiwizacja na dysk |
Type[] GetParameterTypes(string templateFileName, Context context) |
typy parametrów | sprawdzenie, jakich obiektów parametrów wymaga wzorzec |
Pola ReportResult (publiczne, najważniejsze):
| Pole | Typ | Znaczenie |
|---|---|---|
TemplateFileName |
string |
nazwa wzorca (np. "Sprzedaz.repx", "Zakup.repx"). Ustawienie go włącza tryb automatyczny (bez UI). |
DataType |
Type |
typ danych branych z kontekstu: typeof(DokumentHandlowy) (jeden), typeof(DokumentHandlowy[]) (zaznaczone), typeof(DokHandlowe) (cały widok). |
Context |
Context |
kontekst z rekordem(-ami) i parametrami wydruku (Context.Set(...)). |
OutputFormat |
ReportFormats |
PDF, XLSX, XLS, CSV, DOCX, TXT, HTML, MHT, PNG. Domyślnie HTML. |
Target |
ReportTargets |
cel: File, Printer, PrinterService, Preview, Attachment, Email, ShareDocument, OpenApplication. Domyślnie File. |
AskForParameters |
bool |
false = brak okien z pytaniem o parametry (tryb wsadowy). |
PrinterName |
string |
nazwa drukarki dla Target = Printer. |
Encrypt |
string |
hasło szyfrujące PDF. |
Sign, VisibleSignature |
bool |
podpis certyfikatem (tylko tryb interaktywny okienkowy). |
OutputHandler |
Func<Stream,object> |
własna obsługa gotowego strumienia (tryb wzorca; nieobsługiwane przez IReportService — patrz HANDEL-W66). |
ReportName |
string |
nazwa wydruku z menu (tryb interaktywny; wyklucza się z TemplateFileName/IReportService). |
Reguła spójności (
CheckConsistency):IReportServicewymaga ustawionegoTemplateFileNamei nie akceptujeOutputHandleraniReportName.ReportNameiTemplateFileNamewzajemnie się wykluczają. Naruszenie →ArgumentException.
HANDEL-W62 — Wydruk faktury do PDF / na drukarkę
Cel: wygenerować wydruk pojedynczego dokumentu handlowego (faktura sprzedaży FV, faktura zakupu FZ, paragon) do strumienia PDF albo wysłać go na drukarkę.
Warianty:
| Wariant | Ustawienie | Uwaga |
|---|---|---|
| Faktura sprzedaży → PDF | TemplateFileName = "Sprzedaz.repx", OutputFormat = PDF |
strumień %PDF… |
| Faktura zakupu → PDF | TemplateFileName = "Zakup.repx" |
analogicznie |
| Wydruk HTML / TXT | OutputFormat = HTML / TXT |
użyj GenerateReportStr lub GenerateReport |
| Duplikat / oryginał | parametr ParametryWydrukuDokumentu { Duplikat = … } w kontekście |
parametr wzorca |
| Na drukarkę (sprzęt) | Target = Printer, PrintReport(rr) |
wymaga drukarki — patrz „Pułapki” |
| PDF szyfrowany | Encrypt = "hasło" |
hasło otwarcia pliku |
Pola i typy: IReportService.GenerateReport(ReportResult) : Stream,
ReportResult.TemplateFileName : string, ReportResult.DataType : Type,
ReportResult.OutputFormat : ReportFormats, ReportResult.Context : Context,
ParametryWydrukuDokumentu : ContextBase (parametry wzorca dokumentu, m.in. Duplikat : bool).
Snippet:
using Microsoft.Extensions.DependencyInjection;
using Soneta.Business.UI;
using Soneta.Handel;
// 'dok' to zatwierdzona faktura sprzedaży (FV). 'session' — bieżąca sesja.
var raporty = session.GetRequiredService<IReportService>();
// 1. Kontekst: pojedynczy dokument + jego elementy + parametry wzorca.
var context = new Context(session);
context.Set(dok);
context.Set(dok.Definicja);
context.Set(dok.Kontrahent);
context.Set(new DokumentHandlowy[] { dok }); // wymagane przez niektóre wzorce
context.Set(new ParametryWydrukuDokumentu(context) { Duplikat = false });
// 2. Opis wydruku — tryb automatyczny (TemplateFileName) → bez UI.
var rr = new ReportResult {
TemplateFileName = "Sprzedaz.repx", // "Zakup.repx" dla faktury zakupu
DataType = typeof(DokumentHandlowy), // wydruk dla pojedynczego dokumentu
Context = context,
OutputFormat = ReportFormats.PDF,
AskForParameters = false // tryb wsadowy — nie pytaj o parametry
};
// 3. Generowanie do strumienia i zapis do pliku.
using (Stream pdf = raporty.GenerateReport(rr))
using (var plik = new FileStream(@"C:\Temp\FV.pdf", FileMode.Create, FileAccess.Write))
pdf.CopyTo(plik);
Pułapki:
GenerateReportzwracaStreamdla formatów binarnych (PDF, XLSX, PNG). DlaHTML/TXTużyjGenerateReportStr(zwracastring). Zwrócony strumień opakuj wusing.- Kontekst musi zawierać wszystko, czego wymaga wzorzec: rekord (
Context.Set(dok)), tablicę zaznaczeń i instancję parametrów (ParametryWydrukuDokumentu). Brak parametruAskForParameters = truew trybie wsadowym zawiesi się na oczekiwaniu na UI — w kodzie bez interfejsu zawsze ustawAskForParameters = false.
- Wydruk faktury powinien dotyczyć dokumentu zatwierdzonego (
Stan == Zatwierdzony) — dokument w buforze nie ma jeszcze nadanego numeru pełnego. - Sprawdzenie poprawności PDF w teście: pierwsze 4 znaki strumienia to
"%PDF"; HTML zaczyna się od"<!DOCTYPE html". - Druk na fizyczną drukarkę (
PrintReport,Target = Printer) wymaga sprzętu i sterownika — nie da się tego przetestować jednostkowo. W testach i integracjach używaj ścieżkiGenerateReport→ strumień/PDF.
HANDEL-W63 — Wydruk dokumentu magazynowego (PZ/WZ/MM)
Cel: wydrukować dokument magazynowy (PZ, WZ, MM, RW, PW) — identyczny mechanizm jak dla faktury, różni się tylko wzorcem dobranym do rodzaju dokumentu (wg jego definicji).
Warianty:
| Wariant | Wzorzec / DataType |
|---|---|
| Przyjęcie / wydanie magazynowe | wzorzec magazynowy (*.repx), DataType = typeof(DokumentHandlowy) |
| Przesunięcie MM | wzorzec MM |
| Wydruk wg definicji dokumentu | wzorzec domyślny przypisany do dok.Definicja |
Pola i typy: jak w HANDEL-W62 — IReportService.GenerateReport, ReportResult.TemplateFileName,
DokumentHandlowy.Definicja (decyduje o domyślnym wzorcu).
Snippet:
using Microsoft.Extensions.DependencyInjection;
using Soneta.Business.UI;
using Soneta.Handel;
// 'wz' — zatwierdzony dokument WZ (rozchód magazynowy).
var raporty = session.GetRequiredService<IReportService>();
var context = new Context(session);
context.Set(wz);
context.Set(wz.Definicja);
context.Set(wz.Magazyn);
context.Set(new DokumentHandlowy[] { wz });
context.Set(new ParametryWydrukuDokumentu(context) { Duplikat = false });
var rr = new ReportResult {
TemplateFileName = "WydanieZewnetrzne.repx", // wzorzec właściwy dla danego rodzaju dokumentu
DataType = typeof(DokumentHandlowy),
Context = context,
OutputFormat = ReportFormats.PDF,
AskForParameters = false
};
using (Stream pdf = raporty.GenerateReport(rr)) {
// pdf → plik / e-mail / archiwum
}
Pułapki:
- Dokument magazynowy i faktura to ten sam typ
DokumentHandlowy— różni je definicja (dok.Definicja) i przypisany wzorzec. DobierzTemplateFileNamezgodny z rodzajem dokumentu; nie drukuj WZ wzorcem faktury sprzedaży. - Dla dokumentów magazynowych ustaw w kontekście
dok.Magazyn(część wzorców go wymaga). - Nazwy wzorców są elementem konfiguracji wdrożenia (lista wydruków zarejestrowanych dla typu).
Listę typów parametrów, których wymaga konkretny wzorzec, sprawdzisz przez
GetParameterTypes(templateFileName, context)przed wywołaniemGenerateReport.
HANDEL-W64 — Raport dobowy i okresowy (zestawienie za dzień / okres)
Cel: wygenerować zestawienie/rejestr dokumentów za wskazany dzień (raport dobowy) lub wskazany okres (raport okresowy). Dwie odrębne ścieżki:
- Zestawienie/raport bazodanowy — przez
IReportServicez wzorcem zestawienia i parametrem okresu (analizowalny, zapisywalny do PDF/XLSX) — ścieżka testowalna. - Raport fiskalny drukarki (
RaportDobowy/RaportOkresowy) — wydruk na drukarce fiskalnej przezIFiscalPrinterAPI— wymaga sprzętu, nietestowalny jednostkowo.
Warianty:
| Wariant | Mechanizm | Parametr okresu |
|---|---|---|
| Zestawienie sprzedaży za dzień → PDF | IReportService + wzorzec zestawienia, DataType = typeof(DokHandlowe) |
FromTo(dzień, dzień) w parametrach wzorca |
| Zestawienie za okres → PDF/XLSX | jw. | FromTo(od, do) |
| Fiskalny raport dobowy (sprzęt) | IFiscalPrinterAPI.DrukujRaport(nazwaDrukarki) |
dzień bieżący |
| Fiskalny raport okresowy (sprzęt) | IFiscalPrinterAPI.DrukujRaportOkresowy(nazwaDrukarki, RaportOkresowyParams) |
RaportOkresowyParams.RaportZaOkres : FromTo |
Pola i typy:
Soneta.Fiskal.IFiscalPrinterAPI (publiczny): DrukujRaport(string nazwaDrukarki),
DrukujRaportOkresowy(string nazwaDrukarki, RaportOkresowyParams pars),
Fiskalizuj(DokumentHandlowy dok, string nazwaDrukarki).
Soneta.Fiskal.RaportOkresowyParams : ContextBase — RaportZaOkres : FromTo ([Required]),
inicjalizowany na dzień bieżący; ctor RaportOkresowyParams(Context).
Snippet:
using Microsoft.Extensions.DependencyInjection;
using Soneta.Business.UI;
using Soneta.Types; // FromTo, Date
// --- Ścieżka 1: zestawienie bazodanowe za wskazany dzień → PDF (testowalne) ---
var raporty = session.GetRequiredService<IReportService>();
var dzien = Date.Today;
var context = new Context(session);
context.Set(new FromTo(dzien, dzien)); // parametr okresu wzorca zestawienia
var rr = new ReportResult {
TemplateFileName = "ZestawienieSprzedazy.repx", // wzorzec rejestru/zestawienia
DataType = typeof(Soneta.Handel.DokHandlowe), // wydruk dla zbioru dokumentów z widoku
Context = context,
OutputFormat = ReportFormats.PDF,
AskForParameters = false
};
using (Stream pdf = raporty.GenerateReport(rr)) {
// zapis / wysyłka
}
// --- Ścieżka 2: fiskalny raport okresowy (WYMAGA DRUKARKI FISKALNEJ) ---
// var fiskal = session.GetRequiredService<Soneta.Fiskal.IFiscalPrinterAPI>();
// var pars = new Soneta.Fiskal.RaportOkresowyParams(context) {
// RaportZaOkres = new FromTo(new Date(2026, 6, 1), new Date(2026, 6, 30))
// };
// fiskal.DrukujRaportOkresowy("Posnet Thermal", pars); // druk na sprzęcie
Pułapki:
- Rozróżnij dwie rzeczy o podobnej nazwie: raport dobowy/okresowy drukarki fiskalnej
(
IFiscalPrinterAPI, rozliczenie utargu na sprzęcie) vs. bazodanowe zestawienie/rejestr za dzień/okres (IReportService+ wzorzec). Dodatek raportujący zwykle chce ścieżki 2. RaportOkresowyParams.RaportZaOkresjest[Required]; pustyFromToresetuje się do dnia bieżącego, a otwarty zakres (From == MinValue/To == MaxValue) zwija się do jednego dnia.- Fiskalny raport (
DrukujRaport*) wymaga podłączonej drukarki fiskalnej — operacja sprzętowa, nie do testów jednostkowych. Testuj wyłącznie ustawienieRaportOkresowyParamsi ścieżkę bazodanowąGenerateReport.
HANDEL-W65 — Wydruk zbiorczy dla zaznaczonego zbioru dokumentów
Cel: wygenerować jeden wydruk obejmujący wiele dokumentów naraz (np. seria faktur z zaznaczenia listy) zamiast drukować każdy osobno.
Warianty:
| Wariant | DataType |
Kontekst |
|---|---|---|
| Zaznaczone rekordy | typeof(DokumentHandlowy[]) |
context.Set(tablica) zaznaczonych dokumentów |
| Wszystkie z widoku | typeof(DokHandlowe) |
rekordy dostarcza View/ViewInfo |
| Pojedynczy | typeof(DokumentHandlowy) |
jeden rekord (HANDEL-W62) |
DataTypedecyduje, które rekordy trafiają na wydruk:typeof(T)— jeden obiekt,typeof(T[])— zaznaczone,typeof(Tabela)— wszystkie z widoku.
Pola i typy: ReportResult.DataType : Type, ReportResult.Rows : IEnumerable
(jawne wskazanie rekordów do wydruku), Context.Set(DokumentHandlowy[]).
Snippet:
using Microsoft.Extensions.DependencyInjection;
using Soneta.Business.UI;
using Soneta.Handel;
// 'zaznaczone' — tablica zatwierdzonych dokumentów do wydruku zbiorczego.
DokumentHandlowy[] zaznaczone = /* ... */;
var raporty = session.GetRequiredService<IReportService>();
var context = new Context(session);
context.Set(zaznaczone); // zbiór rekordów do wydruku
var rr = new ReportResult {
TemplateFileName = "Sprzedaz.repx",
DataType = typeof(DokumentHandlowy[]), // wydruk dla ZAZNACZONYCH rekordów
Rows = zaznaczone, // jawne wskazanie zbioru (opcjonalne)
Context = context,
OutputFormat = ReportFormats.PDF,
AskForParameters = false
};
using (Stream pdf = raporty.GenerateReport(rr)) {
// jeden strumień PDF z wieloma dokumentami
}
Pułapki:
- Kluczowa różnica vs HANDEL-W62 to
DataType = typeof(DokumentHandlowy[])— typ tablicowy przełącza wzorzec w tryb wielu rekordów. Ztypeof(DokumentHandlowy)wydrukuje się tylko pierwszy/bieżący dokument. Rows(IEnumerable) pozwala jawnie podać zbiór; pole nie działa dla wydruków z menu (tylko dla automatycznego trybu zTemplateFileName).- Do wydruków masowych ustaw
AskForParameters = false— inaczej każdy dokument mógłby wywołać okno parametrów. - Wszystkie dokumenty w zbiorze powinny pasować do jednego wzorca (ten sam rodzaj/definicja).
HANDEL-W66 — Zapis wydruku do strumienia/pliku (integracja, e-mail)
Cel: uzyskać wydruk jako strumień bajtów, bez drukowania — do zapisania w pliku, dołączenia jako załącznik do e-maila, archiwizacji lub przesłania do zewnętrznego systemu.
Warianty:
| Wariant | Mechanizm |
|---|---|
| Do pliku / strumienia | GenerateReport → Stream → FileStream/MemoryStream |
| Wydruk tekstowy (HTML/TXT) | GenerateReportStr → string |
| Załącznik e-mail | Target = ReportTargets.Email lub strumień z GenerateReport jako załącznik |
| Z archiwizacją na druk | PrintReport(rr, archive: true, archivePath: @"C:\Archiwum") |
Własna obsługa strumienia (tryb wzorca, nie IReportService) |
ReportResult.OutputHandler jako rezultat operacji |
Pola i typy: IReportService.GenerateReport(ReportResult) : Stream,
IReportService.GenerateReportStr(ReportResult) : string,
ReportResult.OutputFormat : ReportFormats, ReportResult.Target : ReportTargets,
ReportResult.Encrypt : string (hasło PDF),
ReportResult.OutputHandler : Func<Stream, object> (tylko rezultat operacji UI).
Snippet:
using Microsoft.Extensions.DependencyInjection;
using Soneta.Business.UI;
using Soneta.Handel;
var raporty = session.GetRequiredService<IReportService>();
var context = new Context(session);
context.Set(dok);
context.Set(new DokumentHandlowy[] { dok });
context.Set(new ParametryWydrukuDokumentu(context) { Duplikat = false });
var rr = new ReportResult {
TemplateFileName = "Sprzedaz.repx",
DataType = typeof(DokumentHandlowy),
Context = context,
OutputFormat = ReportFormats.PDF,
Encrypt = "tajne-haslo", // (opcjonalnie) PDF chroniony hasłem
AskForParameters = false
};
// 1. Do pamięci — np. bajty do wysyłki e-mailem przez własny mechanizm:
byte[] pdfBytes;
using (Stream src = raporty.GenerateReport(rr))
using (var ms = new MemoryStream()) {
src.CopyTo(ms);
pdfBytes = ms.ToArray();
}
// pdfBytes → załącznik wiadomości, REST API, repozytorium dokumentów...
// 2. Wariant: niech mechanizm sam wyśle e-mail (rezultat operacji w workerze UI):
// rr.Target = ReportTargets.Email; // wymaga konfiguracji konta pocztowego i szablonu
Pułapki:
GenerateReportto właściwa droga dla integracji — zwraca strumień, którym dysponujesz dowolnie (plik, e-mail, sieć). Zawszeusingna zwróconym strumieniu (PDF i inne formaty binarne).OutputHandlernie jest obsługiwany przezIReportService(CheckConsistencyrzuciArgumentException). Służy jako rezultat operacji w trybie wzorca (worker/Command z UI), nie do wsadowego generowania w czystym kodzie biznesowym.Target = Email/Attachmentto ścieżki integrujące się z modułem pocztowym (kontoKontoPocztowe, szablonSzablonEmail) — wymagają pełnej, skonfigurowanej sesji aplikacyjnej; w czystym kodzie integracyjnym prościej pobrać strumień zGenerateReporti wysłać go własnym kanałem.- Format dobieraj świadomie:
PDF/XLSX/PNG→GenerateReport(Stream);HTML/TXT→GenerateReportStr(string). - Szyfrowanie (
Encrypt) i podpis (Sign) dotyczą PDF; podpis certyfikatem działa tylko w trybie interaktywnym okienkowym (wymaga okna certyfikatu).
Co jest testowalne, a co nie (sekcja 12):
- Testowalne: generowanie wydruku do strumienia/PDF/HTML/TXT przez
IReportService.GenerateReport/GenerateReportStr(HANDEL-W62, HANDEL-W63, HANDEL-W64-ścieżka bazodanowa, HANDEL-W65, HANDEL-W66). Asercja: PDF zaczyna się od"%PDF", HTML od"<!DOCTYPE html".- Nietestowalne jednostkowo (wymaga sprzętu): druk na fizyczną drukarkę (
PrintReport,Target = Printer) oraz fiskalny raport dobowy/okresowy drukarki (IFiscalPrinterAPI.DrukujRaport/DrukujRaportOkresowy,Fiskalizuj). Dla nich testuj tylko poprawne ustawienieReportResult/RaportOkresowyParams, bez faktycznego druku.