Ekspert radzi mechanizm w enova, umożliwiający wskazanie domyślnej drukarki dla danego stanowiska i wydruku. Strona 1 z 8
Spis treści 1. Zarys rozwiązania...3 1.2 Case study...3 1.3 Wymagania...3 2. Projekt...3 2.2 Przygotowanie konfiguracji...3 2.3 Szablon projektu...4 2.4 Rozszerzenie funkcjonalności...5 2.5 Dodatki: pełen kod źródłowy...6 Strona 2 z 8
1. Zarys rozwiązania 1.2 Case study Coraz częstszą praktyką stosowaną w przedsiębiorstwach jest automatyzacja pewnych wzorcowych, powtarzalnych procesów w firmie. Przyjmijmy zatem następujący scenariusz do zaimplementowania w enova. Operator modułu handel, po zakończeniu wystawiana faktury gotówkowej na jednej drukarce drukuje FV, a na innej KP. Następnie na magazynach w rozbiciu na miejsce przebywania towarów drukowały by się wydania zewnętrzne. Dodatkowo można by sterować w ramach wydruku różnymi sterownikami (tzn. wielokrotność zainstalowanej danej drukarki z różnymi preferencjami np.1 sterownik drukuje z podajnika nr 1 gdzie jest włożony papier z nadrukami w kolorze) a sterownik nr 2 drukuje z zasobnika nr2 w którym załadowany jest zwykły papier. Plan zatem, który chcemy osiągnąć: umożliwienie dla danego stanowiska i wydruku - wskazanie domyślnej drukarki. 1.3 Wymagania W celu implementacji poniższego rozwiązania konieczne jest spełnienie następujących składowych: Podstawowa wiedza z zakresu programowania obiektowego (C#,.NET) Skonfigurowane środowisko programistyczne (API) framework.net, aktualne biblioteki logiki enova (Soneta.Business, Soneta.Printer etc.), Microsoft Visual Studio 2005 wzwyż. Środowisko testowe enova, kilka osobnych stanowisk, różne sterowniki drukarek. 2. Projekt 2.2 Przygotowanie konfiguracji W naszym przykładzie stworzymy tylko prosty zarys rozwiązania, które następnie będzie można do woli modyfikować i rozbudowywać o nowe funkcjonalności. Podstawą będzie trywialna podmiana domyślnej drukarki na czas wydruku na jednym stanowisku. Jako, że chcemy by w dalszej przyszłości zmiany były zależne od operatora oraz wzorca wydruku, przygotujmy wstępnie taką konfigurację, która umożliwi nam osiągnięcie takiej funkcjonalności bez zbędnych zabiegów środowiskowych czy rekompilacji dodatku. Strona 3 z 8
W tym celu nasz worker wzbogacimy o parsowanie własnego XML wrzuconego do tej samej lokalizacji co pliki konfiguracyjne enova (%APPDATA%\Soneta) gdzie będzie definiowany sterownik drukarki. Przykładowa struktura pliku XML (Ustawienia drukarki.xml) wykorzystana w poniższym przykładzie. Bez problemu dzięki temu można rozbudować funkcjonalność np. odnośnie skojarzenia wzorca aspx (wystarczy dodanie zupełnie nowej gałęzi do Items np. < report>handel \ Sprzedaż.aspx</ report>) z drukarką i kontekstem w którym operator aktualnie znajduje się w programie oraz odpowiednią przeciążyć metodę parsującą. Za obsługę natomiast od strony stanowiska odpowiada już sam XML konfiguracyjny. 2.3 Szablon projektu Pełen kod projektu wraz z komentarzami zamieszczono na końcu artykułu. Projekt rozpoczynamy od załadowania wymaganych bibliotek enova (klauzula using). Następnie definiujemy własny namespace i budujemy w niej główną klasę naszego projektu. Przykładowy worker został jak widać zarejestrowany dla kontekstu obiektu Zadania CRM oraz przypisany na sztywno tylko do jednego wzorca aspx. W rozbudowanej formie Strona 4 z 8
będziemy mogli jednak zarejestrować go globalnie (niezależnie od kontekstu, niezależnie czy wywołanie z poziomu listy czy też formatki danego obiektu) poprzez rejestrację w atrybucie assembly dla typu Soneta.Business.App.Login, natomiast same dane odnośnie wydruków pobierać z XML. Cała idea naszego dodatku będzie opierać się zatem na załadowaniu XML a konfiguracyjnego i następnie odpowiednim sparsowaniu go pod kątem potrzebnych nam danych (dane sterownika drukarki, wzorca wydruku, kontekstu etc.). Przed przestawieniem sterownika drukarki dla danego wydruku pobierzemy dodatkowo dane o aktualnej domyślnej drukarce w systemie (celem przywrócenia jej ustawienia po zakończeniu generowania wydruku). Po wybraniu już docelowego dla nas sterownika, generujemy wydruk z danego wzorca aspx wykorzystując obiekt Soneta.Printer.AspGenerator. Przykład wywołania workera z przestawieniem domyślnej drukarki na PDFCreator dla danego wydruku. 2.4 Rozszerzenie funkcjonalności. Jak już wspomniano na wstępie, wykorzystanie idei XML z konfiguracją pozwala nam nie tylko na bezinwazyjne rozszerzanie funkcjonalności naszego serwisu ale dodatkowo na łatwą personalną konfigurację zdefiniowaną np. pod kątem specyficznego stanowiska lub operatora. W celu rozbudowy dodatku wystarczy w zasadzie dodanie nowych gałęzi odwołujących się do dodatkowych danych tj. np. wzorzec wydruku który chcemy przypisać do danej drukarki lub format wydruku. Inną możliwością jest zdefiniowanie własnej klasy parametrów i przekazywanie z niej listy wszystkich wydruków w danym kontekście. Do tego celu będzie można wykorzystać nowo dodaną klasę (od wersji 8.0) opartą na interfejsie IWizardGetReportPagesService. Została ona przygotowana specjalnie na potrzeby użycia w kreatorach a dokładnie w obiektach WizardStepDefinition (typ kroku zakładka wydruku). Strona 5 z 8
2.5 Dodatki: pełen kod źródłowy using System; using System.Collections.Generic; using System.Linq; using System.Text; using Soneta.Business; using Soneta.Types; using Soneta.Printer; using Soneta.Tools; using Soneta.Forms; using System.Management; using System.Drawing.Printing; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Xml; using System.IO; using Soneta.Business.Db.Wizard; using Soneta.Business.App; using Soneta.Business.Forms.Reports; // Rejestracja workera [assembly: Worker(typeof(ASPgenerator.Print),typeof(Soneta.Zadania.Zadanie))] namespace ASPgenerator public class Print // Przypnij na Toolbar w enova [Action( "Drukuj Raport", Description = "", CommandShortcut = Soneta.Commands.CommandShortcut.F5, Priority = 1000, Icon = ActionIcon.Wizard, Target = ActionTarget.Menu ActionTarget.ToolbarWithText)] public void printer_run(context cx) string RaportName = "CRM/26etykieta.aspx"; string PrinterName = DefaultPrinterName(); string drukarka_kodow = DefinedPrinter(); SetAsDefaultPrinter(drukarka_kodow); Strona 6 z 8
// Generuj wydruk ze wzorca aspx try Soneta.Zadania.Zadanie zadanie = (Soneta.Zadania.Zadanie)cx[typeof(Soneta.Zadania.Zadanie)]; cx.set(zadanie); Soneta.Printer.AspGenerator generator = new Soneta.Printer.AspGenerator(); generator.name = "Zadanie CRM"; generator.templatefilename = RaportName; generator.prompt = true; generator.destination = Soneta.Printer.AspGenerator.Destinations.Printer; generator.print(soneta.forms.formstools.mainform, cx, false, new Soneta.Zadania.Zadanie[] zadanie ); catch (System.IO.FileNotFoundException) throw new Exception("Nie znaleziono wzorca wydruku"); catch throw new Exception("Problem z drukowaniem raportu"); finally // Poczekaj na zakończenie wydruku System.Threading.Thread.Sleep(1000); // Przywróć domyślną drukarkę SetAsDefaultPrinter(PrinterName); // Rejestracja workera /// <summary> /// Zwróć nazwę domyślnaje drukarki w systemie /// </summary> public static string DefaultPrinterName() string functionreturnvalue = null; System.Drawing.Printing.PrinterSettings ops = new System.Drawing.Printing.PrinterSettings(); try functionreturnvalue = ops.printername; catch (System.Exception ex) functionreturnvalue = ""; finally ops = null; return functionreturnvalue; static int SetAsDefaultPrinter(string printerdevice) int ret = 0; string path = "win32_printer.deviceid='" + printerdevice + "'"; using (ManagementObject printer = new ManagementObject(path)) ManagementBaseObject outparams = printer.invokemethod("setdefaultprinter", null, null); ret = (int)(uint)outparams.properties["returnvalue"].value; Strona 7 z 8
/// <summary> /// Metoda parsująca XML konfiguracyjny /// </summary> private stringdefinedprinter() string modeldrukarki = ""; string EnviromentPath = System.Environment.GetEnvironmentVariable("APPDATA"); string strfilename = EnviromentPath + "\\Soneta\\Ustawienia drukarki.xml"; XmlDocument xmldoc = new XmlDocument(); FileStream xmlstream = null; if (File.Exists(strFilename)) xmlstream = new FileStream(strFilename, FileMode.Open, FileAccess.Read); xmldoc.load(xmlstream); XmlNodeList fnames = xmldoc.getelementsbytagname("model"); modeldrukarki = fnames[0].innertext; return modeldrukarki; /// <summary> /// Metoda przestawiająca domyślną drukarkę na pobraną z konfiguracji /// wykorzystaując delegatę systemową InvokeMethod() oraz WMI /// </summary> static int SetAsDefaultPrinter(string printerdevice) int ret = 0; string path = "win32_printer.deviceid='" + printerdevice + "'"; using (ManagementObject printer = new ManagementObject(path)) ManagementBaseObject outparams = printer.invokemethod("setdefaultprinter", null, null); ret = (int)(uint)outparams.properties["returnvalue"].value; return ret; public static class myprinters [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool SetDefaultPrinter(string Name); Strona 8 z 8