refunds cont. add billing to xact
authorBill Erickson <berick@esilibrary.com>
Tue, 27 May 2014 18:51:06 +0000 (14:51 -0400)
committerBill Erickson <berick@esilibrary.com>
Tue, 27 May 2014 18:51:06 +0000 (14:51 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/circ/patron/index.tt2
Open-ILS/src/templates/staff/circ/patron/t_bill_patron_dialog.tt2
Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/bills.js

index 12c07e3..05b3ef3 100644 (file)
@@ -28,6 +28,8 @@
 <script>
 angular.module('egCoreMod').run(['egStrings', function(s) {
   s.ANNOTATE_PAYMENT_MSG = "[% l('Please annotate this payment') %]";
+  s.CONFIRM_REFUND_PAYMENT = 
+    "[% |l('{{xactIds}}') -%]Are you sure you would like to refund excess payment on bills [_1]?  This action will simply put the amount in the Payment Pending column as a negative value.  You must still select Apply Payment!  Certain types of payments may not be refunded.  The refund may be applied to checked transactions that follow the refunded transaction.[% END %]"
 }]);
 </script>
 
index ab1cd05..4f84971 100644 (file)
             '{{patron.second_given_name()}}',
             '{{patron.card().barcode()}}') %]
       </h4>
+
+      <div ng-if="xact">
+        <hr/>
+        <div class="row">
+          <div class="col-md-3">[% l('Bill #') %]</div>
+          <div class="col-md-3">{{xact.id}}</div>
+          <div class="col-md-3">[% l('Total Billed') %]</div>
+          <div class="col-md-3">{{xact.total_owed | currency}}</div>
+        </div>
+        <div class="row">
+          <div class="col-md-3">[% l('Type') %]</div>
+          <div class="col-md-3">{{xact.xact_type}}</div>
+          <div class="col-md-3">[% l('Total Paid') %]</div>
+          <div class="col-md-3">{{xact.total_paid | currency}}</div>
+        </div>
+        <div class="row">
+          <div class="col-md-3">[% l('Start') %]</div>
+          <div class="col-md-3">{{xact.xact_start | date:'short'}}</div>
+          <div class="col-md-3">[% l('Total Billed') %]</div>
+          <div class="col-md-3">{{xact.balance_owed | currency}}</div>
+        </div>
+        <div class="row">
+          <div class="col-md-3">[% l('Finish') %]</div>
+          <div class="col-md-3">{{xact.xact_finish | date:'short'}}</div>
+          <div class="col-md-3">[% l('Renewal?') %]</div>
+          <div class="col-md-3">
+            <span ng-if="xact.circulation.desk_renewal == 't'">[% l('Desk') %]</span>
+            <span ng-if="xact.circulation.phone_renewal == 't'">[% l('Phone') %]</span>
+            <span ng-if="xact.circulation.opac_renewal == 't'">[% l('OPAC') %]</span>
+          </div>
+        </div>
+      </div>
     </div>
     <div class="modal-body">
       <div class="form-group">
index 4373b01..5827591 100644 (file)
     handler="voidAllBillings"></eg-grid-action>
 
   <eg-grid-action label="[% l('Refund') %]" 
-    handler=""></eg-grid-action>
+    handler="refundXact"></eg-grid-action>
 
   <eg-grid-action label="[% l('Add Billing') %]" 
-    handler=""></eg-grid-action>
+    handler="addBilling"></eg-grid-action>
 
   <eg-grid-action label="[% l('Full Details') %]" 
-    handler=""></eg-grid-action>
+    handler="showFillDetails"></eg-grid-action>
 
   <eg-grid-field label="[% ('Balance Owed') %]" path='balance_owed'></eg-grid-field>
   <eg-grid-field label="[% ('Bill #') %]" path='id'></eg-grid-field>
index d0a3fcf..4286563 100644 (file)
@@ -56,7 +56,7 @@ function($q , egCore , patronSvc) {
         });
     }
 
