Skocz do zawartości

[Sfera zdarzeniowa] Reakcja na zmianę pola własnego zaawansowanego, w dokumencie


Zobacz rozwiązanie Rozwiązane przez Radomił Ząbik,

Polecane posty

Chciałbym po zmianie wartości w polu własnym zaawansowanym, wywołać czynności kontrolujące z udziałem innych danych w dokumencie. Niestety nie mogę namierzyć, jak wykryć zmianę w konkretnym polu.

Próbowałem od strony Dokumentu (ale tu podejrzewałem, że nie zadziała:

public override void PoZmianieWlasciwosciObiektu(IKontekstZdarzeniaPoZmianieWlasciwosciObiektu<IDokument> kontekst)
{
if (kontekst.NazwaWlasciwosci.Equals(nameof(PolaWlasneDokumentZK_Adv2.B19)) && kontekst.Dane is DokumentZK zk && (kontekst.StanObiektu == StanObiektu.Dodawany || kontekst.StanObiektu == StanObiektu.Poprawiany))Debug.WriteLine(zk.NumerWewnetrzny.PelnaSygnatura);
}

Myślałem, ze można też dostać się od strony pól własnych, ale tutaj nie znalazłem odpowiedniego interfejsu, który by współpracował z kontekstem.

Link to postu

Proszę rzucić okiem na przykład w SDK: $SDK\Przyklady\SferaZdarzeniowa\ObslugaLogistyki\Walidacja\WymagalnoscSamochoduDostawczegoPlugin.cs gdzie jest zaimplementowana wymagalność wybranego pola własnego (w tym przypadku słownikowego). Pana kod w zasadzie wydaje się być ok, ale z tego co pamiętam to przy zmianie pola własnego w IKontekst...Dane przychodzi encja pól własnych, a nie całego dokumentu więc tutaj jest problem. Aczkolwiek w wyżej wspomnianym przykładzie zaimplementowane jest to bez ustawiania w kodzie identyfikatora pola własnego na sztywno.

  • Lubię to 1
Link to postu

Jeszcze się tylko upewnię - takie zdefiniowanie zmiennej nie wycieknie z bieżącego okna dokumentu - chodzi o to, że jakby użytkownik odpalił wiele okien tworzenia dokumentu, to nie będzie wzajemnie nadpisywać jej wartości? Tylko się upewniam, odnośnie działania Sfery Zdarzeniowej.

public class FajnaWtyczka : KlientSferyZdarzeniowej<IDokument>
{
private bool? zmiennaLogiczna = null;
public override void PrzedZmianaWlasciwosciObiektu(IKontekstZdarzeniaPrzedZmianaWlasciwosciObiektu<IDokument> kontekst) {}
public override void PoZmianieWlasciwosciObiektu(IKontekstZdarzeniaPoZmianieWlasciwosciObiektu<IDokument> kontekst) {}
}

 

Link to postu
26 minut temu, Radomił Ząbik napisał:

chodzi o to, że jakby użytkownik odpalił wiele okien tworzenia dokumentu, to nie będzie wzajemnie nadpisywać jej wartości?

Oczywiście gdyby znalazł się taki magik, który jedną myszką potrafi kliknąć jednocześnie w dwa różne checkboxy to oczywiście dałoby się osiągnąć taki efekt z interfejsu użytkownika 😀 Jednak oczywiście wyobrażam sobie taką sytuację gdzie rozwiązanie sferyczne wykonuje pewne operacje wielowątkowo i setter danego pola jest wywoływany jednocześnie dla dwóch różnych encji. Wtedy faktycznie flow mógłby być taki:

PrzedZmianaWlasciwosciObiektu dla encji nr 1

PrzedZmianaWlasciwosciObiektu dla encji nr 2

PoZmianieWlasciwosciObiektu dla encji nr 1

PoZmianieWlasciwosciObiektu dla encji nr 2

Wtedy rzeczywiście oba wywołania PoZmianieWlasciwosciObiektu korzystałyby z wartości zapamiętanej z encji nr 2. Jednakże można się przed tym zabezpieczyć zapisując wartości przed zmianą nie w postaci prostego pola, a słownika, w którym jako klucz byłby np. hash (GetHashCode) modyfikowanej encji, a wartością - wartość przed zmianą pola encji o danym hash'u.

W przykładach do sfery zdarzeniowej jest kod realizujący ustawianie czerwonej flagi po edycji zapisu VAT z okresu objętego deklaracją VAT ($SDK\Przyklady\SferaZdarzeniowa\SferaZdarzeniowaPrzyklady\Ksiegowosc\UstawienieFlagiPoEdycjiZapisuVATZOkresuObjetegoDeklaracjaVAT.cs). Co prawda tam akurat słownik jako klucz przyjmuje identyfikator obiektu (gdyż reakcja jest na zapis obiektu) zamiast jego hash'a jednak idea jest taka sama. W przypadku reakcji na zmianę pola lepiej jest skorzystać właśnie z GetHashCode gdyż identyfikator może jeszcze nie być nadany gdy obiekt jeszcze nie został zapisany.

  • Lubię to 1
Link to postu
  • Rozwiązanie
24 minuty temu, Wojciech Szopiński napisał:

Oczywiście gdyby znalazł się taki magik, który jedną myszką potrafi kliknąć jednocześnie w dwa różne checkboxy to oczywiście dałoby się osiągnąć taki efekt z interfejsu użytkownika

Wieży mi Pan, pod jakiś 20 latach w zawodzie, tak, tacy magicy są się w stanie pojawić :D

 

To teraz dla potomnych, kod uwzględniający rozwiązania problemów z wątku:

- przyznam się bez bicia, nie chciało mi się rozgryzać/szukać sposobu na znalezienie klucza pola własnego, po nazwie, bo rozwiązanie, które pisze, jest bardzo indywidualne

private IDictionary<int, bool?> poprzedniaWartosc = new Dictionary<int, bool?>();
public override void PrzedZmianaWlasciwosciObiektu(IKontekstZdarzeniaPrzedZmianaWlasciwosciObiektu<IDokument> kontekst)
  {
  Dokument dokument = kontekst.ObiektBiznesowy.Dokument;					
  if (kontekst.NazwaWlasciwosci == "B19") // reagujemy na zmianę określonego pola
	{
	var zkPW = kontekst.Uchwyt.PodajObiektTypu<IPolaWlasneAdv2AccessorFactory>().Utworz(dokument, true); // dostajemy się do pól własnych
	poprzedniaWartosc.Add(dokument.GetHashCode(), zkPW.PobierzWartoscTypuLogicznego("Pole własne")); // rejestrujemy wartość poprzednia
	}
  }
public override void PoZmianieWlasciwosciObiektu(IKontekstZdarzeniaPoZmianieWlasciwosciObiektu<IDokument> kontekst)
  {
  Dokument dokument = kontekst.ObiektBiznesowy.Dokument;
  
  if (kontekst.NazwaWlasciwosci == "B19")
	{
    var zkPW = kontekst.Uchwyt.PodajObiektTypu<IPolaWlasneAdv2AccessorFactory>().Utworz(dokument, true);
	bool? poleWlasne = zkPW.PobierzWartoscTypuLogicznego("Pole własne");
	if (poprzedniaWartosc[dokument.GetHashCode()] != poleWlasne && poleWlasne == false)
	  {
	  // wykonujemy czynność, tylko gdy nasze pole jest odznaczone, a wcześniej było w innym stanie
	  }
	else {}
	poprzedniaWartosc.Remove(dokument.GetHashCode()); // kasujemy naszą wartość poprzednią, bo nie jest nam już potrzebna
	}
}

 

Link to postu

Panie Wojtku, jeszcze naciągnę na jedną podpowiedź :)

