Skip Navigation LinksALVAO 10.4Rozšiřující modulyALVAO Service Desk Custom AppsAplikaceAutomatické akce na základě událostí na požadavku Skip Navigation Links.


Automatické akce na základě událostí na požadavku

Automatické akce se mohou spouštět v těchto případech:

  • Změna hodnoty položky požadavku (vlastní/systémová)
  • Založení nového požadavku
  • Vytvoření nové události
  • Úprava události
  • Odstranění události
  • Načtení nové zprávy ze schránky služby
Upozornění:
Špatnou definicí automatické akce může být nenávratně poškozena databáze ALVAO, proto vytváření a testování vždy provádějte na kopii databáze v testovacím prostředí.
Tip:
Předpokladem pro vytvoření funkční automatické akce je dobrá znalost databáze ALVAO, Service Desk WebService API a Alvao.API.

Příprava nové automatické akce

V aplikaci vytvořte nový skript podle šablony ITicketAutoAction resp. IActAutoAction a vhodně jej pojmenujte podle funkčnosti, kterou akce provádí.

V nově vytvořeném skriptu nastavte v konstruktoru třídy akce hodnotu vlastnosti name (název automatické akce).

Pro uložení vlastností a nastavení akce doporučujeme definovat třídu Settings v samostatném skriptu, který vytvoříte ze šablony Knihovna tříd, např.:

public static class Settings {
    public const string ActionName = "Vyřešeno ve verzi – předat do testu";

    public const string ServiceName = "Programové úpravy"; // Název služby, ve které má být požadavek, aby se mohl předat testerům (příklad Akce prováděné při změně položky požadavku)
    public const int ControlStateId = 1; // ID stavu, ve kterém má být požadavek, aby se mohl předat testerům (příklad Akce prováděné při změně položky požadavku)
    public const string SolverGroupName = "Testeři";
}

Příklad

Definice třídy:


class AssignToTester : ITicketAutoAction
{
    public string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public AssignToTester()
    {
        name = Settings.ActionName;
    }
}

Definice podmínek a vykonávaných operací pro automatickou akci

Upozornění:
Pokud v rámci automatické akce chcete použít jen některé z metod implementovaného rozhraní, tak v těle ostatních metod z rozhraní vraťte výjimku NotImplementedException. Například takto:

public void OnTicketChanged(SqlConnection con, SqlTransaction trans, int ticketId, int personId, string properties)
{
    throw new NotImplementedException();
}

Akce prováděné při změně položky požadavku

Automatické akce je možné vykonávat při změně těchto položek:

tabulka.sloupec Položka požadavku
tHdTicket.TicketStateId Stav
tHdTicket.liHdTicketSlaId SLA
tHdTicket.dHdTicketDeadline Termín
tHdTicket.liHdTicketHdSectionId Služba
tHdTicket.iHdTicketUser Žadatel
tHdTicket.liHdTicketSolverPersonId Řešitel
tHdTicket.sHdTicket Název požadavku
tHdTicket.liHdTicketPriorityId Priorita
tHdTicket.Impact Dopad
tHdTicket.Urgency Naléhavost
tHdTicket.mHdTicketNotice Poznámky
tHdTicket.sHdTicketGroup Skupina
tHdTicket.sHdTicketDeviceCode Číslo zařízení
tHdTicket.FeedbackSolveSpeed Rychlost řešení
tHdTicket.FeedbackProfessionality Profesionalita
tHdTicket.FeedbackExpertise Odbornost
tHdTicket.FeedbackComment Komentáře a poznámky
tHdTicket.RelatedAccountId Související organizace
tHdTicket.Objects Objekty
tHdTicket.RequestedForPersonId Požadováno pro
tHdTicketCust.* Vlastní položky

Ve vytvořené třídě akce implementujte rozhraní ITicketAutoAction a z něho metodu OnTicketChanged. Vstupními parametry jsou:

  • ticketId (číslo požadavku),
  • personId (id osoby, která provedla událost na požadavku) – V některých případech mohl být systém, pak je hodnota NULL,
  • properties (změněné položky požadavku oddělené čárkou – tabulka.sloupec).

V implementované metodě definujte jak podmínky pro vykonání operací, tak samotné operace s požadavkem.

Příklad automatické akce při změně položky požadavku:

Předání požadavku řešiteli ze skupiny Testeři v případě, že požadavek je ve službě Programové úpravy a ve stavu s id 1.


