--- /dev/null
+# 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
+
+
+
+
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]
# 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.
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;
}
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)
+
import re
import sys
from django.forms.models import modelformset_factory
+from conifer.custom import lib_integration
#-----------------------------------------------------------------------------
# Z39.50 Support
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) — %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 — %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'))
<?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"
<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/>