initial support for credit card payments via selfcheck. 2 caveats. 1) the code...
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 21 Dec 2009 16:33:23 +0000 (16:33 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 21 Dec 2009 16:33:23 +0000 (16:33 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@15208 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/web/css/skin/default/selfcheck.css
Open-ILS/web/js/dojo/openils/Event.js
Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js
Open-ILS/web/js/ui/default/circ/selfcheck/selfcheck.js
Open-ILS/web/templates/default/circ/selfcheck/circ_page.tt2
Open-ILS/web/templates/default/circ/selfcheck/main.tt2
Open-ILS/web/templates/default/circ/selfcheck/payment.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/circ/selfcheck/summary.tt2

index d17cf3a..986b46f 100644 (file)
@@ -79,6 +79,9 @@ body {
     text-align: right;
     width: 100%;
 }
+#oils-selfck-content-header span {
+    padding-left: 5px;
+}
 
 #oils-selfck-info-nav {
     margin: 15px 10px 15px 10px;
@@ -86,9 +89,11 @@ body {
     border-bottom: 1px dashed #888;
 }
 
+#oils-selfck-circ-info-div span {
+    padding-right: 8px;
+}
 #oils-selfck-info-nav span {
     padding-left: 8px;
-    padding-right: 8px;
 }
 
 #oils-selfck-info-nav span.selected {
@@ -118,4 +123,13 @@ body {
     color: red;
 }
 
+#oils-selfck-cc-payment-summary {
+    font-weight:bold;
+    padding: 30px;
+}
+
+#oils-selfck-cc-payment-table td {
+    padding: 5px;
+}
+
 
index a37f6ff..b2bf745 100644 (file)
@@ -29,12 +29,15 @@ if(!dojo._hasResource["openils.Event"]) {
             this.servertime = kwargs.servertime;
             this.ilsperm = kwargs.ilsperm;
             this.ilspermloc = kwargs.ilspermloc;
+            this.note = kwargs.note;
         },
 
         toString : function() {
             var s = 'Event: ' + (this.code || '') + ':' + this.textcode + ' -> ' + new String(this.desc);
             if(this.ilsperm)
                 s += ' ' + this.ilsperm + '@' + this.ilspermloc;
+            if(this.note)
+                s += '\n' + this.note;
             return s;
         }
     });
index a3358ed..cbb1f85 100644 (file)
@@ -16,6 +16,7 @@
     'MAX_RENEWALS' : 'No more renewals allowed for item ${0}',
     'ITEM_NOT_CATALOGED' : 'Item ${0} was not found in the system.  Try re-scanning the item.',
     'WORKSTATION_REQUIRED' : 'A workstation is required to log in to selfcheck.  You can set the  workstation name with URL param "ws".  \n\nWould you like to register a new workstation for this self-check interface?',
-    'WORKSTATION_EXISTS' : 'This workstation has already been registered.  Would you like to use it for this self-check station?'
+    'WORKSTATION_EXISTS' : 'This workstation has already been registered.  Would you like to use it for this self-check station?',
+    'CC_PAYABLE_BALANCE' : 'You have \$${0} in fines payable by credit card.'
 }
 
index be436f8..493d1c3 100644 (file)
@@ -1,5 +1,7 @@
 dojo.require('dojo.date.locale');
 dojo.require('dojo.date.stamp');
+dojo.require('dijit.form.CheckBox');
+dojo.require('dijit.form.NumberSpinner');
 dojo.require('openils.CGI');
 dojo.require('openils.Util');
 dojo.require('openils.User');
@@ -19,6 +21,7 @@ const SET_AUTO_RENEW_INTERVAL = 'circ.checkout_auto_renew_age';
 const SET_WORKSTATION_REQUIRED = 'circ.selfcheck.workstation_required';
 const SET_ALERT_POPUP = 'circ.selfcheck.alert.popup';
 const SET_ALERT_SOUND = 'circ.selfcheck.alert.sound';
