Skocz do zawartości

Wojciech Szopiński

InsERT
  • Liczba zawartości

    1 568
  • Rejestracja

  • Ostatnia wizyta

  • Wygrane w rankingu

    14

Zawartość dodana przez Wojciech Szopiński

  1. Problemem w Pana kodzie jest prawdopodobnie ta linia: parametryGrupowania.MetodaWyliczeniaCen = MetodaWyliczeniaCen.Brak; Powoduje ona, że ceny nie są w ogóle przepisywane z dokumentu realizującego i program wstawia tam po prostu aktualne ceny z cennika. Proszę zmienić ją na: parametryGrupowania.MetodaWyliczeniaCen = MetodaWyliczeniaCen.BezKonsolidacji; W zasadzie w przypadku braku konsolidacji pozycji: parametryGrupowania.MetodaGrupowaniaPozycji = MetodaGrupowaniaPozycji.BezKonsolidacji; Nie ma większego znaczenia, która metoda wyliczania cen zostanie ustawiona w parametrach grupowania - istotne jest żeby nie był to Brak. Inne metody wyliczania cen mają znaczenie gdy stosujemy konsolidację pozycji.
  2. Domniemam, że rozwiązanie jest uruchamiane poprzez skopiowanie zawartości sdk do katalogu z rozwiązaniem własnym, a nie poprzez wgranie go do binariów podmiotu. Jeśli tak to czy wspomniany plik jest faktycznie skopiowany do katalogu z rozwiązaniem? Plik wnf.pak zawiera wzorce dla wydruków niefskalnych - czy domyślnym wzorcem jest w tym przypadku wzorzec niefiskalny?
  3. Faktura wystawiona w konfiguracji własnego typu dokumentu ma dokładnie te same funkcjonalności co faktura wystawiona na podstawie typu wbudowanego. Innymi słowy - faktura z własnym typem dokumentu to dalej faktura. Tak. Należy skorzystać z menedżera IKonfiguracje: IKonfiguracje konfiguracje; IEnumerable<Konfiguracja> dostepneTypyDokumentow = konfiguracje .Dane .Wszystkie() .Where(k => k.Domyslna || k.KonfiguracjaBazowaId.HasValue) .ToArray(); Krótkie wyjaśnienie powyższego kodu: Konfiguracje wbudowane w program są oznaczone flagą "Domyslna = 1". Modyfikacja konfiguracji wbudowanej polega na utworzeniu jej kopii z symbolem konfiguracji wbudowanej poprzedzonym znakiem podkreślenia oraz identyfikatorem konfiguracji wbudowanej w polu KonfiguracjaDomyslna_Id. Jest to mechanizm, który pozwala na wprowadzanie zmian w ustawieniach konfiguracji wbudowanych tak aby zachować zmiany wprowadzone przez użytkownika. Konfiguracje własne (własne typy dokumentów) są tworzone zawsze na podstawie jakiejś konfiguracji wbudowanej i mają jej identyfikator wpisany w polu KonfiguracjaBazowaId. Wszystko jest w tabeli ModelDanychContainer.Konfiguracje.
  4. Mimo wszystko jeszcze będę dopytywał - chodzi o wpisanie numeru całkowicie "z ręki" z pominięciem mechanizmu numeracji czy może chodzi o zmianę definicji numeracji "w trakcie wystawiania/edycji dokumentu"? Nie ma natywnego wsparcia dla obu przypadków, ale można się posiłkować pewnymi obejściami. W przypadku chęci wpisania numeru "z ręki" to nie ma możliwości zrobienia czegoś takiego: IDokumentSprzedazy dokument = ...; //... dokument.Dane.NumerWewnetrzny.PelnaSygnatura = "mój nowy numer"; Gdyż pole PelnaSygnatura jest generowane przez mechanizm numeracji i to spowoduje błąd. Można ten numer "ręczny" umieścić w polu własnym dokumentu lub w innym polu, które nie jest wykorzystywane - np. uwagi, podtytuł. Można również sferycznie wpisać go do istniejącego pola na dokumencie NumerZewnetrzny i od wersji 50 będzie można takie pole wyświetlić jako własną kolumnę w widoku dokumentów. Niestety ze względu na to, że dokumenty wystawiane przez użytkownika (w odróżnieniu od dokumentów wprowadzanych z zewnątrz takie jak faktury zakupu) nie mają natywnej obsługi pola NumerZewnetrzny więc nie będzie ono widoczne na formatce dokumentu. Jeśli chodzi o zmianę definicji numeracji w trakcie wystawiania bądź też jak Pan napisał: To również wprost się nie da gdyż konfiguracja musi być ustawiona raz na początku wystawiania dokumentu co powoduje, że dokument inicjalizuje się odpowiednimi parametrami - w tym też używaną definicją numeracji. Można skorzystać z własnych typów dokumentów i zdefiniować sobie osobny typ z inną definicją numeracji. Jeśli w Pana aplikacji zajdzie potrzeba zmiany typu dokumentu w trakcie jego wystawiania można po prostu zapamiętać dane wypełnione na dodawanym dokumencie (klient, pozycje etc), porzucić jego dodawanie (Dispose()) i dodać go od nowa w wybranej konfiguracji wypełniając go uprzednio zapamiętanymi danymi.
  5. Chodzi o podmianę domyślnej numeracji w parametrach czy podmianę numeracji w trakcie dodawania/edycji obiektu (dokumentu)?
  6. Jak sam Pan zauważył: Tu jak rozumiem chodzi o brak możliwości wprowadzenia danych szczegółowych na ręcznie wpisanym adresie dostawy na dokumencie? Bo inne miejsca wpisywania adresu są wolne od tego typu ograniczeń.
  7. Ogólnie adresy są przechowywane w kilku tabelach. Główny aktualny adres przechowywany jest w tabeli Adresy i jest tam zapisywany w formie liniowej. Każdy adres wpisywany do tabeli adresów jest również zapisywany w formie szczegółowej z podziałem na ulicę, miejscowość etc. w tabeli AdresySzczegoly. Wpisy głównej tabeli adresów są również historiowane (tzn. każda edycja adresu zapisuje nowy wpis historyczny) w tabeli AdresHistorie również w postaci liniowej. Dodatkowo w wersji 32 InsERT nexo zostało dodane historiowanie również adresów w postaci szczegółowej i od tej wersji po edycji adresu powstaje również wpis w AdresSzczegolyHistorie. Powyższy opis dotyczy obiektów, które mają powiązanie z encją typu Adres (tabela Adresy) - są to obiekty takie jak Podmiot, Magazyn, Oddział etc. Teraz przechodząc do obsługi adresów dostawy na dokumentach można rozróżnić dwa przypadki. Adres dostawy może być pobierany z jakiegoś zewnętrznego obiektu w systemie powiązanego z dokumentem (tzn. klienta, magazynu, oddziału etc). Wtedy na dokumencie w polu MiejsceDostawyTyp w tabeli Dokumenty jest ustawiona wartość z typu wyliczeniowego InsERT.Moria.Dokumenty.Logistyka.MiejsceDostawyTyp inna niż Reczny (64), a w polu MiejsceDostawyZewnetrzneId jest wskazanie na odpowiedni wpis historyczny z tabeli AdresHistorie. Zakładając, że mamy do czynienia z obiektem dodawanym w wersji późniejszej niż 32 to od tego wpisu w AdresHistorie można dojść do historycznego wpisu szczegółowego w tabeli AdresSzczegolyHistorie (obiekty dodawane PRZED wersją 32 nie mają wpisu historycznego ze szczegółami). Dodatkowo takie powiązanie adresem dostawy powoduje, że dokument nie może takiego adresu edytować - jest on możliwy do zmodyfikowania tylko poprzez obiekt, którego ten adres dotyczy. Szczególnym przypadkiem adresu dostawy na dokumencie jest adres wpisany ręcznie (MiejsceDostawyTyp = InsERT.Moria.Dokumenty.Logistyka.MiejsceDostawyTyp.Reczny = 64). Wtedy w tabeli Dokumenty w odróżnieniu od powyższego przypadku adresu "zewnętrznego" jest tworzony nowy wpis historyczny w tabeli AdresHistorie, który NIE ma powiązania z głównym adresem (AdresHistorie.Adres_Id IS NULL), a także nie tworzy się dla niego wpis historyczny w tabeli AdresSzczegolyHistorie. Taki adres wpisany ręcznie na dokumencie jest już możliwy do modyfikacji tylko i wyłącznie od strony dokumentu, który go stworzył. Teraz spróbuję odpowiedzieć na postawione przez Pana pytania: Ciężko tutaj powiedzieć jaki jest dokładnie powód takiego stanu rzeczy, ale może mieć na to wpływ to co napisałem wcześniej - obiekty "zewnętrzne" (klient, oddział, magazyn etc), z których został pobrany adres dostawy zostały dodane do nexo PRZED wersją 32 i dla nich po prostu w tej tabeli nie ma odpowiedniego wpisu. W takim przypadku proszę spróbować edytować np. klienta z którego został pobrany adres, zmienić "coś" w adresie, zapisać i wystawić na tego klienta nowy dokument - wpis w AdresSzczegolyHistorie powinien się pojawić. Jeśli nie to będziemy potrzebowali więcej szczegółów do przeanalizowania tego przypadku. To nie zadziała. Dokument z adresem wpisanym ręcznie tworzy jak wspomniałem wcześniej wpis w tabeli AdresHistorie BEZ powiązania z adresem głównym (Adresy) tym samym nie ma możliwości powiązania go z rekordem w AdresSzczegoly. Nie zadziała również sferyczna próba podłączenia do utworzonego na dokumencie adresu dostawy wpisu w AdresSzczegolyHistorie z prostego powodu - dokumenty po prostu nie mają zaimplementowanej obsługi parsowania adresu liniowego na szczegóły.
  8. Numeracja operuje w obrębie jednego "obiektu numerowanego" i nie śledzi zmian w obiektach powiązanych. Powinien zadziałać plugin sfery zdarzeniowej reagujący na zdarzenie po zapisie dokumentu, w którym edytujemy dokumenty automatyczne i korzystając z metody ZarezerwujNumer() wymuszamy nadanie numeru z uwzględnieniem nowego numeru dokumentu nadrzędnego.
  9. A sprawdzał Pan na najnowszej wersji nexo? Ta jest już dość "archiwalna". Jeszcze raz ponawiam prośbę o: Może być w wiadomości prywatnej. Czy w Subiekcie pozycje zamówienia są oznaczone jako częściowo/w całości zrealizowane? Jaki jest stan realizacji takiego zamówienia w Subiekcie? Czy na dokumencie realizującym jest widoczne powiązanie z zamówieniem? Proszę jeszcze podesłać zrzuty ekranu z zamówienia oraz dokumentu realizującego (zakładka podstawowe oraz powiązania).
  10. Rozumiem, że dokładnie to samo rozwiązanie uruchamiane na wersji 36.0.2 po zapisie dokumentu realizującego (jak rozumiem zmienna dok jest dokumentem sprzedaży lub wydaniem zewnętrznym?) powoduje, że na zakładce powiązania w zamówieniu jest widoczny utworzony dokument, a na wersji 38.0.1 już nie? Czy sprawdzał Pan na aktualnej wersji nexo? Jedyne co mi przychodzi do głowy to dalsze operacje na pozycjach - jeśli te pozycje, które zostaną utworzone poprzez WypelnijNaPodstawie zostaną usunięte i później dodamy te same pozycje na nowo to takie zachowanie jest normalne gdyż realizacja opiera się na pozycjach i usuwając pozycje odłączamy dokument realizujący od realizowanego. Czy mógłby Pan podesłać większy kawałek kodu?
  11. Jeśli chce Pan zachować "procent" płatności przy przewalutowywaniu dokumentu wystarczy przed zmianą waluty ustawić odpowiedni tryb przeliczania: using (IZamowienieOdKlienta zamowienie = zamowienia.Znajdz(...)) { zamowienie.Platnosci.TrybPrzeliczania |= TrybPrzeliczaniaPlatnosci.PrzeliczanieWgProcentu; // zmiana waluty } Warto jednak wspomnieć, że w przypadku gdy zmienia Pan walutę na dokumencie z już dodanymi pozycjami to samo ustawianie jej tak jak to zostało opisane w przytoczonym wątku może być niewystarczające gdyż wtedy NIE zostaną przeliczone odpowiednio ceny na pozycjach więc będziemy mieli "pomieszane różne systemy walutowe". Można wtedy skorzystać z metody Przewalutuj, która przelicza również odpowiednio ceny na pozycjach: ILinieKursowWalut linieKursow = sfera.LinieKursowWalut(); var linia = linieKursow.Dane.Wszystkie().Where(...).FirstOrDefault(); using (IZamowienieOdKlienta zamowienie = zamowienia.Znajdz(...)) { Waluta usd = sfera.Waluty().DaneDomyslne.USD; Waluta pln = waluty.DaneDomyslne.PLN; zamowienie.Platnosci.TrybPrzeliczania |= TrybPrzeliczaniaPlatnosci.PrzeliczanieWgProcentu; zamowienie.ObslugaWaluty.Przewalutuj( // ustawiana waluta: usd // wybrana linia kursów walut: , linia // kurs na wybrany dzień: , linieKursow.Dane.PobierzKursNaDzien(linia, usd, pln, zamowienie.Dane.DataWprowadzenia) , true , null , null); if (!zamowienie.Zapisz()) zamowienie.WypiszBledy(); }
  12. Można dodać szablon "na podstawie asortymentu wzorcowego":
  13. Najlepiej jest skorzystać z szablonów projektów dla Visual Studio. Proszę spojrzeć do dokumentacji SDK w sekcji Pierwsze kroki -> Szablony projektów dla Visual Studio gdzie opisana jest instalacja szablonów. Kompilując projekt utworzony na bazie jednego z szablonów (tutaj najlepiej wybrać oczywiście szablon "Sfera zdarzeniowa") jest tworzony automatycznie instalator rozwiązania, którym można łatwo wdrożyć swoje rozwiązanie na bazie nexo.
  14. Idea jest ok, ale kilka rzeczy trzeba dociągnąć 1. Przy reagowaniu na zmiany własności jakiegoś obiektu warto określić, że chcemy reagować tylko na zmianę tego co nas interesuje. W powyższym kodzie nawet zmieniając nazwę, opis czy uwagi będzie się uruchamiała Pana procedura. Można wtedy skorzystać z IKontekstCzegośTamWSferzeZdarzeniowej.NazwaWlasnosci mniej więcej tak: if (PoleWlasneSkrotGrupyIstnieje(kontekst.Uchwyt) && kontekst.Dane is Asortyment asortyment // wykonujemy kod TYLKO gdy zmieniła się grupa && kontekst.NazwaWlasciwosci == nameof(Asortyment.Grupa)) { //... } 2. Do funkcji StworzSkrotGrupy próbuje Pan podać identyfikator grupy. Już pomijając fakt, że encja Asortyment nie posiada własności Grupa_Id zakładam, że chce Pan tam podać NAZWĘ grupy żeby z niej wyciągnąć trzy pierwsze znaki. Wtedy po prostu przechodząc od asortymentu do ustawionej grupy pobieramy jej nazwę: asortyment.PolaWlasneAdv2.Set(ALIAS_POLA_WLASNEGO, StworzSkrotGrupy(asortyment.Grupa?.Nazwa)); Małe wyjaśnienie odnośnie tego "pytajnika" - grupa może NIE być ustawiona wtedy własność asortyment.Grupa zwróci null co jest prostą drogą do ulubionego wyjątku programistów C# - odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu. Ten znak zapytania zabezpiecza nas przed tym i jeśli to co jest przed nim jest null'em to całe wyrażenie również zwraca null. Oczywiście można to też zapisać jawnie: asortyment.PolaWlasneAdv2.Set(ALIAS_POLA_WLASNEGO, StworzSkrotGrupy(asortyment.Grupa == null ? null : asortyment.Grupa.Nazwa)); 3. Tutaj: if (String.IsNullOrWhiteSpace(skrotgrupy) brakuje nawiasu na końcu przez co kod się nie skompiluje. Dodatkowo piętro niżej zwraca Pan null - lepiej zwrócić pusty ciąg znaków ("" lub string.Empty). Poza tym powinno być OK.
  15. "Szukajcie, a znajdziecie" Ale niestety nie w tym przypadku... Będzie zrealizowane tak jak dla innych "realizacji". Trochę tak, ale pod "zleceniem serwisowym" i tak powstaje rekord w tabeli dokumentów z pozycjami.
  16. Potwierdzam, zapisałem do uzupełnienia. A tu proszę o rozjaśnienie - o co dokładnie chodzi?
  17. W nexo zaliczka dokumentu jest zawsze rozpisywana na pozycje i do obsługi tej procedury służy obiekt implementujący interfejs IFunkcjaRozdzielajacaZaliczkeNaPozycje. W nexo wbudowane są trzy algorytmy rozdzielania zaliczki na pozycje (proporcjonalnie, kolejno wg pozycji i kolejno wg stawki). Na dokumencie zaliczkowym wybrany algorytm rozdzielania określany jest w polu IDokumentSprzedazy.Dane.AspektZaliczki.FunkcjaRozdzielajacaZaliczke i podawany jest tam identyfikator (Guid) wybranej funkcji (domyślnie zawsze jest to algorytm proporcjonalny o identyfikatorze FF809F2F-8136-44DC-A088-46C1FFBA114D). Wszystkie funkcje można przeglądać i "powoływać do życia" przy pomocy obiektu implementującego interfejs IFabrykaFunkcjiRozdzielajacychZaliczkeNaPozycje, który to można pobrać "legalnie" z uchwytu do sfery. Kod mógłby więc wyglądać mniej więcej tak: using (IDokumentSprzedazy zaliczka = dokumentySprzedazy.UtworzFaktureZaliczkowa()) { IFabrykaFunkcjiRozdzielajacychZaliczkeNaPozycje fabrykaFunkcjiRozdzielajacychZaliczke = sfera.PodajObiektTypu<IFabrykaFunkcjiRozdzielajacychZaliczkeNaPozycje>(); zaliczka.PodmiotyDokumentu.UstawNabywceWedlugNIP("8945986588"); zaliczka.Pozycje.Dodaj("DZSO20", 10m).Cena.BruttoPoRabacie = 10m; zaliczka.Pozycje.Dodaj("POYAR01", 10m).Cena.BruttoPoRabacie = 10m; zaliczka.Dane.AspektZaliczki.Zaliczka = 100m; zaliczka.Dane.AspektZaliczki.FunkcjaRozdzielajacaZaliczke = new Guid("FF809F2F-8136-44DC-A088-46C1FFBA114D"); zaliczka.Dane.Uwagi = "proporcjonalnie - wywołane ręcznie"; if (fabrykaFunkcjiRozdzielajacychZaliczke.SprobujZnalezc(zaliczka.Dane.AspektZaliczki.FunkcjaRozdzielajacaZaliczke.Value, out IFunkcjaRozdzielajacaZaliczkeNaPozycje funkcja)) funkcja.RozdzielZaliczke(zaliczka.Dane); else throw new InvalidOperationException("Niepoprawny identyfikator funkcji rozdzielającej zaliczkę."); zaliczka.Platnosci.DodajDomyslnaPlatnoscNatychmiastowaNaKwoteDokumentu(); if (!zaliczka.Zapisz()) throw new InvalidOperationException("Nie udało się zapisać zaliczki częściowej."); } Dodam jeszcze, że do wersji wiosennej mamy w planach usprawnienie pewnych aspektów tego tematu. Identyfikatory wbudowanych funkcji rozdzielających zaliczkę będzie można uzyskać ze statycznej klasy, a samo wywoływanie algorytmu rozpisywania będzie możliwe od strony obiektu biznesowego dokumentu sprzedaży (IDokumentSprzedazy) bez konieczności powoływania do życia we własnym kodzie fabryki funkcji. Warto również wspomnieć o tym, że można również implementować własne algorytmy rozpisywania zaliczki na pozycji i wdrażać do nexo w postaci plugina.
  18. Przeglądanie błędów obiektu zrealizowane zgodnie z dokumentacją SDK pozwala również na pokazanie encji oraz pola, na którym dany błąd wystąpił. W tym przypadku jest to pole "Dokument.IdentyfikatorPodatkowyKlienta", które odpowiada tej kontrolce na formatce dokumentu: Z jakiegoś powodu jest ono u Pana puste (null). Doraźnie można je ustawić tak: IDokumentSprzedazy faktura; //... faktura.Dane.IdentyfikatorPodatkowyKlienta = (byte)RodzajIdentyfikatoraPodatkowegoKlienta.NIP; //lub: faktura.Dane.IdentyfikatorPodatkowyKlienta = (byte)RodzajIdentyfikatoraPodatkowegoKlienta.NIPUE; Jednakże nie jestem w stanie bez obejrzenia większego kawałka kodu stwierdzić dlaczego u Pana tak się dzieje. To jest tylko ostrzeżenie, które nie blokuje zapisu dokumentu więc jeśli zapis faktury nie powiódł się to oznacza, że są tam jeszcze jakieś inne błędy. Proszę spróbować zrealizować wypisywanie błędów zapisu tak jak zostało to opisane w dokumentacji (Pierwsze kroki --> Walidacja, błędy i ostrzeżenia) i wtedy będzie widać co w rzeczywistości blokuje zapis.
  19. Wbrew pozorom ma swoje zalety - dzięki takiemu podejściu można z wyjątku wyczytać kto i na jakim stanowisku dany obiekt zablokował więc można przekazać użytkownikowi istotne informacje. Sami tak robimy w nexo dzięki czemu nexo zamiast informować o tym, że "Nie można zablokować podanego zasobu" pokazuje informację o tym, że "Obiekt został zablokowany na stacji X przez operatora Y". Wywołanie Zablokuj() musi wystąpić przed pierwszą edycją czegokolwiek na obiekcie gdyż modyfikacja jakiegokolwiek pola będzie próbowała tę blokadę nałożyć co skończy się wyjątkiem. Cytat z dokumentacji: Pole Zablokowany tej encji określa, że dokument jest zablokowany przed edycją. To w ogóle nie ma związku z blokadami aplikacyjnymi.
  20. Można oczywiście wyłapywać wyjątki pojawiające się przy próbie edycji zablokowanego obiektu: using (IDokumentSprzedazy dokumentSprzedazy = dokumentySprzedazy.Znajdz(dokument)) { try { dokumentSprzedazy.Dane.Uwagi = "zmieniam uwagi!!!"; } catch (InsERT.Mox.Locking.AppLockNotAcquiredException e) { Console.WriteLine($"Dokument {dokumentSprzedazy.Dane.NumerWewnetrzny.PelnaSygnatura} " + $"zablokowany na stacji {e.OwningWorkstationName} " + $"przez użytkownika o Id: {e.OwningUserId}"); } } Ale we wszystkich obiektach biznesowych istnieje też metoda Zablokuj(), która nakłada blokadę aplikacyjną na dany obiekt i jeśli się to nie uda (czyli obiekt został zablokowany na innym stanowisku) - zwraca false: using (IDokumentSprzedazy dokumentSprzedazy = dokumentySprzedazy.Znajdz(dokument)) { if (dokumentSprzedazy.Zablokuj()) { Console.WriteLine("Zablokowano - możemy działać."); } else { Console.WriteLine("Nie zablokowano - trzeba poczekać."); } }
  21. Można po prostu sprawdzić czy encja dokumentu jest określonego typu: w => w is DokumentDZ // dokument zakupu || w is DokumentDS // dokument sprzedaży || w is DokumentKDS // korekta dokumentu sprzedaży
  22. Proszę skopiować plik Xml.pak do katalogu z binariami rozwiązania.
×
×
  • Dodaj nową pozycję...