first actual SIP integration
authorgfawcett <gfawcett@6d9bc8c9-1ec2-4278-b937-99fde70a366f>
Fri, 3 Apr 2009 01:31:41 +0000 (01:31 +0000)
committergfawcett <gfawcett@6d9bc8c9-1ec2-4278-b937-99fde70a366f>
Fri, 3 Apr 2009 01:31:41 +0000 (01:31 +0000)
Doing patron and item-info lookups through SIP. checkout is next. woohoo!

git-svn-id: svn://svn.open-ils.org/ILS-Contrib/servres/trunk@250 6d9bc8c9-1ec2-4278-b937-99fde70a366f

conifer/custom/lib_integration.py [new file with mode: 0644]
conifer/libsystems/sip/sipclient.py
conifer/static/main.css
conifer/syrup/models.py
conifer/syrup/views.py
conifer/templates/phys/checkout.xhtml

diff --git a/conifer/custom/lib_integration.py b/conifer/custom/lib_integration.py
new file mode 100644 (file)
index 0000000..9dbce90
--- /dev/null
@@ -0,0 +1,27 @@
+# Our integration-point with back-end library systems.
+
+# TODO: write some documentation about the lib_integration interface.
+
+# Our example configuration: 
+# Z39.50 for catalogue search, 
+# SIP for patron and item_info, and for item checkout and checkin,
+# OpenSRF for extended item info.
+
+from conifer.libsystems.sip import sipclient
+
+
+def patron_info(barcode):
+    conn = sipclient.sip_connection()
+    resp = sipclient.sip_connection().patron_info(barcode)
+    conn.close()
+    return resp
+
+def item_info(barcode):
+    conn = sipclient.sip_connection()
+    resp = conn.item_info(barcode)
+    conn.close()
+    return resp
+
+    
+
+
index b7ceaab..5a84383 100644 (file)
@@ -374,6 +374,10 @@ class SipClient(object):
         self.socket = so
         self.seqno = self.error_detect and 1 or 0
 
+    def close(self):
+        # fixme, do SIP close first.
+        self.socket.close()
+
     def send(self, outmsg, inmsg, args=None):
         msg_template = MESSAGES[outmsg]
         resp_template = MESSAGES[inmsg]
@@ -395,12 +399,56 @@ class SipClient(object):
     # Common protocol methods
 
     def login(self, uid, pwd, locn):
-        return self.send(LOGIN, LOGIN_RESP, 
-                         dict(uid=uid, pwd=pwd, locn=locn))
+        msg = self.send(LOGIN, LOGIN_RESP, 
+                        dict(uid=uid, pwd=pwd, locn=locn))
+        return msg.get('okay') == '1'
 
     def status(self):
         return self.send(SC_STATUS, ACS_STATUS)
 
+    def patron_info(self, barcode):
+        msg = self.send(PATRON_INFO,PATRON_INFO_RESP,
+                        {'patron':barcode,
+                         'startitem':1, 'enditem':2})
+        return msg
+
+    def item_info(self, barcode):
+        msg = self.send(ITEM_INFORMATION, ITEM_INFO_RESP,
+                        {'item':barcode})
+        decode_status = {
+            '01': 'Other',
+            '02': 'On order',
+            '03': 'Available',
+            '04': 'Charged',
+            '05': 'Charged; not to be recalled until',
+            '06': 'In process',
+            '07': 'Recalled',
+            '08': 'Waiting on hold shelf',
+            '09': 'Waiting to be re-shelved',
+            '10': 'In transit between library locations',
+            '11': 'Claimed returned',
+            '12': 'Lost',
+            '13': 'Missing ',
+            }
+        msg['available'] = msg['circstat'] == '03'
+        msg['status'] = decode_status[msg['circstat']]
+        return msg
+
+
+# ------------------------------------------------------------
+# Django stuff. Optional.
+
+try:
+    from django.conf import settings
+    def sip_connection():
+        sip = SipClient(*settings.SIP_HOST)
+        if not sip.login(*settings.SIP_CREDENTIALS):
+            raise 'SipLoginError'
+        return sip
+
+except ImportError:
+    pass
+
 
 # ------------------------------------------------------------
 # Test code.
index 513f84d..4582472 100644 (file)
@@ -30,7 +30,7 @@ min-height: 300;
     position: relative;
     top: -5px;
     float: right;
-    margin:0.2em 0 1em;
+    margin: 0.2em 0 0 0;
     padding:0 0.2em 0 0.5em;
     color: #ccc;
 }
