Interfejs dla reorganizacji partnerów

Partnerzy i role oznaczone do usunięcia mogą zostać usunięte w ramach procesu reorganizacji.
Aby fizycznie usunąć dane ze znacznikiem usuwania, należy sprawdzić, czy nie są one wykorzystywane w innych procesach.

W niniejszym artykule wyjaśnione zostaną technicznie rejestry oraz opisane zostało, jak może wyglądać rozszerzenie dla własnych obiektów podlegających weryfikacji.

Grupa docelowa

  • Programiści

Interfejs programowania

Tworzenie klas użytkowania

Z wyjątkiem roli Podstawowa i Pracownik, wszystkie role partnerów są zapisywane w sposób zależny od organizacji. Oznacza to, że do uzyskania dostępu do tych danych zawsze wymagana jest organizacja. W związku z tym, w używanych obiektach biznesowych również należy określić powiązanie z organizacją. Obsługiwane są niektóre standardowe przypadki:

  • wykorzystywany jest jedynie GUID partnera, bez odniesienia do organizacji, np. dla użycia, które mają być zachowane wyłącznie na poziomie klienta lub odnoszą się do danych podstawowych

  • GUID partnera i GUID organizacji znajdują się w tym samym obiekcie biznesowym (BO)

  • GUID partnera znajduje się w jednym BO, a GUID organizacji w innym, połączonym prostym join

  • GUID partnera znajduje się w jednym BO, a GUID organizacji w innym BO, który jest połączony za pomocą złożonego (dwukrotnego) join

W typowych przypadkach obiekty biznesowe zawierają tylko jedno atrybutowe odniesienie do partnera. Join są zwykle realizowane również przez jedno pole. Dla takich przypadków dostępne są metody createUsage(..), które umożliwiają ich odwzorowanie. Istnieje logika standardowa, która na podstawie informacji rejestracyjnych generuje odpowiednie zapytania OQL, wykonuje je i identyfikuje możliwe powiązania. Zwracanym wynikiem metod createUsage(..) jest instancja klasy StandardUsage, która implementuje tę logikę.

Dostępna jest także wersja metody createUsage, której sygnatura obsługuje najbardziej ogólny przypadek w ramach logiki standardowej. Join mogą wtedy obejmować wiele atrybutów, a także możliwe jest, że dany BO zawiera wiele atrybutów z identyfikatorami artykułów, które mają być sprawdzane jednocześnie.

W przypadku bardziej złożonych modeli danych lub konieczności uwzględnienia szczególnych warunków, należy zaprogramować klasę kontrolną, która implementuje interfejs  com.cisag.app.general.partner.reorg.Usage.

GUID partnera bez odniesienia organizacyjnego

Wywołanie metody

createUsage(clazz, "partnerAttribute")

Generuje standardową instancję logiczną, która zawiera następujące zapytanie OQL:

Select .. from clazz uc where uc:partnerAttribute = ?

GUID partnera i organizacji w BO

Wywołanie metody:

createUsage(clazz, "partnerAttribute", "organizationalUnitAttribute")

Generuje standardową instancję logiczną, która zawiera następujące zapytanie OQL:

Select .. from clazz uc where uc:partnerAttribute = ? and uc:organizationalUnitAttribute = ?

GUID partnera i organizacji w różnych BO (podwójne sprzężenie)

Wywołanie metody:

createUsage(clazz, "partnerAttribute", "source", targetClass, "target", "organizationalUnitAttribute")

Generuje standardową instancję logiczną, która zawiera następujące zapytanie OQL:

Select .. from clazz uc
join targetClass tc on uc:source = tc:target
where uc:partnerAttribute = ? and tc:organizationalUnitAttribute = ?

Rejestrowanie klas użytkowania

Obiekty biznesowe do sprawdzenia są rejestrowane w klasie:

com.cisag.app.general.partner.reorg.PartnerUsageRegistry.

Te obiekty biznesowe muszą zawierać partnera jako klucz obcy. Ponadto nadal potrzebują one danych partnera. Jeśli obiekt biznesowy co prawda zawiera partnera jako klucz obcy, ale nie wymaga już samych danych partnera, to taki obiekt nie musi być rejestrowany. Rejestracja zawiera informacje o obiektach biznesowych, które — pod pewnymi warunkami — mogą zablokować trwałe usunięcie danych partnera.

Podczas rejestracji należy uwzględnić rodzaj użycia partnera oraz to, czy dany obiekt biznesowy dotyczy danych podstawowych. Dla każdego typu użycia istnieje metoda, której nazwa odpowiada wpisom w zestawie wartości ValueSet SubapplicationSelection.

Przykład
registerBase( false, createUsage(com.cisag.app.inventory.obj.InventoryOnhand.class, "owner" ));

W tym przykładzie obiekt biznesowy InventoryOnhand zostaje zarejestrowany z użyciem jednej z opisanych metod createUsage.
Dane podstawowe partnera mogą zostać usunięte tylko wtedy, gdy nie istnieją żadne wpisy w obiekcie biznesowym InventoryOnhand, które poprzez atrybut owner odnosiłyby się do danego partnera.

