Combine parts for bib or per-part
authorArt Rhyno <art632000@yahoo.ca>
Wed, 9 Jul 2014 17:02:27 +0000 (13:02 -0400)
committerArt Rhyno <art632000@yahoo.ca>
Wed, 9 Jul 2014 17:02:27 +0000 (13:02 -0400)
There are now 2 flags in settings for merging parts
for the display. There's some funkiness in the call
number call for parts that I need to sort out, it
could be something about my test environment.

Signed-off-by: Art Rhyno <art632000@yahoo.ca>
conifer/integration/evergreen_site.py
conifer/settings.py
conifer/syrup/models.py
conifer/templates/components/site.xhtml

index 8d8be6c..0928191 100644 (file)
@@ -83,10 +83,6 @@ class EvergreenIntegration(object):
     # end of variables dependent on EVERGREEN_SERVER
     # ----------------------------------------------------------------------
 
-    # BIB_PART_MERGE: display multiple parts for one bib title
-    # that have been scanned in separately in one section
-    BIB_PART_MERGE = bool(getattr(settings, 'BIB_PART_MERGE', True))
-
     # OPAC_LANG and OPAC_SKIN: localization skinning for your OPAC
 
     OPAC_LANG = getattr(settings, 'EVERGREEN_OPAC_LANG', 'en-CA')
@@ -98,10 +94,9 @@ class EvergreenIntegration(object):
     # the given item.
 
     RESERVES_DESK_NAME = getattr(settings, 'RESERVES_DESK_NAME', None)
+    BIB_PART_MERGE = getattr(settings, 'BIB_PART_MERGE', None)
+    PART_MERGE = getattr(settings, 'PART_MERGE', None)
 
-    # BIB_PART_MERGE: if True, merge parts under one title
-    BIB_PART_MERGE = getattr(settings, 'BIB_PART_MERGE', False)
-    
     # USE_Z3950: if True, use Z39.50 for catalogue search; if False, use OpenSRF.
     # Don't set this value directly here: rather, if there is a valid Z3950_CONFIG
     # settings in local_settings.py, then Z39.50 will be used.
@@ -224,6 +219,7 @@ class EvergreenIntegration(object):
 
            return objset
 
+        #is current barcode one of identified sets
         def collect_set(barcode,bcs,ids):
            bc_dups = []
            id_dups = []
@@ -238,8 +234,15 @@ class EvergreenIntegration(object):
         #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,bcs,ids):
+        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:
@@ -255,25 +258,36 @@ class EvergreenIntegration(object):
                   thisloc = thisloc.get("name")
 
               #create copy object for supplied barcode - will be all barcodes if none supplied
-              if thisloc in reserves_loc and (barcode==circbarcode or circbarcode in bcs_set):
+              if part_flag:
                   circ_modifier = circinfo.get("circ_modifier")
                   circs = circinfo.get("circulations")
                   parts = circinfo.get("parts")
-                  part_label = ''
-                  part_sort = None
                   part = None
                   if parts:
                       part = parts[0]
-                  if part:
+                  if part and (bib_part_flag or part_flag):
                       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))
 
-           return sorted(copy_list, key=lambda copy: copy.part_sort)
+           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,
@@ -384,6 +398,18 @@ class EvergreenIntegration(object):
 
             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
@@ -431,16 +457,20 @@ class EvergreenIntegration(object):
                         callprefix,callsuffix,callno,voltest,attachtest,vol)
 
                     if version >= 2.1:
+                        #oh-oh, something inconsistent on multiple calls here
+                        #print "called", [prefix,sort_callno,suffix]
+                        #print "org", org
+                        #print "==>", E1(OPENSRF_CN_CALL, bib_id, [prefix,sort_callno,suffix], org)
                         copyids = E1(OPENSRF_CN_CALL, bib_id, [prefix,sort_callno,suffix], org)
                     else:
                         copyids = E1(OPENSRF_CN_CALL, bib_id, sort_callno, org)
 
                     #get copy information