Czemu w rozwinięciu powyższego kodu, metoda DodajOstrzezenie działa, a metoda DodajBlad nie? Wcześniej jako obiekt wskazywałem pozycja i zachowanie było analogiczne.

foreach(var pozycja in dokument.Pozycje)
{
kontekst.UsunWszystkieBledyIOstrzezenia(dokument, "pozycja" + pozycja.GetHashCode());
if(warunek==true) kontekst.DodajBlad("Błąd.", dokument, "pozycja" + pozycja.GetHashCode());
else kontekst.DodajOstrzezenie("Ostrzeżenie.", dokument, "pozycja" + pozycja.GetHashCode());
}

 

Link to postu
  • 2 miesiące temu...

Witam, ja mam problem z zapisem wartości do pola własnego w dokumencie. Wartość jak najbardziej pobieram. Zapis przechodzi bez błędu ale pole własne się nie zmienia. Co robię źle?

 

                            var dok = sfera.Dokumenty();
                            var flaga = sfera.FlagiWlasne();

                            var encjaDok = dok.Dane.Pierwszy(d => d.Id == zam.ID);
                            IPolaWlasneAdv2Accessor polaWl = sfera.UtworzPolaWlasneAdv2Accessor(encjaDok);

                            bool? smsKieroChecked = polaWl.PobierzWartoscTypuLogicznego("SMSKierowca");
                            bool? smsKlientChecked = polaWl.PobierzWartoscTypuLogicznego("SMSKlient");
                            polaWl.UstawWartoscTypuLogicznego("SMSKierowca", true);
                            polaWl.UstawWartoscTypuLogicznego("SMSKlient", true);

 

