Streamlining spine label workflow through ALMA API

Bernardo Gomez, Laura Trittin
Emory University
Atlanta - Georgia USA

SpineOMatic: Windows application that works with Ex Libris' Alma to print spine labels, pocket labels, flag slips and other custom labels.

Documentation

Problem to tackle: Last step in producing spine labels is setting the item's final ALMA location.

Setting the final ALMA location involves removing two work orders.

Two work orders because process involves two departments: "Technical Services" and "Circulation Desk"

Removing the work orders for a given barcode:

Scan in #1: set Current location to "Technical Services"

Scan in #2: set Current location to "Circulation"

Scanning a batch of 150 barcodes takes 3 and 1/2 hours.

    Removing work orders through API

  • Step #1: Capture barcodes from SpineOMatic

  • Step #2: Drop text file with barcodes into Webform

  • Step #3: Open email with results produced by Webform

Capture barcodes from SpineOMatic

Assign name to batch (User field)batch-name

Drop text file with barcodes in webform

Screenshot

Read email attachment with results

Processing time via ALMA API: 150 barcodes in 8 minutes

Web service highlights

Configuration file:
                  
alma_url=https://api-na.hosted.exlibrisgroup.com/almaws/v1/items?item_barcode=
apikey_get=your-api-key
apikey_post=your-api-key
secretword=xxxxxx
max_file_size=400000
sys_email=xxxxx@emory.edu
directory=pathto/webserver/integrations/spines
file_prefix=spine_result_list_
form_file=/sirsi/webserver/docs/finish_spine_process.html
library_step1=UNIV
circ_desk_step2=DEFAULT_CIRC_DESK
department=AcqDeptUNIV
wo_type=AcqWorkOrder
                  
                  

Web service highlights

Process webform
                   

def process_form(form_file, max_file_size,result_file,source_file,url,apikey_get,apikey_post,mail_list,library_step1,circ_desk_step2,department,wo_type):
  """
     it receives all the fields from the web form
     and additional variables to perform the
     ALMA operations via the ALMA API.
  """
  if source_file.file:
    in_string=source_file.file.read()
    source_file.file.close()
    lines=in_string.split("\n")
    list=[]
    excel_buster="' "
    for barcode in lines:
      if barcode == "":
         continue
      try:
            int(barcode)
      except:
          list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"barcode is not an integer"+""+delim+"\n")
          continue

      api_url=url+str(barcode)
   ###  validate barcode via
   ###  https://api-na.hosted.exlibrisgroup.com/almaws/v1/items?item_barcode=&apikey= 
      item_url,outcome=get_record_info(api_url,apikey_get)
      if outcome == 0:
  ##  process xml string
            library=library_step1
            circ_desk=""
            done="true"
            place_on_hold_shelf="false"
            confirm="false"
            register="false"
            auto_print_slip="false"
            register_in_house_use="false"
            response,outcome=scan_item_step1(item_url,apikey_post,library,department,wo_type,done,auto_print_slip,place_on_hold_shelf,confirm,register)
            if outcome == 0:
                library,outcome=get_owning_library(response)
                if outcome == 0:
                   circ_desk=circ_desk_step2
                   done="false"
                   response,outcome=scan_item_step2(item_url,apikey_post,library,circ_desk,done,auto_print_slip,place_on_hold_shelf,confirm,register)
                   if outcome == 0:
                      result_description,outcome=get_additional_info(response)
                      if outcome == 0:
                         list.append(excel_buster+str(barcode)+delim+"OK"+delim+str(result_description)+delim+""+delim+"\n")
                      else:
                         list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"couldn't parse result from second scan"+delim+"report to core-services"+delim+"\n")
                  else:
                        list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"second scan failed"+delim+"report to core-services"+delim+"\n")
               else:
                   list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"couldn't get library code"+delim+"report to core-services"+delim+"\n")
           else:
               list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"first scan failed"+delim+"report to core-services"+delim+"\n")
      else:
           list.append(excel_buster+str(barcode)+delim+"ERROR"+delim+"bad barcode"+delim+"correct barcode"+delim+"\n")
      
      ### email result next...
      return 0

