5.2 KiB
5.2 KiB
CRM01 — Wyszukiwanie i identyfikacja
Wspólne fakty o typie, podstawowe typy i szablon wzorca: ../crm.md.
CRM-W1 — Wyszukiwanie kontrahenta
Cel: odnaleźć istniejącego kontrahenta po wybranym kluczu, zanim zaczniemy go modyfikować lub zanim utworzymy nowy rekord.
Warianty:
| Wariant | Klucz | Uwaga |
|---|---|---|
| Po kodzie | Kod |
indeks WgKodu, klucz unikalny — zwraca pojedynczy rekord |
| Po nazwie / fragmencie | Nazwa |
indeks WgNazwy (nieunikalny) lub SubTable[pattern] |
| Po NIP / EU VAT | NIP, EuVAT |
normalizacja: Nip.Flat / EuVat.Flat przed porównaniem |
| Po adresie | Adres.* |
miejscowość, kod pocztowy, ulica |
| Po PESEL / REGON / KRS | PESEL, REGON, KRS |
osoby fizyczne / podmioty |
| Dedup przed dodaniem | NIP |
sprawdzenie, czy podmiot już istnieje |
| Kontrahent incydentalny | JestIncydentalny |
systemowy rekord (Kontrahent.INCYDENTALNY) |
Pola i typy: Kod: string, NIP: string, EuVAT: string, Nazwa: string,
Adres: Soneta.Core.Adres, PESEL/REGON/KRS: string, JestIncydentalny: bool.
Snippet:
var crm = session.GetCRM();
// 1. Po kodzie — klucz unikalny, zwraca pojedynczy rekord lub null
Kontrahent poKodzie = crm.Kontrahenci.WgKodu["ABC"];
// 2. Po nazwie — indeks nieunikalny, zwraca zbiór; bierzemy pierwszy
Kontrahent poNazwie = crm.Kontrahenci.WgNazwy["Firma XYZ"].FirstOrDefault();
// 3. Po NIP — filtr serwerowy; warunek aplikujemy na indeksie. Porównania tekstowe są case-insensitive
var nip = Nip.Flat("123-456-32-18"); // usuwa myślniki
Kontrahent poNip = crm.Kontrahenci.WgNIP[(Kontrahent k) => k.NIP == nip].FirstOrDefault();
// 4. Po fragmencie nazwy / mieście — serwerowy LIKE (warunek na indeksie WgNazwy)
foreach (Kontrahent k in crm.Kontrahenci.WgNazwy[(Kontrahent k) =>
k.Nazwa.Contains("bud") && k.Adres.Miejscowosc == "Kraków"])
{
// ...
}
// 5. Dedup przed dodaniem nowego kontrahenta
bool juzIstnieje = crm.Kontrahenci.WgNIP[(Kontrahent k) => k.NIP == nip].Any();
Pułapki:
WgKodu[...]zwraca pojedynczy rekord (klucz unikalny) — może byćnull.WgNazwy[...]zwraca zbiór (klucz nieunikalny), trzeba.FirstOrDefault()/iterację.- Nie iteruj całej tabeli
Kontrahencizifw pamięci — to tabela kartotekowa (rośnie z biznesem). Filtruj przez warunek aplikowany na indeksie, np.crm.Kontrahenci.WgKodu[(Kontrahent k) => …](warunek wykonywany przez SQL). Indeksator samej tabeli (crm.Kontrahenci[…]) służy do dostępu poID/kluczu, nie przyjmuje wyrażenia LINQ. Patrzrowcondition.mdisafe-code.md§6. - W
RowCondition(wyrażeniu LINQ) wolno użyć tylko pól bazodanowych.NazwaFormatowana,KodKraju,Platniksą kalkulowane → rzucąLinqConditionException. - Porównania tekstowe w warunku są case-insensitive — nie dubluj
ToLower(). - Przed porównaniem NIP/EU VAT normalizuj wejście (
Nip.Flat,EuVat.Flat), bo w bazie bywają formaty z myślnikami i bez.
CRM-W2 — Walidacja NIP / REGON / EU VAT
Cel: sprawdzić poprawność NIP/REGON (suma kontrolna) i EU VAT (format/kraj) przed zapisem, niezależnie od weryfikacji online (CRM-W15).
Warianty:
| Wariant | Wejście | Metoda publiczna |
|---|---|---|
| NIP krajowy | 10 cyfr lub DDD-DDD-DD-DD |
Soneta.Core.Nip.Test(string) |
| REGON 9/14 | 9 lub 14 cyfr | Soneta.Core.Regon.Test(string) |
| EU VAT | prefiks kraju + numer | Soneta.Core.EuVat.Test(string, ISessionable) |
| Normalizacja | usunięcie myślników/spacji | Nip.Flat, Nip.Format, EuVat.Flat |
| Rozbicie EU VAT | kraj + numer | EuVat.Split(value, out country, out nip) |
Pola i typy: NIP: string, REGON: string, EuVAT: string. Walidatory są statyczne;
EuVat.Test wymaga ISessionable (sprawdza listę krajów UE w bazie).
Snippet:
// Walidatory rzucają NullReferenceException dla null — najpierw odsiej puste wejście.
if (!nip.IsNullOrEmpty() && Nip.Test(nip)) { /* NIP poprawny */ }
if (!regon.IsNullOrEmpty() && Regon.Test(regon)) { /* REGON poprawny */ }
if (!euVat.IsNullOrEmpty() && EuVat.Test(euVat, session)) { /* EU VAT poprawny */ }
// Rozbicie EU VAT "PL1234563218" -> kraj "PL", numer "1234563218"
EuVat.Split(euVat, out string kodKraju, out string numer);
// Walidacja w event-handlerze zapisu (rzut PRZED Commit/Save):
if (!kontrahent.NIP.IsNullOrEmpty() && !Nip.Test(kontrahent.NIP))
throw new RowException(kontrahent, "Nieprawidłowy NIP".Translate(), nameof(kontrahent.NIP));
Pułapki:
Nip.Test,Regon.Test,EuVat.TestrzucająNullReferenceExceptiondlanull(odwołują się do.Length). Zawsze najpierw sprawdźIsNullOrEmpty.- To walidacja formatu/sumy kontrolnej, a nie weryfikacja w MF/VIES — patrz CRM-W15.
- Komunikaty walidacyjne rzucaj jako
RowException(row, "…".Translate(), nameof(Pole))przedCommit()(safe-code §5.1). Wyjątek poCommit()nie wycofa zmiany z sesji. - Ustawienie
NIP/EuVATna samymKontrahenturuchamia wbudowaną synchronizację (NIP↔EuVAT, auto-zmianaRodzajPodmiotu) — własna walidacja jest dodatkiem, nie zastępstwem.