-                    copies = get_copydetails(barcode,copyids,self.RESERVES_DESK_NAME,bcs,ids)
+                    copies, desk, lib = get_copydetails(barcode,copyids,self.RESERVES_DESK_NAME,
+                        self.BIB_PART_MERGE,self.PART_MERGE,bcs,ids)
 
-                    desk = get_desk_counts(counts)
-                    if barcode:
-                        desk = len(copies)
+                    if desk==0:
+                        desk = get_desk_counts(counts)
 
                     avail = desk
                     copy_parts = []
@@ -450,15 +480,7 @@ class EvergreenIntegration(object):
                     # we want to identify the copy that will be returned first if
                     # all are checked out
                     for copy in copies:
-                        #this condition should only ever be true when a multipart is in full display
-                        #in that case, the most available copy should be selected
-                        if len(ids) == 1:
-                            if ids[0][0] == '':
-                                avail = 1 
                         if copy.part_label:
-                            #print "callno", callno
-                            #print "sort_callno", sort_callno
-
                             callno = sort_callno + " " + copy.part_label
                             if copy.part_sort in copy_parts and len(copy_parts) > 0:
                                 #leave alone if locked - otherwise mark as ready
@@ -466,7 +488,7 @@ class EvergreenIntegration(object):
                                     allcalls[len(allcalls) - 1] = [callno,READY,copy.syrup_id,copy.part_label]
                                     
                             else:
-                                allcalls.append([callno,READY,copy.syrup_id,copy.part_label])
+                                allcalls = callparts(callno,READY,copy.syrup_id,copy.part_label,allcalls)
                             copy_parts.append(copy.part_sort)
 
                         bringfw = attachtest
@@ -492,7 +514,6 @@ class EvergreenIntegration(object):
 
                         if copy.circs and isinstance(copy.circs, list):
                             if (earliestdue is None or duetime < earliestdue):
-                                #print "SETTING earliest to", duetime
                                 earliestdue = duetime
                                 dueinfo = time.strftime(self.DUE_FORMAT,earliestdue)
                                 #will want the link to be to the earliest item if not multipart
index 12b9733..d5e1310 100644 (file)
@@ -123,6 +123,10 @@ CAS_AUTHENTICATION       = False
 # one entry on public display
 BIB_PART_MERGE = False
 
+# This flag will merge titles with parts into
+# one entry on public display PER PART -
+# so all V.2s will appear together (for example)
+PART_MERGE = True
 
 #---------------------------------------------------------------------------
 # local_settings.py
index 373c347..8eaeee8 100644 (file)
@@ -3,6 +3,7 @@ import re
 
 from collections                     import defaultdict
 from conifer.libsystems              import marcxml as MX
+from conifer.libsystems.evergreen.support import E1
 from conifer.plumbing.genshi_support import get_request
 from conifer.plumbing.hooksystem     import *
 from datetime                        import datetime, timedelta, date
@@ -20,13 +21,15 @@ from genshi                          import Markup
 # refer to static values in the module.
 
 integration_class = None
+OPENSRF_BARCODE           = "open-ils.search.asset.copy.fleshed2.find_by_barcode"
 
 if hasattr(settings, 'INTEGRATION_CLASS'):
     modname, klassname = settings.INTEGRATION_CLASS.rsplit('.', 1) # e.g. 'foo.bar.baz.MyClass'
     mod = __import__(modname, fromlist=[''])
     integration_class = getattr(mod, klassname)
 
-BIB_PART_MERGE = bool(getattr(settings, 'BIB_PART_MERGE', True))
+BIB_PART_MERGE = bool(getattr(settings, 'BIB_PART_MERGE', False))
+PART_MERGE = bool(getattr(settings, 'PART_MERGE', True))
 
 #----------------------------------------------------------------------
 
@@ -411,7 +414,27 @@ class Site(BaseModel):
                         return True
             return False
 
