def login(self, username, password, workstation=None): """Return True if the username/password are good, False otherwise.""" seed = E1('open-ils.auth.authenticate.init', username) """ We get away with no workstation in proxy auth setup at Windsor, need to track down but use staff station for now """ if workstation: patronws = workstation else: patronws = getattr(settings, 'OPENSRF_STAFF_WORKSTATION', None) result = E1( 'open-ils.auth.authenticate.complete', { 'workstation': patronws, 'username': username, 'password': _hsh(seed + _hsh(password)), 'type': 'opac' }) try: authkey = result['payload']['authtoken'] #cleanup session - we do not use eg authkey locally E1('open-ils.auth.session.delete', [authkey]) return authkey except: return None
def get_copydetails(barcode, copyids, reserves_loc, bib_part_flag, part_flag, bcs, ids): copies_desk = len(copyids) copies_lib = copies_desk copy_list = [] lib_parts_list = [] res_parts_list = [] copy_sort = None part_sort = None part_label = '' bcs_set, ids_set = collect_set(barcode, bcs, ids) for copyid in copyids: circinfo = E1(OPENSRF_FLESHED2_CALL, copyid) circbarcode = None if barcode is not None: circbarcode = circinfo.get("barcode") thisloc = circinfo.get("location") if thisloc: thisloc = thisloc.get("name") #create copy object for supplied barcode - will be all barcodes if none supplied if bib_part_flag or part_flag: circ_modifier = circinfo.get("circ_modifier") circs = circinfo.get("circulations") parts = circinfo.get("parts") part = None if parts: part = parts[0] if part: part_label = part.get("label") part_sort = part.get("label_sortkey") if thisloc in reserves_loc: res_parts_list.append(part_sort) lib_parts_list.append(part_sort) if thisloc in reserves_loc and (barcode == circbarcode or circbarcode in bcs_set): if part_sort is not None and copy_sort is None: copy_sort = part_sort id_ind = -1 if circbarcode in bcs_set: id_ind = ids_set[bcs_set.index(circbarcode)] copy_list.append( copy_obj(circ_modifier, circs, part_label, part_sort, id_ind)) desk_count = len(res_parts_list) lib_count = len(lib_parts_list) if part_flag and copy_sort is not None: desk_count = res_parts_list.count(copy_sort) lib_count = lib_parts_list.count(copy_sort) return sorted( copy_list, key=lambda copy: copy.part_sort), desk_count, lib_count
def get_label(bc): partlabel = None copyinfo = E1(OPENSRF_BARCODE, bc) parts = copyinfo.get("parts") if parts: part = parts[0] if part: partlabel = part['label'] return partlabel
def lookup(self, username, login_token=None): """Given a username, return a dict, or None. The dict must have four keys (first_name, last_name, email, external_username), where external_username value is the username parameter.""" # for now, this backend only returns a user if a login_token is # provided; in other words, the only time your personal info is # fetched is when you log in. if login_token: resp = E1('open-ils.auth.session.retrieve', login_token) person = dict((j, resp.get(k)) for j, k in [( 'first_name', 'first_given_name'), ( 'last_name', 'family_name'), ('email', 'email'), ('external_username', 'usrname')]) return person
def __init__(self): # establish our OpenSRF connection. initialize(self) if OSRF_LIB_INSTALLED: ils_startup(self.EVERGREEN_SERVER, self.IDL_URL) # set up the available/reshelving codes, for the item_status routine. status_decode = [ (str(x['id']), x['name']) for x in E1('open-ils.search.config.copy_status.retrieve.all') ] #for x in E1('open-ils.search.config.copy_status.retrieve.all'): # print "x", x self.AVAILABLE = [ id for id, name in status_decode if name == 'Available' ][0] self.RESHELVING = [ id for id, name in status_decode if name == 'Reshelving' ][0] self.CHECKEDOUT = [ id for id, name in status_decode if name == 'Checked out' ][0]
def cat_search(self, query, start=1, limit=10): barcode = '' bibid = '' partlabel = '' is_barcode = re.search('\d{14}', query) if query.startswith(self.OPAC_URL): results = [] # query is an Evergreen URL # snag the bibid at this point if "=" in query and "&" in query: params = dict([x.split("=") for x in query.split("&")]) for key in params.keys(): if key.find('?r') != -1: bibid = params[key] results = M.marcxml_to_records(I.url_to_marcxml(query)) else: # likely template opac # first seq of digits after a / should be the bibid match = re.search(r'/(\d+)', query) if match: bibid = match.group(1) results = M.marcxml_to_records( self.bib_id_to_marcxml(bibid)) numhits = len(results) elif is_barcode: results = [] numhits = 0 barcode = query.strip() bib = E1('open-ils.search.bib_id.by_barcode', barcode) if bib: bibid = bib copy = E1('open-ils.supercat.record.object.retrieve', bib) copyinfo = E1(OPENSRF_BARCODE, barcode) parts = copyinfo.get("parts") if parts: part = parts[0] if part: partlabel = part['label'] marc = copy[0]['marc'] # In some institutions' installations, 'marc' is a string; in # others it's unicode. Convert to unicode if necessary. if not isinstance(marc, unicode): marc = unicode(marc, 'utf-8') tree = M.marcxml_to_records(marc)[0] results.append(tree) numhits = 1 else: # query is an actual query if self.USE_Z3950: cat_host, cat_port, cat_db = settings.Z3950_CONFIG results, numhits = PZ.search(cat_host, cat_port, cat_db, query, start, limit) else: # use opensrf if not self.OSRF_CAT_SEARCH_ORG_UNIT: raise NotImplementedError, \ 'Your integration must provide a value for OSRF_CAT_SEARCH_ORG_UNIT.' EVERGREEN_SEARCH_DEPTH = getattr(settings, 'EVERGREEN_SEARCH_DEPTH', 1) superpage = E1( 'open-ils.search.biblio.multiclass.query', { 'org_unit': self.OSRF_CAT_SEARCH_ORG_UNIT, 'depth': EVERGREEN_SEARCH_DEPTH, 'limit': limit, 'offset': start - 1, 'visibility_limit': 3000, 'default_class': 'keyword' }, query, 1) ids = [id for (id, ) in superpage['ids']] results = [] for rec in E1('open-ils.supercat.record.object.retrieve', ids): marc = rec['marc'] # In some institutions' installations, 'marc' is a string; in # others it's unicode. Convert to unicode if necessary. if not isinstance(marc, unicode): marc = unicode(marc, 'utf-8') tree = M.marcxml_to_records(marc)[0] results.append(tree) numhits = int(superpage['count']) return results, numhits, bibid, barcode, partlabel
def sort_out_status(barcode, sort_vol, counts, version, sort_lib, sort_desk, sort_avail, sort_callno, sort_dueid, sort_dueinfo, sort_circmod, sort_allcalls, sort_alldues, prefix, suffix, bcs, ids, sort_copyids): vol = sort_vol lib = sort_lib desk = sort_desk avail = sort_avail callno = sort_callno dueinfo = sort_dueinfo circmod = sort_circmod allcalls = sort_allcalls alldues = sort_alldues dueid = sort_dueid copyids = sort_copyids duedisplay = None partdisplay = "" try: if loc in self.RESERVES_DESK_NAME: callprefix = '' callsuffix = '' # get initial call number and total library count callno, lib = initialVals(prefix, suffix, callno, lib) # volume check - based on v.1, etc. in call number voltest = re.search(self.IS_EMBEDDEDVOL, callno) # attachment test attachtest = re.search(self.IS_ATTACHMENT, callno) dueinfo = '' # combine volume designations for embedded values callprefix, callno, callsuffix = add_in_embedded_parts( prefix, suffix, callprefix, callsuffix, callno, voltest, attachtest, vol) if version >= 2.1: #oh-oh, something inconsistent on multiple calls here tmp_copyids = E1(OPENSRF_CN_CALL, bib_id, [prefix, sort_callno, suffix], org) copyids.extend(tmp_copyids) else: tmp_copyids = E1(OPENSRF_CN_CALL, bib_id, sort_callno, org) copyids.extend(tmp_copyids) #get copy information copies, desk, copy_lib = get_copydetails( barcode, copyids, self.RESERVES_DESK_NAME, self.BIB_PART_MERGE, self.PART_MERGE, bcs, ids) if desk == 0 or copy_lib == 0: desk = get_desk_counts(counts) else: lib = copy_lib avail = desk copy_parts = [] duetime = None earliestdue = None # we want to identify the copy that will be returned first if # all are checked out for copy in copies: if copy.part_label: callno = sort_callno + " " + copy.part_label if copy.part_sort in copy_parts and len( copy_parts) > 0: partdisplay = copy.part_label #leave alone if locked - otherwise mark as ready if allcalls[len(allcalls) - 1][1] != LOCKED: allcalls[len(allcalls) - 1] = [ callno, READY, copy.syrup_id, copy.part_label ] else: allcalls = callparts(callno, READY, copy.syrup_id, copy.part_label, allcalls) copy_parts.append(copy.part_sort) bringfw = attachtest # multiple volumes in identified in call number if voltest and callno.find(voltest.group(0)) == -1: bringfw = True if copy.circs and isinstance(copy.circs, list): circ = copy.circs[0] rawdate = circ.get("due_date") #remove offset info, %z is flakey for some reason rawdate = rawdate[:-5] duetime = time.strptime(rawdate, self.TIME_FORMAT) elif len(allcalls) == 0 and copy.syrup_id != -1: dueid = [copy.syrup_id, LOCKED] #get due information - lots of extra pieces needed for embedded parts dueinfo, callprefix, callno, callsuffix = deal_with_dues( duetime, avail, bringfw, copy, callprefix, callsuffix, callno, earliestdue, attachtest, voltest, sort_callno, dueinfo) alldisplay = callno + ' (Available)' if copy.circs and isinstance(copy.circs, list): if (earliestdue is None or duetime < earliestdue): earliestdue = duetime dueinfo = time.strftime( self.DUE_FORMAT, earliestdue) #will want the link to be to the earliest item if not multipart if len(allcalls) == 0 and dueid[ 1] != LOCKED and copy.syrup_id != -1: dueid = [copy.syrup_id, DUE] #alldisplay = '%s (DUE: %s)' % (callno,time.strftime(self.DUE_FORMAT,earliestdue)) duedisplay = '%s (DUE: %s)' % ( callno, time.strftime(self.DUE_FORMAT, earliestdue)) if len(allcalls) > 0: if allcalls[len(allcalls) - 1][1] != LOCKED: allcalls[len(allcalls) - 1] = [ duedisplay, DUE, copy.syrup_id, copy.part_label ] if avail >= 1: avail -= 1 elif avail >= 1: avail -= 1 if copy.part_label and copy.part_label not in alldisplay: duedisplay = '%s %s (DUE: %s)' % ( callno, copy.part_label, time.strftime(self.DUE_FORMAT, earliestdue)) elif len(allcalls) > 0: allcalls[len(allcalls) - 1] = [ callno, LOCKED, copy.syrup_id, copy.part_label ] if avail == 0 and duedisplay is not None: alldisplay = duedisplay alldues.append(alldisplay) if voltest or attachtest: callno, vol = last_check_embed( callprefix, callno, callsuffix, voltest, vol) except: print "due date/call problem: ", bib_id print "*** print_exc:" traceback.print_exc() if avail != 0 and len(allcalls) > 0: if allcalls[len(allcalls) - 1][1] == DUE: allcalls[len(allcalls) - 1] = [ alldisplay, READY, allcalls[len(allcalls) - 1][2], allcalls[len(allcalls) - 1][3] ] return (vol, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, copyids)
def _item_status(self, bib_id, barcode, bclist, idlist): #sanity variables for multipart titles DUE = 0 READY = 1 LOCKED = 2 #lock in an available copy class copy_obj: def __init__(self, circ_modifier, circs, part_label, part_sort, syrup_id): self.circ_modifier = circ_modifier self.circs = circs self.part_label = part_label self.part_sort = part_sort self.syrup_id = syrup_id def make_obj_list(objlist): objset = [] objcoll = objlist.split(";") for o in objcoll: objset.append(o.split("/")) return objset #is current barcode one of identified sets def collect_set(barcode, bcs, ids): bc_dups = [] id_dups = [] i = 0 for bc in bcs: if barcode in bc: return bc, ids[i] i = i + 1 return bc_dups, id_dups #syrup tries to store as little as possible about an #item, which leads to a lot of hoops when combining #volumes/parts def get_copydetails(barcode, copyids, reserves_loc, bib_part_flag, part_flag, bcs, ids): copies_desk = len(copyids) copies_lib = copies_desk copy_list = [] lib_parts_list = [] res_parts_list = [] copy_sort = None part_sort = None part_label = '' bcs_set, ids_set = collect_set(barcode, bcs, ids) for copyid in copyids: circinfo = E1(OPENSRF_FLESHED2_CALL, copyid) circbarcode = None if barcode is not None: circbarcode = circinfo.get("barcode") thisloc = circinfo.get("location") if thisloc: thisloc = thisloc.get("name") #create copy object for supplied barcode - will be all barcodes if none supplied if bib_part_flag or part_flag: circ_modifier = circinfo.get("circ_modifier") circs = circinfo.get("circulations") parts = circinfo.get("parts") part = None if parts: part = parts[0] if part: part_label = part.get("label") part_sort = part.get("label_sortkey") if thisloc in reserves_loc: res_parts_list.append(part_sort) lib_parts_list.append(part_sort) if thisloc in reserves_loc and (barcode == circbarcode or circbarcode in bcs_set): if part_sort is not None and copy_sort is None: copy_sort = part_sort id_ind = -1 if circbarcode in bcs_set: id_ind = ids_set[bcs_set.index(circbarcode)] copy_list.append( copy_obj(circ_modifier, circs, part_label, part_sort, id_ind)) desk_count = len(res_parts_list) lib_count = len(lib_parts_list) if part_flag and copy_sort is not None: desk_count = res_parts_list.count(copy_sort) lib_count = lib_parts_list.count(copy_sort) return sorted( copy_list, key=lambda copy: copy.part_sort), desk_count, lib_count #deal with call numbers that have embedded parts - ugh! def get_dueinfo(callprefix, callsuffix, callno, earliestdue, attachtest, voltest, sort_callno, bringfw, dueinfo): tmpinfo = '' _callprefix = callprefix _callsuffix = callsuffix _callno = callno _dueinfo = dueinfo if voltest: if (int(voltest.group(1)) > vol): if len(_dueinfo) > 0: _dueinfo = _dueinfo + "/" _dueinfo = _dueinfo + voltest.group( 0) + ': ' + time.strftime(self.DUE_FORMAT, earliestdue) else: tmpinfo = _dueinfo _dueinfo = voltest.group(0) + ': ' + time.strftime( self.DUE_FORMAT, earliestdue) if len(tmpinfo) > 0: _dueinfo = _dueinfo + "/" + tmpinfo _callprefix = _callsuffix = '' elif attachtest: tmpinfo = _dueinfo _dueinfo = attachtest.group(0) + ': ' + time.strftime( self.DUE_FORMAT, earliestdue) if len(_callno) > 0: _callno = _callno + '/' + sort_callno _callprefix = _callsuffix = '' else: _callno = sort_callno if len(tmpinfo) > 0: _dueinfo = _dueinfo + "/" + tmpinfo if not bringfw: _dueinfo = time.strftime(self.DUE_FORMAT, earliestdue) #_callno = sort_callno return _dueinfo, _callno, _callprefix, _callsuffix #get due information - lots of pieces passed on for embedded parts def deal_with_dues(duetime, avail, bringfw, copy, callprefix, callsuffix, callno, earliestdue, attachtest, voltest, sort_callno, dueinfo): earlydue = earliestdue due = dueinfo due_callprefix = callprefix due_callno = callno due_callsuffix = callsuffix if copy.circs and len(copy.circs) > 0: if len(dueinfo) == 0 or bringfw: earlydue = duetime due, due_due_callno, due_callprefix, due_callsuffix = get_dueinfo( callprefix, callsuffix, callno, earlydue, attachtest, voltest, sort_callno, bringfw, dueinfo) if (earlydue is None or duetime < earlydue) and not bringfw: earlydue = duetime due = time.strftime(self.DUE_FORMAT, earliestdue) return due, due_callprefix, due_callno, due_callsuffix #create initial call no and counts def initialVals(prefix, suffix, callno, lib): initial_callno = callno if prefix: initial_callno = prefix + callno if suffix: initial_callno = callno + suffix initial_avail = stats.get(self.AVAILABLE, 0) initial_avail += stats.get(self.RESHELVING, 0) anystatus_here = sum(stats.values()) return initial_callno, lib + anystatus_here #sometimes part information is in the callno directly, try to combine for display by #shifting to suffix - otherwise treat normally def add_in_embedded_parts(prefix, suffix, callprefix, callsuffix, callno, voltest, attachtest, vol): embed_prefix = callprefix embed_callno = callno embed_suffix = callsuffix if (voltest and vol > 0): if (int(voltest.group(1)) > vol): embed_suffix = "/" + callno else: embed_prefix = callno + "/" elif attachtest and callno.find(attachtest.group(0)) == -1: if len(callno) > 0: embed_suffix = "/" + callno else: embed_prefix = callno else: embed_callno = prefix + callno + suffix return embed_prefix, embed_callno, embed_suffix #probably not needed but final sanity check for embedded parts def last_check_embed(callprefix, callno, callsuffix, voltest, vol): last_call = callno last_vol = vol if callno.find(callprefix) == -1: last_call = callprefix + callno if callno.find(callsuffix) == -1: last_call = last_call + callsuffix if voltest: last_vol = int(voltest.group(1)) return last_call, last_vol #make sure request call number is limited to unique entries def callparts(callno, status, syrup_id, label, allcalls): partcalls = allcalls if len(partcalls) > 0: multipart = allcalls[len(partcalls) - 1] if callno != multipart[0] and label != multipart[3]: partcalls.append([callno, status, syrup_id, label]) else: partcalls.append([callno, status, syrup_id, label]) return partcalls #use counts from system if not parts def get_desk_counts(counts): desk_count = 0 for i, j, k, l, m, n in counts: if m in self.RESERVES_DESK_NAME: desk_count += n.get(self.AVAILABLE, 0) desk_count += n.get(self.RESHELVING, 0) desk_count += n.get(self.CHECKEDOUT, 0) return desk_count #pull together status information def sort_out_status(barcode, sort_vol, counts, version, sort_lib, sort_desk, sort_avail, sort_callno, sort_dueid, sort_dueinfo, sort_circmod, sort_allcalls, sort_alldues, prefix, suffix, bcs, ids, sort_copyids): vol = sort_vol lib = sort_lib desk = sort_desk avail = sort_avail callno = sort_callno dueinfo = sort_dueinfo circmod = sort_circmod allcalls = sort_allcalls alldues = sort_alldues dueid = sort_dueid copyids = sort_copyids duedisplay = None partdisplay = "" try: if loc in self.RESERVES_DESK_NAME: callprefix = '' callsuffix = '' # get initial call number and total library count callno, lib = initialVals(prefix, suffix, callno, lib) # volume check - based on v.1, etc. in call number voltest = re.search(self.IS_EMBEDDEDVOL, callno) # attachment test attachtest = re.search(self.IS_ATTACHMENT, callno) dueinfo = '' # combine volume designations for embedded values callprefix, callno, callsuffix = add_in_embedded_parts( prefix, suffix, callprefix, callsuffix, callno, voltest, attachtest, vol) if version >= 2.1: #oh-oh, something inconsistent on multiple calls here tmp_copyids = E1(OPENSRF_CN_CALL, bib_id, [prefix, sort_callno, suffix], org) copyids.extend(tmp_copyids) else: tmp_copyids = E1(OPENSRF_CN_CALL, bib_id, sort_callno, org) copyids.extend(tmp_copyids) #get copy information copies, desk, copy_lib = get_copydetails( barcode, copyids, self.RESERVES_DESK_NAME, self.BIB_PART_MERGE, self.PART_MERGE, bcs, ids) if desk == 0 or copy_lib == 0: desk = get_desk_counts(counts) else: lib = copy_lib avail = desk copy_parts = [] duetime = None earliestdue = None # we want to identify the copy that will be returned first if # all are checked out for copy in copies: if copy.part_label: callno = sort_callno + " " + copy.part_label if copy.part_sort in copy_parts and len( copy_parts) > 0: partdisplay = copy.part_label #leave alone if locked - otherwise mark as ready if allcalls[len(allcalls) - 1][1] != LOCKED: allcalls[len(allcalls) - 1] = [ callno, READY, copy.syrup_id, copy.part_label ] else: allcalls = callparts(callno, READY, copy.syrup_id, copy.part_label, allcalls) copy_parts.append(copy.part_sort) bringfw = attachtest # multiple volumes in identified in call number if voltest and callno.find(voltest.group(0)) == -1: bringfw = True if copy.circs and isinstance(copy.circs, list): circ = copy.circs[0] rawdate = circ.get("due_date") #remove offset info, %z is flakey for some reason rawdate = rawdate[:-5] duetime = time.strptime(rawdate, self.TIME_FORMAT) elif len(allcalls) == 0 and copy.syrup_id != -1: dueid = [copy.syrup_id, LOCKED] #get due information - lots of extra pieces needed for embedded parts dueinfo, callprefix, callno, callsuffix = deal_with_dues( duetime, avail, bringfw, copy, callprefix, callsuffix, callno, earliestdue, attachtest, voltest, sort_callno, dueinfo) alldisplay = callno + ' (Available)' if copy.circs and isinstance(copy.circs, list): if (earliestdue is None or duetime < earliestdue): earliestdue = duetime dueinfo = time.strftime( self.DUE_FORMAT, earliestdue) #will want the link to be to the earliest item if not multipart if len(allcalls) == 0 and dueid[ 1] != LOCKED and copy.syrup_id != -1: dueid = [copy.syrup_id, DUE] #alldisplay = '%s (DUE: %s)' % (callno,time.strftime(self.DUE_FORMAT,earliestdue)) duedisplay = '%s (DUE: %s)' % ( callno, time.strftime(self.DUE_FORMAT, earliestdue)) if len(allcalls) > 0: if allcalls[len(allcalls) - 1][1] != LOCKED: allcalls[len(allcalls) - 1] = [ duedisplay, DUE, copy.syrup_id, copy.part_label ] if avail >= 1: avail -= 1 elif avail >= 1: avail -= 1 if copy.part_label and copy.part_label not in alldisplay: duedisplay = '%s %s (DUE: %s)' % ( callno, copy.part_label, time.strftime(self.DUE_FORMAT, earliestdue)) elif len(allcalls) > 0: allcalls[len(allcalls) - 1] = [ callno, LOCKED, copy.syrup_id, copy.part_label ] if avail == 0 and duedisplay is not None: alldisplay = duedisplay alldues.append(alldisplay) if voltest or attachtest: callno, vol = last_check_embed( callprefix, callno, callsuffix, voltest, vol) except: print "due date/call problem: ", bib_id print "*** print_exc:" traceback.print_exc() if avail != 0 and len(allcalls) > 0: if allcalls[len(allcalls) - 1][1] == DUE: allcalls[len(allcalls) - 1] = [ alldisplay, READY, allcalls[len(allcalls) - 1][2], allcalls[len(allcalls) - 1][3] ] return (vol, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, copyids) #get lists of barcodes and ids bcs = make_obj_list(bclist) ids = make_obj_list(idlist) # At this point, status information does not require the opensrf # bindings, I am not sure there is a use case where an evergreen # site would not have access to these but will leave for now # since there are no hardcoded references assert self.RESERVES_DESK_NAME, 'No RESERVES_DESK_NAME specified!' lib = desk = avail = vol = anystatus_here = 0 dueid = ['', READY] dueinfo = '' callno = '' circmod = '' allcalls = [] alldues = [] tot_allcalls = [] tot_alldues = [] copyids = [] cpname = 'copies' EVERGREEN_STATUS_ORG = getattr(settings, 'EVERGREEN_STATUS_ORG', 1) EVERGREEN_STATUS_DEPTH = getattr(settings, 'EVERGREEN_STATUS_DEPTH', 0) counts = E1(OPENSRF_COPY_COUNTS, bib_id, EVERGREEN_STATUS_ORG, EVERGREEN_STATUS_DEPTH) version = getattr(settings, 'EVERGREEN_VERSION', 2.4) if version >= 2.1: #this loop is needed in case there are multiple reserves locations for org, prefix, callno, suffix, loc, stats in counts: if len(prefix) > 0: prefix += ' ' if len(suffix) > 0: suffix = ' ' + suffix vol, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, copyids = sort_out_status( barcode, vol, counts, version, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, prefix, suffix, bcs, ids, copyids) tot_allcalls.extend(allcalls) tot_alldues.extend(alldues) else: for org, callno, loc, stats in counts: vol, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, copyids = sort_out_status( barcode, vol, counts, version, lib, desk, avail, callno, dueid, dueinfo, circmod, allcalls, alldues, bcs, ids, copyids) if len(allcalls) > 0: cpname = 'copies/parts' return (cpname, lib, desk, avail, callno, dueid[0], dueinfo, circmod, allcalls, alldues)