Weryfikacja zduplikowanych adresów

Wprowadzenie

W systemie adresy są zapisywane w osobnej jednostce. Dzięki temu możliwe jest rozszerzanie atrybutów typu String dostępnych w standardowym systemie i dodawanie nowych. Dodatkowo obsługiwane są kontrole duplikatów i kontrole list wykluczeń.

W artykule wyjaśniono technicznie niezbędne atrybuty jednostki, omówiono podstawowe klasy pomocnicze oraz sposób, w jaki można przeprowadzić kontrolę duplikatów.

Grupa docelowa

  • programiści

Interfejs programistyczny

Model danych

Adresy są przechowywane w jednostce com.cisag.app.general.obj.AddressData. Atrybuty tej jednostki można podzielić na dane użytkowe, takie jak ulica i miejscowość, oraz atrybuty wynikające z wymogów technicznych.

Technicznie niezbędne atrybuty to:

Atrybut Opis
guid Klucz główny.
hashCode Wartość liczbową (hash), wyznaczona na podstawie danych użytkowych, do identyfikacji adresu. Część unikalnego klucza w procedurze HashCode (byPrevious).
previous Odwołanie do poprzedniej instancji o tym samym hashu. Część unikalnego klucza w procedurze HashCode (byPrevious).
next Odwołanie do następnej instancji o tym samym hashu
code Część klucza merytorycznego (byCode)
keyExtension Część klucza merytorycznego (byCode)
backup Flaga rozróżniająca oryginalne adresy od kopii adresów na potrzeby dokumentów

Procedura HashCode używana dla adresów występuje również w innych miejscach w systemie i zapobiega tworzeniu identycznych rekordów danych dla struktur danych bez merytorycznego klucza. Podczas zapisywania adresu, numer jest obliczany na podstawie danych użytkownika przy użyciu funkcji hash. Funkcja hash powinna unikać konfliktu wartości hash jesli tylko to jest możliwe, aby zapewnić wysoką wydajność procesu. Ponieważ mimo to mogą istnieć inne adresy, dla których obliczono ten sam numer, najpierw podejmowana jest próba załadowania takiego adresu przy użyciu unikalnego klucza (byPrevious: hashCode=? + previous=Guid.ZEROGUID). Jeśli adres z tym kluczem zostanie znaleziony, a jego zawartość nie będzie zgodna z zawartością adresu, który ma zostać zapisany, wyszukiwany i sprawdzany jest następny adres, przy czym klucz główny wcześniej znalezionego adresu jest używany jako poprzedni. Jeśli zostanie znaleziony całkowicie identyczny adres, nie jest konieczne zapisywanie adresu; klucz główny istniejącego adresu jest używany jako odniesienie. Jeśli nie znaleziono identycznego adresu, klucz główny ostatniego znalezionego adresu jest wprowadzany z tą samą wartością hash w poprzednim atrybucie nowego adresu i jest on zapisywany.

W standardowym systemie adresy nie są identyfikowane za pomocą unikalnego kodu. Powinno być jednak możliwe zarządzanie adresami za pomocą merytorycznego klucza w ramach adaptacji (dostosowania). Wymagany do tego model danych jest dostępny w standardowym systemie i składa się z dwóch atrybutów code i keyExtension, a także klucza biznesowego byCode (składa się z code + keyExtension). Dla instancji AddressData utworzonych w systemie standardowym atrybut code zawiera pusty ciąg znaków. Aby jednak zapewnić unikalność klucza byCode, klucz główny jest wprowadzany w atrybucie keyExtension. Oznacza to, że klucz jest unikalny, ale nie ma znaczenia dla standardu, ponieważ jego zawartość jest równoważna kluczowi głównemu. Aby klucz mógł być używany jako część adaptacji, atrybut keyExtension musi być wypełniony Guid.ZEROGUID i należy określić unikalny kod do identyfikacji. W takim przypadku klucz byPrevious używany w procedurze hashCode nie może być już stosowany. Atrybut hashCode musi zawierać wartością 0, a atrybut previous musi posiadać wartość klucza głównego.