def scan_item_step1(item_url,apikey,library,department,wo_type,done,auto_print_slip,place_on_hold_shelf,confirm,register):
   """
     this function performs a SCAN operation.
   """
   response=""
   outcome=1
   headers={ 'Content-Type':'application/xml'}
   payload={'op':'SCAN','external_id':'false', 'library':library,'done':done,'auto_print_slip':auto_print_slip,'place_on_hold_shelf':place_on_hold_shelf,'confirm':confirm,'department':department,'work_order_type':wo_type,'register_in_house_use':register,'apikey':apikey}
   try:
      r=requests.post(item_url,params=payload, headers=headers)
   except:
      sys.stderr.write("http request failed:"+url+"\n")
      return "",1
   return_code=r.status_code
   if str(return_code) == "200":
     xml_string=r.content
     return xml_string,0
   else:
       sys.stderr.write("scan step1 failed:"+str(return_code)+" "+r.content+"\n")
       return "",1

def  scan_item_step2(item_url,apikey,library,circ_desk,done,auto_print_slip,place_on_hold_shelf,confirm,register):
   """
      this function performs an ALMA SCAN operation on an item.
   """
   response=""
   outcome=1

   headers={ 'Content-Type':'application/xml'}
   payload={'op':'SCAN','external_id':'false', 'library':library,'done':done,'auto_print_slip':auto_print_slip,'place_on_hold_shelf':place_on_hold_shelf,'confirm':confirm,'circ_desk':circ_desk,'register_in_house_use':register,'apikey':apikey}
   try:
      r=requests.post(item_url,params=payload, headers=headers)
   except:
      return "",1

   return_code=r.status_code
   if str(return_code) == "200":
     xml_string=r.content
     return xml_string,0
   else:
       sys.stderr.write("scan step2 failed:"+str(return_code)+" "+r.content+"\n")
       return "",1
   return "",1
       
           

Web service highlights

Scan-in #2 response
                    
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<item link="https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9936649236002486/holdings/22335968680002486/items/23335968660002486"><bib_data link="https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9936649236002486"><mms_id>9936649236002486</mms_id><title>Advances in ergonomics in design : proceedings of the AHFE 2017 International Conference on Ergonomics in Design, July 17-21, 2017, The Westin Bonaventure Hotel, Los Angeles, California, USA /</title><author>AHFE International Conference on Ergonomics in Design (2017 : Los Angeles, Calif.)</author><isbn>331960581X</isbn><network_numbers><network_number>(OCoLC)994713729</network_number><network_number>ocn994713729</network_number></network_numbers><place_of_publication>Cham, Switzerland :</place_of_publication><publisher_const>Springer</publisher_const></bib_data>
<holding_data link="https://api-na.hosted.exlibrisgroup.com/almaws/v1/bibs/9936649236002486/holdings/22335968680002486"><holding_id>22335968680002486</holding_id><call_number_type desc="Library of Congress classification">0</call_number_type><call_number>T59.7 .A534 2017</call_number><accession_number></accession_number><copy_id></copy_id><in_temp_location>false</in_temp_location><temp_library/><temp_location/><temp_call_number_type></temp_call_number_type><temp_call_number></temp_call_number><temp_policy></temp_policy></holding_data>
<item_data>
<pid>23335968660002486</pid>
<barcode>010003017946</barcode>
<creation_date>2017-08-25Z</creation_date>
<modification_date>2017-08-31Z</modification_date>
<base_status desc="Item in place">1</base_status>
<physical_material_type desc="Book">BOOK</physical_material_type>
<policy></policy><provenance></provenance>
<po_line></po_line>
<is_magnetic>false</is_magnetic>
<year_of_issue></year_of_issue>
<enumeration_a></enumeration_a>
<chronology_i></chronology_i>
<description></description>
<receiving_operator>0009017</receiving_operator>
<process_type></process_type>
<library desc="Robert W. Woodruff Library">UNIV</library>
<location desc="Woodruff Book Stacks">STACK</location>
<alternative_call_number></alternative_call_number>
<alternative_call_number_type></alternative_call_number_type>
<storage_location_id></storage_location_id>
<pages></pages>
<pieces></pieces>
<public_note></public_note>
<fulfillment_note></fulfillment_note>
<internal_note_1></internal_note_1>
<internal_note_2></internal_note_2>
<internal_note_3></internal_note_3>
<statistics_note_1></statistics_note_1>
<statistics_note_2></statistics_note_2>
<statistics_note_3></statistics_note_3>
</item_data>
<additional_info>Item's destination is: Reshelve to Woodruff Book Stacks. Request/Process Type: . Requester: . Requester ID: . Place in Queue: 0</additional_info>
</item>
                   
                   

Acknowledgment: Alex Cooper (helped to debug SCAN API call)

Source code

Thank you!

Questions?