-    service.billPatron = function(args) {
+    service.createGroceryXact = function(args) {
         var groc = new egCore.idl.mg();
         groc.billing_location(egCore.auth.user().ws_ou());
         groc.note(args.note);
@@ -72,25 +72,42 @@ function($q , egCore , patronSvc) {
         ).then(function(xact_id) {
             if (evt = egCore.evt.parse(xact_id)) 
                 return alert(evt);
+            return xact_id;
+        });
+    }
 
-            var bill = new egCore.idl.mb();
-            bill.xact(xact_id);
-            bill.amount(args.amount);
-            bill.btype(args.billingType);
-            bill.billing_type(egCore.env.cbt.map[args.billingType].name());
-            bill.note(args.note);
-
-            return egCore.net.request(
-                'open-ils.circ', 
-                'open-ils.circ.money.billing.create',
-                egCore.auth.token(), bill
-            );
+    service.createBilling = function(xact_id, args) {
+        var bill = new egCore.idl.mb();
+        bill.xact(xact_id);
+        bill.amount(args.amount);
+        bill.btype(args.billingType);
+        bill.billing_type(egCore.env.cbt.map[args.billingType].name());
+        bill.note(args.note);
+
+        return egCore.net.request(
+            'open-ils.circ', 
+            'open-ils.circ.money.billing.create',
+            egCore.auth.token(), bill
 
         // check the billing response
-        }).then(function(bill_id) {
-            if (evt = egCore.evt.parse(bill_id)) 
-                return alert(evt);
+        ).then(function(bill_id) {
+            if (evt = egCore.evt.parse(bill_id)) {
+                alert(evt);
+            } else {
+                return bill_id;
+            }
+        });
+    }
+
+    service.billPatron = function(args, xact) {
 
+        // apply a billing to an existing transaction
+        if (xact) return service.createBilling(xact.id, args);
+
+        // create a new grocery xact, then apply a billing
+        return service.createGroceryXact(args)
+        .then(function(xact_id) { 
+            return service.createBilling(xact_id, args);
         });
     }
 
@@ -102,8 +119,10 @@ function($q , egCore , patronSvc) {
  * Manages Bills
  */
 .controller('PatronBillsCtrl',
-       ['$scope','$q','$routeParams','$locale','egCore','egGridDataProvider','billSvc','patronSvc','egPromptDialog','$modal',
-function($scope,  $q , $routeParams,  $locale , egCore , egGridDataProvider , billSvc , patronSvc , egPromptDialog , $modal) {
+       ['$scope','$q','$routeParams','$locale','egCore','egConfirmDialog',
+        'egGridDataProvider','billSvc','patronSvc','egPromptDialog','$modal',
+function($scope,  $q , $routeParams,  $locale , egCore , egConfirmDialog , 
+         egGridDataProvider , billSvc , patronSvc , egPromptDialog , $modal) {
 
     $scope.initTab('bills', $routeParams.id);
     billSvc.userId = $routeParams.id;
@@ -207,41 +226,36 @@ function($scope,  $q , $routeParams,  $locale , egCore , egGridDataProvider , bi
         // reset all to zero..
         angular.forEach(allItems, function(item) {item.payment_pending = 0});
 
-        // then apply the current payment amounts
-        var payments = generatePayments();
-        angular.forEach(payments, function(payment) {
-            var item = selectedItems.filter(function(item) {
-                return (item.id == payment[0])
-            })[0];
-            item.payment_pending = payment[1];
-        });
-    }
-
-    // builds payment arrays ([xact_id, ammount]) for all transactions
-    // which have a pending payment amount.
-    function generatePayments() {
-        var payments = [];
-        var paymentAmount = $scope.pending_payment();
+        var payment_amount = $scope.pending_payment();
 
         for (var i = 0; i < selectedItems.length; i++) { // for/break
             var item = selectedItems[i];
             var owed = Number(item.balance_owed);
 
-            if (paymentAmount > owed) {
+            if (payment_amount > owed) {
                 // pending payment exceeds balance of current item.
                 // pay the entire item.
-                payments.push([item.id, owed]);
-                paymentAmount -= owed;
+                item.payment_pending = owed;
+                payment_amount -= owed;
 
             } else {
                 // balance owed on the current item matches or exceeds
                 // the pending payment.  Apply the full remainder of
                 // the payment to this item.. and we're done.
-                payments.push([item.id, paymentAmount]);
+                item.payment_pending = payment_amount;
                 break;
             }
         }
+    }
 
+    // builds payment arrays ([xact_id, ammount]) for all transactions
+    // which have a pending payment amount.
+    function generatePayments() {
+        var payments = [];
+        angular.forEach(selectedItems, function(item) {
+            if (item.payment_pending == 0) return;
+            payments.push([item.id, item.payment_pending]);
+        });
         return payments;
     }
 
@@ -261,14 +275,25 @@ function($scope,  $q , $routeParams,  $locale , egCore , egGridDataProvider , bi
             billSvc.fetchSummary().then(function(s) {$scope.summary = s});
         })
     }
+    
+    // For now, only adds billing to first selected item.
+    // Could do batches later if needed
+    $scope.addBilling = function(all) {
+        if (all[0]) showBillDialog(all[0]);
+    }
+
+    $scope.showBillDialog = function($event) {
+        showBillDialog();
+    }
 
-    $scope.showBillDialog = function() {
-        $modal.open({
+    function showBillDialog(xact) {
+        return $modal.open({
             templateUrl: './circ/patron/t_bill_patron_dialog',
             controller: 
                        ['$scope','$modalInstance','billingTypes',
                 function($scope , $modalInstance , billingTypes) {
                 $scope.focus = true;
+                $scope.xact = xact;
                 $scope.patron = patronSvc.current;
                 $scope.billingTypes = billingTypes;
                 $scope.location = egCore.org.get(egCore.auth.user().ws_ou()),
@@ -288,7 +313,7 @@ function($scope,  $q , $routeParams,  $locale , egCore , egGridDataProvider , bi
             function(args) {
                 // send the billing to the server using the arguments
                 // provided in the billing dialog, then refresh
-                billSvc.billPatron(args).then(refreshDisplay);
+                billSvc.billPatron(args, xact).then(refreshDisplay);
             }
         );
     }
@@ -351,6 +376,27 @@ function($scope,  $q , $routeParams,  $locale , egCore , egGridDataProvider , bi
             });
         });
     }
+
+    // note this is functionally equivalent to selecting a neg. transaction
+    // then clicking Apply Payment -- this just adds a speed bump (ditto
+    // the XUL client).
+    $scope.refundXact = function(all) {
+        var items = all.filter(function(item) {return item.balance_owed < 0});
+        if (items.length == 0) return;
+
+        var ids = items.map(function(item) {return item.id});
+            
+        egConfirmDialog.open(
+            egCore.strings.CONFIRM_REFUND_PAYMENT, '', 
+            {   xactIds : ''+ids,
+                ok : function() {
+                    // reset the received payment amount.  this ensures
+                    // we're not mingling payments with refunds.
+                    $scope.payment_amount = 0;
+                }
+            }
+        );
+    }
 }])