+const SET_CC_PAYMENT_ALLOWED = 'credit.payments.allow';
 
 function SelfCheckManager() {
 
@@ -94,7 +97,8 @@ SelfCheckManager.prototype.init = function() {
     // connect onclick handlers to the various navigation links
     var linkHandlers = {
         'oils-selfck-hold-details-link' : function() { self.drawHoldsPage(); },
-        'oils-selfck-pay-fines-link' : function() { self.drawFinesPage(); },
+        'oils-selfck-view-fines-link' : function() { self.drawFinesPage(); },
+        'oils-selfck-pay-fines-link' : function() { self.drawPayFinesPage(); },
         'oils-selfck-nav-home' : function() { self.drawCircPage(); },
         'oils-selfck-nav-logout' : function() { self.logoutPatron(); },
         'oils-selfck-nav-logout-print' : function() { self.logoutPatron(true); },
@@ -190,7 +194,8 @@ SelfCheckManager.prototype.loadOrgSettings = function() {
             SET_AUTO_OVERRIDE_EVENTS,
             SET_PATRON_PASSWORD_REQUIRED,
             SET_AUTO_RENEW_INTERVAL,
-            SET_WORKSTATION_REQUIRED
+            SET_WORKSTATION_REQUIRED,
+            SET_CC_PAYMENT_ALLOWED
         ]
     );
 
@@ -364,7 +369,25 @@ SelfCheckManager.prototype.drawCircPage = function() {
     if(!this.circTemplate)
         this.circTemplate = this.circTbody.removeChild(dojo.byId('oils-selfck-circ-row'));
 
-    // items out, holds, and fines summaries
+    // fines summary
+    this.updateFinesSummary();
+
+    // holds summary
+    this.updateHoldsSummary();
+
+    // items out summary
+    this.updateCircSummary();
+
+    // render mock checkouts for debugging?
+    if(this.mockCheckouts) {
+        for(var i in [1,2,3]) 
+            this.displayCheckout(this.mockCheckout, 'checkout');
+    }
+}
+
+
+SelfCheckManager.prototype.updateFinesSummary = function() {
+    var self = this; 
 
     // fines summary
     fieldmapper.standardRequest(
@@ -372,27 +395,19 @@ SelfCheckManager.prototype.drawCircPage = function() {
         {   async : true,
             params : [this.authtoken, this.patron.id()],
             oncomplete : function(r) {
+
                 var summary = openils.Util.readResponse(r);
+
                 dojo.byId('oils-selfck-fines-total').innerHTML = 
                     dojo.string.substitute(
                         localeStrings.TOTAL_FINES_ACCOUNT, 
                         [summary.balance_owed()]
                     );
+
+                self.creditPayableBalance = summary.balance_owed();
             }
         }
     );
-
-    // holds summary
-    this.updateHoldsSummary();
-
-    // items out summary
-    this.updateCircSummary();
-
-    // render mock checkouts for debugging?
-    if(this.mockCheckouts) {
-        for(var i in [1,2,3]) 
-            this.displayCheckout(this.mockCheckout, 'checkout');
-    }
 }
 
 
@@ -446,9 +461,11 @@ SelfCheckManager.prototype.drawItemsOutPage = function() {
 SelfCheckManager.prototype.goToTab = function(name) {
     this.tabName = name;
 
+    openils.Util.hide('oils-selfck-fines-page');
     openils.Util.hide('oils-selfck-payment-page');
     openils.Util.hide('oils-selfck-holds-page');
     openils.Util.hide('oils-selfck-circ-page');
+    openils.Util.hide('oils-selfck-pay-fines-link');
     
     switch(name) {
         case 'checkout':
@@ -461,6 +478,9 @@ SelfCheckManager.prototype.goToTab = function(name) {
             openils.Util.show('oils-selfck-holds-page');
             break;
         case 'fines':
+            openils.Util.show('oils-selfck-fines-page');
+            break;
+        case 'payment':
             openils.Util.show('oils-selfck-payment-page');
             break;
     }
@@ -645,6 +665,117 @@ SelfCheckManager.prototype.drawHolds = function(holds) {
 }
 
 
+SelfCheckManager.prototype.drawPayFinesPage = function() {
+    this.goToTab('payment');
+
+    dojo.byId('oils-selfck-cc-payment-summary').innerHTML = 
+        dojo.string.substitute(
+            localeStrings.CC_PAYABLE_BALANCE,
+            [this.creditPayableBalance]
+        );
+
+    oilsSelfckCCNumber.attr('value', '');
+    oilsSelfckCCMonth.attr('value', '01');
+    oilsSelfckCCAmount.attr('value', this.creditPayableBalance);
+    oilsSelfckCCYear.attr('value', new Date().getFullYear());
+    oilsSelfckCCFName.attr('value', this.patron.first_given_name());
+    oilsSelfckCCLName.attr('value', this.patron.family_name());
+    var addr = this.patron.billing_address() || this.patron.mailing_address();
+
+    if(addr) {
+        oilsSelfckCCStreet.attr('value', addr.street1()+' '+addr.street2());
+        oilsSelfckCCCity.attr('value', addr.city());
+        oilsSelfckCCState.attr('value', addr.state());
+        oilsSelfckCCZip.attr('value', addr.post_code());
+    }
+
+    dojo.connect(oilsSelfckEditDetails, 'onChange', 
+        function(newVal) {
+            dojo.forEach(
+                [   oilsSelfckCCFName, 
+                    oilsSelfckCCLName, 
+                    oilsSelfckCCStreet, 
+                    oilsSelfckCCCity, 
+                    oilsSelfckCCState, 
+                    oilsSelfckCCZip
+                ],
+                function(dij) { dij.attr('disabled', !newVal); }
+            );
+        }
+    );
+
+
+    var self = this;
+    dojo.connect(oilsSelfckCCSubmit, 'onClick',
+        function() {
+            progressDialog.show(true);
+            self.sendCCPayment();
+        }
+    );
+}
+
+
+// In this form, this code only supports global on/off credit card 
+// payments and does not dissallow payments to transactions that started
+// at remote locations or transactions that have accumulated billings at 
+// remote locations that dissalow credit card payments.
+// TODO add per-transaction blocks for orgs that do not support CC payments
+
+SelfCheckManager.prototype.sendCCPayment = function() {
+
+    var args = {
+        userid : this.patron.id(),
+        payment_type : 'credit_card_payment',
+        payments : [],
+        cc_args : {
+            where_process : 1,
+            number : oilsSelfckCCNumber.attr('value'),
+            expire_year : oilsSelfckCCYear.attr('value'),
+            expire_month : oilsSelfckCCMonth.attr('value'),
+            billing_first : oilsSelfckCCFName.attr('value'),
+            billing_last : oilsSelfckCCLName.attr('value'),
+            billing_address : oilsSelfckCCStreet.attr('value'),
+            billing_city : oilsSelfckCCCity.attr('value'),
+            billing_state : oilsSelfckCCState.attr('value'),
+            billing_zip : oilsSelfckCCZip.attr('value')
+        }
+    }
+
+    var funds = oilsSelfckCCAmount.attr('value');
+
+    xacts = this.finesData.sort(
+        function(a, b) {
+            if(a.transaction.xact_start() < b.transaction.xact_start()) 
+                return -1;
+            return 1;
+        }
+    );
+
+    for(var i in xacts) {
+        var xact = xacts[i].transaction;
+        var paying = Math.min(funds, xact.balance_owed());
+        args.payments.push([xact.id(), paying]);
+        funds -= paying;
+        if(funds <= 0) break;
+    }
+
+    var resp = fieldmapper.standardRequest(
+        ['open-ils.circ', 'open-ils.circ.money.payment'],
+        {params : [this.authtoken, args]}
+    );
+
+    progressDialog.hide();
+
+    var evt = openils.Event.parse(resp);
+    if(evt) {
+        alert(evt);
+    } else {
+        this.updateFinesSummary();
+        this.drawFinesPage();
+    }
+}
+
+
 SelfCheckManager.prototype.drawFinesPage = function() {
 
     // TODO add option to hid scanBox
@@ -653,6 +784,10 @@ SelfCheckManager.prototype.drawFinesPage = function() {
     this.goToTab('fines');
     progressDialog.show(true);
 
+    if(this.creditPayableBalance > 0 && this.orgSettings[SET_CC_PAYMENT_ALLOWED]) {
+        openils.Util.show('oils-selfck-pay-fines-link', 'inline');
+    }
+
     this.finesTbody = dojo.byId('oils-selfck-fines-tbody');
     if(!this.finesTemplate)
         this.finesTemplate = this.finesTbody.removeChild(dojo.byId('oils-selfck-fines-row'));
@@ -662,6 +797,7 @@ SelfCheckManager.prototype.drawFinesPage = function() {
     var self = this;
     var handler = function(dataList) {
         self.finesCount = dataList.length;
+        self.finesData = dataList;
         for(var i in dataList) {
             var data = dataList[i];
             var row = self.finesTemplate.cloneNode(true);
index b1abfb4..36830b8 100644 (file)
@@ -7,7 +7,7 @@
                 <td>Title</td>
                 <td>Author</td>
                 <td>Due Date</td>
-                <td>Renewals Left</td>
+                <td class='hidden'>Renewals Left</td>
                 <td>Type</td>
             </tr>
         </thead>
@@ -18,7 +18,7 @@
                 <td name='title'></td>
                 <td name='author'></td>
                 <td name='due_date'></td>
-                <td name='remaining'></td>
+                <td  class='hidden' name='remaining'></td>
                 <td>
                     <div name='checkout' class='hidden'>Checkout</div>
                     <div name='renew' class='hidden'>Renewal</div>
index 8e4939c..1549a4f 100644 (file)
@@ -10,7 +10,8 @@
 <div id='oils-selfck-bottom-div'>
     <div id='oils-selfck-content-div'>
         <div id='oils-selfck-content-header'>
-            <a id='oils-selfck-print-list-link' href='javascript:void(0);'>Print List</a>
+            <span><a class='hidden' href='javascript:void(0);' id='oils-selfck-pay-fines-link'>Pay Fines</a></span>
+            <span><a id='oils-selfck-print-list-link' href='javascript:void(0);'>Print List</a></span>
         </div>
         <div id='oils-selfck-circ-page' class='hidden'>
             <!-- Checkout / renewal and items out interface -->
             <!-- Patron holds interface -->
             [% INCLUDE 'default/circ/selfcheck/holds_page.tt2' %]
         </div>
-        <div id='oils-selfck-payment-page' class='hidden'>
-            <!-- Fines and credit card payments interface -->
+        <div id='oils-selfck-fines-page' class='hidden'>
+            <!-- Fines and interface -->
             [% INCLUDE 'default/circ/selfcheck/fines.tt2' %]
         </div>
+        <div id='oils-selfck-payment-page' class='hidden'>
+            <!-- credit card payments interface -->
+            [% INCLUDE 'default/circ/selfcheck/payment.tt2' %]
+        </div>
     </div>
     <div id='oils-selfck-summary-div'>
         [% INCLUDE 'default/circ/selfcheck/summary.tt2' %]
diff --git a/Open-ILS/web/templates/default/circ/selfcheck/payment.tt2 b/Open-ILS/web/templates/default/circ/selfcheck/payment.tt2
new file mode 100644 (file)
index 0000000..fef4e02
--- /dev/null
@@ -0,0 +1,69 @@
+<div id='oils-selfck-cc-payment-summary'> </div>
+<table id='oils-selfck-cc-payment-table'>
+    <tbody>
+        <tr>
+            <td>Amount</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCAmount' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Credit Card #</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCNumber' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Exipration Month</td>
+            <td>
+                <select dojoType='dijit.form.FilteringSelect' jsId='oilsSelfckCCMonth' required='true'>
+                    <option value='01' selected='selected'>Jan</option>
+                    <option value='02'>Feb</option>
+                    <option value='03'>Mar</option>
+                    <option value='04'>April</option>
+                    <option value='05'>May</option>
+                    <option value='06'>June</option>
+                    <option value='07'>July</option>
+                    <option value='08'>Aug</option>
+                    <option value='09'>Sept</option>
+                    <option value='10'>Oct</option>
+                    <option value='11'>Nov</option>
+                    <option value='12'>Dec</option>
+                </select>
+            </td>
+        </tr>
+        <tr>
+            <td>Expiration Year</td>
+            <td><input dojoType='dijit.form.NumberSpinner' constraints='{pattern:"0000", places:0, maxlength:4}' jsId='oilsSelfckCCYear' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Edit Billing Details</td>
+            <td><input dojoType='dijit.form.CheckBox' jsId='oilsSelfckEditDetails'/></td>
+        </tr>
+        <tr>
+            <td>First Name</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCFName' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Last Name</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCLName' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>Street Address</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCStreet' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>City</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCCity' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>State or Province</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCState' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td>ZIP or Postal Code</td>
+            <td><input dojoType='dijit.form.TextBox' jsId='oilsSelfckCCZip' disabled='disabled' required='true'/></td>
+        </tr>
+        <tr>
+            <td colspan='2' align='center'>
+                <button dojoType='dijit.form.Button' jsId='oilsSelfckCCSubmit'>Submit Payment</button>
+            </td>
+        </tr>
+    </tbody>
+</table>
index d708073..4794e4e 100644 (file)
@@ -19,7 +19,9 @@
     <fieldset>
         <legend>Fines</legend>
         <div id='oils-selfck-fines-total'></div>
-        <div><a href='javascript:void(0);' id='oils-selfck-pay-fines-link'>View Fines</a></div>
+        <div>
+            <span><a href='javascript:void(0);' id='oils-selfck-view-fines-link'>View Details</a></span>
+        </div>
     </fieldset>
 </div>