Jeśli adresy są identyfikowane za pomocą unikalnego kodu, służy to przede wszystkim do zarządzania nimi lub ich zmiany. Zmiana adresów nie może jednak prowadzić do sytuacji, w której przy ponownym wydruku dokumentów, takich jak faktury sprzedażowe, zostanie wydrukowany inny adres niż w momencie generowania dokumentu. Dlatego używanie modyfikowalnych adresów w dokumentach nie jest dozwolone. Modyfikowalny adres musi najpierw zostać przekształcony w adres bez kodu i zapisany przy użyciu procedury HashCode (Snapshot). Tak powstały niezmienny adres może być używany na dokumencie. W wyniku tego procesu powstaje zamierzony duplikat oryginalnego adresu. Aby ułatwić jego wykluczenie w ramach kontroli duplikatów, flaga backup zostaje ustawiona na true.

Klasy pomocnicze

Do wykorzystania adresów dostępne są następujące klasy pomocnicze:

Adres musi być zawsze zapisany przy użyciu klasy HashCodeLogic:

AddressDataAdapter adapter = AddressDataAdapter.getInstance();

byte[] guid = HashCodeLogic.getInstance().save(myAddress, adapter);

myBO.setAddress(guid);
Uwaga
Zmiana i zapisywanie danych użytkownika AddressData bezpośrednio bez użycia klasy HashCodeLogic regularnie prowadzi do nieodwracalnego uszkodzenia danych!

Sprawdzanie duplikatów

Uwagi ogólne

W kolejnych rozdziałach opisano możliwości rozszerzenia o kontrole, takie jak sprawdzanie duplikatów, sprawdzanie na liście wykluczeń lub weryfikacja wystąpienia za pośrednictwem zewnętrznych dostawców (np. poczta) w ramach dostosowań.

Zazwyczaj opisane kontrole nie są wymagane ani pożądane dla wszystkich adresów w systemie. Przykładowo, jeśli w aplikacji Banki zostanie przypisany adres, to ten sam adres powinien móc zostać przypisany także do partnera, jeśli oddział banku ma być traktowany jako np. klient, kontakt. Ponadto kontrola duplikatów lub sprawdzanie listy wykluczeń przy wprowadzaniu danych oddziału banku prawdopodobnie nie jest pożądane.

Przed dostosowaniem należy zdefiniować, w których aplikacjach kontrola ma się odbywać i jakie duplikaty są niepożądane.

W kolejnych rozdziałach przedstawiono kontrole podczas wprowadzania nowego partnera oraz podczas wprowadzania adresu dla pseudopartnera w zamówieniu sprzedaży. Zamiast bezpośredniego sprawdzenia w ramach ogólnych kontroli, weryfikacja istnienia może zostać przeprowadzona także w późniejszym terminie dla wielu nowych adresów jednocześnie.

Dla obiektu biznesowego com.cisag.app.general.obj.AddressData czas utworzenia jest rejestrowany w części updateInfo, co pozwala na łatwe ograniczenie sprawdzania do nowych adresów.

Dodawanie nowego partnera

Po wprowadzeniu nowego partnera adres jest sprawdzany w klasie com.cisag.app.general.partner.log.PartnerBaseValidation. Klasę tę należy również dostosować, jeśli oprócz standardowych kontroli ma zostać przeprowadzona kontrola duplikatów lub podobna. Metoda validateCreate(PartnerBaseData)powinna zostać rozszerzona tak, aby kontrola była przeprowadzana dla wszystkich „prawdziwych” partnerów, tj. pseudo partnerzy i szablony partnerów nie są sprawdzane:

PartnerBaseData base = ...

PartnerValidation pv = PartnerValidation.getInstance();

boolean pseudo = pv.isPseudoPartner(base.getPartnerObject());

boolean template = base.getPartnerEntity().isTemplateMode();

if (!pseudo && !template) {

...

}

Nazwa regularnie wymagana do sprawdzania duplikatów jest określana na podstawie osoby lub organizacji w zależności od typu:

Partner partner = base.getPartnerObject();

