payment receipts
authorBill Erickson <berick@esilibrary.com>
Wed, 4 Jun 2014 14:36:50 +0000 (10:36 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 4 Jun 2014 14:36:50 +0000 (10:36 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/circ/patron/t_bills.tt2
Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
Open-ILS/src/templates/staff/share/print_templates/t_bill_payment.tt2 [new file with mode: 0644]
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/services/idl.js

index 6d68f83..b8ab917 100644 (file)
 [% INCLUDE 'staff/circ/patron/t_bills_list.tt2' %]
 </div>
 
+<!-- pull-right is causing the content to flow several pixels 
+off to the right.  flex-row is honoring the boundaries better. 
+not sure what's up, there. -->
+<div class="flex-row">
+  <div class="flex-cell"></div>
+  <form class="form-inline" role="form">
+   <div class="checkbox">
+      <label>
+        <input type="checkbox" ng-model="receipt_on_pay"/> 
+        [% l('Receipt On Payment') %]
+      </label>
+    </div>
+    <div class="form-group" style="margin-left:10px">
+      <label for="bill-receipt-copies">[% l('# Copies') %]</label>
+      <input type="number" min="1" style="width:5em"
+        ng-model="receipt_count"
+        class="form-control" id="bill-receipt-copies"/>
+    </div>
+  </form>
+</div>
+
index 0e31b75..e1058f6 100644 (file)
@@ -51,6 +51,9 @@
   <eg-grid-field label="[% ('Total Paid') %]" path='summary.total_paid'></eg-grid-field>
   <eg-grid-field label="[% ('Type') %]" path='xact_type'></eg-grid-field>
 
+  <!-- receipt data -->
+  <eg-grid-field path='summary.last_billing_type' required></eg-grid-field>
+
   <eg-grid-field label="[% l('Title') %]" name="title"
     path='circulation.target_copy.call_number.record.simple_record.title'>
     <a href="[% ctx.base_path %]/opac/record/{{item.record_id}}">{{item.title}}</a>
@@ -60,7 +63,7 @@
     label="[% l('Record ID') %]" name="record_id" required hidden>
   </eg-grid-field>
 
-  <eg-grid-field label="[% l('Barcode') %]" 
+  <eg-grid-field label="[% l('Barcode') %]" required
     path='circulation.target_copy.barcode' name="copy_barcode">
     <a href="./cat/item/{{item.copy_id}}" target="_self">
       {{item.copy_barcode}}
diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_bill_payment.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_bill_payment.tt2
new file mode 100644 (file)
index 0000000..766c9c6
--- /dev/null
@@ -0,0 +1,68 @@
+Welcome to {{current_location.name}}!<br/>
+A receipt of your  transaction:<hr/>
+
+<table style="width:100%"> 
+  <tr> 
+    <td>[% l('Original Balance:') %]</td> 
+    <td align="right">{{previous_balance | currency}}</td> 
+  </tr> 
+  <tr> 
+    <td>[% l('Payment Method:') %]</td> 
+    <td align="right">
+      <div ng-switch="payment_type">
+        <div ng-switch-when="cash_payment">[% l('Cash') %]</div>
+        <div ng-switch-when="check_payment">[% l('Check') %]</div>
+        <div ng-switch-when="credit_card_payment">[% l('Credit Card') %]</div>
+        <div ng-switch-when="credit_payment">[% l('Patron Credit') %]</div>
+        <div ng-switch-when="work_payment">[% l('Work') %]</div>
+        <div ng-switch-when="forgive_payment">[% l('Forgive') %]</div>
+        <div ng-switch-when="goods_payment">[% l('Goods') %]</div>
+      </div>
+    </td>
+  </tr> 
+  <tr> 
+    <td>[% l('Payment Received:') %]</td> 
+    <td align="right">{{payment_total | currency}}</td> 
+  </tr> 
+  <tr> 
+    <td>[% l('Payment Applied:') %]</td> 
+    <td align="right">{{payment_applied | currency}}</td> 
+  </tr> 
+  <tr> 
+    <td>[% l('Billings Voided:') %]</td> 
+    <td align="right">{{amount_voided | currency}}</td> 
+  </tr> 
+  <tr> 
+    <td>[% l('Change Given:') %]</td> 
+    <td align="right">{{change_given | currency}}</td> 
+  </tr> 
+  <tr> 
+    <td>[% l('New Balance:') %]</td> 
+    <td align="right">{{new_balance | currency}}</td> 
+  </tr> 
+</table> 
+
+<p>[% l('Note: [_1]', '{{payment_note}}') %]</p>
+
+<p>
+[% l('Specific Bills') %]
+  <blockquote>
+    <div ng-repeat="payment in payments">
+      <table style="width:100%">
+        <tr>
+          <td>[% l('Bill # [_1]', '{{payment.xact.id}}') %]</td>
+          <td>{{payment.xact.summary.last_billing_type}}</td>
+          <td>[% l('Received: [_1]', '{{payment.amount | currency}}') %]</td>
+        </tr>
+        <tr>
+          <td colspan="2">{{payment.xact.copy_barcode}}</td>
+          <td colspan="3">{{payment.xact.title}}</td>
+        </tr>
+      </table>
+      <br/>
+    </div>
+  </blockquote>
+</p> 
+<hr/>
+<br/><br/> 
+{{current_location.shortname}} {{today | date:'short'}}
index d6a7e91..9dc5e36 100644 (file)
@@ -177,8 +177,13 @@ function($q , $timeout , $location , egCore,  egUser , $locale) {
     service.setDefault = function(id, user, force) {
         if (user) {
             if (!force && service.current && 
-                service.current.id() == user.id()) 
-                return $q.when();
+                service.current.id() == user.id()) {
+                if (service.patron_stats) {
+                    return $q.when();
+                } else {
+                    return service.fetchUserStats();
+                }
+            }
 
             service.resetPatronLists();
             service.current = user;
@@ -186,8 +191,13 @@ function($q , $timeout , $location , egCore,  egUser , $locale) {
             return service.fetchUserStats();
 
         } else if (id) {
-            if (!force && service.current && service.current.id() == id) 
-                return $q.when();
+            if (!force && service.current && service.current.id() == id) {
+                if (service.patron_stats) {
+                    return $q.when();
+                } else {
+                    return service.fetchUserStats();
+                }
+            }
 
             service.resetPatronLists();
 
index 218b9b5..5b4cf14 100644 (file)
@@ -44,6 +44,7 @@ function($q , egCore , patronSvc) {
             // payment API returns the update xact id so we can track it
             // for future payments without having to refresh the user.
             patronSvc.current.last_xact_id(resp.last_xact_id);
+            return resp.payments;
         });
     }
 
@@ -225,6 +226,8 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
     $scope.payment_type = 'cash_payment';
     $scope.focus_payment = true;
     $scope.annotate_payment = false;
+    $scope.receipt_count = 1;
+    $scope.receipt_on_pay = false;
     $scope.gridRevision = 0;
 
     // pre-define list-returning funcs in case we access them
@@ -370,14 +373,60 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
     // generates payments, collects user note if needed, and sends payment
     // to server.
     function sendPayment(note) {
+        var make_payments = generatePayments();
         billSvc.applyPayment(
-            $scope.payment_type, generatePayments(), note)
-        .then(function() {
+            $scope.payment_type, make_payments, note)
+        .then(function(payment_ids) {
+
+            if ($scope.receipt_on_pay) {
+                printReceipt(
+                    $scope.payment_type, payment_ids, make_payments, note);
+            }
+
             refreshDisplay();
             billSvc.fetchSummary().then(function(s) {$scope.summary = s});
         })
     }
 
+    function printReceipt(type, payment_ids, payments_made, note) {
+        var payment_blobs = [];
+        angular.forEach(payments_made, function(payment) {
+            var xact_id = payment[0];
+
+            // find the original transaction in the grid..
+            var xact = $scope.gridControls.allItems().filter(
+                function(item) {return item.id == xact_id})[0];
+
+            payment_blobs.push({
+                xact : egCore.idl.flatToNestedHash(xact),
+                amount : payment[1]
+            });
+        });
+
+        console.log(js2JSON(payment_blobs[0]));
+
+        // page data not yet refreshed, capture data from current scope
+        var print_data = {
+            previous_balance : $scope.summary.balance_owed,
+            payment_total : $scope.payment_amount,
+            payment_applied : $scope.pending_payment(),
+            amount_voided : $scope.session_voided,
+            change_given : $scope.pending_change(),
+            payments : payment_blobs,
+            current_location : egCore.idl.toHash(
+                egCore.org.get(egCore.auth.user().ws_ou()))
+        }
+
+        print_data.new_balance = (
+            print_data.previous_balance * 100 - 
+            print_data.payment_applied * 100) / 100;
+
+        for (var i = 0; i < $scope.receipt_count; i++) {
+            egCore.hatch.printFromTemplate(
+                'receipt', 'bill_payment', print_data);
+        }
+    }
+
     $scope.showHistory = function() {
         $location.path('/circ/patron/' + 
             patronSvc.current.id() + '/bill_history/transactions');
index 8ad4b66..1fe7129 100644 (file)
@@ -99,6 +99,32 @@ angular.module('egCoreMod')
         return hash;
     }
 
+    // Transforms a flattened hash (see toHash() or egGridFlatDataProvider)
+    // to a nested hash.
+    //
+    // e.g. {"call_number.label" : "foo"} => {"call_number":{"label":"foo"}}
+    service.flatToNestedHash = function(obj) {
+        var hash = {};
+        angular.forEach(obj, function(val, key) {
+            var parts = key.split('.');
+            var sub_hash = hash;
+            var last_key;
+            for (var i = 0; i < parts.length; i++) {
+                var part = parts[i];
+                if (i == parts.length - 1) {
+                    sub_hash[part] = val;
+                    break;
+                } else {
+                    if (!sub_hash[part])
+                        sub_hash[part] = {};
+                    sub_hash = sub_hash[part];
+                }
+            }
+        });
+
+        return hash;
+    }
+
     return service;
 }]);