From: Bill Erickson Date: Tue, 5 Nov 2013 16:08:19 +0000 (-0500) Subject: ff ui : move to all flattener; needs more testing X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=d5b6795b147648f684ef956c9ff8561bdd765dda;p=evergreen%2Fequinox.git ff ui : move to all flattener; needs more testing Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/templates/staff/fulfillment/t_item_table.tt2 b/Open-ILS/src/templates/staff/fulfillment/t_item_table.tt2 index 335e130c4e..7238ee784b 100644 --- a/Open-ILS/src/templates/staff/fulfillment/t_item_table.tt2 +++ b/Open-ILS/src/templates/staff/fulfillment/t_item_table.tt2 @@ -10,10 +10,19 @@ - # + [% l('Request ID') %] + [% l('Transit ID') %] + [% l('Circ ID') %] + [% l('Item Barcode') %] - [% l('Owning Library') %] + [% l('Copy Library') %] + + + [% l('Request Date') %] + [% l('Expire Date') %] + [% l('Requesting Library') %] + [% l('Pickup Library') %] [% l('Transit Date') %] @@ -39,18 +48,29 @@ {{item.index + 1}} + + {{item.hold_id}} + {{item.transit_id}} + {{item.circ_id}} + - {{item.item_barcode}} + href="./fulfillment/status/{{item.copy_barcode_enc}}"> + {{item.copy_barcode}} - {{item.source_lib}} + {{item.copy_circ_lib}} + + {{item.request_time | date}} + {{item.expire_time | date}} + {{item.request_lib}} + {{item.pickup_lib}} + {{item.transit_time | date}} {{item.transit_source}} {{item.transit_dest}} {{item.hold_shelf_time | date}} - {{item.patron_name}} - {{item.patron_card}} - {{item.circ_xact_start | date}} + {{item.patron_given_name}} {{item.patron_family_name}} + {{item.patron_barcode}} + {{item.xact_start | date}} {{item.due_date | date}} {{item.circ_circ_lib}} {{item.title}} diff --git a/Open-ILS/src/templates/staff/fulfillment/t_pending.tt2 b/Open-ILS/src/templates/staff/fulfillment/t_pending.tt2 index 0ba6995729..614a6ac970 100644 --- a/Open-ILS/src/templates/staff/fulfillment/t_pending.tt2 +++ b/Open-ILS/src/templates/staff/fulfillment/t_pending.tt2 @@ -21,6 +21,9 @@
+
+ + diff --git a/Open-ILS/web/js/ui/default/staff/fulfillment/app.js b/Open-ILS/web/js/ui/default/staff/fulfillment/app.js index f9d6db5a2d..2766c06838 100644 --- a/Open-ILS/web/js/ui/default/staff/fulfillment/app.js +++ b/Open-ILS/web/js/ui/default/staff/fulfillment/app.js @@ -2,6 +2,7 @@ * TODO: * Instead of making pcrud calls, followed by per-item server calls, * consider a server-side API for all of this stuff for speed, etc. + * OR consider using all flattener-based calls. * * Consolidate the various item structures into one common, * authoritative structure for display and print templates. @@ -115,7 +116,6 @@ function ($scope, $route, egStartup, orgSelector, egAuth, egUser) { egAuth.logout(); return true; }; - }]) @@ -144,142 +144,119 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, $scope.illRouteParams = $routeParams; $scope.itemList = egList.create({limit : 10}); // limit TBD - - // apply some local list additions - $scope.itemList.addItem = function(item) { - // TODO: id version - item.index = $scope.itemList.count() - $scope.itemList.items.push(item); - egNet.request( - 'open-ils.circ', - 'open-ils.circ.item.transaction.disposition', - egAuth.token(), - orgSelector.current().id(), - item.barcode - ).then(function(items) { - if (items[0]) { - $scope.itemList.flattenItem(item, items[0]); - } else { - $scope.itemList.items.pop().not_found = true; - } - }); - } - - // given an item disposition blob, flatten it for display - $scope.itemList.flattenItem = function(item, item_data) { - /* - * TODO: most of this is unnecessary, since we can access - * fields directly in the template. Consider pairing - * this down to fields that need munging only - */ - var copy = item_data.copy; - var transit = item_data.transit; - var circ = item_data.circ; - var hold = item_data.hold; - if (hold) { - if (!transit && hold.transit()) { - transit = item_data.hold.transit(); - } - } else if (transit && transit.hold_transit_copy()) { - hold = transit.hold_transit_copy().hold(); - } - - item.copy = item_data.copy; - item.item_barcode = copy.barcode(); - item.item_barcode_enc = encodeURIComponent(copy.barcode()); - item.source_lib = egOrg.get(copy.source_lib()).shortname(); - item.circ_lib = egOrg.get(copy.circ_lib()).shortname(); - item.title = copy.call_number().record().simple_record().title(); - item.author = copy.call_number().record().simple_record().author(); - item.call_number = copy.call_number().label(); - item.bib_id = copy.call_number().record().id(); - item.remote_bib_id = copy.call_number().record().remote_id(); - item.next_action = item_data.next_action; - item.can_cancel_hold = (item_data.can_cancel_hold == 1); - item.can_retarget_hold = (item_data.can_retarget_hold == 1); - - switch(item_data.next_action) { - // capture lender copy for hold - case 'ill-home-capture' : - item.needs_capture = true; - break; - // receive item at borrower - case 'ill-foreign-receive': - // receive lender copy back home - case 'transit-home-receive': - // transit item for cancelled hold back home (or next hold) - case 'transit-foreign-return': - item.needs_receive = true; - break; - // complete borrower circ, transit item back home - case 'ill-foreign-checkin': - item.needs_checkin = true; - break; - // check out item to borrowing patron - case 'ill-foreign-checkout': - item.needs_checkout = true; - break; - } - - item.status_str = copy.status().name(); - if (copy.status().id() == 8 /* holds shelf */ && - hold && - hold.transit() && - hold.transit().dest_recv_time()) { - item.status_str += ' @ ' + egOrg.get(hold.transit().dest()).shortname(); - } else if (copy.status().id() == 1 /* checked out */ && circ) { - item.status_str += ' @ ' + egOrg.get(circ.circ_lib()).shortname(); + + // map of flattener fields to retrieve for each query type + $scope.flatFields = { + ahr : { + id : {path : 'id'}, + hold_id : {path : 'id'}, + request_time : {path : 'request_time'}, + expire_time : {path : 'expire_time'}, + patron_id : {path : 'usr.id'}, + patron_barcode : {path : 'usr.card.barcode'}, + patron_given_name : {path : 'usr.first_given_name'}, + patron_family_name : {path : 'usr.family_name'}, + request_lib : {path : 'request_lib.shortname'}, // TODO: causes query problem, wha? + pickup_lib : {path : 'pickup_lib.shortname'}, + title : {path : 'bib_rec.bib_record.simple_record.title'}, + author : {path : 'bib_rec.bib_record.simple_record.author'}, + copy_id : {path : 'current_copy.id'}, + copy_status : {path : 'current_copy.status.name'}, + copy_barcode : {path : 'current_copy.barcode'}, + copy_circ_lib : {path : 'current_copy.circ_lib.shortname'}, + call_number : {path : 'current_copy.call_number.label'} + }, + circ : { + id : {path : 'id'}, + circ_id : {path : 'id'}, + patron_id : {path : 'usr.id'}, + patron_barcode : {path : 'usr.card.barcode'}, + patron_given_name : {path : 'usr.first_given_name'}, + patron_family_name : {path : 'usr.family_name'}, + title : {path : 'target_copy.call_number.record.simple_record.title'}, + author : {path : 'target_copy.call_number.record.simple_record.author'}, + copy_id : {path : 'target_copy.id'}, + copy_status : {path : 'target_copy.status.name'}, + copy_barcode : {path : 'target_copy.barcode'}, + copy_circ_lib : {path : 'target_copy.circ_lib.shortname'}, + call_number : {path : 'target_copy.call_number.label'}, + circ_circ_lib : {path : 'circ_lib.shortname'}, + due_date : {path : 'due_date'}, + xact_start : {path : 'xact_start'}, + checkin_time : {path : 'checkin_time'} + }, + atc : { + id : {path : 'id'}, + transit_id : {path : 'id'}, + hold_id : {path : 'hold_transit_copy.hold.id'}, + request_lib : {path : 'hold_transit_copy.hold.request_lib'}, + pickup_lib : {path : 'hold_transit_copy.hold.pickup_lib.shortname'}, + patron_id : {path : 'hold_transit_copy.hold.usr.id'}, + patron_barcode : {path : 'hold_transit_copy.hold.usr.card.barcode'}, + patron_given_name : {path : 'hold_transit_copy.hold.usr.first_given_name'}, + patron_family_name : {path : 'hold_transit_copy.hold.usr.family_name'}, + title : {path : 'target_copy.call_number.record.simple_record.title'}, + author : {path : 'target_copy.call_number.record.simple_record.author'}, + copy_status : {path : 'target_copy.status.name'}, + copy_id : {path : 'target_copy.id'}, + copy_barcode : {path : 'target_copy.barcode'}, + copy_circ_lib : {path : 'target_copy.circ_lib.shortname'}, + call_number : {path : 'target_copy.call_number.label'}, + transit_time : {path : 'source_send_time'}, + transit_source : {path : 'source.shortname'}, + transit_dest : {path : 'dest.shortname'} } + }; - item.copy_status_warning = (copy.status().holdable() == 'f'); + // set display=true for each flattener field + angular.forEach($scope.flatFields, function(val) { + angular.forEach(val, function(val2) { + val2.display = true; + }); + }); - if (transit) { - item.transit = transit; - item.transit_source = transit.source().shortname(); - item.transit_dest = transit.dest().shortname(); - item.transit_time = transit.source_send_time(); - item.transit_recv_time = transit.dest_recv_time(); - item.open_transit = !Boolean(transit.dest_recv_time()); + $scope.setCollector = function(class_, query) { + $scope.collector = { + query : query, + class_ : class_ } + } - if (circ) { - item.circ = circ; - item.due_date = circ.due_date(); - item.circ_circ_lib = egOrg.get(circ.circ_lib()).shortname(); - item.circ_xact_start = circ.xact_start(); - item.circ_stop_fines = circ.stop_fines(); - // FF patrons will all have cards, but some test logins may not - item.patron_card = circ.usr().card() ? - circ.usr().card().barcode() : circ.usr().usrname(); - item.patron_name = circ.usr().first_given_name() + ' ' + circ.usr().family_name() // i18n - item.can_mark_lost = (item.circ && item.copy.status().id() == 1); // checked out - } + $scope.setMunger = function(func) { + $scope.munger = func; + } - if (hold) { - item.hold = hold; - item.patron_card = hold.usr().card() ? - hold.usr().card().barcode() : hold.usr().usrname(); - item.patron_name = hold.usr().first_given_name() + ' ' + hold.usr().family_name() // i18n - item.hold_request_lib = egOrg.get(hold.request_lib()).shortname(); - item.hold_pickup_lib = egOrg.get(hold.pickup_lib()).shortname(); - item.hold_request_time = hold.request_time(); - item.hold_capture_time = hold.capture_time(); - item.hold_shelf_time = hold.shelf_time(); - if (hold.cancel_time()) { - item.hold_cancel_time = hold.cancel_time(); - if (hold.cancel_cause()) { - item.hold_cancel_cause = hold.cancel_cause().label(); + $scope.collect = function() { + $scope.lookupComplete = false; + $scope.itemList.items = []; + egNet.request( + 'open-ils.fielder', + 'open-ils.fielder.flattened_search', + egAuth.token(), + $scope.collector.class_, + $scope.flatFields[$scope.collector.class_], + $scope.collector.query, + { sort : [$scope.itemList.sort], + limit : $scope.itemList.limit, + offset : $scope.itemList.offset + } + ).then( + null, // success/oncomplete + null, // error + function(item) { // notify/onresponse handler + $scope.lookupComplete = true; + item.index = $scope.itemList.count(); + if (item.copy_barcode) { + item.copy_barcode_enc = + encodeURIComponent(item.copy_barcode); } + if ($scope.munger) $scope.munger(item); + $scope.itemList.items.push(item); } - } - - // TODO: another unnecessary layer of data munging, - // this time to fit the print templates. Can be unified. - item.barcode = item.item_barcode; - item.status = item.status_str; - item.item_circ_lib = item.circ_lib; + ); } + /* Actions * Performed on flattened items (see above) */ @@ -293,7 +270,7 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, 'open-ils.circ.checkin.override', egAuth.token(), { circ_lib : orgSelector.current().id(), - copy_id: item.copy.id(), + copy_id: item.copy_id, ff_action: item.next_action } ).then(function(response) { @@ -321,8 +298,8 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, 'open-ils.circ.checkout.full.override', egAuth.token(), { circ_lib : orgSelector.current().id(), - patron_id : item.hold.usr().id(), - copy_id: item.copy.id(), + patron_id : item.user_id, + copy_id: item.copy_id, ff_action: item.next_action } ).then(function(response) { @@ -348,7 +325,7 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, $scope.action_pending = true; egNet.request( 'open-ils.circ', 'open-ils.circ.hold.cancel', - egAuth.token(), item.hold.id() + egAuth.token(), item.hold_id ).then(function() { $scope.action_pending = false; deferred.resolve(); @@ -361,7 +338,7 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, $scope.action_pending = true; egNet.request( 'open-ils.circ', 'open-ils.circ.hold.reset', - egAuth.token(), item.hold.id() + egAuth.token(), item.hold_id ).then(function() { $scope.action_pending = false; deferred.resolve(); @@ -374,7 +351,7 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, $scope.action_pending = true; egNet.request( 'open-ils.circ', 'open-ils.circ.transit.abort', - egAuth.token(), {transitid : item.transit.id()} + egAuth.token(), {transitid : item.transit_id} ).then(function() { $scope.action_pending = false; deferred.resolve(); @@ -407,6 +384,12 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, (item.circ ? 'circ' : (item.transit ? 'transit' : 'copy')); + // TODO: line up print template variables with + // local data structures + item.barcode = item.copy_barcode || item.item_barcode; + item.status = item.status_str || item.copy_status; + item.item_circ_lib = item.copy_circ_lib || item.circ_lib; + egNet.request( 'open-ils.actor', 'open-ils.actor.web_action_print_template.fetch', @@ -452,7 +435,23 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, }; // default batch action handlers. - // when a batch is done, reload the route (unless printing). + // when a batch is done, reload the route, unless printing. + + function performAction(action, item) { + console.debug(item.index + ' => ' + action); + $scope.actions[action](item).then( + // when all items are done processing, reload the route + function(resp) { + console.debug(item.index + ' => ' + action + ' : done'); + if (--total == 0 && action != 'print') + $route.reload() + }, + function(resp) { + console.error("error in " + action + ": " + resp); + } + ); + } + angular.forEach( Object.keys($scope.actions), function(action) { @@ -462,228 +461,316 @@ function ($scope, $q, $compile, $timeout, $rootScope, $location, function(val, idx) { var item = $scope.itemList.items.filter( function(i) {return i.index == idx})[0]; - console.debug(item.index + ' => ' + action); - $scope.actions[action](item).then( - // when all items are done processing, reload the route - function(resp) { - console.debug(item.index + ' => ' + action + ' : done'); - if (--total == 0 && action != 'print') - $route.reload() - }, - function(resp) { - console.error("error in " + action + ": " + resp); - } - ); + performAction(action, item) } ); }; } ); - // data collection and pagination - - // collector function collects the list of items - // and calls itemList.addItem for each one. - $scope.setCollector = function(colFn) { - $scope.collector = colFn; - } - $scope.firstPage = function() { $scope.itemList.offset = 0; - $scope.collector(); + $scope.collect(); }; $scope.nextPage = function() { $scope.itemList.incrementPage(); - $scope.collector(); + $scope.collect(); }; $scope.prevPage = function() { $scope.itemList.decrementPage(); - $scope.collector(); + $scope.collect(); }; }]) -.controller('TransitsCtrl', - ['$scope','$q','egPCRUD','orgSelector', -function ($scope, $q, egPCRUD, orgSelector) { +.controller('PendingRequestsCtrl', + ['$scope','$q','$route','egNet','egAuth','egPCRUD','egOrg','orgSelector', +function ($scope, $q, $route, egNet, egAuth, egPCRUD, egOrg, orgSelector) { - $scope.setCollector(function() { - $scope.itemList.items = []; - $scope.lookupComplete = false; + $scope.itemList.sort = 'request_time'; - var fullPath = orgSelector.relatedOrgs(); + var fullPath = orgSelector.relatedOrgs(); - var dest = fullPath; // inbound transits - var circ_lib = fullPath; // our copies + var query = { + capture_time : null, + cancel_time : null, + frozen : 'f' + }; - if ($scope.orientation_borrower) { - // borrower always means not-our-copies - circ_lib = {'not in' : fullPath}; - } - if ($scope.tab_outbound) { - // outbound transits away from "here" - dest = {'not in' : fullPath}; + if ($scope.orientation_borrower) { + // holds for my patrons originate "here" + // current_copy is not relevant + query.request_lib = fullPath; + } else { + // holds for other originate from not-"here" and + // have a current copy at "here". + query.request_lib = {'not in' : fullPath}; + query.current_copy = { + "in" : { + select: {acp : ['id']}, + from : 'acp', + where: { + deleted : 'f', + circ_lib : fullPath, + id : {'=' : {'+ahr' : 'current_copy'}} + } + } } - - var query = { - dest_recv_time : null, - dest : dest, - target_copy : { - 'in' : { - select: {acp : ['id']}, - from : 'acp', - where : { - deleted : 'f', - id : {'=' : {'+atc' : 'target_copy'}}, - circ_lib : circ_lib - } + } + + $scope.setCollector('ahr', query); + $scope.setMunger(function(item) { + if ($scope.orientation_lender) + item.next_action = 'ill-home-capture'; + }); + + $scope.collect(); +}]) + + +.controller('TransitsCtrl', + ['$scope','$q','egPCRUD','orgSelector', +function ($scope, $q, egPCRUD, orgSelector) { + + $scope.itemList.sort = 'transit_time'; + var fullPath = orgSelector.relatedOrgs(); + var dest = fullPath; // inbound transits + var circ_lib = fullPath; // our copies + + if ($scope.orientation_borrower) { + // borrower always means not-our-copies + circ_lib = {'not in' : fullPath}; + } + if ($scope.tab_outbound) { + // outbound transits away from "here" + dest = {'not in' : fullPath}; + } + + var query = { + dest_recv_time : null, + dest : dest, + target_copy : { + 'in' : { + select: {acp : ['id']}, + from : 'acp', + where : { + deleted : 'f', + id : {'=' : {'+atc' : 'target_copy'}}, + circ_lib : circ_lib } } - }; - - return egPCRUD.search('atc', query, - { limit : $scope.itemList.limit, - offset : $scope.itemList.offset, - flesh : 1, - flesh_fields : {atc : ['target_copy']}, - order_by : {'atc' : 'source_send_time, id'} - }, {atomic : true} - ).then(function(transits) { - $scope.lookupComplete = true; - angular.forEach(transits, function(transit) { - $scope.itemList.addItem( - {barcode : transit.target_copy().barcode()}); - }); - }); + } + }; + + $scope.setCollector('atc', query); + $scope.setMunger(function(item) { + if ($scope.tab_inbound) { + if ($scope.orientation_borrower) { + item.next_action = 'ill-foreign-receive'; + } else { + item.next_action = 'transit-home-receive'; + } + } }); - - return $scope.collector(); + + return $scope.collect(); }]) .controller('OnShelfCtrl', ['$scope','$q','egPCRUD','orgSelector', function ($scope, $q, egPCRUD, orgSelector) { - $scope.setCollector(function() { - $scope.itemList.items = []; - $scope.lookupComplete = false; + $scope.itemList.sort = 'shelf_time'; - var fullPath = orgSelector.relatedOrgs(); + var fullPath = orgSelector.relatedOrgs(); - var copy_lib = {'not in' : fullPath}; // not our copy - var shelf_lib = fullPath; // on our shelf + var copy_lib = {'not in' : fullPath}; // not our copy + var shelf_lib = fullPath; // on our shelf - if ($scope.orientation_lender) { - shelf_lib = {'not in' : fullPath}; - copy_lib = fullPath; - } - - var query = { - frozen : 'f', - cancel_time : null, - fulfillment_time : null, - shelf_time : {'!=' : null}, - current_shelf_lib : shelf_lib, - current_copy : { - 'in' : { - select: {acp : ['id']}, - from : 'acp', - where : { - deleted : 'f', - id : {'=' : {'+ahr' : 'current_copy'}}, - circ_lib : copy_lib, - status : 8 // On Holds Shelf - } + if ($scope.orientation_lender) { + shelf_lib = {'not in' : fullPath}; + copy_lib = fullPath; + } + + var query = { + frozen : 'f', + cancel_time : null, + fulfillment_time : null, + shelf_time : {'!=' : null}, + current_shelf_lib : shelf_lib, + current_copy : { + 'in' : { + select: {acp : ['id']}, + from : 'acp', + where : { + deleted : 'f', + id : {'=' : {'+ahr' : 'current_copy'}}, + circ_lib : copy_lib, + status : 8 // On Holds Shelf } } - }; - - return egPCRUD.search('ahr', query, - { limit : $scope.itemList.limit, - offset : $scope.itemList.offset, - flesh : 1, - flesh_fields : {ahr : ['current_copy']}, - order_by : {ahr : 'request_time, id'} - }, {atomic : true} - ).then(function(holds) { - $scope.lookupComplete = true; - angular.forEach(holds, function(hold) { - $scope.itemList.addItem( - {barcode : hold.current_copy().barcode()}); - }); - }); + } + }; + + $scope.setCollector('ahr', query); + $scope.setMunger(function(item) { + if ($scope.orientation_borrower) { + item.next_action = 'ill-foreign-checkout'; + } }); - - // outbound tab defaults to lender view - return $scope.collector(); -}]) + return $scope.collect(); +}]) .controller('CircCtrl', - ['$scope','$q','egPCRUD','orgSelector', -function ($scope, $q, egPCRUD, orgSelector) { + ['$scope','$q','egPCRUD','orgSelector','egNet','egAuth', +function ($scope, $q, egPCRUD, orgSelector, egNet, egAuth) { - $scope.setCollector(function() { - $scope.itemList.items = []; - $scope.lookupComplete = false; + $scope.itemList.sort = 'xact_start'; - var fullPath = orgSelector.relatedOrgs(); + var fullPath = orgSelector.relatedOrgs(); - var copy_lib = fullPath; // our copies - var circ_lib = fullPath; // circulating here + var copy_circ_lib = fullPath; // our copies + var circ_circ_lib = fullPath; // circulating here - if ($scope.orientation_lender) { - // borrower always means not-our-copies - circ_lib = {'not in' : fullPath}; - } else { - copy_lib = {'not in' : fullPath}; - } - - var query = { - checkin_time : null, - circ_lib : circ_lib, - target_copy : { - 'in' : { - select: {acp : ['id']}, - from : 'acp', - where : { - deleted : 'f', - id : {'=' : {'+circ' : 'target_copy'}}, - circ_lib : copy_lib - } + if ($scope.orientation_lender) { + // circulating elsewhere + circ_circ_lib = {'not in' : fullPath}; + } else { + // borrower always means not-our-copies + copy_circ_lib = {'not in' : fullPath}; + } + + var query = { + checkin_time : null, + circ_lib : circ_circ_lib, + target_copy : { + 'in' : { + select: {acp : ['id']}, + from : 'acp', + where : { + deleted : 'f', + id : {'=' : {'+circ' : 'target_copy'}}, + circ_lib : copy_circ_lib } } - }; - - return egPCRUD.search('circ', query, - { limit : $scope.itemList.limit, - offset : $scope.itemList.offset, - flesh : 1, - flesh_fields : {circ : ['target_copy']}, - order_by : {'circ' : 'xact_start, id'} - }, {atomic : true} - ).then(function(circs) { - $scope.lookupComplete = true; - angular.forEach(circs, function(circ) { - $scope.itemList.addItem( - {barcode : circ.target_copy().barcode()}); - }); - }); + } + }; + + $scope.setCollector('circ', query); + $scope.setMunger(function(item) { + if ($scope.orientation_borrower) { + item.next_action = 'ill-foreign-checkin'; + } }); - - // outbound tab defaults to lender view - return $scope.collector(); + + return $scope.collect(); }]) .controller('ItemStatusCtrl', - ['$scope','$q','$route','$location','egPCRUD','orgSelector', -function ($scope, $q, $route, $location, egPCRUD, orgSelector) { + ['$scope','$q','$route','$location','egPCRUD','orgSelector','egNet','egAuth','egOrg', +function ($scope, $q, $route, $location, egPCRUD, orgSelector, egNet, egAuth, egOrg) { $scope.focusMe = true; + // TODO: can we trim this down? + function flattenItem(item, item_data) { + var copy = item_data.copy; + var transit = item_data.transit; + var circ = item_data.circ; + var hold = item_data.hold; + if (hold) { + if (!transit && hold.transit()) { + transit = item_data.hold.transit(); + } + } else if (transit && transit.hold_transit_copy()) { + hold = transit.hold_transit_copy().hold(); + } + + item.copy = item_data.copy; + item.item_barcode = copy.barcode(); + item.item_barcode_enc = encodeURIComponent(copy.barcode()); + item.source_lib = egOrg.get(copy.source_lib()).shortname(); + item.circ_lib = egOrg.get(copy.circ_lib()).shortname(); + item.title = copy.call_number().record().simple_record().title(); + item.author = copy.call_number().record().simple_record().author(); + item.call_number = copy.call_number().label(); + item.bib_id = copy.call_number().record().id(); + item.remote_bib_id = copy.call_number().record().remote_id(); + item.next_action = item_data.next_action; + item.can_cancel_hold = (item_data.can_cancel_hold == 1); + item.can_retarget_hold = (item_data.can_retarget_hold == 1); + + switch(item_data.next_action) { + // capture lender copy for hold + case 'ill-home-capture' : + item.needs_capture = true; + break; + // receive item at borrower + case 'ill-foreign-receive': + // receive lender copy back home + case 'transit-home-receive': + // transit item for cancelled hold back home (or next hold) + case 'transit-foreign-return': + item.needs_receive = true; + break; + // complete borrower circ, transit item back home + case 'ill-foreign-checkin': + item.needs_checkin = true; + break; + // check out item to borrowing patron + case 'ill-foreign-checkout': + item.needs_checkout = true; + break; + } + + item.status_str = copy.status().name(); + item.copy_status_warning = (copy.status().holdable() == 'f'); + + if (transit) { + item.transit = transit; + item.transit_source = transit.source().shortname(); + item.transit_dest = transit.dest().shortname(); + item.transit_time = transit.source_send_time(); + item.transit_recv_time = transit.dest_recv_time(); + item.open_transit = !Boolean(transit.dest_recv_time()); + } + + if (circ) { + item.circ = circ; + item.due_date = circ.due_date(); + item.circ_circ_lib = egOrg.get(circ.circ_lib()).shortname(); + item.circ_xact_start = circ.xact_start(); + item.circ_stop_fines = circ.stop_fines(); + // FF patrons will all have cards, but some test logins may not + item.patron_card = circ.usr().card() ? + circ.usr().card().barcode() : circ.usr().usrname(); + item.patron_name = circ.usr().first_given_name() + ' ' + circ.usr().family_name() // i18n + item.can_mark_lost = (item.circ && item.copy.status().id() == 1); // checked out + } + + if (hold) { + item.hold = hold; + item.patron_card = hold.usr().card() ? + hold.usr().card().barcode() : hold.usr().usrname(); + item.patron_name = hold.usr().first_given_name() + ' ' + hold.usr().family_name() // i18n + item.hold_request_lib = egOrg.get(hold.request_lib()).shortname(); + item.hold_pickup_lib = egOrg.get(hold.pickup_lib()).shortname(); + item.hold_request_time = hold.request_time(); + item.hold_capture_time = hold.capture_time(); + item.hold_shelf_time = hold.shelf_time(); + if (hold.cancel_time()) { + item.hold_cancel_time = hold.cancel_time(); + if (hold.cancel_cause()) { + item.hold_cancel_cause = hold.cancel_cause().label(); + } + } + } + } + $scope.draw = function(barcode) { if ($scope.illRouteParams.barcode != barcode) { // keep the scan box and URL in sync @@ -691,9 +778,20 @@ function ($scope, $q, $route, $location, egPCRUD, orgSelector) { encodeURIComponent(barcode)); } else { $scope.itemList.items = []; - $scope.item = {barcode : barcode}; - $scope.itemList.addItem($scope.item); + $scope.item = {index : 0, barcode : barcode}; $scope.selectMe = true; + $scope.itemList.items.push($scope.item); + egNet.request( + 'open-ils.circ', + 'open-ils.circ.item.transaction.disposition', + egAuth.token(), orgSelector.current().id(), barcode + ).then(function(items) { + if (items[0]) { + flattenItem($scope.item, items[0]); + } else { + $scope.itemList.items.pop().not_found = true; + } + }); } } @@ -717,122 +815,6 @@ function ($scope, $q, $route, $location, egPCRUD, orgSelector) { } }]) - - -/** - * Table of pending requests - * This is the only table based purely on holds instead of items, - * so the data is managed a little differently. - */ -.controller('PendingRequestsCtrl', - ['$scope','$q','$route','egNet','egAuth','egPCRUD','egOrg','orgSelector', -function ($scope, $q, $route, egNet, egAuth, egPCRUD, egOrg, orgSelector) { - - $scope.itemList.sort = 'request_time'; - - $scope.drawTable = function() { - $scope.itemList.items = []; - $scope.lookupComplete = false; - - var fullPath = orgSelector.relatedOrgs(); - - var query = { - capture_time : null, - cancel_time : null, - frozen : 'f' - }; - - if ($scope.orientation_borrower) { - // holds for my patrons originate "here" - // current_copy is not relevant - query.request_lib = fullPath; - } else { - // holds for other originate from not-"here" and - // have a current copy at "here". - query.request_lib = {'not in' : fullPath}; - query.current_copy = { - "in" : { - select: {acp : ['id']}, - from : 'acp', - where: { - deleted : 'f', - circ_lib : fullPath, - id : {'=' : {'+ahr' : 'current_copy'}} - } - } - } - } - - // circ_lib and request_lib are retrieved as IDs since - // our query blob assumes they are IDs - var fields = { - id : {path : 'id'}, - request_time : {path : 'request_time'}, - expire_time : {path : 'expire_time'}, - patron_barcode : {path : 'usr.card.barcode'}, - patron_given_name : {path : 'usr.first_given_name'}, - patron_family_name : {path : 'usr.family_name'}, - request_lib : {path : 'request_lib'}, - pickup_lib : {path : 'pickup_lib.shortname'}, - title : {path : 'bib_rec.bib_record.simple_record.title'}, - author : {path : 'bib_rec.bib_record.simple_record.author'}, - copy_barcode : {path : 'current_copy.barcode'}, - circ_lib : {path : 'current_copy.circ_lib'}, - call_number : {path : 'current_copy.call_number.label'} - }; - angular.forEach(fields, function(f) { f.display = true }); - - egNet.request( - 'open-ils.fielder', - 'open-ils.fielder.flattened_search', - egAuth.token(), "ahr", fields, - query, - { sort : [$scope.itemList.sort], - limit : $scope.itemList.limit, - offset : $scope.itemList.offset - } - ).then( - null, // success - null, // error - function(hold) { // notify handler - $scope.lookupComplete = true; - hold.index = $scope.itemList.count(); - - hold.request_lib = egOrg.get(hold.request_lib).shortname(); - if (hold.circ_lib) { - hold.circ_lib = egOrg.get(hold.circ_lib).shortname(); - hold.copy_barcode_enc = encodeURIComponent(hold.copy_barcode); - } - - if ($scope.orientation_lender) - hold.next_action = 'ill-home-capture'; - - // we don't use itemList.addItem(), - // since we're managing our own data fetching - $scope.itemList.items.push(hold); - } - ); - } - - - $scope.firstPage = function() { - $scope.itemList.offset = 0; - $scope.drawTable(); - }; - - $scope.nextPage = function() { - $scope.itemList.incrementPage(); - $scope.drawTable(); - }; - - $scope.prevPage = function() { - $scope.itemList.decrementPage(); - $scope.drawTable(); - }; - - $scope.drawTable(); -}]) - // http://stackoverflow.com/questions/17629126/how-to-upload-a-file-using-angularjs-like-the-traditional-way .factory('formDataObject', function() { return function(data) {