Ciekawa strona dla użytkowników Postgres’a

15 październik 2009, Michał Szymański

Ostatnio natrafiłem na bardzo ciekawą stronę zawierającą zapis wszystkich prezentacji, które odbyły się przy okazji konferencji PGCon w Ottawie w 2009 - Strona PGCon. Warta polecenia jest prezentacja ‘VACUUM Strategy’ pani Seleny Deckelmann jak działał dotychczas VACUUM i jakie zmiany zostały wprowadzone w wersji Postgres 8.4. Z naszych pierwszych testów wynika, że faktycznie został dokonany duży krok naprzód.

Nowa wersja API 2.04

18 lipiec 2009, Michał Szymański

Pod koniec zeszłego tygodnia na produkcji została wdrożona nowa wersja API oznaczona numerem 2.04. W wersjach od 2.02 do 2.04 zostały wprowadzone następujące zmiany:

  • Dodanie do funkcji startMassDial kodu błędu invalidPresentationNum
  • Dodanie do funkcji sendFax / startMassDial parametru campaignName. Teraz kampania może mieć swoją nazwe
  • Wprowadzenie nowego kodu błędu functionCallLimitsExceeded - błąd ten informuje o tym, że zostały przekroczone limity częstotliwości wywołań danej funkcji (limity ustawione są per system a w przyszłości będą ustawione per grupa)
  • Dodanie możliwości pobrania kolumny z identyfikatorem kampanii wysyłki faksu (batchId) dla funkcji getFaxCurrent oraz getFaxSent

Nowości w bazie Postgres 8.4

08 lipiec 2009, Michał Szymański

Baza Postgres jest mi dość bliska ponieważ jest to jedna z baz, z której korzystamy we Freeconecie. Z tego powodu dość uważnie obserwujemy co się zmieniło w kolejnych wersjach i z jakich nowych funkcjonalności będzie można skorzystać.
Niecały tydzień temu na stronie Postgres’a została udostępniona wersja 8.4. Wersja jest za ‘młoda’ żeby użyć ją w rozwiązaniach produkcyjnych, jednakże dokładnie przeanalizowałem co uległo zmianie i w tym artykule chciałbym zwrócić waszą uwagę na najciekawsze (moim zdaniem) nowe funkcjonalności. Ze względu, na to że głównymi czytelnikami bloga są programiści mam nadzieje, że dla części artykuł będzie interesujący. Poniżej lista nowości.

Windowing Function
Są to operacje pozwalające na dokonanie obliczeń na zbiorze wierszy jednakże funkcje umożliwiają odnieść wynik do bieżącego wiersza. Funkcje działają podobnie do funkcji grupujących z tą różnicą, że wynik nie jest grupowany do jednego wiersza. Bardziej zrozumiałe to będzie jeśli użyje przykładu z dokumentacji.
W wyniku takiego zapytania

SELECT nazawaoddzialu, empno, zarobki, avg(zarobki) OVER (PARTITION BY nazwaoddzialu) FROM empsalary;

otrzymamy

nazwaoddzialu empno zarobki avg
develop 11 5200 5020.0000000000000000
develop 7 4200 5020.0000000000000000
develop 9 4500 5020.0000000000000000
develop 8 6000 5020.0000000000000000
develop 10 5200 5020.0000000000000000
personnel 5 3500 3700.0000000000000000
personnel 2 3900 3700.0000000000000000

Pierwsze trzy kolumny są kolumnami tabeli empsalary, natomiast ostatnia kolumna jest średnią z kolumny zarobki z tym, że ta średnia podawana jest przy każdym wierszy pracownika z danego nazwaoddzialu i liczona jest z wierszy mających tą samą wartość nazwaoddziału. Pełna lista dostępnych funkcji można znaleźć na stronie http://www.postgresql.org/docs/8.4/interactive/functions-window.html z przykładowych funkcji można wymienić row_number() wyświetlającą numer porządkowy w danym ‘okienku’, co pozwala na numeracje wierszy.

Common Table Expressions & Recursive Queries
Jest to głównie odmienny zapis podzapytań dla skomplikowanych zapytań SQL. Przykładowe zapytanie z dokumentacji Postgresa

WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales; (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;

W tym zapytaniu fragment definiujący regional_sales jest jakby podstawiany do obliczania top_regional a wartość
top_regional podstawiana jest do głównego zapytania. Podane zapytanie można przepisać tak żeby nie zawierała konstrukcji WITH jednak wtedy mamy dwa poziomy sub-select’ów. Konstrukcje WITH możemy potraktować jako tymczasową tablice. Zupełnie nową funkcjonalność daje konstrukcja WITH RECURSIVE
Przykład z dokumentacji:

WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

Podany zapytanie zsumuje liczby od 1 do 100, nie jest to może zbyt praktyczny przykład ale jeden z prostszych. Tego typu konstrukcje w SQL znajdą zastosowanie w trakcie operacji na danych, które są zdefiniowane w postaci drzewa albo są przechowywane w sposób hierarchiczny.

Visibility Map
Wprowadzono kolejne poprawki minimalizujące potrzeby VACUUMów. W systemach czasu rzeczywistego musimy maksymalnie unikać tej operacji ponieważ istotnie blokuje inne operacje na bazie.

Nowe funkcjonalności w monitoringu aktywności bazy
Pojawiła się możliwość monitorowania czasu i ilości wywołań procedur bazodanowych jak również samych zapytań SQL. Co istotne statystyki przechowywane są w bazie. Funkcjonalność bardzo przydatna, ponieważ dotychczas ‘długie zapytania’ można było rejestrować jedynie w pliku log bazy danych, dodatkowo rozwiązanie pozwalało monitorować jedynie zapytania, które trwają dłużej niż zdefiniowana wartość. W sytuacji gdy dane zapytanie było wykonywane bardzo często ale nie trwało dłużej niż określony czas taki przypadek ‘wymykał się’ z analizy.

RETURNS TABLE
W wersji 8.4 oprócz możliwości zwracania typów podstawowych takich jak INT,NUMERIC i typów złożonych (ang.composite) zdefiniowanych w postaci typów i definicji opartych o istniejące tabele (chodzi o konstrukcje z SETOF) dodano konstrukcje RETURNS TABLE. Poniżej przykład użycia takiej konstrukcji:

CREATE OR REPLACE FUNCTION test_procedure() RETURNS TABLE (rv_id INT8,rv_test VARCHAR)
AS $$
BEGIN
RETURN QUERY SELECT id  as t_id, test as t_test FROM test_table;
END;

Zaletą takiej konstrukcji jest, to że nie musimy tworzyć typu specjalnie na potrzeby zwracania rezultatów z funkcji. Teoretycznie można w wielu sytuacjach użyć takiej konstrukcji

CREATE OR REPLACE FUNCTION test_procedure() RETURN SETOF test_table

gdzie test_table jest tablicą. Problem może się pojawić gdy zmieni się struktura bazy danych - funkcja może raportować błędy o tym, że definicja parametrów zwracanych jest inna niż to co faktycznie zwracamy z funkcji. Problem ten zgłosiłem dwa razy na grupę użytkowników Postgresa
jednak innych rad niż przeładowanie bazy nie było (oryginalny post na grupie).

Parametr -j w pg_restore
Program pg_restore (służący do odtwarzania bazy z pliku) można wywołać z parametrem -j. Tą opcje regulujemy ile równoległych procesów będzie importować dane do bazy. Według informacji znalezionych na sieci prędkość importu może wzrosnąć nawet ośmiokrotnie co jest wielkością niemałą przy odtwarzaniu naprawdę dużych baz.

Osoby chcące poznać wszystkie zmiany, które pojawiły się w Postgres’ie 8.4 zapraszam na strone http://www.postgresql.org/about/press/features84.html .

Nowa wersja API 2.01

22 czerwiec 2009, Michał Szymański

Dzisiaj na produkcji zainstalowaliśmy nową wersje Rest API 2.01. Dodano możliwość pobrania kolumny z identyfikatorem kampanii MassDial (batchId) dla funkcji getMassDialCurrent oraz getMassDialCalled. Aplikacje napisane dla wersji 2.00 są całkowicie zgodne z wersją 2.01. Zaktualizowana dokumentacja została udostępniona na stronie Dokumentacja RestAPI .

API 2.0 już dostępne

18 czerwiec 2009, Michał Szymański

W dniu dzisiejszym została uruchomiona nowa wersja API, oznaczona jako 2.0. Dokumentacja do tej wersji została udostępniona na stronie Dokumentacja RestAPI . Zachęcam do lektury i przeprowadzania własnych testów. Uwagi odnośnie dokumentu jak i samego API przesyłajcie na adres techblog@freeconet.pl .

Nadchodzi Freeconet REST API 2.0

03 czerwiec 2009, Michał Szymański

Chciałbym oficjalnie poinformować wszystkich zainteresowanych, że w drugiej połowie czerwca zostanie wdrożone Freeconet REST API w wersji 2.00. Dokładny termin uruchomienia API zostanie podany w najbliższym tygodniu. Wersja ta udostępni parę ciekawych funkcjonalności pomocnych w integracji usług Freeconet z zewnętrznymi systemami informatycznymi. Przejdźmy jednak do konkretów. Z najbardziej istotnych zmian można wymienić:

  • Możliwość odbierania i wysyłania faksów. Dostępne będą następujące funkcje:
    • przeglądanie historii faksów odebranych(getFaxReceived, getFaxReceivedCount)
    • wysyłanie faksów (sendFax)
    • pobieranie informacji o faksach oczekujących w kolejce do wysłania (getFaxCurrent, getFaxCurrentCount)
    • pobieranie informacji o faksach wysłanych (getFaxSent,getFaxSentCount)
    • upload plików na serwer, pliki te później mogą być użyte przy wysyłce (uploadFile)
  • Możliwość sterowaniem usługa masowego dzwonienia (MassDial). Usługa ta pozwala zadzwonić na wybrany numer i odtworzyć nagrany albo zsyntetyzowany komunikat użytkownikowi. Dla tej usługi dostępne będą funkcje:
    • startowanie zadania masowego dzwonienia (startMassDial)
    • pobieranie historii wykonanych zadań (getMassDialCalledCount, getMassDialCalled)
    • pobieranie listy aktualnie realizowanych zadań MassDial (getMassDialCurrCount, getMassDialCurr)
  • Funkcjonalność zestawiania połączeń bez potrzeby używania serwisu ‘Zestaw połączenie’. W wersji API 2.0 funkcja makeCall będzie można wywołać na dwa sposoby:
    • z parametrem idService, takie wywołanie wymaga stworzenia instancji serwisu ‘Zestaw połączenie’. Użycie tej usługi daje nam pełną kontrolę nad czasem realizacji i typem połączenia. Możemy między innymi zdecydować w jakich godzinach będą akceptowane rozmowy, na jakie prefiksy może dzwonić. Po obu stronach połączenia możemy podać identyfikator serwisu, nazwę konta albo numer.
    • bez parametru idService. W takim przypadku nie jest wymagane tworzenie instancja serwisu w grupie. Podstawowym ograniczeniem tej metody jest to, że po obu stronach rozmowy musi być podany numer.
  • Funkcjonalność umożliwiająca pobieranie statusu rejestracji kont zdefiniowanych w obrębie grupy. Poprzez wywołanie funkcji getRegistrationStatus możemy uzyskać informacje o statusie zalogowania bramki VoIP na dane konto.
  • Funkcjonalność pobierania informacji o rekordach billingowych. Używając funkcji getBilling/getBillingCount będzie można pobrać określone rekordy billingowe. W kryterium wyboru rekordów możemy zastosować między innymi nazwa użytkownika, typ rozmowy, data rozpoczęcia rozmowy czy też identyfikator użytkownika w systemie Call-eX.
  • Funkcjonalność pobierania informacji o numerze istniejącym w systemie Freeconet. Podając numer do funkcji getNumInfo, możemy dowiedzieć się między innymi jakiego rodzaju jest numer (miejski/numer przeniesiony/Telarenowy czy też numer wewnętrzny) albo do jakiego konta jest podpięty.

Oprócz zmian wprowadzających nowe funkcjonalności pojawia się kilka poprawek dających podstawy pod dalszą rozbudowę API jak również porządkujących całość API.

  • Wszystkie wartości w odpowiedzi funkcji umieszczane będą w elementach XML’a a nie w atrybutach. Niestety ta zmiana powoduje, że nie będzie wstecznej kompatybilności z XML’em z wersji API 1.x
  • Sekcja <errors> może się znajdować w sekcji funkcji ale również poza nią
  • Pojawia się pole authSystem określające do jakiego systemu chcemy się zautoryzować natomiast przestaje istnieć pole userDomain
  • Zostały zmienione nazwy pól w funkcji getVersion
  • Nastąpił podział na API użytkownika panelu Freeconet, systemu partnerskiego i systemu CRM

Pod linkiem Freeconet REST API 2.0 Beta możecie pobrać roboczą wersje dokumentacji nowej wersji API.

Integracja CRM z FreecoNet (part 2)

16 kwiecień 2009, Marcin Gala

CRM oraz zarządzanie faksami

Platforma FreecoNet od kilku miesięcy udostępnia funkcjonalność wirtualnego faksu (WF). Składa się ona z następujących funkcji:

Mamy, więc kompletną funkcjonalność do zarządzania faksami w naszym przedsiębiorstwie. Jak teraz wbudować ją do naszego CRM? Zacznijmy więc od metod najprostszych, a mianowicie wykorzystajmy mail2fax - do wysyłki.

CRM z wykorzystaniem print2fax

Aby zintegrować CRM z Wirtualnym Faksem należy tylko zainstalować sterownik print2fax, tak gdzie mamy uruchomionego klienta systemu CRM. W trakcie instalacji sterownik poprosi Nas o konfigurację usługi. Jeśli będziemy chcieli wysłać dokument do klienta faksem, wystarczy że go otworzymy, a następnie wejdziemy w opcję Drukuj –> Wirtualny Fax, podamy numer telefonu i voila!

CRM z wykorzystaniem web2fax/fax2web

W posiadanym panelu CRM możemy dać użytkownikom przycisk Konsola faksowa, po kliknięciu którego otworzy się przeglądarka internetowa i użytkownik zaloguje się do swojej konsoli. Będzie mógł w pełni zarządzać swoim faksem (wysyłać, odbierać, drukować itp.). Przycisk Konsola faksowa powinien wywoływać adres https://konsola.t37fax.pl/?login=<TwojLogin>&password=<TwojeHaslo>. Rozwiązanie to wymaga jedynie dodawania odpowiednich linków w CRM, więc jest możliwe do wdrożenia równie szybko jak print2fax.  Następne rozwiązania wymagają już modyfikacji systemu CRM przez osoby posiadające wiedzę programistyczną.

CRM z wykorzystaniem mail2fax

Po stronie naszego systemu CRM przygotować musimy skrypt, który zautoryzuje się na użytkownika SMTP (zgodnie z konfiguracją usługi WF). W polu ‘To:’ podajemy adres fax@t37fax.pl, w polu ‘Subject:’ podajemy numery telefonów,  na które ma on zostać wysłany w postaci +48221234567 i wykonujemy metodę send() [w większości klas tak się nazywa]. Jeśli stosujemy technologię skryptową - PHP, to możemy skorzystać z pakietu PEAR’s Mail, w innych technologiach (C++, C#, Java) również istnieją stosowne klasy, które dostarczają wymaganej funkcjonalności.

CRM z wykorzystaniem fax2mail

Usługa wirtualny faks pozwala na zdefiniowanie adresów email, na które to wysyłane będą wszystkie faksy odebrane. Jeśli system CRM zintegrowany jest z serwerem pocztowym to możemy dodać w nim skrzynkę, na którą WF będzie kierował wszystkie faksy odebrane. Na podstawie informacji w odebranej wiadomość email, system CRM może następnie przerzucać faksy do skrzynek odpowiednich klientów razem ze wszystkimi danymi (czas i data odebrania faksu, ilość stron itp.). Spójrzmy na strukturę takiego emaila.

Data: 16 kwiecień 2009

Godzina: 13:34:39

Identyfikator faksu: FreecoNet S.A.

Nadawca: +48580099001

Odbiorca: +48221234567

Ilość stron: 1

Widzimy, że dzięki polu Nadawca możemy wyszukiwać klienta CRM po numerze. Może się jednak zdarzyć, że nadawca nie prezentował się numerem, jak w przykładzie poniżej:

Data: 16 kwiecień 2009

Godzina: 13:34:39

Identyfikator faksu: FreecoNet S.A.

Nadawca: Unknown

Odbiorca: +48221234567

Ilość stron: 1

W takim przypadku niestety nie będziemy mogli jednoznacznie określić klienta na podstawie wiadomości email - konieczne było by zajrzenie do nagłówka faksu (w pliku PDF), co jest operacją trudniejszą do zautomatyzowania. Większość maszyn faksowych wysyła również pole Remote Fax ID, czyli Identyfikator faksu. W polu tym zamieszczają nazwę firmy lub też numer telefonu maszyny faksowej. Możemy zatem skorzystać również z tej informacji i odnaleźć klienta w bazie danych CRM, a następnie przerzucić odebrany faks do jego skrzynki. Dzięki temu zarejestrowany mamy również kontakt faskowy z kontrahentem.

Integracja CRM z fax2mail wymaga on Nas napisania narzędzia (skryptu), który przeglądał będzie odpowiednie skrzynki pocztowe z serwera pocztowego, pobierał otrzymane wiadomości faksowe i analizował informacje zawarte w treści wiadomości.

CRM z wykorzystaniem API FAX

… w następnym artykułe

Integracja CRM z FreecoNet

15 kwiecień 2009, Marcin Gala

Z uwagi na fakt, iż w ostatnim czasie pojawia się sporo zapytań o możliwości integracji FreecoNet z systemami klasy CRM, postanowiłem napisać serię artykułów na ten temat. Pozwoli to potencjalnym klientom zapoznać się z możliwościami platformy FreecoNet.

Pewnie wiele czytelników  integrację będzie kojarzyło z dodaniem kanału głosowego do systemu CRM. Mają oni rację! …choć nie do końca. Integrację można wykonać w wielu płaszczyznach, a mianowicie:

  1. CRM oraz połączenia
  2. CRM oraz zarządzanie faksami
  3. CRM oraz kontakty
  4. CRM oraz powiadomienia
  5. to be continued….

Tak na prawdę ograniczeni jesteśmy tutaj w dużej mierze naszą wyobraźnią i czasowo możliwościami FreecoNet API, które jest dostępne tutaj. Piszę czasowo, gdyż to co dzisiaj wymyślisz drogi Czytelniku dzisiaj może nie być w API, ale już jutro… :)

CRM oraz połączenia

CRM nieodwołalnie wiąże się z kontaktem z klientem i bardzo często jest to kontakt telefoniczny. Zacznijmy więc od niego. Wyróżnijmy na wstępie 2 rodzaje kontaktu telefonicznego:

  1. Połączenie przychodzące od klienta
  2. Połączenie wychodzące do klienta

Ad.1 Połączenie przychodzące od klienta możemy dodatkowo podzielić na połączenie typu CLIP oraz CLIR. Gdy połączenie jest typu CLIP to jesteśmy w stanie zidentyfikować naszego klienta w CRM na podstawie jego numeru telefonu. Spójrzmy teraz na usługi, które oferuje FreecoNet… mamy do dyspozycji:

  • numerację miejską
  • usługę Zintegruj, która umożliwia integrację platformy FreecoNet z dowolną aplikacją zewnętrzną.

Załóżmy więc, że połączenie przyszło na numer z TelAreny, do którego jest podłączona usługa Zintegruj. W usłudze podajemy adres www naszego webservice np. http://moja.domena.pl/CRM/polaczenie.php.Skrypt polaczenie.php będzie pobierał numer telefonu klienta dzwoniącego CLIP i zapisywał w bazie w CRM - rejestrowanie połączenia. Następnie zwróci wynik = 0. Na wyjściu z usługi Zintegruj we FreecoNet ustawiamy przekierowanie na nową usługę CallCenter, które będzie dzwoniła po konsultantach naszego CRM. Taki konsultant otrzyma połączenie głosowe i będzie mógł sprawdzić w CRM kto dzwoni… i rozwiązywać problem klienta… zapisując notatkę z rozmowy.

Ad.2 Połączenie wychodzące do klienta z systemu CRM. Zwróćmy uwagę, że inicjatorem takiego połączenia może być system CRM lub użytkownik tego systemu CRM. W obu przypadkach, do inicjacji połączenia, możemy wykorzystać usługę Zestaw Połączenie. Wizualnie użytkownik w systemie CRM będzie widział przycisk do zadzwonienia, po kliknięciu którego zadzwoni jego telefon i następnie połączenie zostanie zestawione z klientem, którego kliknął na stronie.  Dzięki FreecoNet API po takim połączeniu możemy uzyskać koszt tej rozmowy - jednak z punktu widzenia użytkownika CRM nie jest to informacja istotna - stanowi ona koszt obsługi CRM i będzie ważniejsza dla działu finansowego. Nadmienię również, że jeśli pracownik CRM i klient są we FreecoNet to rozmowa będzie bezpłatna.

Jak już wspomniałem inicjatorem może być również system CRM, jednak do tego zagadnienia wrócę w kolejnych artykułach z tej serii.

Cuda w informatyce..

20 styczeń 2009, Michał Szymański

Można w cuda nie wierzyć jednak to co się wydarzyło w trakcie ostatniego patcha w naszym systemie można zaliczyć przynajmniej do cudów informatycznych. Zapewne słyszeliście starą anegdotę o tym, że naukowcy jednego z państw byłego bloku wschodniego stworzyli tak szybki komputer, że pętle nieskończoną robił w 10min, my spotkaliśmy się z czymś podobnym. W trakcie ‘patchowania’ systemu Freeconet do wersji 3.04 musieliśmy dokonać zmian w jednej tabeli nazwijmy ją ABC, ta tabela posiada klucz główny na polu ABC_ID. Dla przypomnienia klucz główny to klucz który jednoznacznie identyfikuje wiersz w tabeli (pełna definicję terminu ‘klucz główny’ znajdziecie tutaj). Przed zmianami w tabeli zrobiliśmy eksport danych z tej tabeli i dla pewności jeden z pracowników zaproponował sprawdzenie czy nasz eksport bez problemu się zaimportuje (to tak na wszelki wypadek jakby coś nie poszło z naszym patchem). Nieco się zdziwiłem jak okazało się, że wyeksportowanych danych nie można zaimportować, ale jak zobaczyłem powód tego problemu to zrobiłem naprawdę duże oczy. Okazało się że w tabeli ABC są dwa wiersze z tą samą wartością pola ABC_ID !!! Rzecz niemożliwa a jednak się zdarzyła :) Oczywiście jest to błąd bazy, który wynikł zapewne z błędnego działania RAIDU. Praktyka pokazuje, że i na takie sytuacje trzeba się przygotować w praktyce inżyniera oprogramowania.

Głosujemy na Blog Roku 2008!

19 styczeń 2009, Michał Szymański

Na prośbę naszego działu marketingu wklejam poniższy tekst.

TechBlog FreecoNet bierze udział w konkursie „Blog Roku 2008” (http://www.blogroku.pl/) organizowanym przez portal Onet.pl. Aby oddać swój głos na ten Blog, należy wysłać SMSa o treści B00250 na numer 7144 (1,22 zł z VAT). Z każdej kategorii 10 blogów z największą ilością głosów przejdzie do III etapu, polegającym na ocenie blogów przez Kapitułę Konkursu oraz wyborze tych najlepszych.
Dochód z wysłanych SMSów zostanie przeznaczony na szczytny cel. Wszystkie osoby głosujące w II i III etapie Konkursu mają szansę na wygranie jednego z 10 aparatów fotograficznych Casio Exilim EX-Z80 o wartości 499 zł każdy.
Zdajemy sobie sprawę, że tematyka naszego bloga jest raczej mało popularna, a grupa odbiorców ściśle związana z tematyką VoIP, jednak mamy nadzieję, że nasi czytelnicy oraz użytkownicy FreecoNet nie pozostaną bierni, docenią nasze starania i pomogą dostać nam się do kolejnego etapu.