Wpis, który teraz czytasz, został zainspirowany pytaniem, które ostatnio zobaczyłem na swoim Twitterze. Użytkownik pytał, czy możliwe jest przypisanie zadania do innego pracownika, jeśli aktualny przypisany jest nieobecny, bez dostępu do swojej usługi Office 365. Kwestia zmiany wykonawcy zadania czy generalnie przypisania zadania innemu pracownikowi jest bezpośrednio powiązana z dobrze znaną funkcjonalnością aplikacji biznesowych o nazwie „zastępstwa”.

Zastępstwa to funkcjonalność, którą można wdrożyć na różne sposoby, ale ostatecznie ma ona tylko jeden cel – poinformowanie systemu, komu powinien przypisać konkretne zadanie, jeśli pierwotny wykonawca jest/ będzie nieobecny.

Zatem scenariusze są różne – czy zadanie powinno zostać przydzielone oryginalnemu wykonawcy i jego zastępcy, a może tylko zastępcy. Czy przepływ powinien czekać na wszystkie odpowiedzi lub tylko na pierwszą. Jeśli zmiana przypisanego będzie wykonywana już po przydzieleniu zadania – czy proces powinien również powiadomić nowego wykonawcę o zadaniu, a może nie. Może powinien również powiadomić pierwotnego wykonawcę, że jego zadanie zostało przydzielone komuś innemu. Liczba pytań wzrasta im więcej wiemy nt. procedur i zasad obowiązujących w danej firmie. Jednak jedno pozostaje bez zmian – zadanie należy przypisać innej osobie, niż powinno być to wykonane pierwotnie.

Na początek – screencast

Zanim naprawdę przejdę do szczegółów, obejrzyj nagranie, które nagrałem, aby dokładnie przedstawić Ci opisywane rozwiązania.

Zastępstwa w Microsoft Flow

Ważne! Poniższe rozwiązania wymagają posiadania subskrypcji P1 dla Microsoft Flow (i PowerApps, jeśli chcesz zbudować aplikację), abyś mógł uzyskać dostęp do Common Data Services (CDS)

Common Data Service

Nie każdy wie, że wszystkie zadania akceptacji w Microsoft Flow są przechowywane w Common Data Services. Poniżej znajduje się prosty schemat relacji między encjami biorącymi udział w tym procesie:

Common Data Services schema for Microsoft Flow approvals

Poniżej krótki opis każdej z encji:

  1. Approval – jest to główna encja. Przechowuje ogólne informacje dla każdego zatwierdzania, takie jak tytuł, data utworzenia, kto utworzył i kto jest ustawiony jako wnioskujący, a także wyniki: kiedy zostało zakończone, jaki był wynik.
  2. Approval Request – jest to encja przechowująca szczegóły każdego utworzonego zadania – do kogo jest przypisane, kiedy zostało, jakie są możliwe wyniki, opis. Im więcej osób przypisanych do zadania, tym więcej wpisów zostanie utworzonych tutaj. Właściwie – jeden na każdego wykonawcę.
  3. Approval Response – ta encja przechowuje wszystkie informacje o zakończonych zadaniach. Jeśli zadanie jest skonfigurowane by czekać na odpowiedź od każdego wykonawcy, tutaj znajdą się szczegółowe informacje o każdym zakończonym zadaniu. Jeśli będzie czekać tylko na pierwsze – będzie tylko jeden wpis.
  4. User – jest to kluczowa encja. Mapuje użytkowników AAD na rekordy używane w CDS. Zasadniczo każdy obiekt użytkownika w CDS nie jest rozpoznawany przy użyciu adresu e-mail, ale unikalnego identyfikatora GUID, który jest przechowywany w encji User. Aby wiedzieć, kto jest przypisany do zadania, musisz wykonać join pomiędzy daną encją i encją User, by używając identyfikatora GUID poznać dane faktycznego użytkownika.
  5. Flow Approval – ta encja przechowuje szczegółowe informacje o przydzielonych zadaniach z perspektywy Flow. Dostarczy Ci informacji o przepływach, które wygenerowały zadania – ich identyfikatory GUID, nazwy itp.

Mając teraz powyższą wiedzę można łatwo wnioskować, że kluczowymi encjami dla operacji podmiany wykonawcy będą Approval i Approval Request. I na nich się skupię.

Jak przepisać zadanie?

Odpowiedź jest dość prosta. W encji „Approval Request” znajduje się kolumna o nazwie „Owner”:

WHere to find Owner in CDS

Zastąpienie wartości w tej kolumnie wartością wskazującą innego użytkownika pozwoli przepisać zadanie do innego pracownika.

Najłatwiej jest otworzyć encję w pliku Excel, a następnie po prostu zmodyfikować wartość kolumny, wybierając innego użytkownika z listy dostępnych:

Korzystając z tego podejścia, możesz zmienić wykonawcę, nawet jeśli nie ma go w biurze i nie jest w stanie tego zrobić w swoim imieniu.

Podejście z użyciem PowerApps

Aplikacja PowerApps, którą pokazałem w screencaście jest dostępna tutaj: https://powerusers.microsoft.com/t5/Community-Apps-Gallery/Approval-tasks-reassignment-app/td-p/342522.

Jest to dość prosta aplikacja, która ma skonfigurowane trzy encje z CDS jako źródła danych: User, Approval i Approval Request. Na początku pobiera dane z tych encji i zapisuje je w kolekcjach, ponieważ posiadanie ich w aplikacji delikatnie poprawia wydajność, ale pozwala mi również używać wyrażeń, których nie można delegować. Operacja wykorzystuje również funkcję „Concurrent”, aby załadować dane jeszcze szybciej:

Concurrent(
    ClearCollect(
        ActiveApprovals,
        Filter(
            Approvals,
            IsBlank(Result)
        )
    ),
    ClearCollect(
        ActiveAssignments,
        'Approval Requests'
    )
)

Aplikacja jest zbudowana z trzech obszarów. Pierwszy to galeria aktualnie istniejących, nieukończonych zadań, zbudowana przy użyciu wyrażenia:

SortByColumns(Filter(ActiveAssignments, 'Approval Id Index' in ActiveApprovals.msdyn_flow_approvalid), "createdon", Ascending)

Nazwa wykonawcy jest pobierana i ustawiana przy użyciu poniższego wyrażenia:

"Assigned to: " & AsType( ThisItem.Owner, [@Users] ).'Full Name'

Musiałem użyć funkcji „AsType”, ponieważ kolumna Owner jest odnośnikiem polimorficznym „polymorphic lookup”) – oznacza to, że ta sama kolumna może zależnie od kontekstu działać w kontekście zespołu i użytkownika (https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/working-with-references).

Drugi to obszar pokazujący informacje o aktualnym wykonawcy. Każda labelka używa tej samej funkcji „AsType”, aby uzyskać informacje z CDS o użytkowniku, np.:

AsType( Gallery1.Selected.Owner, [@Users] ).'Full Name'
Office365Users.UserPhotoV2(AsType( Gallery1.Selected.Owner, [@Users] ).internalemailaddress)

Trzeci to combobox z listą użytkowników, do których można przepisać zadanie. Używa encji „User” jako źródła danych:

Combobox using User entity as datasource

Poniżej znajduje się karta pokazująca informacje o wybranym użytkowniku. Ponieważ wybrany element w comboboxie jest obiektem, etykiety po prostu korzystają z tego odwołania, aby uzyskać szczegółowe informacje od encji User, np.

DataCardValue3.Selected.'Full Name'

Na dole znajduje się przycisk do zapisania. Jego naciśnięcie wykonuje operację „patch” na rekordzie w CDS wskazanym przez wybrany element w galerii, która zastępuje wartość w kolumnie „Owner”:

Patch(
    'Approval Requests',
    LookUp(
        'Approval Requests',
        'Approval Id Index' = Gallery1.Selected.'Approval Id Index'
    ),
    {Owner: DataCardValue3.Selected}
);

I to tyle. Teraz opiszę rozwiązanie z użyciem Microsoft Flow.

Microsoft Flow approach

Zasadniczo jest to rozwiązanie, które można nazwać mechanizmem zastępstw. A przynajmniej wprowadzeniem do niego 😉

Działa w oparciu o źródło danych, które powinno przechowywać informacje o zastępstwach, np. encja w CDS (jak w moim przykładzie). Źródło powinno przynajmniej dostarczać informacji o tym kto jest nieobecny, kto powinien zastępować, od kiedy i do kiedy:

Entity keeping information about substitutions

Sam przepływ powinien być uruchamiany zgodnie z harmonogramem, np. codziennie po północy, a następnie:

Substitutions Microsoft Flow
  1. Powinien obliczyć aktualną datę, aby…
  2. Użyć jej do pobrania listy zastępstw zaczynających się od podanej daty – za pomocą zapytania filtrującego odata:

  3. Następnie powinien pobrać listę niezakończonych zadań – tych, które nie mają żadnej wartości w kolumnie „Result”:

  4. Następnie Flow pobiera listę wszystkich przypisanych zadań od encji Approval Request.
  5. Teraz chcę utworzyć tablicę zawierającą tylko identyfikatory GUID zadań, które nie zostały zakończone. Aby to zrobić, używam akcji o nazwie „Select” (w „Data Operations”). Jako „From” używam „value” z kroku nr 3 i jako „Map” używam „Approval” również od kroku nr 3:

  6. Następnie używam akcji „Filter”, aby zostawić tylko te elementy z encji „Approval Request” – czyli tylko te przypisane zadania, które nie zostały jeszcze zakończone – których identyfikatory GUID znajdują się na liście od kroku nr 5:

  7. Następnie dla każdego zastępstwa pobranego w kroku nr 2…
  8. Zostawiam tylko te rekordy, które mają w polu „Owner” taką samą osobę jak w polu „SubstitutionFor” a liście zastępstw – dzięki temu odfiltruję listę przypisanych zadań z kroku nr 6 o te niepowiązane z zastępowanym pracownikiem w bieżącym kroku pętli:
  9. I na końcu, dla każdego, takiego zadania…
  10. Zastępuję oryginalnego „Ownera” wartością pobraną z rekordu, z listy zastępstw:

I to w zasadzie wszystko! Przepływ, który opisałem powyżej, służy po prostu zastąpieniu obecnych wykonawców innymi pracownikami w oparciu o zdefiniowane reguły w encji „Substitutions”. Można to rozwiązanie nazwać MVP (Minimum Viable Product). Może być używane jednak nie tylko do zmiany w już przydzielonym zadaniu, ale także do zmiany wykonawcy zadania na innego pracownika w trakcie generowania zadania.

Można również dodać funkcje powiadomień, aby nowy wykonawca (jeśli zadanie zostało przypisane ponownie) został poinformowany o zadaniu do wykonania. Także pierwotny wykonawca może zostać poinformowany o udanym zastępstwie. Można także dodać funkcjonalności, które po upływie czasu substytucji ponownie przepiszą wszystkie zadania z zastępcy do pierwotnego zatwierdzającego.

Mam nadzieję, że ten post okaże się bardzo przydatny. Szeruj, komentuj, wszelkie opinie bardzo mile widziane. Jeśli masz jakieś pytania dotyczące wdrożenia lub chciałbyś poprosić o pomoc – skontaktuj się ze mną!