if (partner.isHuman()) {

PersonMutable person = partner.getMutablePerson();

String name = person.getSurname();

...

} else {

OrganisizationalUnitMutable ou =

partner.getMutableOrganisationalUnit();

String[] names = ou.getName();

...

}

Jeśli wyłącznie dokładnie takie same adresy mają być rozpoznawane jako duplikaty, można użyć wartości hash wyznaczonej w standardzie do zawężenia zakresu adresów do sprawdzenia. W przeciwnym razie zaleca się wprowadzenie nowego atrybutu do wstępnej selekcji i odpowiednie indeksowanie podobnych adresów za pomocą odpowiedniego algorytmu.

Poniższa metoda określa klucz główny dokładnie takiego samego adresu jako przykład. Zwróconą wartość można następnie wykorzystać m.in. do określenia partnerów, do których przypisany jest potencjalnie już istniejący adres. Jeśli nazwa partnera do sprawdzenia pasuje do nazwy jednego z partnerów określonych w ten sposób, jest to duplikat.

private byte[] findDuplicateCopy(AddressData address) {

AddressDataAdapter adapter = AddressDataAdapter.getInstance();

int hash = adapter.hashCode(data.getAddressData());

byte[] previous = Guid.ZEROGUID;

while(true) {

AddressData temp = (AddressData)

om.getObject(AddressData.buildByPreviousKey(hash, previous));

if (temp == null) return null;

if (!temp.isBackup() && equals(address, temp))

return temp.getGuid();

previous = temp.getGuid();

}

}

Należy założyć, że funkcja hashująca rzadko wyznacza tę samą wartość hash dla różnych adresów, co oznacza, że konflikty powinny występować sporadycznie. Dlatego zaleca się ładowanie adresów pojedynczo za pomocą unikalnego klucza byPrevious, zamiast używania CisObjectIterator do jednoczesnego pobierania wszystkich adresów o tym samym hashu.

Do porównywania adresów nie można używać metody contentEquals z klasy AddressData, ponieważ metoda ta porównuje również atrybuty techniczne, takie jak hashCode, previous itp. Zamiast tego porównanie danych użytkowych musi zostać zaprogramowane w sposób jawny.

Pseudopartnerzy na zamówieniu sprzedaży

Kontrola duplikatów dla pseudopartnerów na zamówieniu sprzedaży powinna zapewnić, że klient nie jest już zarejestrowany jako „normalny” partner. Oznacza to, że nie może istnieć żaden partner, którego nazwa i adres pasują do danych wprowadzonych na zamówieniu.

Domyślnie adres klienta jest sprawdzany w klasie com.cisag.app.sales.order.log.OrderHeaderValidation. Metodę validateCustomerData(Data)można odpowiednio rozszerzyć, dzięki czemu sprawdzanie musi być przeprowadzane tylko wtedy, gdy jest to pseudopartner:

Data header = ...

Partner partner = header.getCustomer().retrievePartner();

boolean pseudo =

PartnerValidation.getInstance().isPseudoPartner(partner);

Nazwa wymagana do sprawdzenia jest zawarta w obiekcie OrderCustomerDataInfo (również obiekt biznesowy, który jest zarządzany za pomocą metody HashCode), a sam adres jest dostępny za pośrednictwem metody getCustomerAddressData():

String name = header.getCustomerData().getName();

AddressData address = header.getCustomerAddressData();

Ponieważ kontrola musi być przeprowadzana tylko wtedy, gdy dane są zmieniane, zaleca się porównanie z danymi, które są już w systemie. Dostęp do nich można uzyskać za pomocą funkcji getPersistentCustomerData lub getPersistentCustomerAddressData().

Podobnie jak w przypadku wprowadzania nowego partnera, duplikaty można określić, najpierw identyfikując identyczne lub podobne adresy, a następnie porównując nazwy powiązanych partnerów.

Adresy odbiorców dostaw i odbiorców faktur mogą być sprawdzane w ten sam sposób poprzez rozszerzenie metod validateDeliveryCustomerData i validateInvoiceCustomerData.

Czy ten artykuł był pomocny?