Przemianowałem istnijące skille na prostsze nazwy - porządki
This commit is contained in:
@@ -1,10 +1,16 @@
|
|||||||
# Soneta / enova365 AI Skills
|
# Soneta / enova365 AI Skills
|
||||||
|
|
||||||
Zestaw skills dla asystentów AI (Claude, Cursor, Windsurf, itp.) wspierających programowanie i projektowanie z platformą **enova365/Soneta Enterprise**.
|
Zestaw skills dla asystentów AI (Claude, Cursor, Windsurf, itp.) wspierających programowanie, projektowanie i konfigurację platformy **enova365 / Soneta Enterprise / Triva**.
|
||||||
|
|
||||||
## Dostępne skille
|
## Dostępne skille
|
||||||
|
|
||||||
### 1. soneta-programming-basics
|
### 0. soneta-erp (meta-skill)
|
||||||
|
|
||||||
|
Mapa i przewodnik po pozostałych skillach. Pomaga wybrać właściwy skill w zależności od warstwy zadania (dane, UI, logika, płace).
|
||||||
|
|
||||||
|
**Kiedy używać:** rozpoczynasz nowe zadanie dla enova365/Soneta/Triva i nie wiesz, który skill zastosować; zadanie obejmuje wiele warstw platformy i potrzebna jest koordynacja między skillami.
|
||||||
|
|
||||||
|
### 1. soneta-programming
|
||||||
|
|
||||||
Fundamentalne klasy ORM platformy enova365/Soneta Enterprise.
|
Fundamentalne klasy ORM platformy enova365/Soneta Enterprise.
|
||||||
|
|
||||||
@@ -68,36 +74,36 @@ System projektowy (design system) Soneta / enova365 do budowania aplikacji webow
|
|||||||
|
|
||||||
**Kiedy używać:** projektowanie stron/aplikacji w stylu enova365, dashboardy, formularze, strony logowania, panele administracyjne.
|
**Kiedy używać:** projektowanie stron/aplikacji w stylu enova365, dashboardy, formularze, strony logowania, panele administracyjne.
|
||||||
|
|
||||||
### 6. soneta-mcp-ui-guide
|
### 6. soneta-place-def-elementow
|
||||||
|
|
||||||
Obsługa programów Soneta (enova365, Triva) przez narzędzia MCP `soneta_ui`.
|
Tworzenie i konfiguracja definicji elementów wynagrodzenia w enova365 (moduł Płace).
|
||||||
|
|
||||||
**Zakres:**
|
**Zakres:**
|
||||||
- Nawigacja po modułach i folderach programu (Handel, Kadry, Księgowość, CRM, itp.)
|
- Algorytmy naliczania: kreator, edytor C# (`_Param`, `_Wylicz`, `_Wartość1h`), algorytmy wbudowane
|
||||||
- Przeglądanie list z filtrowaniem i stronicowaniem
|
- 12 wzorców dla Dodatków, 5 dla Nieobecności, 5 dla Dodatków automatycznych (z analizy ~247 definicji)
|
||||||
- Otwieranie formularzy i przełączanie zakładek
|
- Receptury kodu C#: iterowanie po elementach, staż pracy, wymiar etatu, czas pracy, wskaźniki, cechy pracownika
|
||||||
- Edycja danych na formularzach (pola oznaczone jako `edytowany`)
|
- Konfiguracja zakładek: Ogólne, Deklaracje (PIT/ZUS), Nieobecności, Algorytm
|
||||||
- Dodawanie nowych obiektów
|
- Metody sterujące naliczaniem (`_PodstawaUrlopu`, `_PodstawaZasiłku`)
|
||||||
- Mapa ~100 najczęściej używanych folderów programu
|
|
||||||
|
|
||||||
**Kiedy używać:** odczyt/edycja danych w enova365 lub Triva przez MCP — kontrahenci, faktury, pracownicy, towary, stany magazynowe, przelewy, deklaracje.
|
**Kiedy używać:** tworzenie/modyfikacja definicji elementu wynagrodzenia, pisanie algorytmów płacowych (premia procentowa, dodatek stażowy, zasiłek chorobowy, ekwiwalent za urlop).
|
||||||
|
|
||||||
## Powiązania między skillami
|
## Powiązania między skillami
|
||||||
|
|
||||||
Skille są zaprojektowane do współpracy:
|
Skille są zaprojektowane do współpracy:
|
||||||
|
|
||||||
1. **soneta-addon-planning** → planuje strukturę nowego dodatku
|
1. **soneta-erp** → wskazuje właściwy skill dla danego zadania
|
||||||
2. **soneta-business-xml** → definiuje obiekty biznesowe w XML
|
2. **soneta-addon-planning** → planuje strukturę nowego dodatku
|
||||||
3. **soneta-programming-basics** → pokazuje jak pracować z wygenerowanymi klasami C#
|
3. **soneta-business-xml** → definiuje obiekty biznesowe w XML
|
||||||
4. **soneta-form-xml** → tworzy formularze UI dla obiektów
|
4. **soneta-programming** → pokazuje jak pracować z wygenerowanymi klasami C#
|
||||||
5. **soneta-ui-style** → styluje interfejs webowy zgodnie z design systemem enova365
|
5. **soneta-form-xml** → tworzy formularze UI dla obiektów
|
||||||
6. **soneta-mcp-ui-guide** → obsługuje dane w działającej instancji enova365/Triva przez MCP
|
6. **soneta-ui-style** → styluje interfejs webowy zgodnie z design systemem enova365
|
||||||
|
7. **soneta-place-def-elementow** → konfiguruje warstwę płacową (definicje elementów wynagrodzenia)
|
||||||
|
|
||||||
## Instalacja
|
## Instalacja
|
||||||
|
|
||||||
### Claude Code
|
### Claude Code
|
||||||
|
|
||||||
Skopiuj folder ze skillem do `~/.claude/skills/`.
|
Skopiuj foldery skilli do `~/.claude/skills/`.
|
||||||
|
|
||||||
### Cursor / Windsurf / inne IDE
|
### Cursor / Windsurf / inne IDE
|
||||||
|
|
||||||
@@ -105,4 +111,4 @@ Dodaj zawartość skilli do kontekstu projektu lub rules.
|
|||||||
|
|
||||||
## Licencja
|
## Licencja
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
@@ -87,7 +87,7 @@ Plan projektu generowany jest jako dokument Markdown z następującą strukturą
|
|||||||
|
|
||||||
Po zatwierdzeniu planu projektu:
|
Po zatwierdzeniu planu projektu:
|
||||||
1. **enova365-business-xml** - generowanie pliku business.xml na podstawie modelu danych
|
1. **enova365-business-xml** - generowanie pliku business.xml na podstawie modelu danych
|
||||||
2. **soneta-programming-basics** - implementacja workerów i logiki biznesowej
|
2. **soneta-programming** - implementacja workerów i logiki biznesowej
|
||||||
|
|
||||||
## Szczegółowa dokumentacja
|
## Szczegółowa dokumentacja
|
||||||
|
|
||||||
|
|||||||
@@ -325,4 +325,4 @@ Po zakończeniu wszystkich etapów wygeneruj dokument TODO z kolejnymi krokami:
|
|||||||
Po zatwierdzeniu planu projektu:
|
Po zatwierdzeniu planu projektu:
|
||||||
1. **soneta-business-xml** — generowanie pliku business.xml na podstawie modelu danych z Etapu 3
|
1. **soneta-business-xml** — generowanie pliku business.xml na podstawie modelu danych z Etapu 3
|
||||||
2. **soneta-form-xml** — generowanie formularzy i widoków UI na podstawie sekcji 3.4 i 3.5
|
2. **soneta-form-xml** — generowanie formularzy i widoków UI na podstawie sekcji 3.4 i 3.5
|
||||||
3. **soneta-programming-basics** — implementacja logiki biznesowej, workerów
|
3. **soneta-programming** — implementacja logiki biznesowej, workerów
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: soneta-erp
|
||||||
|
description: >
|
||||||
|
Mapa i przewodnik po wyspecjalizowanych skillach do pracy z platformą Soneta ERP
|
||||||
|
(enova365, Soneta Enterprise, Triva). Pomaga wybrać właściwy skill w zależności od
|
||||||
|
zadania: programowanie ORM (soneta-programming), planowanie dodatków
|
||||||
|
(soneta-addon-planning), definicje obiektów biznesowych (soneta-business-xml),
|
||||||
|
formularze UI (soneta-form-xml), definicje elementów wynagrodzenia
|
||||||
|
(soneta-place-def-elementow). Używaj tego skilla ZAWSZE gdy użytkownik: (1) rozpoczyna
|
||||||
|
nowe zadanie związane z enova365/Soneta/Triva i nie jest jasne, który wyspecjalizowany
|
||||||
|
skill zastosować; (2) pyta ogólnie o tworzenie dodatków, modułów lub rozszerzeń dla
|
||||||
|
Soneta ERP; (3) wspomina o platformie enova, Soneta Enterprise, Triva bez sprecyzowania
|
||||||
|
warstwy (dane, UI, logika, płace); (4) chce poznać dostępne narzędzia/skille do pracy
|
||||||
|
z ekosystemem Soneta; (5) realizuje zadanie obejmujące wiele warstw platformy
|
||||||
|
(np. nowy moduł z bazą danych, formularzami i logiką) i potrzebuje koordynacji między
|
||||||
|
skillami.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Mapa skills podczas pracy z Soneta ERP (enova/Triva)
|
||||||
|
|
||||||
|
* `/soneta-programming` - Fundamentalne klasy ORM platformy enova365/Soneta Enterprise. Obejmuje mapowanie
|
||||||
|
obiektowo-relacyjne (Row, Table, Module), zarządzanie sesją (Session), logowanie (Login, Database, BusApplication),
|
||||||
|
paczki danych (Datapack, GuidedRow) oraz kontekst (Context). Używaj gdy użytkownik pyta o podstawowe klasy logiki
|
||||||
|
biznesowej, strukturę obiektów ORM, sesje i transakcje, hierarchię klas Row/Table/Module, mechanizm Datapack i
|
||||||
|
synchronizację danych, lub kontekst aplikacji enova365, Context
|
||||||
|
* `/soneta-addon-planning` - Planowanie projektów dodatków dla platformy enova365/Soneta Enterprise. Tworzy
|
||||||
|
kompletną dokumentację projektową obejmującą: strukturę danych (tabele, relacje),
|
||||||
|
elementy konfigurowalne, definicje list i menu, formularze, workery i raporty.
|
||||||
|
Używaj gdy użytkownik prosi o zaplanowanie nowego modułu/dodatku enova365,
|
||||||
|
przygotowanie założeń projektu, stworzenie specyfikacji funkcjonalnej dodatku,
|
||||||
|
lub zdefiniowanie struktury danych i interfejsu użytkownika dla nowego modułu.
|
||||||
|
* `/soneta-business-xml` - Generator plików business.xml dla platform Soneta (enova365, Soneta Enterprise).
|
||||||
|
Tworzy definicje obiektów biznesowych (tabel, kolumn, relacji, indeksów) zgodne
|
||||||
|
ze schematem XSD. Używaj gdy użytkownik prosi o stworzenie nowego modułu biznesowego,
|
||||||
|
zdefiniowanie obiektów lub encji do przechowywania w bazie danych, utworzenie relacji
|
||||||
|
między obiektami, lub generowanie plików business.xml dla enova365/Soneta Enterprise.
|
||||||
|
* `/soneta-form-xml` - XML z nieistniejącymi elementami. ZAWSZE używaj tego skilla gdy użytkownik: (1) prosi o utworzenie lub modyfikację pliku pageform.xml, viewform.xml, form.xml, lookupform.xml lub gridform.xml dla enova365/Soneta; (2) pyta o elementy DataForm, Page, Group, Grid, Field, Row, Stack, Flow, Command, Include, Appearance, GroupBy w enova365; (3) pyta o składnię EditValue, DataContext, Visibility, RowCondition, Renderable, CaptionHtml, Footer, Class lub układ UI formularzy enova365; (4) pokazuje istniejący plik form.xml/pageform.xml/viewform.xml i pyta o jego strukturę lub chce go rozszerzyć; (5) pyta o warunkową widoczność, formatowanie warunkowe (Appearance), bindowanie danych lub wzorce UI w Soneta/enova365.
|
||||||
@@ -143,31 +143,46 @@ update_field_value(["_Tekst=public void Nazwa_Param(...) {\\n ...\\n}\\n\\npu
|
|||||||
|
|
||||||
## Wskazówki przy tworzeniu nowych algorytmów
|
## Wskazówki przy tworzeniu nowych algorytmów
|
||||||
|
|
||||||
1. **Wybierz wzorzec** — większość nowych elementów pasuje do jednego z istniejących wzorców. Przeczytaj `references/wzorce-algorytmiczne.md` i zacznij od skopiowania najbliższego wzorca.
|
1. **`Element` to parametr metody** — w kodzie algorytmu `Element` nie jest zmienną globalną ani polem klasy — jest **pierwszym parametrem** każdej metody (`_Param`, `_Wylicz`, `_Wartość1h` itd.).
|
||||||
|
Metoda musi zawsze zawierać te parametry.
|
||||||
|
Typ tego parametru musi odpowiadać rodzajowi definiowanego elementu:
|
||||||
|
- Etat → `Soneta.Place.WypElementEtat Element`
|
||||||
|
- Dodatek → `Soneta.Place.WypElementDodatek Element`
|
||||||
|
- Dodatek automatyczny → `Soneta.Place.WypElementDodatekAutomatyczny Element`
|
||||||
|
- Nieobecność → `Soneta.Place.WypElementNieobecnosc Element`
|
||||||
|
- Nadgodziny → `Soneta.Place.WypElementNadgodziny Element`
|
||||||
|
- Umowa → `Soneta.Place.WypElementUmowa Element`
|
||||||
|
|
||||||
2. **Źródło kwoty** — zdecyduj skąd pochodzi podstawa:
|
Przykład: jeśli algorytm odwołuje się do `Element.DodHistoria.Podstawa`, a definicja jest rodzaju **Dodatek**, to sygnatura metody musi wyglądać:
|
||||||
|
```csharp
|
||||||
|
public void MojDodatek_Param(WypElementDodatek Element, WypSkladnik Składnik) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Wybierz wzorzec** — większość nowych elementów pasuje do jednego z istniejących wzorców. Przeczytaj `references/wzorce-algorytmiczne.md` i zacznij od skopiowania najbliższego wzorca.
|
||||||
|
|
||||||
|
3. **Źródło kwoty** — zdecyduj skąd pochodzi podstawa:
|
||||||
- Kwota z parametrów pracownika → `Element.DodHistoria.Podstawa` (Wzorzec A)
|
- Kwota z parametrów pracownika → `Element.DodHistoria.Podstawa` (Wzorzec A)
|
||||||
- Kwota z konfiguracji programu → `module.Config.Zasiłki.*[Date]` (Wzorzec B)
|
- Kwota z konfiguracji programu → `module.Config.Zasiłki.*[Date]` (Wzorzec B)
|
||||||
- Kwota stała z definicji → `Element.Definicja.Algorytm.KreatorAlgorytmu.Podstawa` (Wzorzec C)
|
- Kwota stała z definicji → `Element.Definicja.Algorytm.KreatorAlgorytmu.Podstawa` (Wzorzec C)
|
||||||
- Procent od zasadniczego → `ZasadniczeNominalne(Date)` + `Element.DodHistoria.Procent` (Wzorzec D)
|
- Procent od zasadniczego → `ZasadniczeNominalne(Date)` + `Element.DodHistoria.Procent` (Wzorzec D)
|
||||||
|
|
||||||
3. **Czas i dni** — prawie wszystkie algorytmy ustawiają czas i dni z normy:
|
4. **Czas i dni** — prawie wszystkie algorytmy ustawiają czas i dni z normy:
|
||||||
```csharp
|
```csharp
|
||||||
CzasDni cd = Element.Pracownik.Czasy.Norma(Składnik.Okres);
|
CzasDni cd = Element.Pracownik.Czasy.Norma(Składnik.Okres);
|
||||||
Składnik.Czas = cd.Czas;
|
Składnik.Czas = cd.Czas;
|
||||||
Składnik.Dni = cd.Dni;
|
Składnik.Dni = cd.Dni;
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Pomniejszenie za nieobecności** — użyj kreatora algorytmu z konfiguracją korekt lub ręcznie: `Element.Pracownik.Czasy.Nieobecnosci(Składnik.Okres).Dni`
|
5. **Pomniejszenie za nieobecności** — użyj kreatora algorytmu z konfiguracją korekt lub ręcznie: `Element.Pracownik.Czasy.Nieobecnosci(Składnik.Okres).Dni`
|
||||||
|
|
||||||
5. **Proporcjonalność do okresu** — gdy okres składnika jest krótszy niż pełny okres naliczania, przelicz proporcjonalnie (jak w Premii procentowej — Wzorzec D).
|
6. **Proporcjonalność do okresu** — gdy okres składnika jest krótszy niż pełny okres naliczania, przelicz proporcjonalnie (jak w Premii procentowej — Wzorzec D).
|
||||||
|
|
||||||
6. **Zasiłki** — zawsze używaj `new PodstawaZasiłku(Element)` i `WyliczPodstawęZasiłkuZaDzień(...)` — nie obliczaj podstawy zasiłku ręcznie.
|
7. **Zasiłki** — zawsze używaj `new PodstawaZasiłku(Element)` i `WyliczPodstawęZasiłkuZaDzień(...)` — nie obliczaj podstawy zasiłku ręcznie.
|
||||||
|
|
||||||
7. **Urlopy okolicznościowe** — używaj `new NaliczanieOkolicznosciowy(Element, Składnik).NaliczPodstawy()` — automatycznie ustawi Podstawa1 (za godziny) i Podstawa2 (za dni).
|
8. **Urlopy okolicznościowe** — używaj `new NaliczanieOkolicznosciowy(Element, Składnik).NaliczPodstawy()` — automatycznie ustawi Podstawa1 (za godziny) i Podstawa2 (za dni).
|
||||||
|
|
||||||
8. **Ekwiwalenty i odprawy** — używaj `new NaliczanieEkwiwalent(Element, Składnik).NaliczPodstawy()`.
|
9. **Ekwiwalenty i odprawy** — używaj `new NaliczanieEkwiwalent(Element, Składnik).NaliczPodstawy()`.
|
||||||
|
|
||||||
9. **Element.DodHistoria.Podstawa vs Element.DodHistoria.Kwota** — w rzeczywistych algorytmach kreatorowych kwota pobierana jest z `Element.DodHistoria.Podstawa` (nie `.Kwota`). Pole `.Kwota` występuje w dokumentacji, ale `.Podstawa` jest częściej stosowane w generowanym kodzie.
|
10. **Element.DodHistoria.Podstawa vs Element.DodHistoria.Kwota** — w rzeczywistych algorytmach kreatorowych kwota pobierana jest z `Element.DodHistoria.Podstawa` (nie `.Kwota`). Pole `.Kwota` występuje w dokumentacji, ale `.Podstawa` jest częściej stosowane w generowanym kodzie.
|
||||||
|
|
||||||
10. **Dodatkowe metody** — jeśli element ma odbiorców płatności (potrącenia, alimenty), zdefiniuj metody `_Odbiorca` i `_RachunekOdbiorcy`. Jeśli okres naliczania wymaga podziału, zdefiniuj `_CięcieOkresu`. Jeśli element wpływa na podstawy urlopów/zasiłków — przeczytaj `references/metody-sterujace-naliczaniem.md`.
|
11. **Dodatkowe metody** — jeśli element ma odbiorców płatności (potrącenia, alimenty), zdefiniuj metody `_Odbiorca` i `_RachunekOdbiorcy`. Jeśli okres naliczania wymaga podziału, zdefiniuj `_CięcieOkresu`. Jeśli element wpływa na podstawy urlopów/zasiłków — przeczytaj `references/metody-sterujace-naliczaniem.md`.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: soneta-programming-basics
|
name: soneta-programming
|
||||||
description: >
|
description: >
|
||||||
Fundamentalne klasy ORM platformy enova365/Soneta Enterprise. Obejmuje mapowanie
|
Fundamentalne klasy ORM platformy enova365/Soneta Enterprise. Obejmuje mapowanie
|
||||||
obiektowo-relacyjne (Row, Table, Module), zarządzanie sesją (Session), logowanie
|
obiektowo-relacyjne (Row, Table, Module), zarządzanie sesją (Session), logowanie
|
||||||
@@ -11,27 +11,19 @@ description: >
|
|||||||
|
|
||||||
# Soneta Programming Basics - Podstawowe klasy ORM
|
# Soneta Programming Basics - Podstawowe klasy ORM
|
||||||
|
|
||||||
Skill zawiera dokumentację fundamentalnych klas logiki biznesowej platformy enova365/Soneta Enterprise. Klasy te stanowią podstawę mapowania obiektowo-relacyjnego (ORM) i są niezbędne do tworzenia dodatków.
|
Skill zawiera dokumentację fundamentalnych klas logiki biznesowej platformy enova365/Soneta Enterprise. Klasy te
|
||||||
|
stanowią podstawę mapowania obiektowo-relacyjnego (ORM) i są niezbędne do tworzenia kodu i dodatków.
|
||||||
|
|
||||||
## Architektura warstw
|
## Architektura warstw
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────┐
|
BusApplication.Instance (singleton) - multihreaded
|
||||||
│ Interfejs graficzny (UI) │
|
└── Database
|
||||||
├─────────────────────────────────────────────────────┤
|
└── Login
|
||||||
│ Context │ ← Komunikacja UI ↔ logika
|
└── Session - singlethreaded
|
||||||
├─────────────────────────────────────────────────────┤
|
└── Module
|
||||||
│ Logika biznesowa │
|
└── Table
|
||||||
│ ┌─────────────────────────────────────────────┐ │
|
└── Row
|
||||||
│ │ BusApplication (Singleton) │ │
|
|
||||||
│ │ └── Database (konfiguracja bazy) │ │
|
|
||||||
│ │ └── Login (uwierzytelnienie) │ │
|
|
||||||
│ │ └── Session (zarządzanie danymi) │ │
|
|
||||||
│ │ └── Module → Table → Row │ │
|
|
||||||
│ └─────────────────────────────────────────────┘ │
|
|
||||||
├─────────────────────────────────────────────────────┤
|
|
||||||
│ Baza danych SQL │
|
|
||||||
└─────────────────────────────────────────────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3 poziomy logiki biznesowej
|
## 3 poziomy logiki biznesowej
|
||||||
@@ -69,8 +61,6 @@ Module (abstrakcyjna)
|
|||||||
- `Context`
|
- `Context`
|
||||||
- oraz wszystkie klasy pochodne
|
- oraz wszystkie klasy pochodne
|
||||||
|
|
||||||
Każdy wątek powinien tworzyć własną sesję.
|
|
||||||
|
|
||||||
### Obiekty multi-threaded (można współdzielić)
|
### Obiekty multi-threaded (można współdzielić)
|
||||||
- `BusApplication`
|
- `BusApplication`
|
||||||
- `Database`
|
- `Database`
|
||||||
@@ -85,10 +75,6 @@ Session to kluczowa klasa do zarządzania danymi. **Każda operacja na danych wy
|
|||||||
```csharp
|
```csharp
|
||||||
// Przez Login
|
// Przez Login
|
||||||
Session session = login.CreateSession(readOnly: false, config: false, name: "MojaSesja");
|
Session session = login.CreateSession(readOnly: false, config: false, name: "MojaSesja");
|
||||||
|
|
||||||
// Parametry konstruktora:
|
|
||||||
// readOnly: true = tylko odczyt, false = edycja
|
|
||||||
// config: true = dane konfiguracyjne (cache), false = dane operacyjne (aktualne)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Typy sesji
|
### Typy sesji
|
||||||
@@ -151,6 +137,7 @@ Zmiany wykonywane są w trybie **optimistic-lock**:
|
|||||||
- Sesja konfiguracyjna używa cache'a (optymalizacja odczytów)
|
- Sesja konfiguracyjna używa cache'a (optymalizacja odczytów)
|
||||||
- Sesja operacyjna zawsze czyta z bazy (aktualność danych)
|
- Sesja operacyjna zawsze czyta z bazy (aktualność danych)
|
||||||
- **Nie mieszaj obiektów z różnych sesji** - użyj `session.Get(obiekt)` aby doczytać obiekt w bieżącej sesji
|
- **Nie mieszaj obiektów z różnych sesji** - użyj `session.Get(obiekt)` aby doczytać obiekt w bieżącej sesji
|
||||||
|
- ID identyfikuje obiekt w tabeli, może powtarzać się w różnych tabelach
|
||||||
|
|
||||||
## Klasa Module
|
## Klasa Module
|
||||||
|
|
||||||
@@ -258,10 +245,163 @@ public static TowaryModule GetTowary(this Session session)
|
|||||||
```csharp
|
```csharp
|
||||||
// Extension method (prostsze)
|
// Extension method (prostsze)
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
|
var tm = context.Session.GetTowary();
|
||||||
|
var tm = towar.Session.GetTowary();
|
||||||
|
|
||||||
// GetInstance (gdy mamy ISessionable, np. Row lub Context)
|
// GetInstance (gdy mamy ISessionable, ale property Session jest niedostępne)
|
||||||
var tm = TowaryModule.GetInstance(context);
|
var tm = TowaryModule.GetInstance(sessionable);
|
||||||
var tm = TowaryModule.GetInstance(towar); // towar implementuje ISessionable
|
```
|
||||||
|
|
||||||
|
## Kod biznesowy vs UI
|
||||||
|
|
||||||
|
Kod biznesowy realizuje operacje logiki biznesowej (jak backend).
|
||||||
|
Kod UI (fronend) jest odpowiedzialny za prezentację danych i interakcję z użytkownikiem.
|
||||||
|
Kod biznesowy może być umieszczony w tej samej klasie z kodem UI.
|
||||||
|
Kod UI to np:
|
||||||
|
- obiekty `View`, `ViewInfo`, extender
|
||||||
|
- metody sterujące `IsReadOnlyXxx`, `IsVisibleXxxx`, `GetListXxx`, `IsEnabledXxx`, `GetNameXxx`, `GetAppearanceXxx`
|
||||||
|
|
||||||
|
### Ważne zasady do stosowania w kodzie biznesowym
|
||||||
|
|
||||||
|
- Nie używaj żadnych obiektów kodu UI, w szczególności `View` - zamiast tego możesz użyć `SubTable[condition]`
|
||||||
|
- Nie należy stosować warunków na prawa dostępu (np `if (Table.AccessRight == AccessRights.Denied) {...}`)
|
||||||
|
|
||||||
|
## Serwisy
|
||||||
|
|
||||||
|
Pozwalają tworzyć obiekty (komponenty), których czas życia będzie zależał od scope:
|
||||||
|
- App (BusApplication.Instance)
|
||||||
|
- Database
|
||||||
|
- Login
|
||||||
|
- Session (default - nie trzeba określać w deklaracji)
|
||||||
|
|
||||||
|
Umieszczając deklarację interface serwisu w assembly wspólnym, pozwalają na udostępnianie serwisów między modułami,
|
||||||
|
nawet gdy nie ma odpowiedniej referencji.
|
||||||
|
|
||||||
|
* **Tylko serwisy scope Session są single-threded, pozostałe są multi-threaded.**
|
||||||
|
* Serwis może być `IDisposable`.
|
||||||
|
* Dla serwisów App, Database, Login nie przechowuj obiektów sesyjnych.
|
||||||
|
* `[RequireOwnService]` tylko dla serwisów, które nie mogą być nadpisywane.
|
||||||
|
|
||||||
|
### Przykład deklaracji
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[assembly: Service<MyNamespace.IRegistry, MyNamespace.Registry>(ServiceScope.Login)]
|
||||||
|
|
||||||
|
namespace MyNamespace;
|
||||||
|
|
||||||
|
[RequireServiceScope(ServiceScope.Login)]
|
||||||
|
public interface IRegistry {
|
||||||
|
void Method();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class Registry : IRegistry {
|
||||||
|
public void Method() {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Odczytanie serwisu w kodzie
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
IRegistry registerRequired = login.GetRequiredService<IRegistry>();
|
||||||
|
IRegistry? registerOptional = login.GetService<IRegistry>();
|
||||||
|
|
||||||
|
foreach (IRegistry registers in login.GetServices<IRegistry>())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Użycie serwisu w worker lub extender - obiekt tworzony przez Context.CreareObject()
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Rozwiązanie lepsze
|
||||||
|
class MyWorker1(IRegistry registry) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyWorker2 {
|
||||||
|
[Context]
|
||||||
|
private IRegistry Registry { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metadane modułów, tabel, kluczy, pól, itp
|
||||||
|
|
||||||
|
Dostęp do metadanych obiektów biznesowych dostępny przez metody `static` klasy `ApplicationInfo`.
|
||||||
|
Odczytanie informacji o tabli `TableInfo info = ApplicationInfo.GetTableInfo(nazwaTabeli)`. Istnieje tylko jedna
|
||||||
|
referencja obiektu TableInfo dla tabeli. Można używać `ReferenceEquals`, `Dictionary`, itp.
|
||||||
|
Odczytanie wszystkich tabel `ApplicationInfo.GetTablesInfo()`, a np tabel dla modułu `ApplicationInfo.GetModuleInfo
|
||||||
|
(moduleName).TableInfos`.
|
||||||
|
|
||||||
|
### Wykorzystuj `TableInfo` do weryfikacji tabeli
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
Row row1 = ...;
|
||||||
|
Row row2 = ...;
|
||||||
|
if (row1.Table.TableInfo==row2.Table.TableInfo) {
|
||||||
|
// Ta sama tabela, nawet gdy różne sesje
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tłumaczenie i formatowanie napisów, tekstów i string
|
||||||
|
|
||||||
|
Biblioteka obsługuje słowniki tłumaczące napisy w aplikacji Soneta.
|
||||||
|
* Tłumaczone napisy muszą używać metody typu string-extender `"napis dotłumaczenia".Translate()`.
|
||||||
|
* Tłumaczenie tekstów formatowanych przez `"napis {0} z wartością {1}".TranslateFormat(arg0, arg1)`.
|
||||||
|
* Gdy string ma być zignorowany przez tłumacza, MUSISZ zaznaczyć do metodą `"nie tłumaczymy".TranslateIgnore()`,inaczej błąd kompilacji.
|
||||||
|
* Jeżeli w metodzie lub klasie jest więcej napisów do zignorowania użyj atrybutu `[TranslateIgnore]`.
|
||||||
|
* Parametr metody jest ignorowany przez tłumacza, użyj atrybutu `[TranslateIgnore]` na parametrze.
|
||||||
|
|
||||||
|
## Log zmian i obserwowalność
|
||||||
|
|
||||||
|
Używaj standardowy narzędzi do logowania `ILogger<T>`. Użyj `[TranslateIgnore]` w metodzie wywołującej log.
|
||||||
|
Używaj `logger.IsEnable(LogLevel)` kiedy parametry wymagają dodatkowych operacji.
|
||||||
|
|
||||||
|
### Użycie `ILogger` oraz exception log
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test
|
||||||
|
{
|
||||||
|
private readonly logger = BusApplication.Instance.GetRequiredService<ILogger<Test>>();
|
||||||
|
|
||||||
|
public decimal Kwota;
|
||||||
|
|
||||||
|
[TranslateIgnore]
|
||||||
|
public void Metoda()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
logger.LogInformation("Wywołanie metody {nazwa}", nameof(Validate));
|
||||||
|
if (kwota<0)
|
||||||
|
logger.LogWarning("Kwota {kwota} nie może być ujemna w metodzie '{metoda}'", Kwota, nameof(Validate));
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
|
||||||
|
// Sposób na wrzucenie exception do trace
|
||||||
|
ex.Log<Test>();
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Śledzenie czasu wykonania z obsługą exception
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test {
|
||||||
|
private static readonly ActSource actSource = new(nameof(Test), ActSource.TraceLevel.Default);
|
||||||
|
|
||||||
|
public void Action() {
|
||||||
|
using var activity = actSource.Start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Algorytm do śledzenia
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
activity.AddExceptionWithError(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Szczegółowa dokumentacja
|
## Szczegółowa dokumentacja
|
||||||
@@ -276,7 +416,7 @@ var tm = TowaryModule.GetInstance(towar); // towar implementuje ISessionable
|
|||||||
### Odczyt danych
|
### Odczyt danych
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using (var session = login.CreateSession(true, false, "Odczyt"))
|
using (var session = login.CreateSession(readOnly: true, config: false, name: "Odczyt"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary(); // Extension method
|
var tm = session.GetTowary(); // Extension method
|
||||||
foreach (Towar t in tm.Towary.WgKodu)
|
foreach (Towar t in tm.Towary.WgKodu)
|
||||||
@@ -289,7 +429,7 @@ using (var session = login.CreateSession(true, false, "Odczyt"))
|
|||||||
### Tworzenie nowego obiektu
|
### Tworzenie nowego obiektu
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using (var session = login.CreateSession(false, false, "Dodawanie"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "Dodawanie"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
|
|
||||||
@@ -309,7 +449,7 @@ using (var session = login.CreateSession(false, false, "Dodawanie"))
|
|||||||
### Modyfikacja istniejącego obiektu
|
### Modyfikacja istniejącego obiektu
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using (var session = login.CreateSession(false, false, "Edycja"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "Edycja"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
var towar = tm.Towary.WgKodu["STARY001"];
|
var towar = tm.Towary.WgKodu["STARY001"];
|
||||||
+2
-4
@@ -22,9 +22,7 @@ Przykładowa zawartość przy otwartej liście kontrahentów:
|
|||||||
| `INavigatorContext` | Kontekst grida (zaznaczenia, focus) |
|
| `INavigatorContext` | Kontekst grida (zaznaczenia, focus) |
|
||||||
| `View` | Źródło danych grida |
|
| `View` | Źródło danych grida |
|
||||||
| `Params` | Klasa parametrów filtrów |
|
| `Params` | Klasa parametrów filtrów |
|
||||||
| `LicencjaProgramu` | Informacje o licencji |
|
|
||||||
| `Login` | Zalogowany użytkownik |
|
| `Login` | Zalogowany użytkownik |
|
||||||
| `MsSqlDatabase` | Baza danych |
|
|
||||||
|
|
||||||
## Odczyt z kontekstu
|
## Odczyt z kontekstu
|
||||||
|
|
||||||
@@ -41,7 +39,7 @@ public void Action(Context context)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Przez indeksator (rzuca wyjątek gdy brak)
|
### Przez indeksator
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public void Action(Context cx)
|
public void Action(Context cx)
|
||||||
@@ -76,7 +74,7 @@ public void Action(Context cx)
|
|||||||
```csharp
|
```csharp
|
||||||
public void Action(Context cx)
|
public void Action(Context cx)
|
||||||
{
|
{
|
||||||
// Przez indeksator
|
// Przez indeksator z określeniem typu
|
||||||
Kontrahent knt = ...;
|
Kontrahent knt = ...;
|
||||||
cx[typeof(Kontrahent)] = knt;
|
cx[typeof(Kontrahent)] = knt;
|
||||||
|
|
||||||
+16
-26
@@ -5,14 +5,14 @@ Dokumentacja klas zarządzających połączeniem z bazą danych i sesjami w plat
|
|||||||
## Hierarchia obiektów
|
## Hierarchia obiektów
|
||||||
|
|
||||||
```
|
```
|
||||||
BusApplication (Singleton)
|
BusApplication.Instance (Singleton)
|
||||||
└── Database[] (kolekcja baz danych)
|
└── Database[] (kolekcja baz danych)
|
||||||
└── Login (uwierzytelniony użytkownik)
|
└── Login (uwierzytelniony użytkownik)
|
||||||
└── Session[] (sesje robocze)
|
└── Session[] (sesje robocze)
|
||||||
└── Module → Table → Row
|
└── Module → Table → Row
|
||||||
```
|
```
|
||||||
|
|
||||||
## BusApplication
|
## Klasa BusApplication
|
||||||
|
|
||||||
Singleton reprezentujący instancję aplikacji ERP. Tworzony podczas inicjalizacji systemu.
|
Singleton reprezentujący instancję aplikacji ERP. Tworzony podczas inicjalizacji systemu.
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ foreach (Database db in BusApplication.Instance)
|
|||||||
| `Is365` | `bool` | `true` = wersja HTML, `false` = wersja okienkowa |
|
| `Is365` | `bool` | `true` = wersja HTML, `false` = wersja okienkowa |
|
||||||
| `this[string]` | `Database` | Indeksator - baza po nazwie |
|
| `this[string]` | `Database` | Indeksator - baza po nazwie |
|
||||||
|
|
||||||
## Database
|
## Klasa Database
|
||||||
|
|
||||||
Abstrakcyjna klasa reprezentująca bazę danych. Konkretne implementacje dla wspieranych silników:
|
Abstrakcyjna klasa reprezentująca bazę danych. Konkretne implementacje dla wspieranych silników:
|
||||||
|
|
||||||
@@ -84,9 +84,9 @@ Login login = db.Login(new LoginParameters
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Login
|
## Klasa Login
|
||||||
|
|
||||||
Obiekt reprezentujący zalogowanego użytkownika. Zarządza sesjami.
|
Obiekt reprezentujący zalogowanego użytkownika. Zarządza sesjami. IDisposable.
|
||||||
|
|
||||||
### Tworzenie
|
### Tworzenie
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ Login login = db.Login(new LoginParameters
|
|||||||
// var ent = login.Entitle; // unikać!
|
// var ent = login.Entitle; // unikać!
|
||||||
|
|
||||||
// ZALECANE: Użyj w konkretnej sesji
|
// ZALECANE: Użyj w konkretnej sesji
|
||||||
using (var session = login.CreateSession(true, false, "Odczyt"))
|
using (var session = login.CreateSession(readOnly: true, config: false, name: "Odczyt"))
|
||||||
{
|
{
|
||||||
var op = session.AuthorizationInfo.Operator;
|
var op = session.AuthorizationInfo.Operator;
|
||||||
Console.WriteLine($"Zalogowany: {op.Name} - {op.FullName}");
|
Console.WriteLine($"Zalogowany: {op.Name} - {op.FullName}");
|
||||||
@@ -153,20 +153,20 @@ var opisDlaSzt = login.ExecuteConfig(configSession =>
|
|||||||
### Sygnatury CreateSession
|
### Sygnatury CreateSession
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public Session CreateSession(bool readOnly, bool config, string name)
|
public Session CreateSession(bool readOnly, bool config, string name) // rekomendowana
|
||||||
public Session CreateSession(bool readOnly, bool config)
|
public Session CreateSession(bool readOnly, bool config)
|
||||||
public Session CreateSession() // readOnly=false, config=false
|
public Session CreateSession() // readOnly=false, config=false
|
||||||
```
|
```
|
||||||
|
|
||||||
## Session
|
## Klasa Session
|
||||||
|
|
||||||
Fundamentalna klasa do zarządzania danymi. **Każda operacja na danych wymaga sesji.**
|
Fundamentalna klasa do zarządzania danymi. **Każda operacja na danych wymaga sesji.** IDisposable.
|
||||||
|
|
||||||
### Tworzenie
|
### Tworzenie
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// ZAWSZE używaj using lub wywołuj Dispose()
|
// ZAWSZE używaj using lub wywołuj Dispose()
|
||||||
using (var session = login.CreateSession(false, false, "MojaSesja"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "MojaSesja"))
|
||||||
{
|
{
|
||||||
// operacje na danych
|
// operacje na danych
|
||||||
session.Save();
|
session.Save();
|
||||||
@@ -218,8 +218,8 @@ session.Save();
|
|||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// Normalne zjawisko - wiele sesji może współistnieć
|
// Normalne zjawisko - wiele sesji może współistnieć
|
||||||
using (var session1 = login.CreateSession(true, false, "Lista1"))
|
using (var session1 = login.CreateSession(readOnly: true, config: false, name: "Lista1"))
|
||||||
using (var session2 = login.CreateSession(true, false, "Lista2"))
|
using (var session2 = login.CreateSession(readOnly: true, config: false, name: "Lista2"))
|
||||||
{
|
{
|
||||||
// Obie sesje mogą odczytywać te same dane
|
// Obie sesje mogą odczytywać te same dane
|
||||||
var tm1 = session1.GetTowary();
|
var tm1 = session1.GetTowary();
|
||||||
@@ -232,7 +232,7 @@ using (var session2 = login.CreateSession(true, false, "Lista2"))
|
|||||||
**WAŻNE:** Każda zmiana obiektu biznesowego MUSI być w transakcji!
|
**WAŻNE:** Każda zmiana obiektu biznesowego MUSI być w transakcji!
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using (var session = login.CreateSession(false, false, "Edycja"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "Edycja"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
var towar = tm.Towary.WgKodu["KOD001"];
|
var towar = tm.Towary.WgKodu["KOD001"];
|
||||||
@@ -254,7 +254,7 @@ using (var session = login.CreateSession(false, false, "Edycja"))
|
|||||||
### Logout(editMode: false) - transakcja tylko do odczytu
|
### Logout(editMode: false) - transakcja tylko do odczytu
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using (var session = login.CreateSession(false, false, "Przeglad"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "Przeglad"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
var towar = tm.Towary.WgKodu["KOD001"];
|
var towar = tm.Towary.WgKodu["KOD001"];
|
||||||
@@ -305,7 +305,7 @@ Login login = db.Login(new LoginParameters
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 4. Utworzenie sesji (zawsze z nazwą!)
|
// 4. Utworzenie sesji (zawsze z nazwą!)
|
||||||
using (var session = login.CreateSession(false, false, "Import"))
|
using (var session = login.CreateSession(readOnly: false, config: false, name: "Import"))
|
||||||
{
|
{
|
||||||
// 5. Pobranie modułu (extension method)
|
// 5. Pobranie modułu (extension method)
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
@@ -342,7 +342,7 @@ using (var session = login.CreateSession(false, false, "Import"))
|
|||||||
Login sharedLogin = db.Login(new LoginParameters { UserName = "admin", UserPassword = "haslo" });
|
Login sharedLogin = db.Login(new LoginParameters { UserName = "admin", UserPassword = "haslo" });
|
||||||
|
|
||||||
Parallel.ForEach(items, item => {
|
Parallel.ForEach(items, item => {
|
||||||
using (var session = sharedLogin.CreateSession(false, false, "Watek"))
|
using (var session = sharedLogin.CreateSession(readOnly: false, config: false, name: "Watek"))
|
||||||
{
|
{
|
||||||
var tm = session.GetTowary();
|
var tm = session.GetTowary();
|
||||||
using (var transaction = session.Logout(editMode: true))
|
using (var transaction = session.Logout(editMode: true))
|
||||||
@@ -354,13 +354,3 @@ Parallel.ForEach(items, item => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sesja bez interfejsu graficznego
|
|
||||||
|
|
||||||
Sesja działa w warstwie logiki biznesowej - **nie wymaga UI**.
|
|
||||||
|
|
||||||
Przykłady użycia bez interfejsu:
|
|
||||||
- **Harmonogram Zadań** - usługa Windows wykonująca operacje bazodanowe
|
|
||||||
- **Importy danych** - procesy wsadowe
|
|
||||||
- **Testy jednostkowe** - automatyczne testy logiki
|
|
||||||
- **API REST** - obsługa żądań HTTP
|
|
||||||
Reference in New Issue
Block a user