-        #collect barcodes for dups
+        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 parts_match(bc1,bc2,labels):
+        def parts_match(bc1,bc2):
+            label1 = get_label(bc1)
+            if label1 is not None:
+                label2 = get_label(bc2)
+                if label1 == label2:
+                    #add label to labels
+                    return True
+            return False
+
+        #collect barcodes for titles with same bib id
         def deal_with_dups(item,items,edit_status,barcodes):
             dup_barcodes = []
             dup_ids = []
@@ -419,7 +442,7 @@ class Site(BaseModel):
 
             if item.item_type == 'HEADING':
                 return push_thru, dup_barcodes, dup_ids
-            if not BIB_PART_MERGE or edit_status:
+            if (not BIB_PART_MERGE and not PART_MERGE) or edit_status:
                 return push_thru, dup_barcodes, dup_ids
             if not is_dup_candidate(item):
                 return push_thru, dup_barcodes, dup_ids
@@ -431,31 +454,37 @@ class Site(BaseModel):
                  if is_dup_candidate(display_item):
                      if display_item.barcode != item.barcode:
                          if display_item.bib_id == item.bib_id and display_item.barcode not in dup_barcodes:
-                             dup_barcodes.append(display_item.barcode)
-                             dup_ids.append(display_item.id)
+                             #if BIB_PART_MERGE or (PART_MERGE and parts_match(item.barcode,display_item.barcode,part_labels)):
+                             if BIB_PART_MERGE or (PART_MERGE and parts_match(item.barcode,display_item.barcode)):
+                                 dup_barcodes.append(display_item.barcode)
+                                 dup_ids.append(display_item.id)
 
        
+            #if added, make sure original is there
             if len(dup_barcodes) > 0 and not item.barcode in dup_barcodes:
                 dup_barcodes.append(item.barcode)
                 dup_ids.append(item.id)
 
+            #sort out based on part_labels
             return push_thru, dup_barcodes, dup_ids
 
-        # walk the tree
+        # walk the tree - if bib or part merge flag, collect ids & barcodes for 
+        # same bib or part, and only pass one instance onwards
         out = []
-        out_barcodes = []
-        out_ids = []
         def walk(parent, accum):
+            out_barcodes = []
+            out_ids = []
             here = dct.get(parent, [])
             for item in here:
                 sub = []
                 walk(item, sub)
                 push_thru, bib_barcodes, syrup_ids = deal_with_dups(item,items,edit_status,out_barcodes)
 
-                if len(bib_barcodes) > 0:
-                    out_barcodes.append(bib_barcodes)
-                    out_ids.append(syrup_ids)
-                if push_thru:
+                if len(bib_barcodes) > 0 and bib_barcodes not in accum:
+                    if bib_barcodes not in out_barcodes:
+                        out_barcodes.append(bib_barcodes)
+                        out_ids.append(syrup_ids)
+                if push_thru and bib_barcodes not in accum:
                     accum.append((item, sub, out_barcodes, out_ids))
         walk(subtree, out)
         return out
index 75f72ac..0de8068 100644 (file)
@@ -114,6 +114,7 @@ searchtext = _('search this site...')
             site_url = site_url[:last_slash+1]
 
             display_calls = []
+            lpart = None
             #parts are worth displaying as separate titles but otherwise limit 
             for j,k,l,m in _allcalls:
                 part = ''
@@ -122,8 +123,9 @@ searchtext = _('search this site...')
                 #link to item if provided, otherwise use provided url
                 if l == -1: 
                     display_calls.append([item.item_url(),item,part])
-                elif len(m) > 0 or len(display_calls) == 0:
+                elif (len(m) > 0 and lpart != m) or len(display_calls) == 0:
                     display_calls.append([site_url + str(l),item,part])
+                lpart = m
         ?>
        <span py:if="item.item_type=='ELEC' and not downloads_allowed">
          <img title="Sorry, this document is not available to you."