index f6e53d6..df32f8e 100644 (file)
@@ -527,3 +527,19 @@ class Target(m.Model):
 
     def __unicode__(self):
         return self.name
+
+#----------------------------------------------------------------------
+# SIP checkout
+
+class Checkout(m.Model):
+    """A log of checkout events."""
+    
+    patron = m.CharField(max_length=100)
+    patron_descrip = m.CharField(max_length=512)
+    item   = m.CharField(max_length=100, null=True)
+    item_descrip = m.CharField(max_length=512, null=True)
+    staff  = m.ForeignKey(User)
+    initiated = m.DateTimeField(auto_now_add=True)
+    completed = m.DateTimeField(default=None, null=True)
+    outcome  = m.CharField(max_length=100, null=True)
+    
index f2c46ae..e47e1f9 100644 (file)
@@ -34,6 +34,7 @@ import django.forms
 import re
 import sys
 from django.forms.models import modelformset_factory
+from conifer.custom import lib_integration
 
 #-----------------------------------------------------------------------------
 # Z39.50 Support
@@ -1226,23 +1227,32 @@ def phys_checkout(request):
         patron, item = post('patron'), post('item')
         if post('step') == '1':
             # patron entered, need item
-            patron_descrip = 'Fred Example, Jr.' # fixme, lookup
+            # first get patron data.
+            msg = lib_integration.patron_info(patron)
+            patron_descrip = '%s (%s) &mdash; %s' % (
+                msg['personal'], msg['home_library'],
+                msg['screenmsg'])
             return g.render('phys/checkout.xhtml', step=2, 
                             patron=patron, 
                             patron_descrip=patron_descrip)
         elif post('step') == '2':
             # patron + item. do SIP calls.
             # log the checkout in a local table.
-            patron_descrip = 'Fred Example, Jr.' # fixme, lookup
-            item_descrip   = 'War and Peace (Reader\'s Digest edition)'
+            # also, make sure the barcode actually matches with a
+            # known barcode in Syrup. We only checkout what we know
+            # about.
+            msg = lib_integration.item_info(item)
+            item_descrip = '%s &mdash; %s' % (
+                msg['title'], msg['status'])
+
+            # do the checkout
             return g.render('phys/checkout.xhtml', step=3, 
                             patron=patron, item=item,
-                            patron_descrip=patron_descrip,
+                            patron_descrip=post('patron_descrip'),
                             item_descrip=item_descrip)
         elif post('step') == '3':
             # continue after checkout. Go to 'checkout another item'.
-            patron_descrip = 'Fred Example, Jr.' # fixme, lookup
             return g.render('phys/checkout.xhtml', step=2, 
                             patron=patron,
-                            patron_descrip=patron_descrip)
+                            patron_descrip=post('patron_descrip'))
         
index 38078cd..737102b 100644 (file)
@@ -1,4 +1,6 @@
 <?python
+import os  # fixme, just for testing.
+sample_item = '31862017122801'  # fixme, just for testing.
 title = _('Patron Checkout of Item')
 ?>
 <html xmlns="http://www.w3.org/1999/xhtml"
@@ -20,26 +22,27 @@ title = _('Patron Checkout of Item')
       <tr py:choose="defined('patron')">
        <th>Patron Barcode</th>
        <td py:when="False">
-         <input type="text" id="patron" name="patron" style="width: 400;"/>
+         <input type="text" id="patron" name="patron" style="width: 400;" value="${os.environ['ART']}"/>
        </td>
        <td py:when="True">
-           ${patron}: ${patron_descrip}
+           ${patron}: ${Markup(patron_descrip)}
            <input type="hidden" name="patron" value="${patron}"/>
+           <input type="hidden" name="patron_descrip" value="${patron_descrip}"/>
        </td>
       </tr>
       <tr py:if="step>1" py:choose="defined('item')">
        <th>Item Barcode</th>
        <td py:when="False">
-         <input type="text" id="item" name="item" style="width: 400;"/>
+         <input type="text" id="item" name="item" style="width: 400;" value="${sample_item}"/>
        </td>
        <td py:when="True">
-         ${item}: ${item_descrip}
+         ${item}: ${Markup(item_descrip)}
          <input type="hidden" name="item" value="${item}"/>
        </td>
       </tr>
       <tr py:if="step==3">
        <th/>
-       <td><b>Success: Item Checked Out.</b></td>
+       <td><b>Success: Item Checked Out (FOR PRETEND! Not doing checkout yet).</b></td>
       </tr>
       <tr>
        <th/>