LP#1759343 Fix annotate payment setting name
[evergreen-equinox.git] / Open-ILS / web / js / ui / default / staff / circ / patron / bills.js
index ce240f9..308fb30 100644 (file)
@@ -12,9 +12,12 @@ function($q , egCore , egWorkLog , patronSvc) {
     // fetch org unit settings specific to the bills display
     service.fetchBillSettings = function() {
         if (service.settings) return $q.when(service.settings);
-        return egCore.org.settings(
-            ['ui.circ.billing.uncheck_bills_and_unfocus_payment_box','ui.circ.billing.amount_warn','ui.circ.billing.amount_limit','circ.staff_client.do_not_auto_attempt_print']
-        ).then(function(s) {return service.settings = s});
+        return egCore.org.settings([
+            'ui.circ.billing.uncheck_bills_and_unfocus_payment_box',
+            'ui.circ.billing.amount_warn', 'ui.circ.billing.amount_limit',
+            'circ.staff_client.do_not_auto_attempt_print',
+            'circ.disable_patron_credit'
+        ]).then(function(s) {return service.settings = s});
     }
 
     // user billing summary
@@ -24,7 +27,9 @@ function($q , egCore , egWorkLog , patronSvc) {
         .then(function(summary) {return service.summary = summary})
     }
 
-    service.applyPayment = function(type, payments, note, check, cc_args) {
+    service.applyPayment = function(
+        type, payments, note, check, cc_args, patron_credit) {
+
         return egCore.net.request(
             'open-ils.circ',
             'open-ils.circ.money.payment',
@@ -34,12 +39,21 @@ function($q , egCore , egWorkLog , patronSvc) {
                 payment_type : type,
                 check_number : check,
                 payments : payments,
-                patron_credit : 0,
+                patron_credit : patron_credit,
                 cc_args : cc_args
             },
             patronSvc.current.last_xact_id()
         ).then(function(resp) {
             console.debug('payments: ' + js2JSON(resp));
+
+            if (evt = egCore.evt.parse(resp)) {
+                // Ideally, all scenarios that lead to this alert appearing
+                // will be avoided by the application logic.  Leave the alert
+                // in place now to root out any that remain to be addressed.
+                alert(evt);
+                return $q.reject(''+evt);
+            }
+
             var total = 0; angular.forEach(payments,function(p) { total += p[1]; });
             var msg;
             switch(type) {
@@ -58,12 +72,14 @@ function($q , egCore , egWorkLog , patronSvc) {
                     'total_amount' : total
                 }
             );
-            if (evt = egCore.evt.parse(resp)) 
-                return alert(evt);
 
             // 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);
+
+            // reload patron data if credit balance has changed:
+            if(type === 'credit_payment' || patron_credit){ patronSvc.refreshPrimary(); }
+
             return resp.payments;
         });
     }
@@ -80,6 +96,17 @@ function($q , egCore , egWorkLog , patronSvc) {
         );
     }
 
+    service.fetchStatement = function(xact_id) {
+        return egCore.net.request(
+            'open-ils.circ',
+            'open-ils.circ.money.statement.retrieve',
+            egCore.auth.token(), xact_id
+        ).then(function(resp) {
+            if (evt = egCore.evt.parse(resp)) return alert(evt);
+            return resp;
+        });
+    }
+
     // TODO: no longer needed?
     service.fetchPayments = function(xact_id) {
         return egCore.net.request(
@@ -161,17 +188,23 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
     $scope.annotate_payment = false;
     $scope.receipt_count = 1;
     $scope.receipt_on_pay = { isChecked: false };
+    $scope.convert_to_credit = {isChecked: false};
     $scope.warn_amount = 1000;
     $scope.max_amount = 100000;
     $scope.amount_verified = false;
     $scope.disable_auto_print = false;
 
-    // check receipt_on_pay setting default persisted
+    // Load persistant settings
     egCore.hatch.getItem('circ.bills.receiptonpay')
                 .then(function(rcptOnPay){
                     if (rcptOnPay) $scope.receipt_on_pay.isChecked = rcptOnPay;
                 });
 
+    egCore.hatch.getItem('eg.circ.bills.annotatepayment')
+                .then(function(annoPay){
+                    if (annoPay) $scope.annotate_payment = annoPay;
+                });
+
     // pre-define list-returning funcs in case we access them
     // before the grid instantiates
     $scope.gridControls = {
@@ -195,6 +228,39 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             return ['xact_start']; 
         }
     }
+    // -------------
+    // Apply coloring to rows based on fines stop reason
+    $scope.colorizeBillsList = {
+        apply: function(item) {
+            if (item['circulation.due_date'] && !item['circulation.checkin_time']) {
+                if (item['circulation.stop_fines'] == 'LOST') {
+                    return 'lost-row';
+                } else if (item['circulation.stop_fines'] == 'LONGOVERDUE') {
+                    return 'longoverdue-row';
+                } else {
+                    return 'overdue-row';
+                }
+            }
+        }
+    }
+
+    // Status Icon Column definition
+    $scope.statusIconColumn = {
+        isEnabled: true,
+        template: function(item) {
+            var icon = '';
+            if (item['circulation.due_date'] && !item['circulation.checkin_time']) {
+                if (item['circulation.stop_fines'] == "LOST") {
+                    icon = 'glyphicon-question-sign';
+                } else if (item['circulation.stop_fines'] == "LONGOVERDUE") {
+                    icon = 'glyphicon-exclamation-sign';
+                } else {
+                    icon = 'glyphicon-time';
+                }
+            }
+            return "<i class='glyphicon " + icon + "'></i>"
+        }
+    }
 
     billSvc.fetchSummary().then(function(s) {$scope.summary = s});
 
@@ -318,26 +384,41 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
     // generates payments, collects user note if needed, and sends payment
     // to server.
     function sendPayment(note, cc_args) {
+        $scope.applyingPayment = true;
         var make_payments = generatePayments();
+        var patron_credit = $scope.convert_to_credit.isChecked ?
+            $scope.pending_change() : 0; 
         billSvc.applyPayment($scope.payment_type, 
-            make_payments, note, $scope.check_number, cc_args)
-        .then(function(payment_ids) {
+            make_payments, note, $scope.check_number, cc_args, patron_credit)
+        .then(
+            function(payment_ids) {
 
-            if (!$scope.disable_auto_print && $scope.receipt_on_pay.isChecked) {
-                printReceipt(
-                    $scope.payment_type, payment_ids, make_payments, note);
-            }
+                if (!$scope.disable_auto_print && $scope.receipt_on_pay.isChecked) {
+                    printReceipt(
+                        $scope.payment_type, payment_ids, make_payments, note);
+                }
 
-            refreshDisplay();
-        })
+                refreshDisplay();
+            },
+            function(msg) {
+                console.error('Payment was rejected: ' + msg);
+            }
+        )
+        .finally(function() { $scope.applyingPayment = false; })
     }
 
     $scope.onReceiptOnPayChanged = function(){
         egCore.hatch.setItem('circ.bills.receiptonpay', $scope.receipt_on_pay.isChecked);
     }
 
+    $scope.onAnnotatePaymentChanged = function(){
+        egCore.hatch.setItem('eg.circ.bills.annotatepayment', $scope.annotate_payment);
+    }
+
     function printReceipt(type, payment_ids, payments_made, note) {
         var payment_blobs = [];
+        var cusr = patronSvc.current;
+
         angular.forEach(payments_made, function(payment) {
             var xact_id = payment[0];
 
@@ -365,7 +446,26 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             payments : payment_blobs,
             current_location : egCore.idl.toHash(
                 egCore.org.get(egCore.auth.user().ws_ou()))
-        }
+        };
+
+        // Not a good idea to use patron_stats.fines for this; it's out of date
+        print_data.patron = {
+            prefix : cusr.prefix(),
+            first_given_name : cusr.first_given_name(),
+            second_given_name : cusr.second_given_name(),
+            family_name : cusr.family_name(),
+            suffix : cusr.suffix(),
+            pref_prefix : cusr.pref_prefix(),
+            pref_first_given_name : cusr.pref_first_given_name(),
+            pref_second_given_name : cusr.pref_second_given_name(),
+            pref_family_name : cusr.pref_family_name(),
+            pref_suffix : cusr.pref_suffix(),
+            card : { barcode : cusr.card().barcode() },
+            expire_date : cusr.expire_date(),
+            alias : cusr.alias(),
+            has_email : Boolean(patronSvc.current.email() && patronSvc.current.email().match(/.*@.*/)),
+            has_phone : Boolean(cusr.day_phone() || cusr.evening_phone() || cusr.other_phone())
+        };
 
         print_data.new_balance = (
             print_data.previous_balance * 100 - 
@@ -438,6 +538,9 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
                 s['circ.staff_client.do_not_auto_attempt_print'].indexOf('Bill Pay') > -1
             );
         }
+        if (s['circ.disable_patron_credit']) {
+            $scope.disablePatronCredit = true;
+        }
     });
 
     $scope.gridControls.allItemsRetrieved = function() {
@@ -475,13 +578,31 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
             {authoritative : true}
         ).then(
             function() {
+                var cusr = patronSvc.current;
                 egCore.print.print({
                     context : 'receipt', 
                     template : 'bills_current', 
                     scope : {   
                         transactions : xacts,
                         current_location : egCore.idl.toHash(
-                            egCore.org.get(egCore.auth.user().ws_ou()))
+                            egCore.org.get(egCore.auth.user().ws_ou())),
+                        patron : {
+                            prefix : cusr.prefix(),
+                            first_given_name : cusr.first_given_name(),
+                            second_given_name : cusr.second_given_name(),
+                            family_name : cusr.family_name(),
+                            suffix : cusr.suffix(),
+                            pref_prefix : cusr.pref_prefix(),
+                            pref_first_given_name : cusr.pref_first_given_name(),
+                            pref_second_given_name : cusr.pref_second_given_name(),
+                            pref_family_name : cusr.pref_family_name(),
+                            pref_suffix : cusr.pref_suffix(),
+                            card : { barcode : cusr.card().barcode() },
+                            expire_date : cusr.expire_date(),
+                            alias : cusr.alias(),
+                            has_email : Boolean(cusr.email() && cusr.email().match(/.*@.*/)),
+                            has_phone : Boolean(cusr.day_phone() || cusr.evening_phone() || cusr.other_phone())
+                        }
                     }
                 });
             }, 
