printing improvemetns; decouple some from hatch
authorBill Erickson <berick@esilibrary.com>
Mon, 16 Jun 2014 21:39:51 +0000 (17:39 -0400)
committerBill Erickson <berick@esilibrary.com>
Mon, 16 Jun 2014 21:39:51 +0000 (17:39 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
13 files changed:
Open-ILS/src/templates/staff/base_js.tt2
Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2
Open-ILS/web/js/ui/default/staff/Gruntfile.js
Open-ILS/web/js/ui/default/staff/admin/workstation/app.js
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/circ/patron/bills.js
Open-ILS/web/js/ui/default/staff/circ/patron/checkout.js
Open-ILS/web/js/ui/default/staff/circ/services/circ.js
Open-ILS/web/js/ui/default/staff/services/coresvc.js
Open-ILS/web/js/ui/default/staff/services/hatch.js
Open-ILS/web/js/ui/default/staff/services/print.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/services/print_templates.js [deleted file]
Open-ILS/web/js/ui/default/staff/test/karma.conf.js

index e56cf47..76bc5a3 100644 (file)
@@ -25,6 +25,7 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/org.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/startup.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/hatch.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/print.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/coresvc.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/navbar.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/statusbar.js"></script>
index abb054f..44712d5 100644 (file)
 
 <div class="flex-row pad-vert">
   <div class="flex-cell"></div>
-  <div class="pad-horiz">
-    <input ng-model="auto_print" type="checkbox"/>
-    [% l('Auto-Print') %]
+  <div class="pad-horiz checkbox">
+    <label>
+      <input ng-model="show_print_dialog" type="checkbox"/>
+      [% l('Show Print Dialog') %]
+    </label>
   </div>
-  <div>
+  <div class="pad-horiz">
     <button class="btn btn-default" 
       ng-click="print_receipt()">[% l('Print Receipt') %]</button>
   </div>
+  <div>
+    <button class="btn btn-default" ng-click="done()">[% l('Done') %]</button>
+  </div>
 </div>
 
index 303cc56..883d6db 100644 (file)
@@ -93,6 +93,7 @@ module.exports = function(grunt) {
             'services/org.js',
             'services/startup.js',
             'services/hatch.js',
+            'services/print.js',
             'services/coresvc.js',
             'services/navbar.js',
             'services/statusbar.js',
index 2a635e8..1dcc683 100644 (file)
@@ -266,25 +266,24 @@ function($scope , egCore) {
 
     $scope.testPrint = function(withDialog) {
         if ($scope.contentType == 'text/plain') {
-            egCore.hatch.print(
-                $scope.context, 
-                $scope.contentType, 
-                $scope.textPrintContent,
-                null,
-                withDialog
-            );
+            egCore.print.print({
+                context : $scope.context, 
+                content_type : $scope.contentType, 
+                content : $scope.textPrintContent,
+                show_dialog : withDialog
+            });
         } else {
-            egCore.hatch.print(
-                $scope.context,
-                $scope.contentType, 
-                $scope.htmlPrintContent, 
-                {
+            egCore.print.print({
+                context : $scope.context,
+                content_type : $scope.contentType, 
+                content : $scope.htmlPrintContent, 
+                scope : {
                     value1 : 'Value One', 
                     value2 : 'Value Two',
                     date_value : '2015-02-04T14:04:34-0400'
                 },
-                withDialog
-            );
+                show_dialog : withDialog
+            });
         }
     }
 
@@ -333,10 +332,6 @@ function($scope , $q , egCore) {
     }
 
     $scope.preview_scope = {
-        current_location : egCore.idl.toHash(
-            egCore.org.get(egCore.auth.user().ws_ou())),
-        today : new Date(),
-
         //bills
         transactions : [
             {
@@ -397,7 +392,6 @@ function($scope , $q , egCore) {
         },
         title : seed_record.title,
         author : seed_record.author,
-        staff : egCore.idl.toHash(egCore.auth.user()),
         patron : egCore.idl.toHash(egCore.auth.user()),
         address : seed_addr
     }
@@ -411,9 +405,12 @@ function($scope , $q , egCore) {
     $scope.preview_scope.payments[1].xact.title = seed_record.title;
     $scope.preview_scope.payments[1].xact.copy_barcode = seed_copy.barcode;
 
+    // today, staff, current_location, etc.
+    egCore.print.fleshPrintScope($scope);
+
     $scope.template_changed = function() {
         $scope.print.load_failed = false;
-        egCore.hatch.getPrintTemplate($scope.print.template_name)
+        egCore.print.getPrintTemplate($scope.print.template_name)
         .then(
             function(html) { 
                 $scope.print.template_content = html;
index 6662f65..c831818 100644 (file)
@@ -506,9 +506,13 @@ function($scope,  $q,  $location , $filter,  egCore,  egUser,  patronSvc) {
     $scope.summary_stat_cats = function() { return patronSvc.summary_stat_cats }
 
     $scope.print_address = function(addr) {
-        egCore.hatch.printFromTemplate('default', 'patron_address', {
-            patron : egCore.idl.toHash(patronSvc.current),
-            address : egCore.idl.toHash(addr)
+        egCore.print.print({
+            context : 'default', 
+            template : 'patron_address', 
+            scope : {
+                patron : egCore.idl.toHash(patronSvc.current),
+                address : egCore.idl.toHash(addr)
+            }
         });
     }
 }])
@@ -1161,8 +1165,11 @@ function($scope,  $routeParams , $location , egCore , patronSvc , $modal) {
     $scope.printNote = function(note) {
         var hash = egCore.idl.toHash(note);
         hash.usr = egCore.idl.toHash($scope.patron());
-        egCore.hatch.printFromTemplate(
-            'default', 'patron_note', {note : hash});
+        egCore.print.print({
+            context : 'default', 
+            template : 'patron_note', 
+            scope : {note : hash}
+        });
     }
 
     // perform the initial note fetch
index f6e7833..5b83989 100644 (file)
@@ -321,8 +321,11 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             print_data.payment_applied * 100) / 100;
 
         for (var i = 0; i < $scope.receipt_count; i++) {
-            egCore.hatch.printFromTemplate(
-                'receipt', 'bill_payment', print_data);
+            egCore.print.print({
+                context : 'receipt', 
+                template : 'bill_payment', 
+                scope : print_data
+            });
         }
     }
 
@@ -403,13 +406,15 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             {authoritative : true}
         ).then(
             function() {
-                egCore.hatch.printFromTemplate(
-                    'receipt', 'bills_current', 
-                    {   transactions : xacts,
+                egCore.print.print({
+                    context : 'receipt', 
+                    template : 'bills_current', 
+                    scope : {   
+                        transactions : xacts,
                         current_location : egCore.idl.toHash(
                             egCore.org.get(egCore.auth.user().ws_ou()))
                     }
-                );
+                });
             }, 
             null, 
             function(xact) {
index c9bfc00..e8a3151 100644 (file)
@@ -5,10 +5,10 @@
 angular.module('egPatronApp').controller('PatronCheckoutCtrl',
 
        ['$scope','$q','$modal','$routeParams','egCore','egUser','patronSvc',
-        'egGridDataProvider','$location','egCirc',
+        'egGridDataProvider','$location','$timeout','egCirc',
 
 function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc , 
-         egGridDataProvider , $location , egCirc) {
+         egGridDataProvider , $location , $timeout , egCirc) {
 
     $scope.initTab('checkout', $routeParams.id);
     $scope.focusMe = true;
@@ -23,8 +23,12 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
         }
     });
 
-    egCirc.get_circ_mods().then(function(list) {
-        $scope.circModifiers = list;
+    var printOnComplete = true;
+    egCore.org.settings([
+        'circ.staff_client.do_not_auto_attempt_print'
+    ]).then(function(settings) { 
+        printOnComplete = !Boolean(
+            settings['circ.staff_client.do_not_auto_attempt_print']);
     });
 
     egCirc.get_noncat_types().then(function(list) {
@@ -123,20 +127,37 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
         }
     }
 
+    // TODO: show print dialog
     $scope.print_receipt = function() {
-        var print_data = {
-            circulations : [],
-            staff : egCore.idl.toHash(egCore.auth.user()),
-            current_location : egCore.idl.toHash(
-                egCore.org.get(egCore.auth.user().ws_ou()))
-        }
+        var print_data = {circulations : []}
+
+        if ($scope.checkouts.length == 0) return $q.when();
+
         angular.forEach($scope.checkouts, function(co) {
             var circ = egCore.idl.toHash(co.payload.circ);
             circ.title = co.payload.record.title;
             print_data.circulations.push(circ);
         });
 
-        egCore.hatch.printFromTemplate('default', 'checkout', print_data);
+        return egCore.print.print({
+            context : 'default', 
+            template : 'checkout', 
+            scope : print_data
+        });
+    }
+
+    // Redirect the user to the barcode entry page to load a new patron.
+    // If configured to do so, print the receipt first
+    $scope.done = function() {
+        if (printOnComplete) {
+
+            $scope.print_receipt().then(function() {
+                $location.path('/circ/patron/bcsearch');
+            });
+
+        } else {
+            $location.path('/circ/patron/bcsearch');
+        }
     }
 }])
 
index 2fd18a7..05a947a 100644 (file)
@@ -425,13 +425,10 @@ function($modal , $q , egCore , egAlertDialog , egConfirmDialog) {
                         transit : egCore.idl.toHash(transit),
                         title : evt.payload.record.title(),
                         author : evt.payload.record.author(),
-                        staff : egCore.idl.toHash(egCore.auth.user()),
                         copy : egCore.idl.toHash(evt.payload.copy),
                         dest_location :
                             egCore.idl.toHash(egCore.org.get(transit.dest())),
                         dest_address : egCore.idl.toHash(destAddr),
-                        current_location : egCore.idl.toHash(
-                            egCore.org.get(egCore.auth.user().ws_ou()))
                     }
 
                     var template = 'transit_slip';
@@ -441,8 +438,11 @@ function($modal , $q , egCore , egAlertDialog , egConfirmDialog) {
                         print_context.patron = egCore.idl.toHash(holdUser);
                     }
 
-                    egCore.hatch.printFromTemplate(
-                        'default', template, print_context);
+                    egCore.print.print({
+                        context : 'default', 
+                        template : template, 
+                        scope : print_context
+                    });
                 }
             }],
             resolve : {
index 8bedf05..6909978 100644 (file)
@@ -9,9 +9,9 @@ angular.module('egCoreMod')
 
 .factory('egCore', 
        ['egIDL','egNet','egEnv','egOrg','egPCRUD','egEvent','egAuth',
-        'egPerm','egHatch','egStartup','egStrings',
+        'egPerm','egHatch','egPrint','egStartup','egStrings',
 function(egIDL , egNet , egEnv , egOrg , egPCRUD , egEvent , egAuth , 
-         egPerm , egHatch , egStartup , egStrings) {
+         egPerm , egHatch , egPrint , egStartup , egStrings) {
 
     return {
         idl     : egIDL,
@@ -23,6 +23,7 @@ function(egIDL , egNet , egEnv , egOrg , egPCRUD , egEvent , egAuth ,
         auth    : egAuth,
         perm    : egPerm,
         hatch   : egHatch,
+        print   : egPrint,
         startup : egStartup,
         strings : egStrings
     };
index 099aa0d..bd3f178 100644 (file)
@@ -11,9 +11,6 @@
  * Most handlers also provide direct remote and local variants to the
  * application can decide to which to use as needed.
  *
- * Printing is handled locally with an egPrintContainer whose contents
- * are made visible during printing using CSS print media.
- *
  * Local storage requests are handled by $window.localStorage.
  *
  * Note that all top-level and remote requests return promises.  All
@@ -28,8 +25,8 @@
 angular.module('egCoreMod')
 
 .factory('egHatch',
-           ['$q','$window','$timeout','$interpolate','$rootScope','$http',
-    function($q , $window , $timeout , $interpolate , $rootScope , $http) {
+           ['$q','$window','$timeout','$interpolate','$http',
+    function($q , $window , $timeout , $interpolate , $http) {
 
     var service = {};
     service.msgId = 0;
@@ -40,8 +37,6 @@ angular.module('egCoreMod')
     service.defaultHatchURL = 'wss://localhost:8443/hatch'; 
     service.hatchRequired = false;
 
-    service.printTemplateBase = 'share/print_templates/t_';
-
     // write a message to the Hatch websocket
     service.sendToHatch = function(msg) {
         var msg2 = {};
@@ -201,51 +196,22 @@ angular.module('egCoreMod')
         }
     }
 
-    service.printFromTemplate = function(context, templateName, printScope) {
+    service.getPrintConfig = function() {
+        if (service.printConfig) 
+            return $q.when(service.printConfig);
 
-        // populate some common print scope values...
-        printScope.today = new Date();
-        return service.getPrintTemplate(templateName)
-        .then(function(template) {
-            service.print(context, 'text/html', template, printScope);
+        return service.getRemoteItem('eg.print.config')
+        .then(function(conf) { 
+            return (service.printConfig = conf || {}) 
         });
     }
 
-    service.print = function(
-        context, contentType, content, printScope, withDialog) {
-
-        var promise;
-        if (contentType == 'text/html') {
-            // all HTML content is assumed to require compilation, regardless
-            // of the print destination
-            promise = service.ingestPrintContent(
-                contentType, content, printScope);
-        } else {
-            // text content does not require compilation for remote printing
-            promise = $q.when(content);
-        }
-
-        return promise.then(function(html) {
-            return service.remotePrint(
-                context, contentType, html, withDialog)['catch'](
-
-                function(msg) {
-                    // remote print not available; 
-                    if (contentType != 'text/html') {
-                        // text content does require compilation 
-                        // (absorption) for browser printing
-                        service.ingestPrintContent(contentType, content, {})
-                        .then(function() { $window.print() });
-                    } else {
-                        // HTML content is already ingested and accessible
-                        // within the page to the printer.  
-                        $window.print();
-                    }
-                }
-            );
-        });
+    service.setPrintConfig = function(conf) {
+        service.printConfig = conf;
+        return service.setRemoteItem('eg.print.config', conf);
     }
 
+
     service.remotePrint = function(
         context, contentType, content, withDialog) {
 
@@ -263,24 +229,6 @@ angular.module('egCoreMod')
         );
     }
 
-    // -------------
-    // print configuration is always stored as remote items,
-    // since there is no concept of a local printer
-    service.getPrintConfig = function() {
-        if (service.printConfig) 
-            return $q.when(service.printConfig);
-
-        return service.getRemoteItem('eg.print.config')
-        .then(function(conf) { 
-            return (service.printConfig = conf || {}) 
-        });
-    }
-    service.setPrintConfig = function(conf) {
-        service.printConfig = conf;
-        return service.setRemoteItem('eg.print.config', conf);
-    }
-    // -----------
-
     // launch the print dialog then attach the resulting configuration
     // to the requested context, then store the final values.
     service.configurePrinter = function(context, printer) {
@@ -468,97 +416,6 @@ angular.module('egCoreMod')
         return keys;
     }
 
-    // loads an HTML print template by name from the server
-    // If no template is available in local/hatch storage, 
-    // fetch the template as an HTML file from the server.
-    service.getPrintTemplate = function(name) {
-        var deferred = $q.defer();
-
-        service.getItem('eg.print.template.' + name)
-        .then(function(html) {
-
-            if (html) {
-                // we have a locally stored template
-                deferred.resolve(html);
-                return;
-            }
-
-            var path = service.printTemplateBase + name;
-            console.debug('fetching template ' + path);
-
-            $http.get(path)
-            .success(function(data) { deferred.resolve(data) })
-            .error(function() {
-                console.error('unable to locate print template: ' + name);
-                deferred.reject();
-            });
-        });
-
-        return deferred.promise;
-    }
-
-    service.storePrintTemplate = function(name, html) {
-        return service.setItem('eg.print.template.' + name, html);
-    }
-
     return service;
 }])
 
-/**
- * Container for inserting print data into the browser page.
- * On insert, $window.print() is called to print the data.
- * The div housing eg-print-container must apply the correct
- * print media CSS to ensure this content (and not the rest
- * of the page) is printed.
- */
-
-// FIXME: only apply print CSS when print commands are issued via the 
-// print container, otherwise using the browser's native print page 
-// option will always result in empty pages.  Move the print CSS
-// out of the standalone CSS file and put it into a template file
-// for this directive.
-.directive('egPrintContainer', ['$compile', function($compile) {
-    return {
-        restrict : 'AE',
-        scope : {}, // isolate our scope
-        link : function(scope, element, attrs) {
-            scope.elm = element;
-        },
-        controller : 
-                   ['$scope','$q','$window','$timeout','egHatch', 
-            function($scope , $q , $window , $timeout , egHatch) {
-
-                egHatch.ingestPrintContent = function(type, content, printScope) {
-
-                    if (type == 'text/csv' || type == 'text/plain') {
-                        // preserve newlines, spaces, etc.
-                        content = '<pre>' + content + '</pre>';
-                    }
-
-                    $scope.elm.html(content);
-
-                    var sub_scope = $scope.$new(true);
-                    angular.forEach(printScope, function(val, key) {
-                        sub_scope[key] = val;
-                    })
-
-                    var resp = $compile($scope.elm.contents())(sub_scope);
-
-                    var deferred = $q.defer();
-                    $timeout(function(){
-                        // give the $digest a chance to complete then
-                        // resolve with the compiled HTML from our
-                        // print container
-
-                        deferred.resolve(
-                            resp.contents()[0].parentNode.innerHTML
-                        );
-                    });
-
-                    return deferred.promise;
-                }
-            }
-        ]
-    }
-}])
-
diff --git a/Open-ILS/web/js/ui/default/staff/services/print.js b/Open-ILS/web/js/ui/default/staff/services/print.js
new file mode 100644 (file)
index 0000000..d033ac2
--- /dev/null
@@ -0,0 +1,187 @@
+/**
+ */
+angular.module('egCoreMod')
+
+.factory('egPrint',
+       ['$q','$window','$timeout','$http','egHatch','egAuth','egIDL','egOrg',
+function($q , $window , $timeout , $http , egHatch , egAuth , egIDL , egOrg) {
+
+    var service = {};
+
+    service.template_base_path = 'share/print_templates/t_';
+
+    /*
+     * context  : 'default', 'receipt','label', etc. 
+     * scope    : data loaded into the template environment
+     * template : template name (e.g. 'checkout', 'transit_slip'
+     * content  : content to print.  If 'template' is set, content is
+     *            derived from the template.
+     * content_type : 'text/html', 'text/plain', 'text/csv'
+     * show_dialog  : boolean, if true, print dialog is shown.  This setting
+     *                only affects remote printers, since browser printers
+     *                do not allow such control
+     */
+    service.print = function(args) {
+        if (!args) return $q.when();
+
+        if (args.template) {
+            // fetch the template, then proceed to printing
+
+            return service.getPrintTemplate(args.template)
+            .then(function(content) {
+                args.content = content;
+                if (!args.content_type) args.content_type = 'html';
+                return service.print_content(args);
+            });
+
+        } 
+
+        return service.print_content(args);
+    }
+
+    // add commonly used attributes to the print scope
+    service.fleshPrintScope = function(scope) {
+        if (!scope) scope = {};
+        scope.today = new Date();
+        scope.staff = egIDL.toHash(egAuth.user());
+        scope.current_location = 
+            egIDL.toHash(egOrg.get(egAuth.user().ws_ou()));
+    }
+
+    // Template has been fetched (or no template needed) 
+    // Process the template and send the result off to the printer.
+    service.print_content = function(args) {
+        service.fleshPrintScope(args.scope);
+
+        var promise;
+        if (args.content_type == 'text/html') {
+
+            // all HTML content is assumed to require compilation, 
+            // regardless of the print destination
+            promise = service.ingest_print_content(
+                args.content_type, args.content, args.scope);
+
+        } else {
+            // text content does not require compilation for remote printing
+            promise = $q.when();
+        }
+
+        return promise.then(function(html) {
+
+            return egHatch.remotePrint(args.context,
+                args.content_type, html, args.show_dialog)['catch'](
+
+                function(msg) {
+                    // remote print not available; 
+
+                    if (args.content_type != 'text/html') {
+                        // text content does require compilation 
+                        // (absorption) for browser printing
+                        return service.ingest_print_content(
+                            args.content_type, args.content, args.scope
+                        ).then(function() { $window.print() });
+                    } else {
+                        // HTML content is already ingested and accessible
+                        // within the page to the printer.  
+                        $window.print();
+                    }
+                }
+            );
+        });
+    }
+
+    // loads an HTML print template by name from the server
+    // If no template is available in local/hatch storage, 
+    // fetch the template as an HTML file from the server.
+    service.getPrintTemplate = function(name) {
+        var deferred = $q.defer();
+
+        egHatch.getItem('eg.print.template.' + name)
+        .then(function(html) {
+
+            if (html) {
+                // we have a locally stored template
+                deferred.resolve(html);
+                return;
+            }
+
+            var path = service.template_base_path + name;
+            console.debug('fetching template ' + path);
+
+            $http.get(path)
+            .success(function(data) { deferred.resolve(data) })
+            .error(function() {
+                console.error('unable to locate print template: ' + name);
+                deferred.reject();
+            });
+        });
+
+        return deferred.promise;
+    }
+
+    service.storePrintTemplate = function(name, html) {
+        return egHatch.setItem('eg.print.template.' + name, html);
+    }
+
+    return service;
+}])
+
+
+/**
+ * Container for inserting print data into the browser page.
+ * On insert, $window.print() is called to print the data.
+ * The div housing eg-print-container must apply the correct
+ * print media CSS to ensure this content (and not the rest
+ * of the page) is printed.
+ */
+
+// FIXME: only apply print CSS when print commands are issued via the 
+// print container, otherwise using the browser's native print page 
+// option will always result in empty pages.  Move the print CSS
+// out of the standalone CSS file and put it into a template file
+// for this directive.
+.directive('egPrintContainer', ['$compile', function($compile) {
+    return {
+        restrict : 'AE',
+        scope : {}, // isolate our scope
+        link : function(scope, element, attrs) {
+            scope.elm = element;
+        },
+        controller : 
+                   ['$scope','$q','$window','$timeout','egHatch','egPrint',
+            function($scope , $q , $window , $timeout , egHatch , egPrint) {
+
+                egPrint.ingest_print_content = function(type, content, printScope) {
+
+                    if (type == 'text/csv' || type == 'text/plain') {
+                        // preserve newlines, spaces, etc.
+                        content = '<pre>' + content + '</pre>';
+                    }
+
+                    $scope.elm.html(content);
+
+                    var sub_scope = $scope.$new(true);
+                    angular.forEach(printScope, function(val, key) {
+                        sub_scope[key] = val;
+                    })
+
+                    var resp = $compile($scope.elm.contents())(sub_scope);
+
+                    var deferred = $q.defer();
+                    $timeout(function(){
+                        // give the $digest a chance to complete then
+                        // resolve with the compiled HTML from our
+                        // print container
+
+                        deferred.resolve(
+                            resp.contents()[0].parentNode.innerHTML
+                        );
+                    });
+
+                    return deferred.promise;
+                }
+            }
+        ]
+    }
+}])
+
diff --git a/Open-ILS/web/js/ui/default/staff/services/print_templates.js b/Open-ILS/web/js/ui/default/staff/services/print_templates.js
deleted file mode 100644 (file)
index e69de29..0000000
index 8389f6a..a27ca66 100644 (file)
@@ -32,6 +32,7 @@ module.exports = function(config){
       'services/env.js',
       'services/org.js',
       'services/hatch.js',
+      'services/print.js',
       'services/coresvc.js',
       'services/user.js',
       'services/startup.js',