class AssignToTester : ITicketAutoAction
{

    public void OnTicketChanged(SqlConnection con, SqlTransaction trans, int ticketId, int personId, string properties)
    {
        if (properties.Contains("tHdTicketCust.solvedInVersion"))
        {
            try
            {
                HelpdeskWebService sdws = new HelpdeskWebService();

                // nacteni hodnot
                string solvedInVersion = sdws.ReadColumn(ticketId, "tHdTicketCust", "solvedInVersion");
                string section = sdws.ReadColumn(ticketId, "TicketForeignKeyInfo", "SectionName");
                int stateId = sdws.ReadColumn(ticketId, "tHdTicket", "TicketStateId");

                // kontrola hodnot
                if (!String.IsNullOrEmpty(solvedInVersion) && section == Settings.ServiceName && stateId == Settings.ControlStateId)
                {
                    // nacteni dat
                    using (SqlCommand Cmd = new SqlCommand($@"SELECT TOP 1 TRP.liRolePersonPersonId newSolverId
                    FROM tRolePerson TRP JOIN tRole TR ON TRP.liRolePersonRoleId=TR.iRoleId WHERE TR.sRole = N'{Settings.SolverGroupName}'", con, trans))
                    {
                        using(SqlDataReader reader = Cmd.ExecuteReader())
                        {
                            int? newSolverId; // id noveho resitele pozadavku

                            if (reader.Read())
                            {
                                newSolverId = int.Parse((reader["newSolverId"]).ToString());
                            }
                            reader.Close();

                            // predani resiteli
                            if(newSolverId.HasValue)
                                Ticket.ChangeSolver(ticketId, newSolverId, new HtmlTextModel(string.Empty));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

}

Celý příklad ke stažení: Example_AssignToTester.zip

Pro spuštění příkladu se předpokládá přidání vlastní položky solvedInVersion typu nvarchar do tabulky tHdTicketCust.

Akce prováděné při založení nového požadavku

Ve vytvořené třídě automatické akce implementujte rozhraní ITicketAutoAction a z něho metodu OnTicketCreated. Vstupními parametry jsou:

  • ticketId (číslo požadavku),
  • personId (id osoby, která požadavek založila – nemusí být vždy žadatel).

Příklad automatické akce při založení nového požadavku:

Při založení nového požadavku ve službě Programové úpravy je zároveň založen navázaný požadavek ve službě Programové úpravy/Návrhy a analýzy pro tvorbu návrhu k založenému požadavku.


class AssignToTester : ITicketAutoAction
{

    public void OnTicketCreated(SqlConnection con, SqlTransaction trans, int ticketId, int personId)
    {
        try
        {
            HelpdeskWebService sdws = new HelpdeskWebService();

            // nacteni hodnot
            bool createAnalysis;
            if ((sdws.ReadColumn(ticketId, "tHdTicketCust", "createAnalysis")) != null)
                createAnalysis = bool.Parse(sdws.ReadColumn(ticketId, "tHdTicketCust", "createAnalysis"));
            else
                createAnalysis = false;

           int? analysisServiceId = null;
           using (SqlCommand Cmd = new SqlCommand($@"SELECT iHdSectionId from tHdSection where sHdSection = @sectionName", con, trans))
           {
                Cmd.Parameters.Add("@sectionName", SqlDbType.NVarChar).Value = Settings.AnalysisServiceName;
                using (SqlDataReader reader = Cmd.ExecuteReader())
                {
                     if (reader.Read())
                     {
                          analysisServiceId = int.Parse((reader["iHdSectionId"]).ToString());
                     }
                }
           }

           string section = sdws.ReadColumn(ticketId, "TicketForeignKeyInfo", "SectionName");
           string name = sdws.ReadColumn(ticketId, "tHdTicket", "sHdTicket");

            // kontrola hodnot
            if (section == Settings.ServiceName && createAnalysis)
            {
                // založení požadavku na vytvoreni navrhu
                var newTicketModel = new NewTicketModel();
                newTicketModel.Ticket.sHdTicket = name + " - návrh";
                newTicketModel.Ticket.liHdTicketUserPersonId = personId;
                newTicketModel.LoadRequesterData = true;
                newTicketModel.Ticket.liHdTicketHdSectionId = analysisServiceId.Value;
                var ticket = Ticket.Create(newTicketModel);
                int newTicketId = ticket.iHdTicketId;

                // vytvoreni vazby
                Relation.Create(ticketId, newTicketId, 2, Person.GetSystem().iPersonId);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

}

Celý příklad ke stažení: Example_CreateAnalysis.zip

Pro spuštění příkladu se předpokládá přidání vlastní položky solvedInVersion typu nvarchar do tabulky tHdTicketCust.

Akce prováděné při vytvoření události

Automatické akce je možné vykonat při těchto situacích:
  • Ruční vytvoření libovolné události příkazem Nová událost nebo Poznámka.
  • Odeslání zprávy příkazem Poslat zprávu, Odpovědět, atd.
  • Načtení e-mailu ze schránky služby aplikací MailboxReader.
  • Ruční načtení zprávy z Outlooku pomocí Outlook Add-in - Uložit do deníku požadavku.
  • Vytvoření zakládající události při vzniku nového požadavku.
  • Zavoláním webové metody CreateAct, případně CreateTicket, kde se vytváří zakládající zpráva.

Ve vytvořené třídě automatické akce implementujte rozhraní IActAutoAction a z něho metodu OnActCreated. Vstupními parametry jsou:

  • actId (id události),
  • personId (id osoby, která událost vytvořila).

Příklad automatické akce při vytvoření události:

Při vytvoření události v některém požadavku ve službě Programové úpravy je tato událost přeposlána v e-mailu každému manažerovi služby, pokud není autorem ani příjemcem události.


class SendMailsAboutNewEvent : IActAutoAction
{
   public string name;

   public string Name
   {
       get { return name; }
       set { name = value; }
   }

   public SendMailsAboutNewEvent()
   {
       name = Settings.ActionName;
   }

   public void OnActChanged(SqlConnection con, SqlTransaction trans, int actId, int personId, string properties) {
       throw new NotImplementedException();
   }
   public void OnActRemoved(SqlConnection con, SqlTransaction trans, int actId, int personId) {
       throw new NotImplementedException();
   }

   public void OnActCreated(SqlConnection con, SqlTransaction trans, int actId, int personId)
   {
       try
       {

           // nacteni hodnot
           int ticketId = 0, fromPersonId = 0, sectionId = 0;
           string actFrom = "", actFromEmail = "", actTo = "", actToEmail = "", actSubject = "", actPlainText = "", sectionName = "", sectionEmail = "";
           using (SqlCommand Cmd = new SqlCommand(@"SELECT liActHdTicketId, liActFromPersonId, sActFrom, sActFromEmail,
           sActTo, sActToEmail, sAct, mActNotice, sHdSection, sHdSectionEmail, iHdSectionId FROM tAct a join tHdTicket t on a.liActHdTicketId=t.iHdTicketId join tHdSection s on t.liHdTicketHdSectionId=s.iHdSectionId WHERE iActId = @actId", con, trans))
           {
               Cmd.Parameters.Add("@actId", SqlDbType.Int).Value = actId;
               using (SqlDataReader reader = Cmd.ExecuteReader())
               {
                   if (reader.Read())
                   {
                       ticketId = int.Parse((reader["liActHdTicketId"]).ToString());
                       fromPersonId = int.Parse((reader["liActFromPersonId"]).ToString());
                       actFrom = (reader["sActFrom"]).ToString();
                       actFromEmail = (reader["sActFromEmail"]).ToString();
                       actTo = (reader["sActTo"]).ToString();
                       actToEmail = (reader["sActToEmail"]).ToString();
                       actSubject = (reader["sAct"]).ToString();
                       actPlainText = "Dobrý den,\n\n na požadavku číslo " + ticketId.ToString() + " byla vytvořena událost:\n\n" + (reader["mActNotice"]).ToString();
                       sectionName = reader["sHdSection"] as string;
                       sectionEmail = reader["sHdSectionEmail"] as string;
                       sectionId = int.Parse((reader["iHdSectionId"]).ToString());
                   }
                   reader.Close();
               }
           }

           // kontrola hodnot
           if (sectionName == Settings.ServiceName)
           {
               List<string> recipients = new List<string>();
               using (SqlCommand Cmd = new SqlCommand(@"select sPersonEmail from HdSectionManager left join tPerson on iPersonId = PersonId where sPersonEmail is not null and HdSectionId = @sectionId", con, trans))
               {
                   Cmd.Parameters.Add("@sectionId", SqlDbType.Int).Value = sectionId;
                   using (SqlDataReader reader = Cmd.ExecuteReader())
                   {
                       string personEmail = "";
                       while (reader.Read())
                       {
                           personEmail = (reader["sPersonEmail"]).ToString();
                           if (!actTo.Contains(personEmail) && !actToEmail.Contains(personEmail) && !actFrom.Contains(personEmail) && !actFromEmail.Contains(personEmail))
                               recipients.Add(personEmail);
                       }
                       reader.Close();
                   }
               }

               //odeslani e-mailu
               if (recipients.Count > 0)
               {
                   string to = String.Join(";", recipients);
                   string from = sectionEmail;
                   string subject = actSubject;
                   string body = actPlainText;
                   System.Net.Mail.MailMessage message = new MailMessage(from, to, subject, body);
                   Alvao.API.Common.Email.QueueMailMessage(message);
               }
           }
       }
       catch (Exception ex)
       {
           throw ex;
       }
   }
}

Celý příklad ke stažení: Example_SendMailsAboutNewEvent.zip

Akce prováděné při úpravě události

Automatické akce je možné vykonat při změně těchto položek:

tabulka.sloupec Položka události
tAct.dAct Datum
tAct.liActKindId Komu
tAct.sActTo Datum
tAct.sAct Předmět
tAct.mActNotice Text
tDocument.liDocumentActId Přílohy
tActHd.bActHdUserRead Zobrazit žadateli
tAct.bWaitingForUser Čekání na žadatele
tAct.nActWorkHours Práce
tAct.nActTravelHours Čas na cestě
tAct.nActTravelKm Vzdálenost
tAct.bNoCharge Nefakturovat

Ve vytvořené třídě automatické akce implementujte rozhraní IActAutoAction a z něho metodu OnActChanged. Vstupními parametry jsou:

  • actId (id události),
  • personId (id osoby, která událost změnila),
  • properties (změněné položky události, oddělené čárkou – tabulka.sloupec).

Akce prováděné při odstranění události

Automatické akce je možné vykonat při odstranění všech zpráv a událostí.

Ve vytvořené třídě automatické akce implementujte rozhraní IActAutoAction a z něho metodu OnActRemoved. Vstupními parametry jsou:

  • actId (id události),
  • personId (id osoby, která událost odstranila).

Akce prováděné při načtení zprávy

Automatické akce je možné vykonat při načtení zprávy ze schránky služby ještě před uložením zprávy do deníku již existujícího požadavku, resp. před vytvořením nového požadavku.

Ve vytvořené třídě automatické akce implementujte rozhraní IMailMessageAutoAction a z něho metodu OnMessageReceived. Vstupními parametry jsou:

  • message (objekt se zprávou),
  • sectionId (id služby, ve které byla zpráva načtena),
  • ticketId (id požadavku, ke kterému zpráva podle předmětu patří, resp. nula, pokud se jedná o vytvoření nového požadavku),
  • fromPersonId (id odesílatele zprávy, resp. účtu Host, pokud odesílatel zprávy nebyl mezi uživateli nalezen).
Z metody OnMessageReceived vraťte návratovou hodnotu true nebo false určující, zda se má zpráva dále standardně zpracovávat nebo ne.

Pokud je těchto automatických akcí implementováno více, volají se postupně do té doby, dokud některá nevrátí hodnotu false, přičemž není garantováno pořadí jejich volání.

Poznámka:
Pokud není zpráva po automatických akcích dále zpracována, do protokolu událostí je o tom zapsáno varování.

Příklad automatické akce při načtení zprávy:

Při načtení zprávy se u existujících požadavků zkoumá text zprávy, zda neobsahuje příkaz pro předání řešiteli „ASSIGNTO: jméno řešitele“. Pokud jej obsahuje a řešitel je podle jména nalezen, požadavek se mu automaticky předá a zpráva nebude zaznamenána do deníku požadavku. Jinak je zpráva zpracována standardním způsobem.

……
public class AssignToSolverByEmail : IMailMessageAutoAction
{
   public string name;

   public string Name
   {
       get { return name; }
       set { name = value; }
   }

   public AssignToSolverByEmail()
   {
       name = Settings.ActionName;
   }

   public bool OnMessageReceived(SqlConnection con, SqlTransaction trans, Rebex.Mail.MailMessage message, int sectionId, int ticketId, int fromPersonId)
   {
       if (ticketId == 0)
           return true;

       if(message.BodyText != null)
       {
           int startIndex = message.BodyText.IndexOf("ASSIGNTO:");
           if(startIndex >= 0)
           {
               int length = message.BodyText.IndexOf("\n", startIndex) - (startIndex + 9);
               string user = message.BodyText.Substring(startIndex + 9, length).Trim();
               int? solverId = null;
               using (SqlCommand Cmd = new SqlCommand(@"exec spPersonSearch @sample, NULL, 0, NULL, '', 1", con, trans))
               {
                   Cmd.Parameters.Add("@sample", SqlDbType.NVarChar).Value = user;
                   using (SqlDataReader reader = Cmd.ExecuteReader())
                   {
                       if (reader.Read())
                       {
                           solverId = reader["PersonId"] as int?;
                       }
                   }

                   if(solverId.HasValue){
                       Alvao.API.SD.Ticket.ChangeSolver(ticketId, solverId, new API.Common.Model.HtmlTextModel(string.Empty), null, fromPersonId);
                       return false;
                   }
               }
           }
       }
       return true;
   }
}

Celý příklad ke stažení: Example_AssignToSolverByEmail.zip

 

Akce prováděné při schvalování

V průběhu schvalování můžete spouštět automatické akce na základě těchto událostí:

  • Schválení požadavku
  • Zamítnutí požadavku
  • Přidání schvalovatele do schvalování
  • Zrušení konkrétního schvalovatele

Automatické akce jsou volány pouze pro ručně spouštěná schvalování s vypnutým automatickým přechodem do dalšího stavu.

V aplikaci vytvořte nový skript podle šablony ITicketApprovalAutoAction a vhodně jej pojmenujte podle funkčnosti, kterou akce provádí. Vstupními parametry metod jsou:

Příklad automatické akce při schvalování

Při schválení požadavku ve službě Nákup všemi schvalovateli přechází požadavek do stavu Objednávka.

public class OrderAfterApprovalTicketApprovalAutoAction : ITicketApprovalAutoAction
{    
    public string Name { get => Settings.ActionName; set => Name = value; }

    public void OnApproved(SqlConnection con, SqlTransaction trans, int ticketId, int approvalItemId)
    {
        HelpdeskWebService sdws = new HelpdeskWebService();
        string sectionName = sdws.ReadColumn(ticketId, "TicketForeignKeyInfo", "SectionName");
        string stateName = Alvao.API.SD.TicketState.GetCurrentStateByTicketId(ticketId)._TicketState;

        // Informace o schválení (schvalovatel, komentář apod.)
        tHdTicketApprovalItem currentApprovalItem = Alvao.API.SD.Approval.GetApprovalItemById(approvalItemId);

        if(sectionName == Settings.ServiceName && stateName == Settings.State)
        {
            // Vrátí seznam schvalovatelů aktuálního schvalování, včetně jejich rozhodnutí.
            IEnumerable<tHdTicketApprovalItem> approvalItems = Alvao.API.SD.Approval.GetCurrentApprovalItems(ticketId);

            // Pokud všichni schválili
            if(approvalItems.Where(s => s.liHdTicketApprovalItemHdTicketApprovalItemResultId == (int)tHdTicketApprovalItem.ApprovalResult.Accepted).Count() == approvalItems.Count())
            {
                Alvao.API.Common.Model.Database.TicketState targetState = Alvao.API.SD.TicketState.GetByName(Settings.TargetState, ticketId);

                if(targetState == null)
                    return;

                int systemPersonId = Alvao.API.Common.Person.GetSystem().iPersonId;

                // Změna stavu
                Alvao.API.SD.Ticket.ChangeState(ticketId, targetState.id, systemPersonId, null);
            }
        }
    }
    ...
}

Celý příklad ke stažení: Example_TicketApprovalAutoAction.zip

Odeslání zprávy v rámci automatické akce

Pokud potřebujete v rámci automatické akce odeslat libovolnou zprávu, využijte k tomu metodu SendMessage. Pokud si nepřejete, aby odeslaná zpráva byla zapsána do deníku požadavku, využijte metodu QueueMailMessage.

Poznámka:
Metody mohou být využity i pro ostatní typy rozšíření.

 

Nenašli jste co jste hledali? Zeptejte se našeho týmu technické podpory.