Przykład
registerCustomer( false, createUsage(com.cisag.app.sales.obj.CustomerInvoiceDetail.class, "deliveryCustomer", "header",com.cisag.app.sales.obj.CustomerInvoice.class, "guid", "invoicingParty" ));

W drugim przykładzie obiekt biznesowy CustomerInvoiceDetail zostaje zarejestrowany z użyciem jednej z opisanych metod createUsage.
Dane klienta danego partnera mogą zostać usunięte tylko wtedy, gdy nie istnieją żadne wpisy w obiekcie biznesowym CustomerInvoiceDetail, które poprzez atrybut deliveryCustomer odnosiłyby się do tego partnera.
W tym przypadku powiązanie z organizacją można określić na podstawie relacji między CustomerInvoiceDetail a CustomerInvoice.

Przykład
registerSupplier( true, new PartnerRelationUsage());

W trzecim przykładzie bezpośrednio rejestrowana jest klasa do weryfikacji zależności w obiekcie biznesowym PartnerRelation w odniesieniu do danych dostawcy danego partnera.
Klasa PartnerRelationUsage musi implementować interfejs Usage.
Jest to sposób na zarejestrowanie własnej procedury sprawdzającej, która wykracza poza standardowe przypadki obsługiwane przez metody createUsage.

Implementacja interfejsu użytkowania

Dla wszystkich obiektów biznesowych (BO), które nie mogą być obsłużone przez wspomniane powyżej standardowe metody, konieczne jest zaprogramowanie klasy sprawdzającej, która implementuje interfejs com.cisag.app.general.partner.reorg.Usage. Konwencja nazewnicza zakłada nazwę sprawdzanego obiektu biznesowego z dodanym sufiksem Usage. Interfejs zawiera metody: getUsageClass, isInUse oraz usedBy. Metoda getUsageClass zwraca zarejestrowaną klasę usageClass i służy głównie do celów konserwacyjnych.
Metoda isInUse sprawdza istnienie referencji do partnera, natomiast usedBy identyfikuje instancje odwołujące się do partnera.

Działanie interfejsu zostało wyjaśnione na przykładzie.