Link to postu

To nie jest w sferze zdarzeniowej. Osobna aplikacja do wysyłki SMS. w polach własnych mam status wysyłki. Przez pośpiech wstawiłem tutaj mój problem ale to chyba zły wątek (nieważne). Ogólnie robię tak jak pokazuje SDK 

 

using (var sfera = UruchomSfere())
{
    var asortymenty = sfera.Asortymenty();
    var asortyment = asortymenty.Znajdz("T1");

    var asoPW2Accessor = sfera.UtworzPolaWlasneAdv2Accessor(asortyment.Dane);

    bool? pzBool = asoPW2Accessor.PobierzWartoscTypuLogicznego("pz bool"); //odczyt
    asoPW2Accessor.UstawWartoscTypuLogicznego("pz bool", true); //zapis
}

Tylko w sdk jest akurat przypisanie do towaru, ja mam dokument. 

Link to postu

Na którym fragmencie dokumentacji się Pan wzorował?

Ogólnie to nie ma prawa zadziałać gdyż pobiera Pan encję dokumentu z bazy, która jest tylko do odczytu i sama z siebie nie potrafi wykonać edycji. Żeby wykonać edycję obiektu przez sferę trzeba utworzyć obiekt biznesowy odpowiedniego typu, który jest odpowiedzialny za edycję danych oraz po wykonaniu modyfikacji go zapisać. W Pana przypadku powinno to wyglądać mniej więcej tak:
 

// najlepiej jest korzystać z menedżerów dla konkretnych typów dokumentów
// np. tutaj zamówienia od klientów:
var dok = sfera.ZamowieniaOdKlientow();
var flaga = sfera.FlagiWlasne();
var encjaDok = dok.Dane.Pierwszy(d => d.Id == zam.ID);
// otwieramy obiekt biznesowy zamówienia do edycji
using (IZamowienieOdKlienta obiektZamowienia = dok.Znajdz(encjaDok))
{
	// tworzymy accessor pól własnych dla edytowanej encji zamówienia:
    IPolaWlasneAdv2Accessor polaWl = sfera.UtworzPolaWlasneAdv2Accessor(obiektZamowienia.Dane);
    bool? smsKieroChecked = polaWl.PobierzWartoscTypuLogicznego("SMSKierowca");
    bool? smsKlientChecked = polaWl.PobierzWartoscTypuLogicznego("SMSKlient");
    polaWl.UstawWartoscTypuLogicznego("SMSKierowca", true);
    polaWl.UstawWartoscTypuLogicznego("SMSKlient", true);
    if (!obiektZamowienia.Zapisz())
    	obiektZamowienia.WypiszBledy();
}

Opis metody "WypiszBledy" znajduje się w dokumentacji SDK w dziale Pierwsze kroki / Walidacja, błędy i ostrzeżenia.

Edytowane przez Wojciech Szopiński
  • Lubię to 2
Link to postu
×
×
  • Dodaj nową pozycję...