@@ -498,8 +619,10 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
                     unrecovered : xact.unrecovered(),
                     xact_finish : xact.xact_finish(),
                     xact_start : xact.xact_start(),
-                    copy_barcode : xact.circulation().target_copy().barcode(),
-                    title : xact.circulation().target_copy().call_number().record().simple_record().title()
+                }
+                if (xact.circulation()) {
+                    newXact.copy_barcode = xact.circulation().target_copy().barcode(),
+                    newXact.title = xact.circulation().target_copy().call_number().record().simple_record().title()
                 }
                 xacts.push(newXact);
             }
@@ -585,6 +708,12 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
                     }
 
                     $scope.ok = function() {
+                        // CC payment form is not a <form>, 
+                        // so apply validation manually.
+                        if ( $scope.context.cc.where_process == 0 && 
+                            !$scope.context.cc.approval_code)
+                            return;
+
                         $uibModalInstance.close($scope.context.cc);
                     }
 
@@ -685,7 +814,7 @@ function($scope , $q , $routeParams , egCore , egConfirmDialog , $location,
     $scope.showFullDetails = function(all) {
         if (all[0]) 
             $location.path('/circ/patron/' + 
-                patronSvc.current.id() + '/bill/' + all[0].id);
+                patronSvc.current.id() + '/bill/' + all[0].id + '/statement');
     }
 
     $scope.activateBill = function(xact) {
@@ -703,6 +832,7 @@ function($scope,  $q , $routeParams , egCore , egGridDataProvider , patronSvc ,
 
     $scope.initTab('bills', $routeParams.id);
     var xact_id = $routeParams.xact_id;
+    $scope.xact_tab = $routeParams.xact_tab;
 
     var xactGrid = $scope.xactGridControls = {
         setQuery : function() { return {xact : xact_id} },
@@ -789,6 +919,13 @@ function($scope,  $q , $routeParams , egCore , egGridDataProvider , patronSvc ,
     }
 
     // -- retrieve our data
+    if ($scope.xact_tab == 'statement') {
+        //fetch combined billing statement data
+        billSvc.fetchStatement(xact_id).then(function(statement) {
+            //console.log(statement);
+            $scope.statement_data = statement;
+        });
+    }
     $scope.total_circs = 0; // start with 0 instead of undefined
     egBilling.fetchXact(xact_id).then(function(xact) {
         $scope.xact = xact;
@@ -902,7 +1039,7 @@ function($scope,  $q , egCore , patronSvc , billSvc , egPromptDialog , $location
     $scope.showFullDetails = function(all) {
         if (all[0]) 
             $location.path('/circ/patron/' + 
-                patronSvc.current.id() + '/bill/' + all[0].id);
+                patronSvc.current.id() + '/bill/' + all[0].id + '/statement');
     }
 
     // For now, only adds billing to first selected item.
@@ -940,13 +1077,31 @@ function($scope,  $q , egCore , patronSvc , billSvc , egPromptDialog , $location
             {authoritative : true}
         ).then(
             function() {
+                var cusr = patronSvc.current;
                 egCore.print.print({
                     context : 'receipt', 
                     template : 'bills_historical', 
                     scope : {   
                         transactions : xacts,
                         current_location : egCore.idl.toHash(
-                            egCore.org.get(egCore.auth.user().ws_ou()))
+                            egCore.org.get(egCore.auth.user().ws_ou())),
+                        patron : {
+                            prefix : cusr.prefix(),
+                            pref_prefix : cusr.pref_prefix(),
+                            pref_first_given_name : cusr.pref_first_given_name(),
+                            pref_second_given_name : cusr.pref_second_given_name(),
+                            pref_family_name : cusr.pref_family_name(),
+                            pref_suffix : cusr.pref_suffix(),
+                            first_given_name : cusr.first_given_name(),
+                            second_given_name : cusr.second_given_name(),
+                            family_name : cusr.family_name(),
+                            suffix : cusr.suffix(),
+                            card : { barcode : cusr.card().barcode() },
+                            expire_date : cusr.expire_date(),
+                            alias : cusr.alias(),
+                            has_email : Boolean(cusr.email() && cusr.email().match(/.*@.*/)),
+                            has_phone : Boolean(cusr.day_phone() || cusr.evening_phone() || cusr.other_phone())
+                        }
                     }
                 });
             }, 
@@ -963,8 +1118,10 @@ function($scope,  $q , egCore , patronSvc , billSvc , egPromptDialog , $location
                     unrecovered : xact.unrecovered(),
                     xact_finish : xact.xact_finish(),
                     xact_start : xact.xact_start(),
-                    copy_barcode : xact.circulation().target_copy().barcode(),
-                    title : xact.circulation().target_copy().call_number().record().simple_record().title()
+                }
+                if (xact.circulation()) {
+                    newXact.copy_barcode = xact.circulation().target_copy().barcode(),
+                    newXact.title = xact.circulation().target_copy().call_number().record().simple_record().title()
                 }
                 xacts.push(newXact);
             }
@@ -1003,7 +1160,7 @@ function($scope,  $q , egCore , patronSvc , billSvc , $location) {
     $scope.showFullDetails = function(all) {
         if (all[0]) 
             $location.path('/circ/patron/' + 
-                patronSvc.current.id() + '/bill/' + all[0]['xact.id']);
+                patronSvc.current.id() + '/bill/' + all[0]['xact.id'] + '/statement');
     }
 
     $scope.totals.selected_paid = function() {