Przykład
public class TaxExemptionUsage implements Usage{private final CisEnvironment env = CisEnvironment.getInstance();

private final CisObjectManager om = env.getObjectManager();

public TaxExemptionUsage() {

}

public Class getUsageClass() {

return TaxExemption.class;

}

public boolean isInUse(Chunk chunk) {

short role=chunk.getRole();

if (role != SubapplicationSelection.CUSTOMER && role != SubapplicationSelection.SUPPLIER) {

throw new IllegalArgumentException("Only customer and supplier role are allowed.");

}

int size = chunk.countToCheck();

if (size <= 0) {

return false;

}

boolean isInUse = false;

StringBuffer oql = new StringBuffer("select o:partner, o:organizationalUnit from ");

oql.append(" TaxExemption o where (");

for (int i = 0; i < size; i++) {

oql.append("(o:partner=? i o:organisationalUnit=?) lub ");

}

oql.setLength(oql.length() - 4);

oql.append(") and o:kind=?");

CisResultSet rs = om.getResultSet( oql.toString() );

try {

int offset = 0;

Iterator comboIt = chunk.retrieveCombinationsToCheck();

while (comboIt.hasNext()) {

Entry currentCombo = (Entry) comboIt.next();

rs.setGuid( ++offset, currentCombo.getGuid() );

rs.setGuid( ++offset, currentCombo.getOrganizationalUnit() );

}

rs.setShort(++offset, role == SubapplicationSelection.CUSTOMER?

TaxExemptionKind.EXTERNAL :

TaxExemptionKind.OWN);

while (rs.next()) {

chunk.setInUse( rs.getGuid( 1 ), rs.getGuid( 2 ) );

isInUse = true;

}

} catch (java.sql.SQLException ex) {

throw new RuntimeException( ex );

} finally {

rs.close();

}

return isInUse;

}

public CisObject[] usedBy(Chunk.Entry entry) {

short role = entry.getRole();

if (role != SubapplicationSelection.CUSTOMER && role != SubapplicationSelection.SUPPLIER) {

throw new IllegalArgumentException("Dozwolone są tylko role klienta i dostawcy

role are allowed.");

}

byte[] partnerGuid = entry.getGuid();

byte[] organizationalUnit = entry.getOrganizationalUnit();

String oql = "select o:guid from " +

"com.cisag.app.financials.obj.TaxExemption o where " +

"o:partner=? and o:organisationalUnit=? " +

"i o:kind=?";

Lista result = new ArrayList();

CisResultSet rs = om.getResultSet( oql );

try {

rs.setGuid( 1, partnerGuid);

rs.setGuid( 2, organizationalUnit);

rs.setShort( 3, role == SubapplicationSelection.CUSTOMER?

TaxExemptionKind.EXTERNAL :

TaxExemptionKind.OWN);

rs.setMaxRows(PartnerReorganisationLogic.MAX_USAGE);

while(rs.next()){

result.add(TaxExemption.buildPrimaryKey(rs.getGuid(1)));

}

} catch (java.sql.SQLException ex) {

throw new RuntimeException( ex );

} finally {

rs.close();

}

CisObject[] resultObj = om.getObjectArray(result, CisObjectManager.READ);

return resultObj;

}

}

Uwaga
Przykład ten służy wyłącznie celom ilustracyjnym. Nie odpowiada on aktualnemu stanowi klasy Java w systemie i nie będzie aktualizowany w przypadku ewentualnych zmian tej klasy w systemie.

Następnie rejestracja odbywa się w następujący sposób:

registerCustomer( true, new TaxExemptionUsage());

Sprawdzenie poprawnej roli odbywa się w metodach isInUse oraz usedBy. Rola może być odczytana zarówno z Chunk, jak i z Entry.

Metoda usedBy identyfikuje kombinacje partner–organizacja, które nadal są referencjonowane przez instancje danego obiektu biznesowego (BO).
Metoda otrzymuje jako parametr obiekt typu Chunk, który zawiera kombinacje partner–organizacja do sprawdzenia.

Jeden Chunk zawsze odnosi się do jednego typu użycia i może zawierać wiele identyfikatorów GUID partnera. Dla każdego identyfikatora partnera zawiera wszystkie identyfikatory organizacji, które należy zweryfikować. Kombinacje, które mają zostać sprawdzone, można pobrać z obiektu Chunk za pomocą metody retrieveCombinationsToCheck.
Następnie metodą setInUse określa się, które z tych kombinacji są nadal wykorzystywane.

Jeśli sprawdzane zastosowanie nie jest zależne od organizacji (np. partner-podstawowe lub pracownik), organizacja nadal zawiera identyfikator klienta, nawet jeśli ta informacja nie jest potrzebna. Należy to uwzględnić przy wywołaniu metody setInUse.

W przypadku metody isInUse należy przy definiowaniu zapytania OQL zwrócić uwagę, aby sprawdzanie obejmowało wiele kombinacji partner–organizacja w ramach jednego zapytania. Pola selekcji powinny odpowiadać tym kombinacjom, aby możliwe było oznaczenie odwołań kombinacji za pomocą setInUse.

Metoda usedBy jest wywoływana tylko wtedy, gdy podczas reorganizacji wymagane są szczegółowe komunikaty. Otrzymuje ona jako parametr Chunk.Entry, który zawiera jedną kombinację partner–organizacja, dla której zostały wykryte instancje referencyjne. Metoda usedBy zwraca te instancje.
W zapytaniu OQL należy jako pole selekcji wybrać klucz główny obiektu biznesowego (BO).

Rejestracja BO do usunięcia

Jeśli dana kombinacja kluczy przejdzie pomyślnie wszystkie testy, odpowiadające jej dane muszą zostać fizycznie usunięte. Wymaga to rejestracji powiązanych obiektów biznesowych (BO).

W przypadku reorganizacji partnerów, rejestracja zazwyczaj obejmuje obiekt biznesowy odpowiadający danej roli (np. com.cisag.app.sales.obj.Customer dla roli klienta) oraz dodatkowe obiekty zależne (Dependents).

Dla każdej roli dostępne są odpowiednie metody rejestracyjne w klasie PartnerUsageRegistry.
Poniżej opisanych zostało kilka przykładów:

Przykład
registerDeletionCustomer(com.cisag.app.sales.obj.SalesOutputSettings.class, "partner", "organizationalUnit");

W pierwszym przykładzie rejestrowane są SalesOutputSettings, które są powiązane z głównym obiektem Customer za pośrednictwem atrybutów partner oraz organizationalUnit.

Przykład
registerDeletionCustomer( new PartnerRelationDeletion());

W drugim przykładzie rejestrowana jest klasa Java, która implementuje interfejs Deletion.

Przykład
registerDeletionCustomer( com.cisag.app.sales.obj.Customer.class);

W ostatnim przykładzie po prostu rejestrowane jest główne obiekt dla roli Klient do usunięcia.

Implementacja interfejsu usuwania

Interfejs usuwania obejmuje metody getDeletionClassdelete i deleteExpiredVersions.

Metoda getDeletionClass zwraca klasę zarejestrowaną do usunięcia deletionClass zarejestrowaną do usuwania i jest używana głównie w celach serwisowych (np. aby wyświetlić klasy zarejestrowane dla danego przypadku użycia).

Metoda deleteExpiredVersions jest przewidziana na potrzeby przyszłych rozszerzeń. W przypadku BO zależnych od czasu, usuwa ona wersje, których okres ważności upłynął przed przekazaną datą. Dla BO, które nie są zależne od czasu metoda musi jedynie zwracać wartość true.

Metoda delete usuwa wszystkie wersje dla BO zależnych od czasu. Informacja o tym, dla których kombinacji partner–organizacja dane mają zostać usunięte, pobierana jest za pomocą metody retrieveFreeCombinations z obiektu typu Chunk.

Przykładem może być klasa:

com.cisag.app.general.partner.reorg.PartnerRelationDeletion, która służy do bezpośredniego usuwania danych powiązanych z artykułem.

Czy ten artykuł był pomocny?