České vysoké učení technické v Praze Fakulta elektrotechnická
ˇ VUT FEL katedra pocˇı´tacˇu˚ C
Bakalářská práce
Počítačová podpora telefonního provozu call-centra Pavel Mikula
Vedoucí práce: Ing. Jan Žďárek
Studijní program: Elektrotechnika a informatika strukturovaný bakalářský Obor: Informatika a výpočetní technika květen 2007
iv
Poděkování Rád bych poděkoval Ing. Jiřímu Zídkovi za ochotu a aktivní přístup při četných konzultacích a řešení nalezených problémů. Rovněž děkuji Ing. Janu Žďárkovi za kvalitní vedení a cenné rady při psaní mé práce. v
vi
Prohlášení Prohlašuji, že jsem svou bakalářskou práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých zákonů (autorský zákon).
V Horoměřicích dne 1.6. 2007
.............................................................
vii
viii
Abstract This work describes analysis and realization of software driven call-centre control based on specific requirements. Software control is provided by cooperating with CSTA libraries. These libraries provide program interface between PBX and an application at the .NET objects level. An analysis and description of realization are followed by explained telephony schema and complete application and necessary PBX setting. There are also discussed some alternative problem solutions and their drawbacks. This document will provide a valuable information for those who search for improvement of efectivity of call-centre, search for already developed solutions and for those, who are planning implementation of their own CSTA application.
Abstrakt Práce popisuje návrh a řešení aplikace pro softwarové řízení call-centra na základě konkrétních požadavků provozovatele. Řízení je zajištěno součinností aplikace s CSTA knihovnami, které poskytují rozhraní mezi ústřednou a programem na úrovni .NET objektů. Kromě analýzy a realizace vlastního software je zde vysvětleno telefonní schéma a kompletní nastavení včetně částí týkající se programování ústředny. V textu jsou rovněž rozebrány některé alternativní možnosti řešení a jejich případné nevýhody. Dokument je adresovaný těm, kteří hledají způsob jak zlepšit efektivitu práce call-centra, hledají již vyvinutá řešení nebo plánují vlastní implementaci aplikace na bázi CSTA knihoven.
ix
x
Obsah Seznam obrázků
xiii
Seznam tabulek
xiii
1 Úvod 1.1 Souhrn požadavků na aplikaci . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Proč právě cesta CSTA a vlastní implementace? . . . . . . . . . . . . . . . . . 1.3 Volba vývojového prostředí . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Analýza a 2.1 Návrh 2.2 Návrh 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.2.20 2.2.21 2.2.22 2.2.23 2.2.24 2.2.25 2.2.26 2.2.27 2.2.28
návrh řešení řešení požadavků . . . . . . . . . . . . . . . tříd . . . . . . . . . . . . . . . . . . . . . . . Enum eCallTarget . . . . . . . . . . . . . Enum eDenniRezim . . . . . . . . . . . . . Enum ePbx . . . . . . . . . . . . . . . . . . Enum eStav . . . . . . . . . . . . . . . . . Enum eExtState . . . . . . . . . . . . . . . Třída NTelService . . . . . . . . . . . . . Třída Global asax . . . . . . . . . . . . . . Třída NTelManager . . . . . . . . . . . . . Třída PbxProvider . . . . . . . . . . . . . Třída NtExtensionTable . . . . . . . . . . Třída NtExtension . . . . . . . . . . . . . Třída NtCallTable . . . . . . . . . . . . . Třída NtCall . . . . . . . . . . . . . . . . . Třída NtPilotTable . . . . . . . . . . . . . Třída NtPilot . . . . . . . . . . . . . . . . Třída NTeClientList . . . . . . . . . . . . Třída NTeClient . . . . . . . . . . . . . . . Třída NTeUserList . . . . . . . . . . . . . Třída NtUserListAfterChangedEventArgs Třída NtUserListChangedEventArgs . . . Třída NtUser . . . . . . . . . . . . . . . . . Třída NumberTable . . . . . . . . . . . . . Třída NTelExportUserList . . . . . . . . . Třída NTelExportUser . . . . . . . . . . . Třída NTelExportCall . . . . . . . . . . . Třída EAI . . . . . . . . . . . . . . . . . . . Třída EAI.EAIreport . . . . . . . . . . . . Třída AnnEAI . . . . . . . . . . . . . . . . .
3 Realizace projektu 3.1 Nastavení aplikace a vlastní běh . . . . . . 3.1.1 Spuštění, zastavení a běh aplikace . 3.1.2 Zotavení z chyb . . . . . . . . . . . . 3.2 Vlákna, zpracování událostí a synchronizace 3.2.1 Zpracování CSTA událostí . . . . . . 3.2.2 Pracovní vlákna . . . . . . . . . . . xi
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . .
1 1 4 5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6 6 8 10 10 11 11 11 11 11 11 12 13 13 13 14 14 14 14 15 15 15 15 16 16 16 16 16 16 16 17
. . . . . .
18 18 20 21 21 21 21
. . . . . . . . . . . . . . . . . . . . . .
21 22 22 22 22 22 23 23 23 25 25 25 25 26 27 27 27 28 28 28 29 29
4 Instalace aplikace 4.1 Požadavky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Instalace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Konfigurace ústředny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30 30 30 31
5 Testování 5.1 Nastavení aplikace a ústředny pro testování . . . . . . . . . 5.2 Průběh testování . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 Testování dílčích funkcí během analýzy a vývoje . . 5.2.1.1 Přehrání začátku hlášky při přesměrování z 5.2.1.2 Událost StatusInconsistency . . . . . . 5.2.1.3 Vracející se hovory . . . . . . . . . . . . . . 5.2.1.4 Nefunkční přesměrování hovoru z pobočky 5.2.1.5 Odregistrování pilotážního bodu . . . . . . 5.2.2 Ověření funkce . . . . . . . . . . . . . . . . . . . . . 5.2.3 Testovací provoz . . . . . . . . . . . . . . . . . . . . 5.3 Výsledky testování . . . . . . . . . . . . . . . . . . . . . . . 5.4 Řešení výpadku aplikace . . . . . . . . . . . . . . . . . . . . 5.4.1 Krátkodobý výpadek . . . . . . . . . . . . . . . . . . 5.4.2 Nouzový režim . . . . . . . . . . . . . . . . . . . . .
33 33 33 33 33 33 34 34 34 34 35 35 36 36 36
3.3
3.4
3.2.2.1 Obsluha Socketu pro klientské aplikace . . . . 3.2.2.2 Mechanismus zpožděného přesměrování hovorů 3.2.3 Časovač pro sledování nepřijatých hovorů . . . . . . . . 3.2.4 Synchronizace . . . . . . . . . . . . . . . . . . . . . . . . 3.2.4.1 SyncLock - zámek kritické sekce . . . . . . . . 3.2.4.2 Technika kopírování kolekce klíčů . . . . . . . Komunikace s okolními aplikacemi a systémy . . . . . . . . . . 3.3.1 Webové rozhraní . . . . . . . . . . . . . . . . . . . . . . 3.3.1.1 Serializace výstupu webových metod . . . . . . 3.3.2 Komunikace s klientskými CRM aplikacemi . . . . . . . 3.3.2.1 Formát zprávy o změně stavu pobočky . . . . 3.3.2.2 Formát zprávy o změně stavu hovoru . . . . . 3.3.3 Připojení do SQL databáze . . . . . . . . . . . . . . . . 3.3.4 Aktualizace seznamu uživatelů . . . . . . . . . . . . . . 3.3.5 Třídy EAI a AnnEAI . . . . . . . . . . . . . . . . . . . . 3.3.5.1 Protokol EAI . . . . . . . . . . . . . . . . . . . 3.3.5.2 Protokol AnnEAI . . . . . . . . . . . . . . . . Techniky použité při programování . . . . . . . . . . . . . . . . 3.4.1 Mechanismus událostí . . . . . . . . . . . . . . . . . . . 3.4.2 Delegáti a asynchronní spouštění událostí . . . . . . . . 3.4.3 Zápis do logu . . . . . . . . . . . . . . . . . . . . . . . . 3.4.4 Interface IDisposable . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . pilotážního bodu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . .
6 Závěr
37
7 Literatura
39
A Seznam pouzitých zkratek
41
B WSDL popis rozhraní webové služby
42
xii
B.1 Data/NTelService.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.2 Data/KeepAlive.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C Obsah přiloženého CD
42 42 43
Seznam obrázků 1.1 1.2
Sekvenční diagram požadavku na běžné call-centrum . . . . . . . . . . . . . . . Sekvenční diagram call-centra NetTravel.cz - zjednodušený prodej zájezdu . . .
1 2
2.1
Přehled vazeb mezi třídami . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
3.1
Komunikace aplikace s okolím . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
Seznam tabulek 3.1 3.2
Formát zprávy o změně stavu pobočky . . . . . . . . . . . . . . . . . . . . . . . Formát zprávy o změně stavu hovoru . . . . . . . . . . . . . . . . . . . . . . . .
xiii
25 26
xiv
KAPITOLA 1. ÚVOD
1
1 Úvod Pracuji pro cestovní agenturu NetTravel.cz s.r.o. jako programátor a byl mi zadán samostatný projekt na realizaci řízení telefonních hovorů call-centra (dále jen CC) a napojení této řídící aplikace na bázi CSTA (Computer-Supported Telephony Application) na stávající CRM (Customer Relationship Management) systém. Společnost se rozhodla pro vybudování CC a nákup pobočkové ústředny. Po první sezóně běhu CC se ukázalo jako nezbytné rozšířit HW řízení hovorů realizované logikou ústředny ještě o logiku odpovídající profilu a požadavkům společnosti a další funkce k zajištění efektivního provozu (např. vytáčení přímo z CRM aplikace, zobrazování informací o volajícím podle databáze, dynamické směrování hovorů apod.). Jak již bylo zmíněno, HW realizace nestačila pro plnění všech vyžadovaných úkolů a neřešila některé kritické problémy. Provoz cestovní agentury neodpovídá provozu běžného CC, jak je naznačeno na obrázku 1.1, s jedním příchozím i odchozím telefonním číslem a principem všeobecných nebo specializovaných operátorů. Toto je jeden ze dvou hlavních důvodů proč nebylo využito HW řešení, ani jiná hotová, dodavatelská, řešení CC. Do budoucnosti se navíc počítalo s vybudováním další pobočky v Bratislavě, která by měla vlastní pobočkovou ústřednu a plán provozu předběžně počítal s možností propojení obou ústředen a jejich společné řízení. Prodej zájezdů vyžaduje osobní přístup ke klientovi založený na principu „Já jsem Váš osobní prodejce a zahrnuje větší množství vzájemných telefonátů, jejichž přibližné schéma je na obrázku 1.2, mezi prodejcem a klientem (vyjasnění detailů, doplnění požadavků, zodpovídání průběžných dotazů, vlastní prodej). Klient zná přímou linku na svého prodejce a v případě potřeby volá přímo jemu, aniž by si musel vyslechnout uvítací hlášku, projít případným AVR systémem, pro komunikaci v českém jazyce stisknout jedničku, a jinému prodejci opět vysvětlit vše od začátku. Paralelně s tímto samozřejmě funguje i obecná infolinka, kterou zvedají všichni přihlášení prodejci.
Obrázek 1.1: Sekvenční diagram požadavku na běžné call-centrum
1.1
Souhrn požadavků na aplikaci
1. Zajištění přepojování hovorů z infolinek na prodejce podle následujících pravidel: • Ústředna přehraje klientovi uvítací hlášku a následně hovor přepojí dále. • Primárně bude hovor přepojen na prodejce, který s volajícím řešil jeho objednávku jako poslední, tato informace je k dispozici v databázi.
2
KAPITOLA 1. ÚVOD
Obrázek 1.2: Sekvenční diagram call-centra NetTravel.cz - zjednodušený prodej zájezdu
KAPITOLA 1. ÚVOD
3
• Existuje-li takový prodejce a nemůže hovor přijmout (není v práci nebo právě hovoří), bude hovor přepojen na jeho zástupce. • Není-li nalezen relevantní, volný prodejce pro přepojení, bude hovor přepojen na dalšího přítomného, volného člena cyklické skupiny. Cyklická skupina je tvořena operátory, kteří jsou do skupiny přihlášeni. Hovory na cyklickou skupinu jsou přesměrovány tak, že se vyhledá další volný operátor za tím, kterému byl hovor přesměrován minule. Vyhledávání těchto členů pak probíhá cyklicky přes celou skupinu. • Není-li nikdo volný, bude klientovi znít hláška o obsazenosti operátorů a pokus o přepojení se bude opakovat. 2. Zajištění přepojení přímého příchozího hovoru v případě obsazenosti nebo nepřítomnosti prodejce podle následujících pravidel • Nemůže-li volaný hovor přijmout (není přítomen nebo hovoří), bude hovor přepojen na jeho zástupce. • Nemůže-li ani zástupce hovor přijmout, je hovor přesměrován na skupinu. • Nepatří-li volané číslo žádnému zaměstnanci (např. linka uvolněná po odchodu zaměstnance) bude hovor směřovat na cyklickou skupinu. 3. Sledování stavu příchozích hovorů a přepojení na jiného prodejce v případě nepřijetí hovoru. • Není-li hovor přijat po stanovené době zvonění, bude přepojen na zástupce (v případě přímého hovoru), nebo na dalšího člena skupiny (v případě hovoru na infolinku). 4. Okamžité informování CRM aplikace příslušného prodejce o změnách stavu hovoru nebo telefonní pobočky. • Budou odesílány informace o příchozích a odchozích, interních i externích hovorech. • Budou odesílány následující informace o hovoru: číslo volaného, volajícího, ID hovoru (označení hovoru vygenerované ústřednou) a stav pobočky. • Budou odesílány následující informace o telefonu: zvednutí a zavěšení sluchátka. • Duplicitní informace nebudou odesílány (je-li hovor ukončen položením sluchátka prodejce, bude to odesláno jako jedna zpráva). 5. Ovládání hovoru nebo telefonní pobočky z CRM aplikace. • Založení hovoru (vytočení čísla), ukončení hovoru. • Přihlášení a odhlášení ze skupiny. • Výpis aktivních hovorů. 6. Průběžná aktualizace vnitřního telefonního seznamu ústředny podle změn v databázi. • Jednou v noci se přepíše celý seznam. • Při každé změně v databázi bude upraven příslušný záznam v ústředně. 7. Zajištění možnosti obsluhy dvou (a více) pobočkových ústředen jednou aplikací. 8. Možnost ručního přepínání denního a nočního režimu obou ústředen.
KAPITOLA 1. ÚVOD
4
1.2
Proč právě cesta CSTA a vlastní implementace?
Stávající HW řešení bylo založeno pouze na ACD (Automatic Call Distribution) a vnitřní logice ústředny, kde se prodejci pro obecnou infolinku přihlašovali tlačítkem na telefonu do cyklické skupiny. Telefonát řídila ústředna, nebylo do něj možné dynamicky zasahovat a každá změna vyžadovala přeprogramování ústředny. Toto nastavení mělo navíc dva zásadní problémy: • Nebyl-li prodejce v práci když mu klient zavolal, hovor zvonil na telefonu, který nikdo nezvedal, případný zástupce daného prodejce se o hovoru nedozvěděl a klientův požadavek nebyl vyřešen. • Zavolal-li klient v době kdy prodejce hovořil, dostal obsazovací tón a jeho požadavek opět zůstával nevyřešen, i když by to mohl vyřešit např. zástupce daného prodejce, který byl v danou chvíli volný. Další možností bylo využít SW M7480 [6] určeného pro řízení provozu CC. M7480 spravuje stav operátorů (odchody a pauzy). Dále umožňuje generovat statistiky a poskytuje klientské ActiveX rozhraní, které je možné integrovat do vlastních systémů a použít pro ovládání hovorů. Pro řízení hovorů lze přednastavit scénáře a spravovat je jednodušším nástrojem než terminálem pro programování ústředny. Tímto se řeší mnoho problémů zavedených HW řešením, SW je však primárně určen pro běžná CC a brzy bychom narazili na jeho hranice, přes které by se nebylo možné dostat. Bylo totiž dáno, že požadavky na vlastní aplikaci se budou s postupem času doplňovat a měnit podle aktuálního nastavení prodejního procesu. Kromě CSTA by bylo možné využít např. MS TAPI [7] (při rozšíření ústředny o příslušný modul TSPI (Telephony Service Provider Interface)). Tuto možnost nám dodavatel ústředny ale doporučil nepoužívat z následujících důvodů:1 • MS TAPI není standard definovaný žádnou normou, • TAPI obsahuje velké množství funkcí, které jsou ale různými dodavateli implementovány s různými výsledky právě kvůli nedostatečnému popisu rozhraní, • ve Windows je telefonní řízení stabilní do verze TAPI 2.2 (pro Windows 95 a NT4), • verze TAPI 3 a TAPI 3.1 je prakticky pouze TAPI 2.2 přepracované do modelu COM, čímž se přidala pouze komplexita COM rozhraní a nestabilita, • obecně panuje shoda v tom, že se TAPI hodí pouze pro zařízení dodávaná společností Microsoft2 a implementace pro telefonní ústředny se nepoužívá, • Microsoft nedoporučuje používat COM rozhraní k TAPI 3 z .NET Framework protože jeho obalující třída nefunguje3 , navíc by bylo volání COM funkcí z .NET Framework složité a logika COM rozhraní neodpovída objektovému modelu .NET. Informace o TAPI dodávaného k ústřednám Matra: • Jedná se o dvoustupňový produkt, kdy na jednom PC běží server MCTAPI, který komunikuje s ústřednou, a druhém ovladač MCTSPI komunikující se serverem, • implementace obsahovala několik zásadních problémů, např. pokud se přeruší spojení mezi klientem a serverem, tak je nutné restartovat celé PC4 , 1
Zdroj: Výsledek schůzky s Ing. J. Zídkem, Atlantis Telecom s.r.o, září 2005. H.323, Multicast Conferencing, NDIS Proxy, Unimodem 3 http://support.microsoft.com/default.aspx?scid=kb;en-us;841712 4 Tento problém byl vyřešen ve verzi 3.2, která byla ale publikována až rok po spuštění řešené aplikace. 2
KAPITOLA 1. ÚVOD
5
V porovnání CSTA a TAPI je CSTA jednoznačně lepší volbou, neboť jsou knihovny5 postavené na technologii .NET a neobsahují žádný kód mimo .NET (unmanaged). CSTA knihovny sice neobsahují takové množství funkcí jako TAPI, ale jejich logika funkcí přesně kopíruje logiku CSTA a jsou plnohodnotným nástrojem pro práci s ústřednou. Pro správu ústředny existuje kromě CSTA ještě proprietární protokol VTI/XML, který ale není určený třetím stranám a je určen pouze pro aplikace výrobce. Využití knihoven CSTA od výrobce poskytovalo jak řešení výše jmenovaných problémů tak dostatečnou flexibilitu pro případné zásahy do struktury aplikace. V době začátku vývoje aplikace byly knihovny ve verzi beta, ale dokázaly efektivně řešit stávající problémy a nejlépe odpovídaly požadavkům na flexibilitu celé aplikace.
1.3
Volba vývojového prostředí
Aplikace bude postavena na .NET Framework a jazyce VB.NET. Prostředí .NET jsem zvolil proto, že CSTA knihovny jsou postaveny na této technologii, ve firmě NetTravel.cz, pro kterou jsem aplikaci psal, je k dispozici server s běžícím .NET Framework a s vývojem aplikací pro tuto platformu mám mnoho zkušeností. Jazyk VB.NET volím z důvodu osobních zkušeností s rychlostí vývoje aplikací ve VB.NET a jazyce C#. K CSTA serveru může být připojena pouze jedna aplikace a řízení hovorů bude realizováno rovněž centrálně. Proto přichází v úvahu vytvořit aplikaci jako systémovou službu Windows nebo jako webovou službu. Tato aplikace bude vytvořena jako webová služba, což umožní zpřístupnění jejích metod jako metody webové služby, které je možné volat přes HTTP GET, POST nebo SOAP a napojení této služby na další aplikace bude tudíž velice jednoduché.
5
CSTA knihovny jsou 3 soubory - Csta.Common.dll, Csta.Engine.dll a CSTAp2.dll.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
6
2 Analýza a návrh řešení 2.1
Návrh řešení požadavků
1. Přepojování hovorů z infolinek. Příchozí hovor na infolinku je ústřednou přesměrován na virtuální pobočku, která má namísto vyzváněcího tónu nastavenou uvítací hlášku („Dobrý den, dovolali jste se informační linku NetTravel.cz . . .) a po odeznění hlášky je hovor přesměrován na pilotážní bod - HW skupinu typu EMPTY. Tato skupina se chová podobně jako běžná pobočka, může na ní vyzvánět více hovorů současně a lze ji z CSTA aplikace zaregistrovat, sledovat a ovládat její hovory. Pro případ výpadku je na pilotážním bodě nastaveno automatické přesměrování na operátorku při uplynutí maximální povolené doby vyzvánění. V každé ústředně je nastavený jeden pilotážní bod symbolizující skupinu poboček v dané ústředně. Tyto pilotážní body má aplikace zaregistrované, sleduje jejich události a zpracovává hovory. Při události Alerting, oznamující že hovor na pobočce zvoní nebo zvoní a čeká ve frontě, je podle čísla pobočky která hovor na pilotážní bod přepojila rozeznáno, že se jedná o hovor na infolinku a tato informace je zapsána k hovoru. Dále se aplikace pokusí v seznamu uživatelů nalézt prodejce, který s volajícím řešil jeho objednávku posledně. Je-li takový prodejce nalezen, ale není volný (právě hovoří nebo není v práci), je vybrán jeho volný zástupce. Je-li nalezen volný prodejce, popř. jeho zástupce, který má hovor přednostně přijmout, je mu hovor přesměrován. V opačném případě je hovor přepojen na cyklickou skupinu. Cyklická skupina je programovou realizací HW skupiny typu CYCLIC. Ta kromě přihlášení prodejce do skupiny a aktuálního stavu pobočky (hovoří/je volný) zohledňuje i stav zaměstnance podle docházky. Hovory na skupinu tak nebudou přepojovány na pobočky u kterých se prodejci zapomněli odhlásit tlačítkem pro odhlášení ze skupiny při odchodu z práce nebo na pauzu. Skupina je reprezentovaná pilotážním bodem, který sdružuje pobočky, infolinky a hovory dané ústředny. Evidence prodejců, kteří jsou přihlášeni do skupiny, bude realizována HW skupinou typu CYCLIC. Každý telefon bude členem cyklické skupiny a na svém telefonu bude mít tlačítko pro přihlášení a odhlášení z této HW skupiny. Na tuto skupinu typu CYCLIC nebudou přesměrovávány žádné hovory a bude sloužit pouze pro účely sledování přihlášení. Tuto evidenci by bylo možné realizovat pouze v aplikaci, ale HW realizace poskytuje několik výhod, jako je možnost přihlášení a odhlášení přímo z telefonu a kontrolu stavu přihlášení přímo na telefonu. Při předání hovoru cyklické skupině se podle čísla pobočky, na které se hovor aktuálně nachází, dohledá příslušný pilotážní bod (pilotážní bod ze stejné ústředny jako aktuální pobočka nebo pilotážní bod sám) a najde se další volný člen této skupiny. Je-li takový člen nalezen je mu hovor přesměrován, jinak se s hovorem nedělá nic. Pokud hovor zůstává na pilotážním bodě, zní hláška „Všichni operátoři jsou momentálně vytíženi, čekejte prosím. V případě, že je hovor přesměrován na skupinu z některé pobočky, je ponechán na této pobočce a nadále vyzvání. Pokus o přepojení se bude později opakovat. 2. Přepojení přímého příchozího hovoru v případě obsazenosti nebo nepřítomnosti prodejce. Každý externí příchozí hovor je hardwarově přesměrován ústřednou na příslušný pilotážní bod, bez ohledu na to, zda je či není pobočka aktuálně zaregistrovaná (např. protože je aktuálně nevyužitá nebo na ní nezbyla licence). Veškeré přímé příchozí hovory se tak dostanou na pilotážní bod, kde aplikace rozhodne co s nimi.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
7
Aplikace zkusí nalézt volného prodejce, z jehož telefonu byl hovor na pilotážní bod přesměrován, nebo jeho volného zástupce a hovor mu přepojí. Není-li takový prodejce nalezen, je hovor přesměrován na cyklickou skupinu. 3. Sledování stavu příchozích hovorů a přepojení na jiného prodejce v případě nepřijetí hovoru. U každého sledovaného hovoru je časovač (instance třídy System.Timers.Timer), který při uplynutí své doby odpočtu zavolá událost na kontrolu uplynutí času vyzvánění. Tato metoda ověří zda hovor vyzvání déle než je povoleno a podle původního cíle volání přepojí hovor na volného zástupce nebo dalšího volného člena cyklické skupiny. U hovoru se sleduje událost CallStatusChanged, která oznamuje změnu stavu hovoru, při které se časovač spouští nebo předčasně ukončuje. Pro zvednuté nebo zavěšené hovory se tak nebude zbytečně ověřovat vypršení časového limitu na vyzvánění. 4. Informování CRM aplikace prodejce o změnách stavu hovoru nebo telefonní pobočky. Aplikace vytvoří instanci třídy System.Net.Sockets.Socket, která bude naslouchat na přednastaveném portu a v blokujícím režimu čekat na příchozí TCP spojení od klientských CRM aplikací. Na začátku každého takového připojení se uvítací frází ověří, zda jde skutečně o aplikaci prodejců. Součástí této fráze je i číslo pobočky, o kterém chce být aplikace informována. Pokud je vše v pořádku, je připojení přijato a zařazeno do seznamu připojených aplikací podle čísla pobočky. Aplikace sleduje kromě událostí hovorů (začátek vyzvánění, ukončení hovoru a další) i události vlastní pobočky (jakými jsou zvednutí sluchátka a zavěšení) a zasílá o těchto událostech zprávy. Druh zprávy (hovor/změna stavu sluchátka) se i s číslem pobočky předá seznamu poboček, který ověří zda je připojena aplikace sledující právě tuto pobočku a zprávu odešle. Při vlastním odesílání si aplikace u konkrétní pobočky pamatuje její poslední stav (zda má zvednuté nebo zavěšené sluchátko) a před odesláním zprávy o změně tohoto stavu nejdříve otestuje, zda tento stav nebyl odeslán v předchozí zprávě. 5. Ovládání hovoru nebo telefonní pobočky z CRM aplikace. Formou webové služby jsou zpřístupněny funkce pro vytvoření a ukončení hovoru, pro nalezení aktuálního hovoru pobočky. Dále jsou k dispozici metody pro přihlášení a odhlášení ze skupiny, výpis stavu prodejců a metoda pro zjištění počtu prodejců přihlášených ve skupině. Tyto metody jsou přístupné metodami GET, POST i SOAP, aby bylo volání rozhraní co nejjednodušší pro CRM aplikaci (GET), umožňovalo ruční ovládání z testovacích formulářů (POST) a poskytovalo interface pro jiné .NET aplikace (SOAP). 6. Průběžná aktualizace vnitřního telefonního seznamu ústředny podle změn v databázi. Každou noc se provede restart celé aplikace pro vyčištění stavu a nahraje se znovu celé nastavení včetně seznamu zaměstnanců. Při této příležitosti se celý telefonní seznam ústředny smaže a opět se nahraje podle stavu databáze. Podle databáze se bude sledovat docházka, přiřazení linek a vytváření nových zaměstnanců a podle těchto změn se upraví informace o zaměstnancích v aplikaci, přehrají se všechny související záznamy v telefonním seznamu (při změně linky se původní záznam odstraní) a aplikaci se odešle událost o změně linek. Ta si v případě potřeby následně upraví registrace příslušných poboček. Vlastní obnova stavu se bude volat před každým pokusem o nalezením volného zaměstnance pro hovor. Metoda pro obnovení si následně sama zajistí, aby nedocházelo k dota-
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
8
zům do databáze příliš často. Dotaz do databáze se bude dělat minimálně v 15 sekundových intervalech, kdy se nejdříve ověří kontrolní součet pro ID, linky a docházku zaměstnanců. Načtení nového seznamu z databáze proběhne pouze v případě, že se tento součet liší od posledního stavu. Při aktualizaci stavu se upraví, resp. přidají pouze ty záznamy, u kterých došlo ke změně. Jinou možností bylo využít např. databázový trigger1 , který by sledoval změny v příslušné tabulce a ukládal ID změněných záznamů do zvláštní tabulky. V tomto případě by ale opět musel být v pravidelných intervalech prováděn dotaz na kontrolu této tabulky. Pro .NET 2.0 a MS SQL Server 2005 existuje mechanismus informování o změnách přímo z SQL serveru, aplikace je ale navržena pro MS SQL 2000 takže tuto variantu není možné využít. 7. Zajištění možnosti obsluhy dvou (a více) pobočkových ústředen jednou aplikací. Řízení dvou a více ústředen je zajištěno tím, že se ústředny nastaví do režimu, ve kterém se z pohledu aplikace chovají jako jeden CSTA systém. V tomto případě se CSTA aplikace připojuje pouze k jedné ústředně a se všemi pobočkami pracuje tak, jako by byly pouze v této ústředně. Druhou možností bylo spustit CSTA server v každé ústředně a řízení provádět paralelně z jedné aplikace. Tato varianta by vyžadovala udržování a sledování více připojení k ústředně. S tím by se zvýšila složitost aplikace, protože by se musely obsluhovat zprávy z různých systémů a jejich obsluha by se musela provádět s ohledem na zdroj zprávy. Řešení by také pravděpodobně vedlo na problémy v nekonzistenci hovorů při přepojování hovorů mezi různými ústřednami. 8. Možnost ručního přepínání denního a nočního režimu obou ústředen. Webová služba obsahuje metodu pro přepnutí denního režimu vybrané ústředny. Každá z ústředen může ležet v jiném státě, a proto je nutné režimy přepínat samostatně pro jednotlivé ústředny. Proto je EAI server nastaven v každé zvlášť a aplikace se připojuje k různý IP adresám. Režim se přepne sekvencí EAI zpráv odeslaných přes protokol TCP/IP do ústředny. Aplikace neobsahuje metodu pro zjištění aktuálního režimu, protože to tento protokol neumožňuje.
2.2
Návrh tříd
Aplikace je postavena na technologii .NET Framework, která poskytuje velké množství již hotových tříd pro práci se sítí, vlákny, kolekcemi a dalšími prvky. Např. pro práci se sítí se využívá jmenný prostor System.Net.Sockets a třída Socket, pro práci s kolekcemi a tabulkami se využívá jmenný prostor System.Collections . Kromě těchto prostorů se využívá např. také SystemIO, System.XML a další. Klíčové třídy celé aplikace jsou třídy NTelManager a PbxProvider. NTelManger řídí logiku celé aplikace a PbxProvider poskytuje rozhraní pro komunikaci s ústřednou. Global asax a NTelService jsou vstupním místem aplikace. Global asax je standardní součást ASP.NET aplikace a sleduje události, jakými jsou výskyt neošetřené výjimky, spuštění a ukončení aplikace. Podle těchto událostí je spouštěno a ukončováno jádro aplikace. NTelService představuje vlastní rozhraní webové služby přístupné metodami GET, POST a SOAP. NTelService přijímá požadavky od jiných aplikací a předává je ke zpracování dále do aplikace. Výsledky jsou pak ve formě XML předávány zpět. 1
Trigger je dávka SQL příkazů spouštěná automaticky při určité akci v databázi, jakými může být přidání, úprava nebo odstranění řádku.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
9
MainThread je modul2 který udržuje hlavní a jedinou instanci třídy NTelManager, stará se o servisní akce aplikace, jakými jsou spuštění a udržení aplikace v chodu, ukončení a ukládání logů. NTelManager je hlavní třída aplikace. Tato třída se stará o vnitřní logiku celé aplikace, řízení telefonních hovorů a zprostředkování ostatních poskytovaných služeb. NTelManager zpracovává a odpovídá na všechny požadavky z webové služby, sleduje události ústředny, zprostředkované třídou PbxProvider a na jejich základě samostatně řídí telefonní provoz. Dále si udržuje seznam připojených CRM aplikací pro zasílání zpráv o hovorech a seznam aktivních uživatelů. PbxProvider obaluje objekt typu Pbx z CSTA knihoven funkcemi potřebnými pro řízení a kontrolu telefonního provozu ústředny a zprostředkovává vlastní komunikaci s CSTA knihovnami. Udržuje si také vlastní seznam přihlášených poboček a seznam probíhajících hovorů. NtExtensionTable je potomkem HashTable, udržuje tabulku objektů typu NtExtension a stará se o synchronizovaný přístup k těmto objektům. Klíčem pro identifikaci NtExtension je číslo pobočky. NtExtension je třída rozšiřující objekt Extension CSTA knihoven o stav registrace. NtCallTable se podobně jako NtExtensionTable, udržuje tabulku aktuálně probíhajících hovorů a stará se o synchronizovaný přístup k těmto objektům. Klíčem pro identifikaci hovorů je ID3 jednotlivých hovorů generované ústřednou. NtPilotTable se podobně jako NtExtensionTable a NtCallTable, udržuje tabulku používaných pilotážních bodů. Hlavní funkcí NtPilotTable je nalezení pilotážního bodu k dané pobočce. NtPilot sdružuje vlastní informace o pilotážním bodě, jeho číslo, aktuální pozici cyklické skupiny a seznam všech poboček patřících do této skupiny. NTeClientList představuje seznam všech aktuálně připojených CRM aplikací, kterým je možné zaslat zprávu. Zajišťuje správu připojených socketů a rozesílání informací o změnách stavu pobočky i informací o probíhajících hovorech příslušným připojeným aplikacím. NTeClient reprezentuje jednoho konkrétního připojeného klienta a stará se o TCP socket. Dále sestavuje, zpracovává a zajišťuje odeslání vlastní zprávy klientovi. NTeUserList se stará o seznam všech aktivních uživatelů a jejich správu. NTeUserList sleduje stav databáze a sama se aktualizuje. O každé změně zasílá informaci nadřazené třídě NTelManager a dále aktualizuje vnitřní telefonní seznam ústředny. NTeUserList také dohledává příjemce hovorů na infolinky v databázi a vybírá další volné členy cyklické skupiny pro přepojení telefonátu. NtUserListChangedEventArgs a NtUserListAfterChangeEventArgs jsou třídy, které pouze přenášejí dodatečné informace při vyvolání události při změně v seznamu uživatelů. Třída NTelManager tyto události zpracovává podle hodnot obsažených v instancích těchto tříd. NTelUser představuje jednoho zaměstnance a jeho aktuální stav. Dohledává také volného zástupce daného zaměstnance. 2
Modul je ve VB.NET speciální třída, která má pouze statické členy a nelze vytvořit její instanci. ID hovoru je text jednoznačně identifikující hovor. Toto ID generuje ústředna a bývá ve tvaru XX-XX-XXXX, kde X je hexadecimální číslice 3
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
10
NtExportCall, NtExportUserList a NtExportUser slouží pouze pro jednoduchou serializaci objektů představující výsledek volání webové služby do vlastní odpovědi pro klienta ve formátu XML. AnnEAI je třída implementující protokol AnnEAI pro komunikaci s ústřednou a správu vnitřního telefonního seznamu ústředny. Třída zajišťuje přidávání i mazání záznamů a sestavování i zasílání zpráv přes protokol TCP/IP ústředně. EAI je třída realizující přepínání denního a nočního režimu ústředny. Podobně jako EAI sestavuje a zasílá zprávy ústředně na základě vlastní implementace EAI protokolu.
Obrázek 2.1: Přehled vazeb mezi třídami
2.2.1
Enum eCallTarget
• Unknown - cíl není známý. • GroupCall - hovor na infolinku. • DirectCall - přímý hovor na číslo prodejce. 2.2.2
Enum eDenniRezim
• Noc - reprezentace nočního režimu ústředny.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
11
• Den - reprezentace denního režimu ústředny. 2.2.3
Enum ePbx
• CC - reprezentace ústředny CC v Praze • BA - reprezentace ústředny v Bratislavě 2.2.4
Enum eStav
• Doma - zaměstnanec není v práci. • Pracuje - zaměstnanec je v práci a může přijímat hovory. • NaPauze - zaměstnanec je v práci, ale není přítomen na svém místě a nemůže přijímat hovory. • Sluzebne - zaměstnanec pracuje mimo budovu a nemůže přijímat hovory. 2.2.5
Enum eExtState
• RegWait - byl odeslán požadavek na zaregistrování a pobočka čeká na jeho potvrzení. • Registered - pobočka je zaregistrovaná a připravená k činnosti. • UnRegWait - byl odeslán požadavek na odregistrování pobočky a čeká na jeho potvrzení. • Unregistered - pobočka je odregistrována. 2.2.6
Třída NTelService
Třída slouží pouze pro zveřejnění metod ve webovém rozhraní. V případě všech volání pouze ošetří chyby při volání (při vypnuté aplikaci se nebude volání předávat) a předá ošetření dále do aplikace a to přímo metodám modulu MainThread nebo instanci NTe typu NTelManager tohoto modulu. 2.2.7
Třída Global asax
Sleduje události Application Start, Application Stop a událost Application Error objektu HttpApplication a předá ošetření modulu MainThread. Při výskytu Application Error odešle zprávu o chybě e-mailem. 2.2.8
Třída NTelManager
AgentLogin, AgentLogout, AgentLogoff jsou metody pro přihlášení a odhlášení ze skupiny. AgentLogin odhlásí pobočku z HW skupiny v ústředně, čímž se po asynchronní události AgentStatusChanged ústředny změní stav zaměstnance. Metoda AgentLogoff slouží pouze pro servisní účely. Je to nepodmíněné odhlášení ze skupiny při problémech s přihlašováním. CreateExtCall, CreateUserCall, ReleaseUserCall slouží pro vytočení a ukončení hovoru dané pobočky (Extension) nebo daného uživatele. DayMode přepíná denní a noční režim zvolené ústředny.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
12
LoggedAgentCount, LoggedAgentList slouží pro export počtu aktuálně přihlášených prodejců ve skupině a export jejich seznamu včetně stavu. DivertToCyclicGroup je metoda, která pro daný hovor dohledá pobočku a příslušného pilota a zjistí dalšího člena cyklické skupiny, kterému hovor přepojí. Pokud není kvůli chybě v nastavení možné pilota nalézt, použije se „pseudonáhodný pilot (ten s větším počtem poboček). FindUser pro dané ID zaměstnance vrátí příslušnou instanci NTelUser Login přihlásí daného uživatele na pobočce příslušné k HW klíči4 daného počítače. Tato metoda je zde pro budoucí použití. Maintenance provede znovunačtení nastavení a zavolá metody Terminace a Start pro restart aplikace. Start spustí chod aplikace, nastartuje všechna servisní vlákna, načte seznam uživatelů a přehraje telefonní seznam ústředny. Dále vytvoří instanci objektu PbxProvider, který se připojí přes CSTA k ústředně. Nakonec zaregistruje virtuální pobočky pilotážích bodů a další pobočky podle priorit až do vyčerpání licencí. Terminace ukončí všechna provozní vlákna, ukončí činnost objektu PbxProvider a smaže všechny udržované seznamy. UserCall pro dané ID zaměstnance vrátí aktivní hovor, který právě probíhá na jeho pobočce. 2.2.9
Třída PbxProvider
Extension pro dané číslo pobočky vrátí instanci NtExtension, je-li pobočka zaregistrovaná. ExtensionNumbers vrátí kopii kolekce čísel všech zaregistrovaných poboček. IsConnected vlastnost indikující, že je objekt Pbx CSTA knihoven připojen k ústředně. IsRegistered vrací informaci o tom, zda je dané číslo pobočky v čase volání zaregistrované a lze s pobočkou pracovat. LoggedAgentCount vrací počet poboček, které jsou právě přihlášené do skupiny. MyPbx je vlastnost vracející právě používanou instanci objetu Pbx CSTA knihoven NtCall pro daný ICall CSTA knihoven najde a vrátí příslušnou instanci objektu NtCall. NtCalls je tabulka všech NtCall reprezentující všechny probíhající hovory. AgentLogin programově přihlásí a odhlásí zvolenou pobočku ze skupiny. ContainsCall ověřuje, zda daný hovor patří dané pobočce. Deregister odregistruje pobočku. ExtensionActiveCall vrátí hovor, který právě probíhá na dané pobočce. Je-li na pobočce více hovorů, bude vybrán ten aktivní. IsAgentLoggedIn ověří, zda je daná pobočka přihlášená do skupiny. 4
Jako HW klíč je možné použít libovolnou jedinečnou identifikaci počítače, pro jednoduchost např. i jeho jméno v doméně
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
13
IsIncomming vrací True 5 v případě, že se jedná o příchozí hovor. IsInternal vrací True v případě, že se jedná o vnitřní hovor. IsOutgoing vrací True v případě, že se jedná o odchozí hovor. Register provede registraci pobočky pro sledování událostí a práci s ní. ReleaseCall zajistí zavěšení daného hovoru pobočky. 2.2.10
Třída NtExtensionTable
Item pro dané číslo pobočky vrátí příslušnou instanci NtExtension. Keys vrátí kopii kolekce čísel všech NtExtension obsažených v NtExtensionTable. Add vytvoří novou instanci NtExtension a podle daného čísla ji přidá do tabulky. Takto přidaná pobočka bude ve stavu RegWait - čekání na potvrzení registrace. Clear u každé NtExtension nastaví stav Unregistered a odstraní referenci na objekt typu Extension CSTA knihoven. Poté vyčistí tabulku. ConfirmAdd potvrdí registraci daného čísla pobočky (nastaví stav na Registered ). Deregister nastaví stav pobočky na UnRegWait - čekání na odregistrování. Remove nastaví stav pobočky na Unregistered a odstraní ji z tabulky. 2.2.11
Třída NtExtension
State udržuje stav objektu NtExtension. Ext je instance příslušného objektu Extension CSTA knihoven. Numer vrátí číslo aktuální pobočky Ext. Není-li Ext nastaveno, bude vráceno -1. 2.2.12
Třída NtCallTable
Item pro dané ID hovoru vrátí příslušnou instanci NtCall. Keys vrátí kopii kolekce čísel všech NtCall obsažených v NtCallTable. Add pokud tabulka již obsahuje ID hovoru tak u stávající instance NtCall nahradí hovor, jinak vytvoří novou instanci třídy NtCall a přidá ji do tabulky. Clear z tabulky odstraní pouze staré hovory. ClearInvoke asynchronně zavolá metodu Clear. FixCallID při změně ID hovoru odstraní původní ID z tabulky a vloží NtCall s jeho novým ID. Remove odstraní z tabulky hovor s daným ID. 5
Hodnota True reprezentuje logickou jedničku, pravdu.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
14 2.2.13
Třída NtCall
AlertingTime vrátí dobu od začátku vyzvánění hovoru v sekundách. Call vrací instanci příslušného hovoru Call CSTA knihoven. CalledNumber je číslo volaného - původní cíl hovoru (nikoli číslo pobočky, která hovor přijala). CallStatus vrací CallStatus příslušné instance Call CSTA knihoven. Created je čas vytvoření instance NtCall. ExtensionNumber je číslo pobočky, na které probíhá hovor. IsAlerting vrací True v případě, že hovor vyzvání. QDivertFails je počet neúspěšných pokusů o přepojení hovoru. RemoteNumber je číslo protistrany hovoru. Target reprezentuje původní označení cíle hovoru podle aplikace. QDivert přesměruje hovor a vymaže požadované číslo příjemce proti duplicitnímu zařazení do fronty přesměrování. V případě neúspěchu zvýší počet neúspěšných pokusů o přesměrování. ResetAlertingTime - vynuluje čas od začátku vyzvánění nastavením na aktuální čas. 2.2.14
Třída NtPilotTable
Add přidá do tabulky pilotážní bod. Clear postupně projde všechny pilotážní body v tabulce, u každého vymaže seznam příslušejících čísel a nakonec odstraní všechny pilotážní body z tabulky. FindShepherd pro dané číslo pobočky najde příslušný pilotážní bod. Nepřísluší-li pobočka žádnému bodu, bude vrácen ten s největším počtem členů. 2.2.15
Třída NtPilot
Number je číslo virtuální pobočky pilotážního bodu. CyclicPos je aktuální pozice pro přepojení v cyklické skupině. Pool je seznam všech čísel poboček, které přísluší aktuální instanci NtPilot. 2.2.16
Třída NTeClientList
GetByIndex vrátí NTeClient podle jeho indexu v seznamu. Item vrátí NTeClient podle čísla pobočky. AddNew odpojí původní CRM aplikaci, pokud je její linka již připojena a vytvoří novou instanci objektu NTeClient, kterou podle čísla linky přidá do seznamu. Clear uzavře všechny objekty NTeClient v seznamu a vymaže seznam. RemoveClient ze seznamu odstraní daného klienta.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
15
SendExtCall v seznamu připojených klientů najde podle čísla pobočky příjemce zprávy a pošle mu informaci o hovoru. SendExtStatus v seznamu připojených klientů najde podle čísla pobočky příjemce zprávy a pošle mu informaci o změně stavu pobočky. 2.2.17
Třída NTeClient
Close odešle klientovi frázi značící uzavření socketu ze strany serveru a uzavře socket. SendData ověří, zda se klient neodpojil, převede danou zprávu do bufferu a odešle klientovi přes socket. SendExtCall převede informace o hovoru na zprávu pro klienta a odešle ji. SendExtStatus převede informace o stavu pobočky na zprávu pro klienta a odešle ji. 2.2.18
Třída NTeUserList
Item podle ID zaměstnance vrátí příslušnou instanci NtUser. Add přidá zaměstnance do seznamu podle jeho ID. AddNew vytvoří instanci NtUser a přidá do seznamu podle ID. CyclicNext vybere ze seznamu dalšího člena cyklické skupiny pro daný pilotáží bod a posune pozici ve skupině. Export vrátí kopii seznamu zaměstnanců určenou pro serializaci do XML. Find najde a vrátí instanci objektu NtUser podle čísla linky. FindByResil podle telefonního čísla dohledá v databázi posledního zaměstnance, který s volajícím řešil jeho objednávku naposledy a vrátí příslušnou instanci NtUser. LoadFromDB načte kompletní seznam aktivních uživatelů z databáze a přehraje podle něho celý vnitřní telefonní seznam ústředny. RefreshStav obnoví seznam zaměstnanců, jejich stav a telefonní linky. Metoda zajišťuje, že se dotazy do databáze budou dělat minimálně v patnáctisekundových intervalech a k načtení seznamu dojde pouze v případě, že se změnil kontrolní součet ID, Linky a stavu zaměstnance. Chybějící uživatelé budou přidáni a u změněných linek dojde k úpravě čísla v telefonním seznamu. 2.2.19
Třída NtUserListAfterChangedEventArgs
ZmenaLinek je nastavena na True, pokud došlo ke změně některé linky. 2.2.20
Třída NtUserListChangedEventArgs
Linka je číslo linky zaměstnance, u kterého došlo ke změně. Stav je nový stav zaměstnance. User je instance objektu NtUser, u které došlo ke změně.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ
16 2.2.21
Třída NtUser
Parent je odkaz na seznam uživatelů, ve kterém se instance NtUser nachází. ID je ID zaměstnance podle databáze. Linka je číslo linky zaměstnance. Pilot je číslo pilotážního bodu, pod který spadá linka zaměstnance. id Zastupce1, id Zastupce2 jsou ID zaměstnanců, kteří zastupují aktuálního zaměstnance. ExtState je stav zaměstnancovy pobočky. ExtAgentStatus je stav přihlášení do skupiny zaměstnancovy pobočky. Zastupce najde a vrátí volného zástupce zaměstnance, který může přijmout hovor. Všechny ostatní vlastnosti jsou kopií informací z databáze. 2.2.22
Třída NumberTable
Item pro danou linku vrátí ID zaměstnance, kterému patří. Add přidá klíč Linka - ID zaměstnance do tabulky. Replace nahradí záznam s původní linkou zaměstnance novou linkou. 2.2.23
Třída NTelExportUserList
Item pro daný index vrátí příslušnou instanci objektu NtExportUser ze seznamu. 2.2.24
Třída NTelExportUser
ExtAgentStatus, ExtState, ID, Linka, Login, Stav jsou kopie informací o instanci objektu NtUser pro serializaci do XML. 2.2.25
Třída NTelExportCall
CallStatus, ConnnectedTimeStamp, ID, OwnerExtension, RedirectingParty, RemoteParty, StartedTimeStamp, Tag, TerminatedTimeStamp ] jsou kopie informací o instanci objektu Call CSTA knihoven pro serializaci do XML. 2.2.26
Třída EAI
Connect připojí se k ústředně a odešle přihlašovací zprávu. V případě neúspěšného přihlášení vyhodí výjimku. DenniRezim vytvoří zprávu protokolu EAI pro přepnutí denního režimu a odešle do ústředny. Disconnect odpojí se od ústředny. 2.2.27
Třída EAI.EAIreport
ResponseMessage převede číslo chyby na zprávu podle dokumentace. IsOK vrací True v případě, že odpověď od ústředny nesignalizuje chybu.
KAPITOLA 2. ANALÝZA A NÁVRH ŘEŠENÍ 2.2.28
17
Třída AnnEAI
Connect se připojí k ústředně a odešle přihlašovací zprávy. Create vytvoří zprávu pro vytvoření položky v telefonním seznamu a odešle ji do ústředny. Delete vytvoří zprávu pro odstranění položky z telefonního seznamu ústředny a odešle ji. DeleteAll odstraní všechny záznamy z telefonního seznamu ústředny. Disconnect odpojí se od ústředny.
KAPITOLA 3. REALIZACE PROJEKTU
18
3 Realizace projektu Systém konfigurace aplikace je navržen tak, aby nevyžadoval žádné speciální nástroje pro provádění změn a současně, aby se parametry daly měnit co nejefektivněji. Proto jsem zvolil možnost umístit nastavení do souboru web.config, na jehož změny stačí textový editor a jehož změna způsobí restart aplikace, takže za běhu není nutné kontrolovat parametry, ani ošetřovat jejich změny.
3.1
Nastavení aplikace a vlastní běh
Veškerá konfigurace aplikace se provádí v souboru web.config. Aplikace je .NET webová služba a .NET Framework sleduje změny zdrojových souborů. Dojde-li k takové změně, je aplikace, nebo její část, překompilována nebo, jako v případě změny souboru web.config, restartována. Soubor web.config obsahuje nastavení vlastní webové aplikace ve formě XML a sekci appSettings. Do této sekce je možné přidávat libovolné položky typu klíč-hodnota, které je možné číst za běhu aplikace. V sekci appSettings se nacházejí následující klíče: APP Debug může obsahovat hodnoty True/False. Při nastavené hodnotě True se budou vypisovat podrobné záznamy o činnosti aplikace. APP Trace může obsahovat hodnoty True/False. Na tuto hodnotu jsou nastaveny všechny parametry metody SetDebugLevel třídy Pbx z CSTA knihoven. Pokud je nastavena na True tak aktivuje podrobný výpis událostí z CSTA knihoven do Trace1 . TCP IP CC je IP adresa první ústředny. Na tuto adresu se připojuje CSTA protokol, EAI pro českou ústřednu i AnnEAI. TCP IP BA je IP adresa druhé ústředny pro přepínání režimu pomocí EAI protokolu. TCP Port je číslo portu CSTA serveru v první ústředně. TCP ServerPort je číslo portu, na kterém aplikace čeká na připojení klientských CRM aplikací pro zasílání informací o hovorech. TCP EAIPort je číslo portu pro EAI protokol. TCP AnnEAIPort je číslo portu pro AnnEAI protokol. EAI PWD je heslo pro navázání EAI komunikace. REGISTER Include obsahuje seznam čísel jednotlivých poboček oddělených čárkami, o které se bude aplikace starat a nespadají do žádné sekce REGISTER Range (viz. níže). REGISTER Exclude obsahuje seznam čísel poboček oddělených čárkami, o které se aplikace nebude starat. A to ani v případě, že bude pobočka zahrnuta v REGISTER Include, nebo některém z REGISTER Range. REGISTER RangeMinNNN spolu s REGISTER RangeMaxNNN určují rozsah linek, o které se bude aplikace starat. REGISTER RangeMinNNN je nejnižší číslo linky v rozsahu s in1
Trace je místo, kam lze zapisovat informace o běhu programu. V případě potřeby je pak možné na Trace připojit třídu implementující ITraceListener která bude zapisované informace sbírat.
KAPITOLA 3. REALIZACE PROJEKTU
19
dexem NNN. Registrovaných rozsahů může být více2 , proto se rozsahy označují indexem NNN, který nabývá hodnot od nuly včetně. Aplikace se pokusí rozsahy načítat až do přerušení řady čísel NNN. REGISTER RangeMaxNNN je nejvyšší číslo linky v rozsahu NNN. PBX Groups obsahuje seznam skupinových linek oddělených čárkami. Hovory z těchto linek jsou označeny jako hovory na infolinku a jsou přesměrovány na prodejce, který řešil klientovu objednávku jako poslední nebo rovnou na cyklickou skupinu. PBX Pilots obsahuje čísla pilotážních bodů oddělených čárkami. Hovory zvonící na těchto linkách jsou určeny k přesměrování na prodejce. PBX LicencedExtensions je počet licencí na pobočky, které je možné současně zaregistrovat. PILOTPOOL XXX Include je seznam čísel jednotlivých poboček oddělených čárkami, které spadají pod pilotážní bod s číslem XXX a budou tudíž patřit do cyklické skupiny pro přidělování hovorů reprezentované tímto pilotážním bodem. PILOTPOOL XXX Exclude obsahuje seznam čísel poboček oddělených čárkami, které nespadají pod pilotážní bod XXX ani v případě, že jsou uvedeny v seznamu PILOTPOOL XXX Include nebo některém PILOTPOOL XXX Range. PILOTPOOL XXX RangeMinNNN spolus s PILOTPOOL XXX RangeMaxNNN určují rozsah linek, které spadají pod pilotážní bod s číslem XXX. Pravidla pro tvorbu rozsahů jsou stejná jako u položky REGISTER RangeMinNNN. PILOTPOOL XXX RangeMaxNNN je nejvyšší číslo linky v rozsahu NNN, které bude spadat pod pilotážní bod s číslem XXX. EXT IgnoreInHuntGroup obsahuje seznam čísel poboček oddělených čárkami. U těchto poboček bude aplikace ignorovat, že jsou přihlášené do skupiny. Tuto možnost je nutné nastavit pro ty pobočky, které patří např. do jiné skupiny řízené hardwarově ústřednou a nejsou určeny pro hovory na infolinky. CALL MaxAlertingTime je počet sekund vyzvánění, po kterých bude hovor z pobočky přesměrován na jinou pobočku. SQL ConnStr je připojovací řetězec (Connection String) pro připojení do databáze SQL. SQL CheckSum je SQL dotaz, který vrátí jednu hodnotu typu celé číslo. Na základě tohoto dotazu se zjišťuje, zda došlo ke změně sledovaných hodnot (stav zaměstnance, číslo linky) od poslední aktualizace. Doporučená forma dotazu je „SELECT CHECKSUM AGG( BINARY CHECKSUM( ID, Stav, Linka)) FROM JmenoTabulky WHERE Aktivni<>0 SQL Refresh je SQL dotaz pro načtení kompletního seznamu zaměstnanců. Výsledek dotazu musí obsahovat sloupce s těmito názvy: ID, Login, Jmeno, Prijmeni, Stav, Linka, id Zastupce1, id Zastupce2. 2 Pokud bude mít aplikace za úkol řídit pobočky s čísly 100, 110-140 kromě 120 a 200-210 tak se hodnoty přířadí následovně: REGISTER Include=100 REGISTER Exclude=120 REGISTER RangeMin000=110 REGISTER RangeMax000=140 REGISTER RangeMin001=200 REGISTER RangeMax001=210
KAPITOLA 3. REALIZACE PROJEKTU
20
SelfKeepAlive.KeepAlive je URL, na které aplikace běží. Tato hodnota je automaticky vytvořena kvůli připojení na vlastní webovou službu a není ji nutné nastavovat. URL se nastavuje automaticky vždy při spuštění aplikace. SMTP From je emailová adresa, ze které se budou odesílat emaily s upozorněními. SMTP To je emailová adresa, na kterou se budou posílat upozornění. SMTP Server je název SMTP serveru, přes který se budou emaily odesílat. 3.1.1
Spuštění, zastavení a běh aplikace
Aplikace je navržena jako webová služba a tomu je přizpůsoben i vlastní běh a spouštění. Při prvním HTTP požadavku na službu .NET Framework nastartuje webovou aplikaci a automaticky zavolá metodu Application Start třídy Global Asax. Z této metody se volá procedury AppInit, pro inicializaci aplikace, a StartApplication modulu MainThread. V této proceduře se pouze nastaví a spustí tři instance objektu System.Timers.Timer. Asynchronní spouštění je důležité proto, aby nebylo blokováno spuštění webové aplikace, popř. aby spouštění a následný běh aplikace nebyl přerušen ThreadAbortException při ukončení webového požadavku na službu. Časovač tmrStart zajišťuje vlastní pokusy o spuštění aplikace. Interval spuštění je nastaven na jednu sekundu. Obsluha časovače vytváří instanci třídy NTelManger a volá metodu Start. Nastane-li během spouštění výjimka, je NTelManager ukončen, interval časovače prodloužen na dvojnásobek (maximálně však deset minut), záznam o chybě je zapsán do logu a pokus o spuštění se opakuje. Časovač tmrSaveLog v intervalu patnácti sekund zajišťuje ukládání záznamů z logu v paměti do souboru. Navíc každé ráno (vždy, když se změní datum od posledního průběhu) restartuje celou aplikaci. Tento restart není teoreticky nezbytný ale slouží pro preventivní vyčištění aplikace a jako pojistka proti dlouhodobě nesoucím se chybám. Časovač tmrKeepAlive pomáhá udržet aplikaci v chodu. Při vývoji aplikace jsem narazil na problém, že IIS (Internetová Informační Služba), na které webová služba běžela, aplikaci zastavovala po dvou hodinách samostatného běhu. To bylo způsobeno tím, že IIS zastavuje pracovní procesy aplikací, na které nechodí žádné webové požadavky z důvody úspory systémových prostředků. Tento problém se dal vyřešit tak, že by se aplikace umístila do samostatného Application Pool, u kterého by se zakázala tato recyklace pracovních procesů. Toto řešení ovšem vyžaduje hlubší znalost práce s IIS a komplikuje nastavení spuštění aplikace. Z tohoto důvodu jsem problém vyřešil tak, že aplikace obsahuje odkaz na vlastní webovou službu (jejíž adresa je sice v klíči SelfKeepAlive.KeepAlive, ale z důvodu jednoduché konfigurace se nastavuje automaticky při prvním spuštění aplikace) a časovač tmrKeepAlive v desetiminutových intervalech provádí volání této webové služby. Tím je zajištěno, že IIS nebude ukončovat pracovní proces aplikace. Ukončení aplikace se provádí procedurou StopApplication v modulu MainThread. Ta zastaví všechny běžící časovače a zavolá metodu Terminace třídy NTelManger. V této metodě se ukončí veškerá činnost CSTA aplikace, odhlásí se telefonní pobočky, ukončí pracovní vlákna a zastaví běh. Proběhne také poslední zápis logu z paměti do souboru. Ukončení aplikace je možné buď z metody StopApplication webové služby nebo z události Application End třídy Global Asax. Metodu Application End, podobně jako Application Start, volá automaticky .NET Framework těsně před ukončením běhu webové aplikace.
KAPITOLA 3. REALIZACE PROJEKTU 3.1.2
21
Zotavení z chyb
V celé aplikaci je kladen důraz na ošetřování výjimek a chybových stavů. Navíc je pro případ výjimky ve webové aplikaci zajištěno, že se v Application Error třídy Global Asax (která je volána automaticky právě při výskytu neošetřené výjimky) odešle email s popisem chyby, který se také zapíše do logu. Dvě nejdůležitější místa ošetření zotavení z chyby jsou při události odpojení ústředny (například z důvodu výpadku sítě) a událost odhlášení pobočky, která představuje pilotážní bod. Změna stavu připojení ústředny je signalizována události Pbx.OnlineStatusChanged. Nastane-li tato událost a aplikace není ve stavu spouštění nebo ukončování, je zavolána metoda Restart, která zajistí ukončení a nové nastartování aplikace s mechanismem kontroly a opakovaného startu. Nastane-li za během provozu aplikace událost Pbx.ExtensionRegistrationChanged, signalizující odregistrování pilotážního bodu, je tento pilotážní bod opět zaregistrován a informace o této události je odeslána emailem.
3.2
Vlákna, zpracování událostí a synchronizace
Charakter celé aplikace je obecně mnoha vláknový, což klade velké nároky na synchronizaci objektů a jejich vzájemnou komunikaci. Tento fakt je navíc zdůrazňen tím, že se jedná o webovou službu, na kterou chodí požadavky zcela asynchronně. 3.2.1
Zpracování CSTA událostí
Veškeré dění v ústředně je přes CSTA zprávy zasíláno CSTA knihovnám, které je zpracovávají a na úrovni .NET objektů předávají dále do aplikace formou událostí. Třída PbxProvider tyto události sleduje, zpracovává a předává dále nadřazené třídě NTelManager. U zpracování těchto událostí je důležitá rychlost, s jakou se událost ošetří. Pokud by např. zpracování události o hovoru trvalo pětinu sekundy a chodilo by deset událostí za sekundu, tak se během první sekundy stihne obsloužit pouze pět událostí a ostatní přetečou do další sekundy a běh aplikace bude trvale zaostávat. Navíc hovor může být za několik málo sekund již v jiném stavu, než o jakém informovala událost, nebo ukončen. Z tohoto důvodu jsou veškeré události zpracovávány v třídě PbxProvider tak, že událost je zachycena a asynchronně je spuštěna nová událost třídy PbxProvider reprezentující původní událost z CSTA knihoven. Tím je CSTA událost jako taková přijata a nedochází ke zpožďování zpráv. Tato technika ovšem klade velký důraz na následnou synchronizaci, protože v aplikaci běží více vláken současně. 3.2.2
Pracovní vlákna
Kromě mechanismu událostí se v aplikaci vyskytují ještě dvě řízená vlákna a vlákna webových požadavků. Při startu třídy NTelManger se spouští vlákna SThread a DThread. 3.2.2.1
Obsluha Socketu pro klientské aplikace
SThread představuje vlákno, ve kterém se otevře naslouchací socket pro příchozí připojení klientských aplikací. Socket se metodou Accept nastaví do blokujícího režimu, dokud se ve frontě příchozích připojení neobjeví nový požadavek. V tomto vlákně se příchozí připojení přijme, zkontroluje se, zda klient poslal ověřovací text a číslo své pobočky. Je-li vše v pořádku, je spojení předáno do seznamu NTeClientList, jinak je spojení uzavřeno a naslouchací socket přejde opět do stavu čekání.
KAPITOLA 3. REALIZACE PROJEKTU
22 3.2.2.2
Mechanismus zpožděného přesměrování hovorů
DThread slouží pro obsluhu zpožděného přesměrování hovoru. Vlákno zkontroluje frontu hovorů k přesměrování a nemá-li být žádný hovor přesměrován, vlákno se statickou metodou Wait třídy Monitor zablokuje (jako zámek zablokování se použije instance třídy Objekt se jménem DivertLock ). Má-li být hovor přesměrován, je u jeho instance třídy NtCall nastavena hodnota QDivertTo na cílové číslo, NtCall je přidán do fronty hovorů pro přesměrování a statickou metodou PulseAll třídy Monitor je zámkem DivertLock odblokováno vlákno DThread. To zkontroluje frontu hovorů a uspí se na padesát milisekund a poté se pokusí hovor přesměrovat. Tím je zajištěna propustnost dvacet přesměrování za sekundu. Pokud metoda pro přesměrování vrátí, že se pokus o přesměrování nepodařil, aplikace se hovor pokusí přesměrovat ještě pětkrát. Po pěti neúspěšných pokusech je hovor pravděpodobně ve stavu, ve kterém se nedá přesměrovat nebo již neprobíhá. Důvod neúspěchu pokusu o přesměrování není možné zjistit. Tento mechanismus zpožďování umožňuje zajistit, že v jeden čas bude odeslán pouze jeden požadavek a požadavky nebudou odesílány bez časové mezery. Dále pokud se aplikace rozhodne hovor přesměrovat na základě události z CSTA knihoven, je zajištěno, že CSTA knihovny stihnout dokončit obsluhu události ještě před odesláním požadavku na přesměrování. Zamezí se tak např. situaci, kdy se z události oznamující začátek vyzvánění provede přesměrování v době, kdy ještě není dokončena událost přesměrování a CSTA knihovny nemají hovor ve stavu ve kterém je možné přesměrování. Kvůli tomuto sledu často docházelo k tomu, že se hovor nepodařilo přesměrovat. 3.2.3
Časovač pro sledování nepřijatých hovorů
Dalším zdrojem událostí je časovač, který se spouští v instanci NtCall, když se stav hovoru změní na vyzvánění. Ošetření tohoto stavu zajišťuje metoda CheckAlertingWatch třídy NTelManger. Ta předává adresu metody formou delegáta třídě PbxProvider, která ji dále předává každé vytvořené instanci NtCall. Obsluha v časovači pak spočívá v zavolání delegáta s parametrem aktuálního NtCall. V metodě CheckAlertingWatch se zkontroluje, zda se skutečně jedná o hovor k přesměrování (např. je-li externí a zda skutečně vypršel časový limit). Následně je vybrán nový cíl hovoru a hovor je přesměrován. 3.2.4 3.2.4.1
Synchronizace SyncLock - zámek kritické sekce
Na většině míst se k zajištění synchronizace používá konstrukce SyncLock, která uzamkne danou kritickou sekci tak, že do ní může současně vstoupit pouze jeden objekt. SyncLock použije jako zámek nějaký objekt, který je mu předán. Na konci sekce se tento zámek opět uvolňuje. Tohoto mechanismu je využito zejména v metodách pro přidání nebo odebrání prvku z kolekce nebo tabulky. U objektů zděděných od třídy HashTable se k vnitřní synchronizaci využívá objekt SyncRoot předka. V ostatních místech se jedná většinou o objekty, které vlastní daná třída. SyncLock je použit tam, kde je kritická sekce krátká (např. přidání nebo odebrání položky z tabulky) nebo v místě, kde je důležité, aby se nezměnily prvky procházené kolekce (např. u hledání aktivního hovoru dané pobočky). 3.2.4.2
Technika kopírování kolekce klíčů
Další důležitou technikou, která je v aplikaci použita je kopírování klíčů tabulky zděděné od HashTable. Pokud je potřeba projít všechny položky tabulky a provést s nimi nějakou operaci,
KAPITOLA 3. REALIZACE PROJEKTU
23
popř. některou najít a vybrat, je důležité, aby to proběhlo rychle a bez synchronizačních kolizí. Např. když během procházení celé tabulky cyklem For Each dojde k přidání nebo odebrání položky, nastane InvalidOperationException. Proto by se do bloku SyncLock musel umístit celý cyklus, včetně jeho těla. Za předpokladu, že danou kolekci potřebuje prohledat nebo upravit více vláken najednou, dochází ke značnému zdržování běhu celé aplikace. Proto je u tříd NtExtensionTable a NtCallTable přepsána vlastnost Keys, která vytvoří novou kolekci a v synchronizovaném bloku SyncLock kolekci naplní klíči aktuální tabulky. Tuto kopii kolekce klíčů následně vrátí. Tím je zajištěno, že při procházení pomocí cyklu For Each nedochází k blokování ostatních vláken po dobu provádění cyklu. Při použití této techniky není problém ani situace, kdy během cyklu dojde ke změně tabulky, protože procházení probíhá již nezávisle na původní kolekci klíčů a hodnot. Při výběru hodnoty z tabulky podle příslušného klíče je ale nutné otestovat, zda byla příslušná hodnota nalezena.
3.3
Komunikace s okolními aplikacemi a systémy
Tato aplikace se chová jako serverová služba, nemá žádné uživatelské rozhraní a s okolními systémy komunikuje výhradně přes TCP/IP spojení. Aplikace přijímá požadavky od klientských aplikací přes webovou službu (formou HTTP GET, POST nebo SOAP požadavků) a informace o hovorech jsou odesílány přes socket, na který se aplikace připojují. Spojení s databází je řešeno standardními objekty ze jmenného prostoru System.Data.SqlClient. Pro komunikaci s ústřednou se využívají CSTA knihovny a vlastní implementace EAI a AnnEAI protokolů přes TCP/IP socket. Důležitým místem, které usnadňuje práci s aplikací jsou testovací formuláře webové služby, které .NET Framework generuje automaticky pro každou metodu. 3.3.1
Webové rozhraní
Aplikace obsahuje dvě třídy, které slouží jako rozhraní webových metod: NTelService a KeepAlive. Obě jsou zděděné od třídy System.Web.Services.WebService, což umožňuje, že veřejné funkce označené atributem WebMethod budou viditelné a přístupné přes webové službu a .NET Framework zajistí vlastní komunikaci mezi aplikací a klientem, který metodu volá. Metody obsahují na svých vstupech pouze parametry s jednoduchými datovými typy, které je možné jednoduše předávat HTTP metodami SOAP, tak i GET a POST. Navíc budou u těchto metod vždy dostupné i testovací formuláře. Třída NTelService slouží pro příjem a předávání požadavků od klientských aplikací dále do aplikace. Na vstupu každé metody otestuje, zda je možné požadavek předat dále a pouze ho předá dále. Není-li aplikace spuštěna, je vrácen prázdný výsledek nebo zamítavá odpověď. Třída KeepAlive obsahuje pouze metodu, která vrací čas její posledního volání a její smysl je pouze odpovídat na požadavky, které udržují aplikaci v chodu. 3.3.1.1
Serializace výstupu webových metod
Serializaci všech výstupních datových typů zajišťuje .NET Framework automaticky. Jednoduché datové typy umísťuje přímo do vráceného XML dokumentu, ostatní objekty jsou serializovány přes pomocné třídy NtExportUserList, NtExportUser a NtExportCall. Ty do svých veřejných členů pouze kopírují hodnotu z příslušné instance vraceného objektu. Tyto veřejné členy jsou označeny atributy XmlAttribute s vyplněným jménem atributu. To zajistí, že ve výstupním XML bude objekt serializován jako jeden XML uzel a všechny jeho vlastnosti budou uloženy jako atributy tohoto uzlu. Třída NtExportUserList, zděděná od třídy ArrayList, je ve výstupu serializována jako pole uzlů, které se serializují podle hodnot ze seznamu.
24
KAPITOLA 3. REALIZACE PROJEKTU
Obrázek 3.1: Komunikace aplikace s okolím
KAPITOLA 3. REALIZACE PROJEKTU Pole ns Stav
Délka 1 ns
25
Význam Počet bytů zprávy S. Má vždy hodnotu 1. Stav pobočky. F=volná (Free), B=obsazená.
Tabulka 3.1: Formát zprávy o změně stavu pobočky 3.3.2
Komunikace s klientskými CRM aplikacemi
Přijatá připojení od klientských aplikací jsou uložena v třídě NTeSocketList. Každé připojení je uloženo pod číslem pobočky, které odpovídá a které klientská aplikace nahlásila při připojení. Ke každé zprávě odeslané do NTeSocketList je vyhledán příjemce, instance třídy NTeClient, podle čísla linky a pokud je nalezen, je mu zpráva předána. NTeClient zprávu převede na textový řetězec, který následně převede na pole o délce 64B a odešle klientské aplikaci. Klientským aplikacím jsou předávány dva druhy zpráv, informace o změně stavu pobočky (volná nebo obsazená) nebo informace o hovoru. Zpráva se skládá z textových řetězců tak, že první byte každého řetězce obsahuje jeho délku a za tímto bytem pokračuje vlastní text o dané délce. Za ním následuje opět dvojice délka a text až do výskytu řetězce s nulovou délkou. Zpráva informující o hovoru obsahuje rovněž informaci o stavu pobočky (pobočka obsazena). Má-li být odeslána zpráva o stavu, který je shodný s posledně odeslaným stavem, není tato zpráva odeslána, protože by se jednalo o duplicitní přenos dat. 3.3.2.1
Formát zprávy o změně stavu pobočky
Tabulka 3.1 ukazuje formát zprávy, která je zaslána CRM aplikaci při změně stavu pobočky, význam jednotlivých polí. Formát zprávy: ns Stav. 3.3.2.2
Formát zprávy o změně stavu hovoru
Tabulka 3.2 ukazuje formát zprávy, která je zaslána CRM aplikaci při změně stavu hovoru, a význam jednotlivých polí. Formát zprávy: ns Stav nid ID nst Status nvy Volaný nvi Volající. 3.3.3
Připojení do SQL databáze
Pro připojení do databáze jsou využity standardní objekty poskytované .NET Frameworkem z jmenného prostoru System.Data a System.Data.SqlClient. Využívají se následující třídy: DataTable je reprezentace jednoduché tabulky. DataRow je reprezentace jednoho řádku DataTable. SqlConnection reprezentuje připojení do SQL databáze. SqlCommand reprezentuje příkaz do SQL databáze, který vrací skalární hodnotu nebo počet změněných řádků. SqlDataAdapter je třída sloužící pro načtení struktury a obsahu dat do DataTable. SqlDataReader je třída pro rychlé čtení z databáze po řádcích. 1
Toto pole může obsahovat jak linku prodejce, tak číslo protistrany.
KAPITOLA 3. REALIZACE PROJEKTU
26 Pole xs Stav nid ID nst Status
Délka 1 1 1 nid 1 nst
nvy Volaný nvi Volající
1 nvy 1 nvi
Význam Počet bytů zprávy S. Má vždy hodnotu 1. Stav pobočky. F=volná (Free), B=obsazená. Délka ID hovoru. ID hovoru generované ústřednou. Délka informace o stavu hovoru. Má vždy hodnotu 2. Stav hovoru. Může nabývat těchto hodnot: AL=Hovor vyzvání (Alerting). AN=Hovor je přijat (Answered). HO=Hovor je přidržen (Hold). DI=Hovor byl ukončen vzdáleným účastníkem (Disconnected). RE=Hovor byl ukončen místním účastníkem (Released). XX=Nedefinovaný stav. Délka čísla volaného účastníka. Číslo volaného účastníka.1 Délka čísla volajícího účastníka. Číslo volajícího účasníka.1
Tabulka 3.2: Formát zprávy o změně stavu hovoru V aplikaci jsou použity následující funkce z knihovny PmLib, které práci s těmito třídami obalují a zjednodušují: sqlNewConn vytvoří novou instanci třídy SqlConnection. sqlExecute vytvoří SqlCommand, spustí jako skalární dotaz a vrátí hodnotu jako Object. sqlGetRow vytvoří SqlDataReader a vrátí první řádek výsledku jako DataRow. sqlGetDT vytvoří SqlDataAdapter, pomocí kterého naplní novou instanci objektu DataTable a tu vrátí. 3.3.4
Aktualizace seznamu uživatelů
Pro správný chod aplikace je nutné, aby měla aplikace stav uživatelů aktuální a mohla správně přepojovat hovory na základě přiřazení linek a stavu operátorů (doma, v práci). K zajištění aktuálnosti dat slouží metoda RefreshStav třídy NtUserList, která je volána před každým pokusem o nalezení volného člena cyklické skupiny nebo zástupce. Aby nedocházelo ke zbytečně velkému množství dotazů do databáze, je na začátku metody kontrola, zda je nutné seznam aktualizovat. Tato kontrola spočívá ve dvou krocích. V prvním se kontroluje, zda uběhlo minimálně patnáct sekund od posledního výpočtu kontrolního součtu podle databáze. Pokud ne, metoda končí. Jinak se ve druhém kroku provede dotaz do tabulky uživatelů, ve kterém se vypočítá kontrolní součet řádků, přes sloupce ID, Stav a Linka uživatele. Tento součet se kontroluje s předchozí hodnotou a k aktualizaci dochází pouze v případě, že se kontrolní součty liší. Celá kontrola se provádí jako kritická sekce v bloku SyncLock, aby nedocházelo ke kolizím při změně hodnot s časem poslední aktualizace a kontrolního součtu a více vláken se nepokoušelo aktualizovat seznam současně. Vlastní aktualizace probíhá tak, že se do DataTable načte seznam ID, stavů a linek zaměstnanců a pro každý řádek z této tabulky se provede kontrola a případná změna stavu. Podle ID se dohledá příslušná instance objektu NtUser a není-li uživatel nalezen, přidá se. Pokud uživatel již existoval, upraví se jeho stav a zkontroluje se, zda nedošlo ke změně
KAPITOLA 3. REALIZACE PROJEKTU
27
linky. Pokud se linka změnila, je tato změna oznámena třídě NTelManager formou události UserChagned třídy NtUserList. Při změně linky jsou také upraveny záznamy v telefonním seznamu ústředny. Na konci aktualizace je v případě výskytu změny linky spuštěna ještě událost AfterChangeEventArgs, aby si třída NTelManager mohla odregistrovat a zaregistrovat změněné linky. 3.3.5
Třídy EAI a AnnEAI
Pro podporu provozu CC jsou do aplikace začleněny dvě pomocné funkcionality - rozhraní pro přepínání denního a nočního režimu vybrané ústředny a dále zajištění automatické aktualizace interního telefonního seznamu ústředny. O přepínání denního a nočního režimu standardně zajišťuje ústředna automaticky podle přednastavených hodnot podle pracovní doby v kalendáři. V některých případech je však nutné režim přepnout ručně (zkrácení pracovní doby, státní svátek apod.). Toto přepnutí je sice možné ručně realizovat např. z telefonu MC520, ale nelze tak změnit režim ve jiné ústředně (na Slovensku), než ke které je telefon připojen, a není možné tento režim změnit vzdáleně, například z domova. Automatická aktualizace interního telefonního seznamu usnadňuje práci zaměstnancům, kteří namísto linky volajícího vidí u interních hovorů rovnou jméno. Tyto úpravy jsou prováděny vždy, když dojde ke změně některé linky v seznamu uživatelů a telefonní seznam zůstává aktuální bez nutnosti ručního zásahu do nastavení ústředny. Tyto dvě části aplikace jsou realizovány vlastní implementací některých částí z EAI a AnnEAI protokolů podle dokumentace [4][5] poskytnuté dodavatelem ústředny. 3.3.5.1
Protokol EAI
Protokol EAI slouží ke statickému nastavování a zjišťování některých provozních parametrů ústředny externí aplikací. Mezi tyto parametry patří denní/noční režim, statistiky probíhajícíh hovorů, nastavování některých vlastností telefonů a další. Veškeré příkazy je možné provádět až po přihlášení do ústředny a odeslání přednastaveného hesla. O zajištění komunikace se stará třída EAI, která se v konstruktoru vytvoří komunikační socket, získá z něho instanci třídy NetworkStream a rovnou přihlásí do ústředny a čeká na požadovanou akci. Třída implementuje pouze metodu pro změnu režimu. Při požadavku na tuto změnu se vytvoří EAI zpráva, složenou jako textový řetězec, pro přepnutí režimu a odešle se do ústředny. Tento řetězec obsahuje druh příkazu, kód vlastního příkazu, doplňkové informace a kontrolní součet, který je počítán funkcí CheckSum třídy EAI. Jako odpověď se vrátí opět řetězec obsahující tzv. EAIReport informující o výsledku operace a příslušné číslo chyby. Toto číslo je v případě výskytu chyby přeloženo na chybovou hlášku. Po skončení operace je nutné zavolat metodu Disconnect třídy EAI, která ukončí TCP spojení s ústřednou. Pro případ nekorektního ukončení práce s třídou EAI implementuje tato třída interface IDisposable, ve kterém se zavolá metoda Disconnect pro uzavření socketu. 3.3.5.2
Protokol AnnEAI
Protokol AnnEAI umožňuje externím aplikacím práci s interním telefonním seznamem ústředny, vyhledávání, čtení a úpravy záznamů. V aplikaci práci s telefonní seznamem zajišťuje třída AnnEAI, která implementuje některé funkce potřebné pro aktualizaci telefonního seznamu. V konstruktoru se vytvoří socket a získá se příslušná instance objektu NetworkStream. Dále se do ústředny odešlou dvě zprávy potřebné pro začátek komunikace a identifikaci verze protokolu.
KAPITOLA 3. REALIZACE PROJEKTU
28
Třída obsahuje metody pro přidání záznamu, odstranění záznamu a vymazání celého seznamu. Každá akce vytvoří zprávu reprezentovanou jako text a odešle do ústředny. Při vytvoření nového záznamu vrátí ústředna index pozice, na které byl záznam pro danou linku vytvořen. Třída AnnEAI si udržuje seznam linek a jejich pozic, který dále používá pro mazání záznamů. Vymazání linky ze seznamu probíhá na základě již zmíněného seznamu, ve kterém se vyhledá index záznamu a odešle se požadavek na jeho odstranění. Protokol neobsahuje příkaz na zjištění počtu záznamů. Proto příkaz na vymazání celého seznamu funguje tak, že maže postupně záznamy od indexu nula a sleduje výsledek těchto operací. Pokud je vrácena chyba desetkrát za sebou, mazání je ukončeno a seznam se považuje za vymazaný. O seznam se stará výhradně aplikace NTelManager a při vytváření záznamů se vyplňují případné neobsazené indexy, takže by nemělo dojít k tomu, že by některý záznam zůstal uložen i po tomto vymazání celého seznamu. Podobně jako třída EAI, i AnnEAI obsahuje metodu Disconnect pro odpojení socketu a implementuje interface IDisposable, díky kterému je zajištěno že k uzavření socketu dojde i při nekorektní práci s třídou AnnEAI.
3.4 3.4.1
Techniky použité při programování Mechanismus událostí
Veškeré předávání zpráv a oznamování událostí v aplikaci probíhá formou událostí. To se týká jak zpráv z CSTA knihoven, které jsou zpracovávány v třídě PbxProvider, následných událostí předávaných dále do aplikace ale i oznamování o změnách v třídě NtUserList. Událost se deklaruje klíčovým slovem Event s deklarací prototypu obslužné procedury. Pro sledování událostí existují dvě možnosti - statické přihlášení s klíčovým slovem Handles za deklarací procedury (objekt generující události musí být deklarován jako WithEvents) nebo dynamicky pomocí příkazu AddHandler. Vlastní vyvolání události se pak provádí příkazem RaiseEvent, který zajistí že budou synchronně zavolány všechny procedury které mají přihlášenou danou událost jedním ze dvou výše jmenovaných způsobů. Po obsluze všech konzumentů události program pokračuje dále za příkazem RaiseEvent.
3.4.2
Delegáti a asynchronní spouštění událostí
Delegát představuje ukazatel na funkci s přesně definovanou signaturou, kterou musí cílová funkce dodržet. Pro zjištění adresy funkce a následné přiřazení do delegáta se provádí příkazem AddressOf, který vrací adresu požadované funkce. Ta se pak přiřadí do objektu delegáta. Po této inicializaci je možné provádět volání delegáta jako by to bylo volání funkce s tím, že ve skutečnosti se zavolá funkce, na kterou delegát ukazuje. Delegát může ukazovat i na více funkcí (se stejným prototypem), které se při volání delegáta volají postupně. Pomocí delegátů se vnitřně realizuje i mechanismus přihlašování událostí, ale .NET Framework se o tuto činnost stará automaticky. Delegáti poskytují kromě jiného i metodu BeginInvoke, která způsobí asynchronní spuštění cílové metody včetně předání parametrů poskytnutých metodě BeginInvoke delegáta. Této techniky se využívá v třídě PbxProvider, kde se zpracovávají události CSTA knihoven a dále do aplikace se zasílají asynchronně. Zavolání BeginInvoke způsobí, že se volání metody zařadí do fronty zpráv aktuálního výpočetního vlákna a program pokračuje dále v provádění. Cílová metoda je v tomto případě zavolána až při výběru zprávy z fronty zpráv. O tyto činnosti se opět stará .NET Framework a v kódu stačí využívat metodu BeginInvoke.
KAPITOLA 3. REALIZACE PROJEKTU 3.4.3
29
Zápis do logu
Informace o činnosti aplikace, přesměrování hovorů a další provozní záznamy jsou ukládány do souborů v adresáři Log. O vlastní zápis se starají procedury FileLog, která na začátek zpráv přidává časové razítko a skládá zprávy v paměti před jejich zapsáním na disk, a SaveLog, která dosud neuloženou část zapíše do souboru. Metoda je z modulu MainThread volána na základě událostí časovače, aby nedocházelo ke zbytečnému zatěžování disku při zápisu každé zprávy. Při startu aplikace se adresa funkce Filolog předá jako delegát třídě NTelManager. Veškerý zápis do logu poté probíhá přes tohoto delegáta. Třída NTelManager tohoto delegáta předává všem dalším třídám, které generují nějaké informace do logu. Každá další třída před tuto metodu předřazuje vlastní funkci Log, ve které se ke zprávě vygenerované v nižší třídě přidá ještě vlastní označení nižší třídy pro snadnější orientaci ve výsledném souboru a zjednodušení implementace. 3.4.4
Interface IDisposable
Třídy, které alokují nějaké prostředky musí tyto prostředky uvolňovat. Těmito prostředky jsou například připojené síťové sockety nebo připojení do databáze. Obecně se uvolňování relizuje tak, že třída implementuje interface IDisposable, jehož metodu Dispose volá .NET Framework automaticky při skončení platnosti objektu. IDisposable definuje metodu Dispose, ve které se zajišťuje uvolnění dosud neuvolněných zdrojů. Rozdíl mezi umístěním uvolňování prostředků pomocí IDisposable a v destruktoru je ten, že volání destruktorů je nederministické a probíhá až při shromažďování a uvolňování paměti. Touto se děje pod řízením Garbage Collectoru3 a v době volání destruktoru už nemusí být zdroje přístupné. Oproti tomu metodu Dispose volá .NET Framework automaticky hned při ukončení platnosti objektu, což je například při opuštění funkce ve které je objekt deklarován nebo při výskytu výjimky, která je ošetřena mimo oblast platnosti objektu. V těchto případech už nebude reference na instanci objektu nadále přístupná a .NET Framework zajistí voláním metody Dispose uvolnění alokovaných prostředků. Metoda Dispose je veřejná takže uvolnění je možné volat také explicitně.
3
Garbage collection je způsob, jakým se řeší správa paměti v .NET Framework. O uvolňování paměti se stará tzv. Garbage Collector.
KAPITOLA 4. INSTALACE APLIKACE
30
4 Instalace aplikace Aplikace je navržena tak, aby vyžadovala minimum konfigurace při instalaci na nový server. Celá instalace spočívá pouze v ověření požadavků a vytvoření nové webové stránky ve službě IIS. Aplikace je postavena na .NET Framework 2.0 takže zdrojové soubory není nutné kompilovat a stačí je pouze zkopírovat do místa, kde aplikace poběží.
4.1
Požadavky
Zde jsou uvedeny požadavky, které je nutné splnit pro správný běh aplikace. • Server s Windows 2000 nebo vyšší s IIS 6.0. • .NET Framework 2.0 • Funkční TCP/IP spojení mezi serverem a ústřednou na portech definovaných v sekci TCP konfigurace 3.1. • MS-SQL 2000 databáze (nebo vyšší) se seznamem uživatelů a přístup do této databáze z webového serveru. • Místo na disku: 1,3MB pro vlastní aplikaci a místo pro ukládání logů. Při zápisu všech událostí vygeneruje aplikace přibližně 50MB textu (podle zatížení) za měsíc provozu. Výpis je možné omezit v nastavení a není nutné jej archivovat. • Ústředna NeXspan s minimální verzí firmware G.1E, nebo jiná kompatibilní s CSTA.
4.2
Instalace
Tato sekce popisuje vlastní instalaci aplikace a vytvoření příslušné stránky v IIS. • Zkopírujte instalační adresář NTeManager na server do výchozího adresáře webové služby (typicky c:\inetpub\ nebo c:\inetpub\wwwroot\). • Otevřete správu Internetové Informační Služby IIS na serveru, otevřete seznam webových serverů a vytvořte nový webový server (Menu/Akce/Nový objekt/Webový server). • Projděte průvodce přidáním nové stránky podle následujícího postupu. • V úvodní obrazovce klikněte na Další. • Do pole popis vyplňte hodnotu NTelManager. Klikněte na Další. • V nastavení IP adresy a portu přiřaďte jednu z IP adres serveru (nebo ponechte všechny nepřiřazené) a vyplňte číslo portu přes který se bude přistupovat k webovému rozhraní aplikace. Rovněž je možné uvést hlavičku hostitele (Host Header) pro případ, že aplikace běží na stejném portu (typicky 80) s jinými aplikacemi. V tomto případě je rozdělení požadavků na aplikace rozděleno podle tohoto jména. • Klikněte na Další. • V následujícím dialogu klikněte na Procházet a vyberte cestu k adresáři NTelManager na serveru. Anonymní přístup nechte povolený, pokud nevyžadujete jiný způsob autorizace. Klikněte na Další.
KAPITOLA 4. INSTALACE APLIKACE
31
• Objeví se dialog s nastavením oprávnění. Zde nechte možnost pouze číst a klikněte na Další. • Klikněte Dokončit. • Nyní je potřeba dokončit nastavení aplikace. V seznamu webových serverů vyberte NTelManager v menu klikněte na Akce/Vlastnosti. • Na úvodní kartě Webový server je možné upravit nastavení IP adres a portů včetně možnosti zapnutí HTTPS. • Na kartě Domovský adresář zkontrolujte, zda je v položce Fond Aplikací vybrán fond, který je vytvořen pro aplikace .NET Framework 2.0. • Na kartě ASP.NET zkontrolujte, že ASP.NET Version je nastavena na hodnotu v2.0. • Na kartě Zabezpečení adresáře máte možnost upravit zabezpečení přístupu k webové službě a jejím formulářům v případě, že vyžadujete omezení přístupu. • Klikněte na Ok, čímž se dokončí vytvoření aplikace. • Nyní proveďte potřebná nastavení v souboru web.config podle nastavení 3.1 pro požadovaný běh aplikace. • Přes webový prohlížeč otevřením stránky /NTelService.asmx spusťte běh aplikace. • Zkontrolujte logovací soubor, zda při spouštění nenastala nějaká chyba.
4.3
Konfigurace ústředny
Pro správný běh aplikace jsou nutné hluboké zásahy do konfigurace aplikace. Tuto konfiguraci provádí zpravidla poskytovatel ústředny, po dohodě je možné provádět některé změny i samostatně. (Položky v menu ústředny pro tuto konfiguraci jsou uvedeny v závorkách. Tam, kde položka menu chybí prováděl v mém případě změnu poskytovatel ústředny.). Před provedením následujících změn proveďte zálohu konfigurace ústředny. Je nutné nastavit následující funkce: • Nastavení CSTA serveru a propojení ústředen tak, aby se chovaly jako jeden CSTA systém. • V parametrech ústředny se nastaví FORWARDING DEPTH na hodnotu 1, jinak se budou hovory po prvním přesměrování z pilotážního bodu vracet zpátky z cílové pobočky na pilotážní bod (menu 1.7.2). Důvod tohoto kroku je popsán v části 5.2.1.3. • V nastavení hlášek se zakáže přehrávání hlášky, že jsou hovory pobočky přesměrovány. Přesměrování bude u pobočky nastaveno natrvalo a hláška tak pouze obtěžuje. • Vytvoření skupin (menu 1.1.4). – Vytvoření pilotážních bodů - HW skupin typu EMPTY s nastavením čekající hlášky. Tato hláška musí začínat jednou sekundou ticha kvůli přechodu hovoru mezi stavy Alerting a AlertingWaiting před přesměrováním hovoru. Bez této sekundy by ústředna volajícímu stihla přehrát kousek hlášky, viz. 5.2.1.1. – Vytvoření cyklických skupin pro evidenci přihlášení do skupiny.
32
KAPITOLA 4. INSTALACE APLIKACE • Nastavení infolinek. Toto je pouze příklad možného řešení, HW řízení hovoru a přehrávání hlášek může být řešeno jiným způsobem. – Vytvoření vnějšího čísla DID CORPORATE NUMBER pro číslo infolinky (menu 1.3.3.4) a CALL DISTRIBUTION (menu 1.5), který podle přednastaveného kalendáře rozdělí hovory na denní a noční (menu 1.6). – CALL DISTRIBUTION pro denní hovory nasměrovat (menu 1.5.2) na virtuální pobočku (ta se vytvoří v menu 1.1.5, upravuje v 1.1.1). U této pobočky je jako vyzváněcí tón nastavena uvítací hláška, která je zajištěna nastavením správné hodnoty DEPARTMENT, a přesměrování externího hovoru při nevyzvednutí na skupinu typu EMPTY - pilotážní bod (menu 1.1.9.6.1). Rovněž musí být nastavené dostatečné množství monitorovacích tlačítek pro číslo virtuální pobočky, aby vyzváněcí hláška mohla znít více klientům současně (menu 1.1.8.1). – CALL DISTRIBUTION pro noční hovory nasměrovat na noční hlášku. • Nastavení pobočky. Nastavení uživatelských funkcí (tlačítka, přesměrování) se zamknou, aby je nebylo možné změnit z telefonu. – Pobočka se zařadí do některé skupiny typu CYCLIC (menu 1.1.4) a nastaví se dvě ovládací tlačítka (menu 1.1.8). Jedno pro přihlášení a odhlášení ze skupiny (Type: Feature, Feature type: Withdraw from huntgroup) a druhé pro dohled čísla pobočky (Type: Monitor your multikey number). Toto umožní přihlašování a odhlašování do skupiny přímo tlačítky na telefonu a rovněž kontrolu stavu přihlášení přímo na telefonu. – Vytvoří se okamžité přesměrování externích hovorů na skupinu typu EMPTY (menu 1.1.9.6.1). Tím se zajistí, že aplikace obslouží i hovory, které přicházejí na pobočky, které nejsou právě zaregistrovány. • Pro přístup pomocí protokolu EAI je nutné nastavit server v ústřednách tak, aby se na IP každé ústředny ovládala právě připojená ústředna, tzn. že se ústředny z pohledu EAI budou chovat jako dva samostatné systémy. V menu 2.7.1 je následně nutné nastavit stejné heslo jako je v konfiguraci. • Vnitřní telefonní seznam a jeho ovládání protokolem AnnEAI bude nastaveno tak, aby se obě ústředny chovaly jako jeden systém a sdílely položky v tomto adresáři. To zjednoduší správu seznamu a zajistí, že tento seznam bude fungovat i při vnitřních hovorech mezi ústřednami. Údaje z nastavení, jako jsou IP adresy, porty, čísla poboček a další je následně nutné nastavit v konfiguraci aplikace.
KAPITOLA 5. TESTOVÁNÍ
33
5 Testování Tato CSTA aplikace řídí tok příchozích hovorů do CC, čímž se zásadním způsobem podílí na obchodních výsledcích firmy a spokojenosti klientů. Výskyt závažné chyby by mohl způsobit, že by se do CC nedalo dovolat, což by způsobilo jak ztrátu zákazníků, tak následné finanční ztráty. Proto bylo před spuštěním aplikace do provozu důležité otestovat všechny funkce a před úplným nasazením nechat aplikaci běžet v testovacím režimu, ve kterém se stará pouze o několik málo operátorů, jejichž případný výpadek nebude mít za následek ochromení provozu CC.
5.1
Nastavení aplikace a ústředny pro testování
CSTA technologie a ústředna NeXspan podporují běh několika CSTA serverů v jedné ústředně současně. Ke každému serveru je možné se připojit na jiném portu a každý zpracovává zprávy a události pouze pro jeho skupinu zaregistrovaných poboček. Tato vlastnost zásadním způsobem zjednodušuje jak testování, tak i vývoj vlastní aplikace, přidávání nových funkcí a jejich testování paralelně s během funkční aplikace starající se o telefonní provoz. Konfiguraci druhého CSTA serveru provede jednorázově dodavatel ústředny a poté stačí pouze spustit druhou instanci aplikaci (buď přímo z vývojového PC nebo druhou, testovací instanci aplikace v IIS serveru) s upravenými hodnotami portů a čísel poboček registrovaných CSTA aplikací. Testovací instance nesmí registrovat pobočky přihlášené hlavní aplikací, aby nedocházelo ke kolizím a zásahům do řízení hovorů. Pokud je testovací instance spouštěna na stejném serveru jako hlavní aplikace, je nutné upravit i naslouchací port pro klientské aplikace aby nedošlo k chybě při pokusu o otevření stejného portu různými aplikacemi.
5.2
Průběh testování
Vlastní testování se skládá z testování funkcí při vývoji a jejich ověření na konci vývoje a dále z testovacího provozu aplikace těsně před uvedením do plného provozu. 5.2.1
Testování dílčích funkcí během analýzy a vývoje
Během analýzy a vývoje jsem z vývojového PC testoval dílčí funkce aplikace a sledoval chování CSTA knihoven. Z výsledků těchto průzkumových testů jsem následně odvozoval řešení některých situací a problémů. Některé situace jsem konzultoval s p. Zídkem jako autorem CSTA knihoven. 5.2.1.1
Přehrání začátku hlášky při přesměrování z pilotážního bodu
Ve chvíli kdy se hovor dostal na pilotážní bod (a je ve stavu Alerting ) a aplikace se rozhodla hovor přesměrovat na některou pobočku se stihla volajícímu přehrát první sekunda z čekací hlášky pilotážního bodu. Po této sekundě se hovor přesměroval a ozval se normální vyzváněcí tón. Toto chování bylo způsobeno tím, že se hovor při čekání na pilotážním bodě stihnul přepnout do stavu AlertingWaiting při kterém zní čekací hláška. Nejjednodušší řešení této situace bylo umístit na začátek hlášky interval ticha v délce jedné sekundy. Hláška tak začne být slyšet až v případě, že hovor není přesměrován okamžitě (např. proto, že jsou všichni operátoři obsazeni). 5.2.1.2
Událost StatusInconsistency
Během testovacích úseků se objevovala událost StatusInconsistency oznamující chybný stav některé pobočky v CSTA knihovnách.
KAPITOLA 5. TESTOVÁNÍ
34
Tyto události jsou způsobeny událostmi poboček, které nemá aplikace zaregistrované a nepracuje s nimi (pobočky mimo CC, faxy). Jejich výskyt je řídký a nemá žádný vliv na chod aplikace. Události jsou pouze zaznamenávány do logu. 5.2.1.3
Vracející se hovory
Během testování funkce pilotáže se stávalo, že byl hovor z pobočky ústřednou přesměrován na pilotážní bod, zde se o něm aplikace dozvěděla a přesměrovala hovor některé pobočce (buď té ze které hovor přišel, zástupci nebo cyklické skupině). Toto přesměrování se provedlo, ale hned po jeho dokončení se hovor dostal opět na pilotážní bod. Po druhém přesměrování na pobočku zůstal již hovor na cílové pobočce, což se dělo i v případě, že byl hovor i podruhé přesměrován na stejnou pobočku jako při prvním pokusu. Popisované chování bylo způsobeno nastavením ústředny, konkrétně parametrem FORWARDING DEPTH, který byl nastaven na hodnotu dva. Ústředna pro externí hovor prováděla maximálně dvě automatická přesměrování (jako pojistku proti cyklickému přesměrování hovorů). Poprvé byl hovor HW přesměrován na pilotážní bod a když aplikace hovor přesměrovala opět na pobočku tak ústředna zkontrolovala HW nastavení přesměrování a hovor opět přesměrovala na pilotážní bod. Potřetí se to již nestalo, protože nastavená hodnota FORWARDING DEPTH byla dva. Tento problém jsem vyřešil nastavením hodnoty FORWARDING DEPTH na hodnotu jedna. Běžnému provozu tato změna nevadí; není potřeba aby HW přesměrování hovorů (i uživatelsky nastavených) fungovalo i pro řadu telefonů za sebou. 5.2.1.4
Nefunkční přesměrování hovoru z pobočky
Pokud hovor zvonil na pobočce a nikdo ho nezvedal, nedařilo se hovor přesměrovat na další pobočku a metoda pro přesměrování vracela odmítavou odpověď. Tuto situaci jsem konzultoval s p. Zídkem, kterému se problém nedařilo nasimulovat. Po osobní návštěvě, testování přímo na naší ústředně jsme zjistili, že máme starší verzi firmware ústředny (G.1D), a že na novější verzi (G.1E) se problém nevyskytuje. V seznamu oprav poslední verze firmware jsme následně našli, že byl opraven problém s přesměrováním a podobnými příznaky. Tento problém byl vyřešen nahráním nové verze firmware do obou ústředen dodavatelem ústředny. 5.2.1.5
Odregistrování pilotážního bodu
V řídkých případech se stávalo, že došlo k odregistrování některého z pilotážních bodů. V tomto případě aplikace nemohla nadále dostávat zprávy o nových hovorech a tím byl ochromen celý chod. Do události odregistrování pobočky jsem přidal kontrolu, která ověří zda právě odregistrovaná pobočka není pilotážní bod a zda se aplikace právě neukončuje. Pokud k odregistrování dojít nemá je pilotážní bod opět zaregistrován a na přednastavený email podle konfigurace 3.1 se odešle upozornění, že došlo k odregistrování pilotážního bodu. 5.2.2
Ověření funkce
Pro ověření všech funkcí ze zadání 1.1 jsem si vytvořil testovací infolinku, pilotážní bod, který se staral o skupinu s jednou pobočkou. Aplikaci jsem spouštěl z vývojového PC a připojoval se k druhému CSTA serveru ústředny. Testování spočívalo v simulaci všech scénářů hovoru, sledování chování hovoru a kontrole událostí v aplikaci podle logu. Testování zahrnovalo kontrolu následujících scénářů:
KAPITOLA 5. TESTOVÁNÍ
35
• Příchozí hovor na infolinku při různých stavech skupiny (skupina je prázdná, ve skupině je přihlášena jedna hovořící pobočka a stav, kdy je ve skupině volná pobočka). • Přímý příchozí hovor při různých stavech pobočky (pobočka je volná, hovoří, je volná ale zaměstnanec není podle informace v databázi v práci). • Kontrola mechanismu sledování nevyzvednutých hovorů a reakce aplikace na hovor, který nikdo nezvedá. • Kontrola správné funkce přesměrování hovoru z jedné pobočky na jinou. • Kontrola algoritmu na vyhledávání volných zástupců. • Kontrola algoritmu pro výběr dalšího člena cyklické skupiny pro různé stavy skupiny. Pro tento test jsem musel využít 3 pobočky. • Kontrola správného zasílání informací připojeným klientským aplikacím a ověření správné funkce přihlašování. • Sledování změn v seznamu uživatelů a telefonním seznamu ústředny při přidání, odstranění a změně linky prodejce. • Kontrola přepínání denního režimu ústředny. • Otestování všech funkcí webové služby a ovládání pobočky přes tuto službu. • Kontrola správného pořadí akcí při spouštění a ukončování aplikace. • Kontrola automatického zotavení aplikace při ztrátě spojení s ústřednou simulované vytažením síťového kabelu. 5.2.3
Testovací provoz
Před spuštěním plného provozu byl v ústředně vytvořen pilotážní bod pro správu hovorů a provedeno nastavení pro pět prodejců jako v ostrém režimu. Na tento pilotážní bod byla nasměrována i jedna z infolinek, která nebyla příliš vytížena a její výpadek by nezpůsobil velkou ztrátu. O hovory pro těchto pět prodejců a jednu infolinku se po dobu 24 hodin starala výhradně aplikace. Během této doby jsem provedl několik testovacích hovorů pro ověření funkčnosti a sledoval chování aplikace podle logů. Prodejci měli za úkol hlásit jakékoliv netypické chování telefonů.
5.3
Výsledky testování
Podle výsledků zjištěných během analytické fáze testování jsem navrhoval budoucí chování částí aplikace. Tyto testy byly důležité z hlediska analýzy a ověření, zda budou navržené postupy fungovat v reálné implementaci. Nejkritičtějším bodem byl problém s nefunkčním přesměrováním nezvednutého hovoru. Kvůli tomuto problému jsem musel nechat přeinstalovat firmware ústředny z verze G.1D na G.1E. Ověřovací fáze sloužila hlavně pro ověření funkčností a kontrolu, zda aplikace splňuje všechny požadavky na ní kladené. Při jakémkoliv zásahu do kódu jsem celý postup opakoval od začátku, abych vyloučil možnost, že provedená oprava způsobila jinou chybu. Testovací provoz měl za úkol ověřit funkce aplikace při práci s více pobočkami současně. Během této fáze jsem prováděl pouze kosmetické úpravy záznamů ukládaných do logu. Během testovacího provozu se nevyskytly žádné problémy a aplikace fungovala správně. Proto bylo změněno programování ústředny a spuštěn plný provoz aplikace.
KAPITOLA 5. TESTOVÁNÍ
36
5.4
Řešení výpadku aplikace
Výpadky systému lze z pohledu aplikace rozdělit na dvě základní skupiny a to krátkodobé, v řádu minut, a dlouhodobé, např. při úplném pádu serveru. Tato sekce popisuje řešení těchto dvou situací. 5.4.1
Krátkodobý výpadek
Za krátkodobý výpadek se považuje výpadek aplikace nebo komunikace s ústřednou v řádu sekund až několika minut. Tento výpadek může být způsoben například výpadkem TCP spojení mezi aplikací a ústřednou, restartováním IIS nebo jinou příčinou nezávislou na aplikaci. Tento druh výpadku aplikace řeší automaticky sama a při výpadku se pokouší o obnovení činnosti, dokud se to nepodaří. Každý pokus znamená kompletní nastartování aplikace, aby v paměti nezůstávaly informace o předchozím běhu které po výpadku nemusí být platné. Po restartování IIS se aplikace spouští automaticky se spuštěním aplikace v IIS. 5.4.2
Nouzový režim
Za dlouhodobý výpadek se v tomto případě považuje jakákoliv situace, kdy se o řízení telefonních hovorů nemůže nadále starat CSTA aplikace, ať už z důvodu úplného výpadku serveru, dlouhodobé ztráty spojení nebo jiného důvodu. Tuto situaci je nutné vyřešit tak, aby veškeré řízení hovorů převzala HW logika ústředny. Nejdříve je nutné pilotážní bod nasměrovat na cyklickou skupinu, aby se hovory dostaly na pobočky. Nejrychlejší varianta je vytvořit okamžité přesměrování (IMMEDIATE FORWARDING) pro pilotáží bod (menu 1.1.9.6.1 ústředny). Toto přesměrování se provede na vnitřní číslo skupiny typu CYCLIC, ve které jsou pobočky z důvodu přihlašování do skupin. Současně s tím se musí zvýšit hodnota FORWARDING DEPTH, aby k přesměrování skutečně došlo. Od toho momentu se příchozí hovory dostanou na pobočky přihlášené v HW skupině. Toto se týká i přímých hovorů, které se stávajícím přesměrováním dostanou na pilotážní bod, skupinu typu EMPTY, a z něho se nově dostanou na cyklickou skupinu a některou z přihlášených poboček. V druhé fázi, v závislosti na tom, zda se to vyplatí s ohledem na předpokládanou dobu výpadku, je nutné zrušit přesměrování poboček na pilotážní bod pro externí hovory. Tento zásah je pracný a je ho nutné provést pro všechny používané pobočky. Po této úpravě budou i přímé hovory zvonit rovnou na volaných pobočkách.
KAPITOLA 6. ZÁVĚR
37
6 Závěr Účelem mé bakalářské práce bylo navrhnout a naprogramovat aplikaci na bázi CSTA knihoven, která by řídila telefonní provoz call-centra, spolupracovala s CRM aplikacemi prodejců a poskytovala kvalitní základ pro případné nové požadavky na rozšíření funkcionality. Pro řízení hovorů se využívá principu pilotáže, kdy jsou veškeré vnější, příchozí hovory přesměrovány na pilotážní bod (HW skupina typu EMPTY). Aplikace tento pilotážní bod sleduje a podle zabudovaných kritérií, informací o hovoru a stavu operátorů hovory z pilotážního bodu přepojuje na konkrétní telefonní pobočky prodejcům. Při implementaci jsem kladl důraz na rychlost zpracování CSTA zpráv, která je pro obsluhu více hovorů současně kritická. Aplikace běží ve více vláknech a zprávy z CSTA knihoven přicházejí asynchronně, proto jsem věnoval pozornost také synchronizačním prostředkům a jejich efektivnímu využívání. Celá aplikace je postavena na technologii .NET Framework, která umožňuje rychlý a efektivní vývoj, a poskytuje velké množství již hotových tříd, které zásadním způsobem zjednodušují a usnadňující tvorbu aplikace, práci s webovou službou, TCP spojením, synchronizací a dalšími prvky. V době návrhu a realizace byla cesta vlastní implementace této aplikace, s ohledem na požadavky, nejschůdnější. Alternativní, srovnatelná možnost byla zakoupit software M7480, který je určen pro řízení běžných CC. M7480 ale nevyhovoval požadavkům kladených na řízení telefonního provozu společnosti NetTravel.cz. Nastavení M7480 nebylo dostatečně flexibilní v možnostech napojení na stávající systémy, čerpání informací z docházkového systému, stávající databáze klientů apod. Dalším důležitým kritériem zde byla předpokládaná budoucí změna požadavků, která by byla realizovatelná pouze v rámci stávajících funkcí M7480 a to bez možnosti zásahu do struktury aplikace. Spuštění mé aplikace do plného provozu vyřešilo problémy s hovory zvonícími na neobsazených telefonech, což se pozitivně projevilo na značném úbytků stížností o nedostupnosti CC. Softwarová kontrola nad telefonním provozem umožnila také další vývoj CRM aplikace prodejců (přímé vytáčení z aplikace jedním kliknutím, oznamování informací o volajícím atd.) pro zvýšení efektivity práce. V neposlední řadě je přínosem rovněž to, že je aplikace a celé řešení navrženo tak, aby bylo možné flexibilně měnit funkce aplikace a dále ji rozvíjet (např. přidáním možnosti přepadu skupin, kdy při vytížení jedné infolinky může příchozí hovory přijmout i jiná skupina - prodejci v jiné pobočce apod.) Aplikace splňuje všechny požadavky ze zadání, stabilně běží v plném provozu už déle než dva roky a v hlavní sezóně (léto 2006) spolehlivě pracovala s šedesáti aktivními operátory rozdělenými mezi českou a slovenskou pobočku. Na základě těchto výsledků hodnotím celý projekt jako úspěšně splněný. Ve své práci jsem vysvětlil jak princip funkce, způsob konfigurace ústředny, popis rozhraní pro spolupracující aplikace, tak i důvody které vedly k některým rozhodnutím o fungování aplikace a možná úskalí, se kterými se může někdo jiný při implementaci podobné aplikaci setkat.
38
KAPITOLA 6. ZÁVĚR
KAPITOLA 7. LITERATURA
39
7 Literatura [1] Ing. Jiří Zídek: emailová komunikace říjen 2005 - květen 2006. [2] Atlantis Telecom s.r.o.: CSTA NeXspan Libraries preliminary documentation. Přiložené CD: Data/Atlantis.Csta.chm [3] Atlantis Telecom s.r.o.: Atlantis.CSTA development. Přiložené CD: Data/Atlantis.Csta Development.ppt [4] T. Legrand, Matra communication: Interface for external applications, 1998. Přiložené CD: Data/EAI protokol iae v11-3en.doc [5] Nortel Mercator: Integrated telephone directory, provisional administrator’s manual. Přiložené CD: Data/ANNEAI protokol Directory - operating instructions 8157baa1 EAI protokol.pdf [6] M7480 Contact Center. http://www.aastra.com/cps/rde/xchg/04/hs.xsl/15787.htm [7] TAPI 2.2 Reference. http://msdn2.microsoft.com/en-us/library/ms737219.aspx [8] Microsoft MSDN Library: Socket Class http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.aspx [9] Microsoft MSDN Library: Delegate Class http://msdn2.microsoft.com/en-us/library/system.delegate.aspx [10] Microsoft MSDN Library: Timer Class http://msdn2.microsoft.com/en-us/library/system.threading.timer.aspx [11] Microsoft MSDN Library: Monitor Class http://msdn2.microsoft.com/en-us/library/system.threading.monitor.aspx [12] Microsoft MSDN Library http://msdn2.microsoft.com/en-us/library/
40
KAPITOLA 7. LITERATURA
PŘÍLOHA A. SEZNAM POUZITÝCH ZKRATEK
41
A Seznam pouzitých zkratek ACD AnnEAI AVR CC COM CRM CSTA EAI GET HTTP HTTPS IIS HW ID MS TAPI PBX POST SMTP SOAP SW TSPI URL VB.NET VTI/XML XML WSDL
Automatic Call Distribution Announcement External Application Interface Automatic Voice Recognition Call-Centrum Component Object Model Customer Relationship Management Computer Supported Telephony Application External Application Interface HTTP metoda pro získání obsahu stránky pouze pomocí URL Hyper Text Transfer Protocol Hyper Text Transfer Protocol over SSH (Secure Shell) Internetová Informační Služba (Internet Information Service) HardWare Identification MicroSoft Telephony Application Program Interface Private Telephone Switch, telefonní pobočková ústředna HTTP metoda pro získání stránky pomocí URL a hodnot obsahu formuláře Simple Mail Transfer Protocol Simple Object Access Protokol SoftWare Telephony Service Provider Interface Uniform Resource Locator Visual Basic.NET Virtual Terminal Interface/eXtensible Markup Language eXtensible Markup Language Web Service Definition Language
42
PŘÍLOHA B. WSDL POPIS ROZHRANÍ WEBOVÉ SLUŽBY
B WSDL popis rozhraní webové služby B.1
Data/NTelService.xml
B.2
Data/KeepAlive.xml
PŘÍLOHA C. OBSAH PŘILOŽENÉHO CD
C Obsah přiloženého CD Index.htm - Úvodní stránka. ReadMe.txt - Popis adresářů, poznámky k instalaci. Data/ - Soubory související s prací. NTelManager/ - Zdrojové kódy aplikace (aplikace se nepřekládá). Text/ - Tento dokument včetně zrdojových kódů.
43