From 9085b328ac2334f5a9371a3e736aa8ee136e4916 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 29 May 2014 16:53:44 -0400 Subject: [PATCH] html template based print support; print bills supported Signed-off-by: Bill Erickson --- .../staff/admin/workstation/t_print_config.tt2 | 2 +- .../staff/admin/workstation/t_print_templates.tt2 | 4 +- Open-ILS/src/templates/staff/css/style.css.tt2 | 2 +- .../share/print_templates/t_bills_current.tt2 | 3 - .../share/print_templates/t_bills_historical.tt2 | 49 ++++++++ .../js/ui/default/staff/admin/workstation/app.js | 11 +- .../web/js/ui/default/staff/circ/patron/bills.js | 28 ++++- Open-ILS/web/js/ui/default/staff/services/hatch.js | 127 +++++++++++---------- 8 files changed, 156 insertions(+), 70 deletions(-) create mode 100644 Open-ILS/src/templates/staff/share/print_templates/t_bills_historical.tt2 diff --git a/Open-ILS/src/templates/staff/admin/workstation/t_print_config.tt2 b/Open-ILS/src/templates/staff/admin/workstation/t_print_config.tt2 index f90fc01a3c..06067accf3 100644 --- a/Open-ILS/src/templates/staff/admin/workstation/t_print_config.tt2 +++ b/Open-ILS/src/templates/staff/admin/workstation/t_print_config.tt2 @@ -157,7 +157,7 @@ ng-init="htmlPrintContent='

[% l('Test HTML Print') %]


- +

[% l('Welcome, Stranger!') %]

{{value1}}

{{value2}}

diff --git a/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 b/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 index cda10b2fd9..911c7d56aa 100644 --- a/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 +++ b/Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2 @@ -30,7 +30,9 @@

[% l('Preview') %]

-
+

[% l('Template') %]

diff --git a/Open-ILS/src/templates/staff/css/style.css.tt2 b/Open-ILS/src/templates/staff/css/style.css.tt2 index c30215b1f8..8cf4d15891 100644 --- a/Open-ILS/src/templates/staff/css/style.css.tt2 +++ b/Open-ILS/src/templates/staff/css/style.css.tt2 @@ -113,7 +113,7 @@ table.list tr.selected td { .pad-horiz {padding : 0px 10px 0px 10px; } .pad-vert {padding : 20px 0px 10px 0px;} -#print-div { display: none; } +/*#print-div { display: none; }*/ /* by default, give all tab panes some top padding */ .tab-pane { padding-top: 20px; } diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_bills_current.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_bills_current.tt2 index 71e6bf23f9..c99cb4d1ee 100644 --- a/Open-ILS/src/templates/staff/share/print_templates/t_bills_current.tt2 +++ b/Open-ILS/src/templates/staff/share/print_templates/t_bills_current.tt2 @@ -1,10 +1,7 @@ Welcome to {{current_location.name}}!
You have the following bills:
- -{{xact.id}}
-
Bill #{{xact.id}}
diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_bills_historical.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_bills_historical.tt2 new file mode 100644 index 0000000000..c99cb4d1ee --- /dev/null +++ b/Open-ILS/src/templates/staff/share/print_templates/t_bills_historical.tt2 @@ -0,0 +1,49 @@ +Welcome to {{current_location.name}}!
+You have the following bills: +
+
+
+
Bill #{{xact.id}}
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[% l('Date:') %]{{xact.xact_start | date:'short'}}
[% l('Type') %]:{{xact.summary.xact_type}}
[% l('Last Billing') %]:{{xact.summary.last_billing_type}}
+ {{xact.summary.last_billing_note}} +
[% l('Total Billed') %]:{{xact.summary.total_owed | currency}}
[% l('Last Payment') %]:{{xact.summary.last_payment_type}}
+ {{xact.summary.last_payment_note}} +
[% l('Total Paid') %]:{{xact.summary.total_paid | currency}}
[% l('Balance') %]:{{xact.summary.balance_owed | currency}}
+
+
+
+
+
+{{current_location.shortname}} {{today | date:'short'}} +

+ diff --git a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js index 9e3a104eb0..645d7805e0 100644 --- a/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js +++ b/Open-ILS/web/js/ui/default/staff/admin/workstation/app.js @@ -342,6 +342,7 @@ function($scope , $q , egCore) { egCore.hatch.getPrintTemplate($scope.print.template_name) .then(function(html) { $scope.print.template_content = html; + console.log('set template content'); }); } @@ -355,7 +356,7 @@ function($scope , $q , egCore) { $scope.template_changed(); // load the default }]) -// TODO: move compilation into egHatch! +// .directive('egPrintTemplateOutput', ['$compile',function($compile) { return function(scope, element, attrs) { scope.$watch( @@ -363,11 +364,13 @@ function($scope , $q , egCore) { return scope.$eval(attrs.content); }, function(value) { + // create an isolate scope and copy the print context + // data into the new scope. + // TODO: see also print security concerns in egHatch var result = element.html(value); + var context = scope.$eval(attrs.context); var print_scope = scope.$new(true); - // copy only the print preview scope data - // into the isolate scope for compilation - angular.forEach(scope.preview_scope, function(val, key) { + angular.forEach(context, function(val, key) { print_scope[key] = val; }) $compile(element.contents())(print_scope); diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/bills.js b/Open-ILS/web/js/ui/default/staff/circ/patron/bills.js index b0bf85a5a3..323179ebe1 100644 --- a/Open-ILS/web/js/ui/default/staff/circ/patron/bills.js +++ b/Open-ILS/web/js/ui/default/staff/circ/patron/bills.js @@ -405,8 +405,32 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location, // TODO: select grid items where refunds are due } - $scope.printBills = function() { - // TODO: print selected bills using the bills print template + $scope.printBills = function(selected) { + console.log('HEREEE'); + + // bills print receipt assumes nested hashes, but our grid + // stores flattener data. Fetch the selected xacts as + // fleshed pcrud objects. (Consider an alternate approach..) + var ids = selected.map(function(t){ return t.id }); + var xacts = []; + egCore.pcrud.search('mbt', + {id : ids}, + {flesh : 1, flesh_fields : {'mbt' : ['summary']}}, + {authoritative : true} + ).then( + function() { + egCore.hatch.printFromTemplate('receipt', 'bills_current', + { transactions : xacts, + current_location : egCore.idl.toHash( + egCore.org.get(egCore.auth.user().ws_ou())) + } + ); + }, + null, + function(xact) { + xacts.push(egCore.idl.toHash(xact)); + } + ); } $scope.applyPayment = function() { diff --git a/Open-ILS/web/js/ui/default/staff/services/hatch.js b/Open-ILS/web/js/ui/default/staff/services/hatch.js index edd6907d7e..e673b5be81 100644 --- a/Open-ILS/web/js/ui/default/staff/services/hatch.js +++ b/Open-ILS/web/js/ui/default/staff/services/hatch.js @@ -201,39 +201,51 @@ angular.module('egCoreMod') } } - service.interpolateHtmlTemplate = function(template, printScope) { - // TODO: for print template security, we must scrub - // the scope object and remove any references to - // functions or objects. Otherwise, print templates - // would have the power to modify data via the scope - var subScope = $rootScope.$new(); - angular.forEach(printScope, function(val, key) {subScope[key] = val}); - var html = $interpolate(template)(subScope); - subScope.$destroy(); - return html; - } + service.printFromTemplate = function(context, templateName, printScope) { + // populate some common print scope values... + printScope.today = new Date(); + return service.getPrintTemplate(templateName) + .then(function(template) { + service.print(context, 'text/html', template, printScope); + }); + } - // supported values for contentType are 'text/html' and 'text/plain' service.print = function( context, contentType, content, printScope, withDialog) { - // generate our HTML content if necessary + var promise; if (contentType == 'text/html') { - content = service.interpolateHtmlTemplate(content, printScope); + // 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 service.remotePrint( - context, contentType, content, printScope, withDialog)['catch']( - function(msg) { - // remote print not available; print locally - return service.browserPrint(msg); - } - ); + 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 { + $window.print(); + } + } + ); + }); } service.remotePrint = function( - context, contentType, content, printScope, withDialog) { + context, contentType, content, withDialog) { return service.getPrintConfig().then( function(conf) { @@ -249,11 +261,6 @@ angular.module('egCoreMod') ); } - // print locally via the browser - service.browserPrint = function(msg) { - service.onBrowserPrint(msg.contentType, msg.content); - } - // ------------- // print configuration is always stored as remote items, // since there is no concept of a local printer @@ -508,44 +515,48 @@ angular.module('egCoreMod') // 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', function() { +.directive('egPrintContainer', ['$compile', function($compile) { return { restrict : 'AE', - template : '
', + scope : {}, // isolate our scope + link : function(scope, element, attrs) { + scope.elm = element; + }, controller : - ['$scope','$window','$timeout','egHatch', - function($scope , $window , $timeout , egHatch) { - - egHatch.onBrowserPrint = function(contentType, content) { - switch(contentType) { - case 'text/csv': - case 'text/plain': - // preserve newlines, spaces, etc. - content = '
' + content + '
'; - case 'text/html': - // TODO: make this angular-y - var div = document.getElementById('eg-print-container-for-html'); - while (div.childNodes[0]) - div.removeChild(div.childNodes[0]); - div.innerHTML = content; + ['$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 = '
' + content + '
'; } - // force the template to absorb the data before printing - // if an apply/digest loop is not already in progress - //if (!$scope.$$phase) $scope.$apply(); - // - // TODO: apply() may no longer be necessary - - $timeout( - function() { - $scope.$apply(); - $window.print(); - } - ); + $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; } } ] } -}); - +}]) -- 2.11.0