<link field="usr" reltype="has_a" key="id" map="" class="au"/>
</links>
</class>
- <class id="aus" controller="open-ils.cstore" oils_obj:fieldmapper="actor::user_setting" oils_persist:tablename="actor.usr_setting" reporter:label="User Setting">
+ <class id="aus" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::user_setting" oils_persist:tablename="actor.usr_setting" reporter:label="User Setting">
<fields oils_persist:primary="id" oils_persist:sequence="actor.usr_setting_id_seq">
<field reporter:label="Setting ID" name="id" reporter:datatype="id" />
<field reporter:label="Name" name="name" reporter:datatype="link"/>
<link field="name" reltype="has_a" key="name" map="" class="cust"/>
<link field="usr" reltype="has_a" key="id" map="" class="au"/>
</links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <retrieve permission="VIEW_USER">
+ <context link="usr" field="home_ou" />
+ </retrieve>
+ </actions>
+ </permacrud>
</class>
<class id="mafe" controller="open-ils.cstore" oils_obj:fieldmapper="metabib::author_field_entry" oils_persist:tablename="metabib.author_field_entry" reporter:label="Author Field Entry">
<fields oils_persist:primary="id" oils_persist:sequence="metabib.author_field_entry_id_seq">
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
- <retrieve permission="VIEW_USER" context_field="home_ou" />
+ <retrieve permission="VIEW_USER user_request.view" context_field="home_ou" />
</actions>
</permacrud>
</class>
<field reporter:label="Notes" name="notes" reporter:datatype="link" oils_persist:virtual="true"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
<field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
+ <field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="notes" reltype="has_many" key="hold" map="" class="ahrn"/>
<link field="current_shelf_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="sms_carrier" reltype="has_a" key="id" map="" class="csc"/>
+ <link field="acq_request" reltype="has_a" key="id" map="" class="aur"/>
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
<field reporter:label="Shelf Expire Time" name="shelf_expire_time" reporter:datatype="timestamp"/>
<field reporter:label="Notes" name="notes" reporter:datatype="link" oils_persist:virtual="true"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
+ <field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
<field reporter:label="Copy Location Sort Order" name="copy_location_order_position" reporter:datatype="int" />
<field reporter:label="User First Given Name" name="usr_first_given_name" reporter:datatype="text" />
<field reporter:label="User Second Given Name" name="usr_second_given_name" reporter:datatype="text" />
<link field="notes" reltype="has_many" key="hold" map="" class="ahrn"/>
<link field="current_shelf_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="sms_carrier" reltype="has_a" key="id" map="" class="csc"/>
+ <link field="acq_request" reltype="has_a" key="id" map="" class="aur"/>
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
<field reporter:label="Notes" name="notes" reporter:datatype="link" oils_persist:virtual="true"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
<field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
+ <field reporter:label="Acquisition Request" name="acq_request" reporter:datatype="link" />
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<link field="cancel_cause" reltype="might_have" key="id" map="" class="ahrcc"/>
<link field="notes" reltype="has_many" key="hold" map="" class="ahrn"/>
<link field="current_shelf_lib" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="acq_request" reltype="has_a" key="id" map="" class="aur"/>
</links>
</class>
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
- <retrieve permission="VIEW_USER">
+ <retrieve permission="VIEW_USER user_request.view">
<context link="usr" field="home_ou" />
</retrieve>
</actions>
<field reporter:label="Need Before Date/Time" name="need_before" reporter:datatype="timestamp" />
<field reporter:label="Max Acceptable Fee" name="max_fee" reporter:datatype="text" />
<field reporter:label="ISxN" name="isxn" reporter:datatype="text" />
+ <field reporter:label="UPC" name="upc" reporter:datatype="text" />
<field reporter:label="Title" name="title" reporter:datatype="text" />
<field reporter:label="Volume" name="volume" reporter:datatype="text" />
<field reporter:label="Author" name="author" reporter:datatype="text" />
<field reporter:label="Mentioned In" name="mentioned" reporter:datatype="text" />
<field reporter:label="Other Info" name="other_info" reporter:datatype="text" />
<field reporter:label="Cancel Reason" name="cancel_reason" reporter:datatype="link" />
+ <field reporter:label="Cancel Date/Time" name="cancel_time" reporter:datatype="timestamp" />
</fields>
<links>
<link field="usr" reltype="has_a" key="id" map="" class="au"/>
</permacrud>
</class>
+ <class id="aurs" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::user_request_status" reporter:label="User Purchase Request with Status" oils_persist="readonly">
+ <oils_persist:source_definition><![CDATA[
+ SELECT r.*, CASE
+ WHEN r.cancel_reason IS NOT NULL THEN 7 -- Canceled
+ WHEN h.fulfillment_time IS NOT NULL THEN 6 -- Fulfilled
+ WHEN l.state = 'received' THEN 5 -- Received
+ WHEN p.state = 'on-order' AND h.id IS NOT NULL THEN 4 -- Ordered, Hold Placed
+ WHEN p.state = 'on-order' AND h.id IS NULL THEN 3 -- Ordered, Hold Not Placed
+ WHEN l.id IS NOT NULL THEN 2 -- Pending
+ WHEN l.id IS NULL THEN 1 -- New
+ ELSE 0 -- Error
+ END AS request_status
+ ,u.home_ou
+ FROM acq.user_request r
+ JOIN actor.usr u ON (r.usr = u.id)
+ LEFT JOIN acq.lineitem l ON (r.lineitem = l.id)
+ LEFT JOIN acq.purchase_order p ON (l.purchase_order = p.id)
+ LEFT JOIN action.hold_request h ON (h.acq_request = r.id)
+ ]]></oils_persist:source_definition>
+ <fields oils_persist:primary="id">
+ <field reporter:label="ID" name="id" reporter:datatype="id" reporter:selector='label'/>
+ <field reporter:label="User" name="usr" reporter:datatype="link" />
+ <field reporter:label="Request Type" name="request_type" oils_obj:required="true" reporter:datatype="link" />
+ <field reporter:label="Place Hold" name="hold" reporter:datatype="bool" />
+ <field reporter:label="Pickup Library" name="pickup_lib" reporter:datatype="link" />
+ <field reporter:label="Holdable Formats" name="holdable_formats" reporter:datatype="text" />
+ <field reporter:label="Phone Notify" name="phone_notify" reporter:datatype="text" />
+ <field reporter:label="Email Notify" name="email_notify" reporter:datatype="bool" />
+ <field reporter:label="PO Line Item" name="lineitem" reporter:datatype="link" />
+ <field reporter:label="Bib Record" name="eg_bib" reporter:datatype="link" />
+ <field reporter:label="Request Date/Time" name="request_date" reporter:datatype="timestamp" />
+ <field reporter:label="Need Before Date/Time" name="need_before" reporter:datatype="timestamp" />
+ <field reporter:label="Max Acceptable Fee" name="max_fee" reporter:datatype="text" />
+ <field reporter:label="ISxN" name="isxn" reporter:datatype="text" />
+ <field reporter:label="UPC" name="upc" reporter:datatype="text" />
+ <field reporter:label="Title" name="title" reporter:datatype="text" />
+ <field reporter:label="Volume" name="volume" reporter:datatype="text" />
+ <field reporter:label="Author" name="author" reporter:datatype="text" />
+ <field reporter:label="Article Title" name="article_title" reporter:datatype="text" />
+ <field reporter:label="Article Pages" name="article_pages" reporter:datatype="text" />
+ <field reporter:label="Publisher" name="publisher" reporter:datatype="text" />
+ <field reporter:label="Publication Location" name="location" reporter:datatype="text" />
+ <field reporter:label="Publication Date" name="pubdate" reporter:datatype="text" />
+ <field reporter:label="Mentioned In" name="mentioned" reporter:datatype="text" />
+ <field reporter:label="Other Info" name="other_info" reporter:datatype="text" />
+ <field reporter:label="Cancel Reason" name="cancel_reason" reporter:datatype="link" />
+ <field reporter:label="Cancel Date/Time" name="cancel_time" reporter:datatype="timestamp" />
+ <field reporter:label="Request Status" name="request_status" reporter:datatype="link" />
+ <field reporter:label="Home Library" name="home_ou" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="usr" reltype="has_a" key="id" map="" class="au"/>
+ <link field="pickup_lib" reltype="has_a" key="id" map="" class="aou"/>
+ <link field="lineitem" reltype="has_a" key="id" map="" class="jub"/>
+ <link field="eg_bib" reltype="has_a" key="id" map="" class="bre"/>
+ <link field="request_type" reltype="has_a" key="id" map="" class="aurt"/>
+ <link field="cancel_reason" reltype="has_a" key="id" map="" class="acqcr"/>
+ <link field="request_status" reltype="has_a" key="id" map="" class="aurst"/>
+ <link field="home_ou" reltype="has_a" key="id" map="" class="aou"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <retrieve permission="user_request.view">
+ <context link="usr" field="home_ou"/>
+ </retrieve>
+ </actions>
+ </permacrud>
+ </class>
+
+ <class id="aurst" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::user_request_status_type" oils_persist:tablename="acq.user_request_status_type" reporter:label="Acquisition Patron Request Status Type">
+ <fields oils_persist:primary="id">
+ <field reporter:label="Status ID" name="id" reporter:datatype="id" reporter:selector='label'/>
+ <field reporter:label="Status" name="label" reporter:datatype="text" oils_persist:i18n="true" />
+ </fields>
+ <links/>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <retrieve/>
+ </actions>
+ </permacrud>
+ </class>
+
<class id="acqct" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::currency_type" oils_persist:tablename="acq.currency_type" reporter:label="Currency Type">
<fields oils_persist:primary="code">
<field reporter:label="Currency Code" name="code" reporter:datatype="text" reporter:selector='label'/>
next unless ($U->is_true( $request->hold ));
+ my $existing_hold = $mgr->editor->search_action_hold_request(
+ {acq_request => $request->id})->[0];
+ if ($existing_hold) {
+ $logger->warn("Existing hold found where acq_request = $request->id");
+ next;
+ }
+ if (! $li->eg_bib_id) {
+ $logger->error("Hold creation attempt for aur $request->id where li.eg_bib_id is null");
+ next;
+ }
+
my $hold = Fieldmapper::action::hold_request->new;
$hold->usr( $request->usr );
$hold->requestor( $request->usr );
$hold->phone_notify( $request->phone_notify );
$hold->email_notify( $request->email_notify );
$hold->expire_time( $request->need_before );
+ $hold->acq_request( $request->id );
if ($request->holdable_formats) {
my $mrm = $mgr->editor->search_metabib_metarecord_source_map( { source => $li->eg_bib_id } )->[0];
}
}
);
+__PACKAGE__->register_method (
+ method => 'update_user_request',
+ api_name => 'open-ils.acq.user_request.set_yes_hold.batch',
+ stream => 1,
+ signature => {
+ desc => 'Set hold to true for a user request or set of requests',
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'ID or array of IDs for the user requests to modify' }
+ ],
+ return => {
+ desc => 'progress object, event on error',
+ }
+ }
+);
sub update_user_request {
my($self, $conn, $auth, $aur_ids, $cancel_reason) = @_;
if($self->api_name =~ /set_no_hold/) {
if ($U->is_true($aur_obj->hold)) {
- $aur_obj->hold(0);
+ $aur_obj->hold(0); # FIXME - this is not really removing holds per the description
+ $e->update_acq_user_request($aur_obj) or return $e->die_event;
+ }
+ }
+
+ if($self->api_name =~ /set_yes_hold/) {
+ if (!$U->is_true($aur_obj->hold)) {
+ $aur_obj->hold(1);
$e->update_acq_user_request($aur_obj) or return $e->die_event;
}
}
if($self->api_name =~ /cancel/) {
if ( $cancel_reason ) {
$aur_obj->cancel_reason( $cancel_reason );
+ $aur_obj->cancel_time( 'now' );
$e->update_acq_user_request($aur_obj) or return $e->die_event;
create_user_request_events( $e, [ $aur_obj ], 'aur.rejected' );
} else {
}
__PACKAGE__->register_method (
+ method => 'clear_completed_user_requests',
+ api_name => 'open-ils.acq.clear_completed_user_requests',
+ stream => 1,
+ signature => {
+ desc => q/
+ Auto-cancel the specified user requests if they are complete.
+ Completed is defined as having either a Request Status of Fulfilled
+ (which happens when the request is not Canceled and has an associated
+ hold request that has a fulfillment time), or having a Request Status
+ of Received (which happens when the request status is not Canceled or
+ Fulfilled and has an associated Purchase Order with a State of
+ Received) and a Place Hold value of False.
+ /,
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'ID for home library of user requests to auto-cancel.' }
+ ],
+ return => {
+ desc => 'progress object, event on error',
+ }
+ }
+);
+
+sub clear_completed_user_requests {
+ my($self, $conn, $auth, $potential_aur_ids) = @_;
+ my $e = new_editor(xact => 1, authtoken => $auth);
+ return $e->die_event unless $e->checkauth;
+ my $rid = $e->requestor->id;
+
+ my $potential_requests = $e->search_acq_user_request_status({
+ id => $potential_aur_ids
+ ,'-or' => [
+ { request_status => 6 }, # Fulfilled
+ { '-and' => [ { request_status => 5 }, { hold => 'f' } ] } # Received
+ ]
+ }
+ );
+ my $aur_ids = [];
+
+ my %perm_test = (); my %perm_test2 = ();
+ for my $request (@$potential_requests) {
+ if ($rid != $request->usr()) {
+ if (!defined $perm_test{ $request->home_ou() }) {
+ $perm_test{ $request->home_ou() } =
+ $e->allowed( ['user_request.view'], $request->home_ou() );
+ }
+ if (!defined $perm_test2{ $request->home_ou() }) {
+ $perm_test2{ $request->home_ou() } =
+ $e->allowed( ['CLEAR_PURCHASE_REQUEST'], $request->home_ou() );
+ }
+ if (!$perm_test{ $request->home_ou() }) {
+ next; # failed test
+ }
+ if (!$perm_test2{ $request->home_ou() }) {
+ next; # failed test
+ }
+ }
+ push @$aur_ids, $request->id();
+ }
+
+ my $x = 1;
+ my %perm_test3 = ();
+ for my $id (@$aur_ids) {
+
+ my $aur_obj = $e->retrieve_acq_user_request([
+ $id,
+ { flesh => 1,
+ flesh_fields => { "aur" => ['lineitem', 'usr'] }
+ }
+ ]) or return $e->die_event;
+
+ my $context_org = $aur_obj->usr()->home_ou();
+ $aur_obj->usr( $aur_obj->usr()->id() );
+
+ if ($rid != $aur_obj->usr) {
+ if (!defined $perm_test3{ $context_org }) {
+ $perm_test3{ $context_org } = $e->allowed( ['user_request.update'], $context_org );
+ }
+ if (!$perm_test3{ $context_org }) {
+ next; # failed test
+ }
+ }
+
+ $aur_obj->cancel_reason( 1015 ); # Canceled: Fulfilled
+ $aur_obj->cancel_time( 'now' );
+ $e->update_acq_user_request($aur_obj) or return $e->die_event;
+ create_user_request_events( $e, [ $aur_obj ], 'aur.rejected' );
+ # FIXME - hrmm, since this is a special type of "cancelation", should we not fire these
+ # events or should we put the burden on A/T to filter things based on cancel_reason if
+ # desired? I don't think anyone is actually using A/T for these in practice
+
+ $conn->respond({maximum => scalar(@$aur_ids), progress => $x++});
+ }
+
+ $e->commit;
+ return {complete => 1};
+}
+
+__PACKAGE__->register_method (
method => 'new_user_request',
api_name => 'open-ils.acq.user_request.create',
signature => {
--- /dev/null
+#!perl
+use strict; use warnings;
+use Test::More tests => 26;
+use OpenILS::Utils::TestUtils;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Application::Acq::Order;
+
+diag("Tests ACQ purchase requests");
+
+my $script = OpenILS::Utils::TestUtils->new();
+$script->bootstrap;
+
+$script->authenticate({
+ username => 'admin',
+ password => 'demo123',
+ type => 'staff'
+});
+
+my $ses = $script->session('open-ils.storage');
+my $req = $ses->request('open-ils.storage.direct.actor.user.retrieve', 87);
+if (my $resp = $req->recv) {
+ if (my $user = $resp->content) {
+# -----------------------------------------------------------------------------
+# 1. We'll use Smith, Sarah (with usrname 99999303411 and home lib SL1)
+# -----------------------------------------------------------------------------
+ is(
+ $user->usrname,
+ '99999303411',
+ 'User with id = 87 is 99999303411'
+ );
+ }
+}
+
+# -----------------------------------------------------------------------------
+# 2. Check for auth
+# -----------------------------------------------------------------------------
+ok($script->authtoken, 'Have an authtoken');
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.acqcr',
+ $script->authtoken, 1015);
+if (my $resp = $req->recv) {
+ if (my $new_cr = $resp->content) {
+# -----------------------------------------------------------------------------
+# 3. Check for Canceled: Fulfilled
+# -----------------------------------------------------------------------------
+ is($new_cr->label,'Canceled: Fulfilled','New cancel reason for fulfilled requests');
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurt',
+ $script->authtoken, 1);
+if (my $resp = $req->recv) {
+ if (my $aurt = $resp->content) {
+# -----------------------------------------------------------------------------
+# 4. Check for user request type Books
+# -----------------------------------------------------------------------------
+ is($aurt->label,'Books','Found user request type Books');
+ }
+}
+
+my $aur;
+my $aur_hash = {};
+$aur_hash->{'request_type'} = 1; # Books
+$aur_hash->{'usr'} = 87; # Smith
+$aur_hash->{'pickup_lib'} = 8; # SL1
+$aur_hash->{'email_notify'} = 'f';
+$aur_hash->{'hold'} = 'f';
+$aur_hash->{'title'} = 'test';
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.user_request.create',
+ $script->authtoken, $aur_hash);
+if (my $resp = $req->recv) {
+ if ($aur = $resp->content) {
+# -----------------------------------------------------------------------------
+# 5. Check for created user request
+# -----------------------------------------------------------------------------
+ is(ref $aur, 'Fieldmapper::acq::user_request', 'User request created');
+ diag('User Request ID = ' . $aur->id);
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurs',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if (my $aurs = $resp->content) {
+# -----------------------------------------------------------------------------
+# 6,7,8. Check for status-enhanced user request
+# -----------------------------------------------------------------------------
+ is($aurs->id,$aur->id,'Found status-enhanced user request');
+ is($aurs->request_status,1,'Request Status = New');
+ is($aurs->home_ou,8,'Home Lib = SL1');
+ }
+}
+
+# open-ils.acq.picklist.create
+# {"__c":"acqpl","__p":[null,1,"4","test",null,null,null,null,1,1]}
+# {"__c":"acqpl","__p":[1,1,4,"test","2018-07-31T16:33:39-0400","now",null,null,1,1]}
+
+my $picklist_id;
+my $picklist = Fieldmapper::acq::picklist->new;
+$picklist->isnew(1);
+$picklist->owner(1); # admin
+$picklist->creator(1); # admin
+$picklist->editor(1); # admin
+$picklist->org_unit(8); # SL1
+$picklist->name( $script->authtoken ); # $picklist->name('22-acq-requests.t');
+$picklist->create_time('now');
+$picklist->edit_time('now');
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.picklist.create',
+ $script->authtoken, $picklist);
+if (my $resp = $req->recv) {
+ if ($picklist_id = $resp->content) {
+# -----------------------------------------------------------------------------
+# 9. Check for created picklist
+# -----------------------------------------------------------------------------
+ ok($picklist_id > 0,'Created picklist aka selection list');
+ diag('Picklist ID = ' . $picklist_id);
+ }
+}
+
+my $jub_id;
+my $jub = Fieldmapper::acq::lineitem->new;
+$jub->selector(1); # admin
+$jub->picklist($picklist_id);
+$jub->create_time('now');
+$jub->edit_time('now');
+$jub->marc('<record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/MARC21/slim" xmlns:marc="http://www.loc.gov/MARC21/slim" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/ standards/marcxml/schema/MARC21slim.xsd"><leader>00000nam a22000007a 4500</leader><marc:datafield tag="245" ind1=" " ind2=" "><marc:subfield code="a">test </marc:subfield></marc:datafield></record>');
+$jub->state('new');
+$jub->creator(1); # admin
+$jub->editor(1); # admin
+$jub->estimated_unit_price(1.00);
+$jub->isnew(1);
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.lineitem.create',
+ $script->authtoken, $jub);
+if (my $resp = $req->recv) {
+ if ($jub_id = $resp->content) {
+# -----------------------------------------------------------------------------
+# 10. Check for created lineitem
+# -----------------------------------------------------------------------------
+ ok($jub_id > 0,'Created lineitem');
+ diag('Lineitem ID = ' . $jub_id);
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aur',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if ($aur = $resp->content) {
+# -----------------------------------------------------------------------------
+# 11. Retrieve bare user request
+# -----------------------------------------------------------------------------
+ is(ref $aur,'Fieldmapper::acq::user_request','Retrieved bare user request');
+ }
+}
+
+$aur->ischanged(1);
+$aur->lineitem($jub_id);
+
+diag('Updating aur->lineitem');
+my $pcrud_ses = $script->session('open-ils.pcrud');
+$pcrud_ses->connect();
+my $xact = $pcrud_ses->request(
+ 'open-ils.pcrud.transaction.begin',
+ $script->authtoken
+)->gather(1);
+my $aur_id = $pcrud_ses->request(
+ 'open-ils.pcrud.update.aur',
+ $script->authtoken,
+ $aur
+)->gather(1);
+# -----------------------------------------------------------------------------
+# 12. Updated user request with lineitem
+# -----------------------------------------------------------------------------
+is($aur_id,$aur->id,'Updated user request with lineitem');
+
+$pcrud_ses->request(
+ 'open-ils.pcrud.transaction.commit',
+ $script->authtoken
+)->gather(1);
+$pcrud_ses->disconnect();
+undef($pcrud_ses);
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.lineitem.batch_update',
+ $script->authtoken, { 'lineitems' => [$jub_id] }, {
+ "item_count" => 1, "location" => 118, "owning_lib" => 4, "fund" => 1});
+if (my $resp = $req->recv) {
+ if (my $return = $resp->content) {
+# -----------------------------------------------------------------------------
+# 13. Check adding of copy to line
+# -----------------------------------------------------------------------------
+ is($return,$jub_id,'Added copy to lineitem');
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurs',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if (my $aurs = $resp->content) {
+# -----------------------------------------------------------------------------
+# 14,15,16. Check user request status and lineitem
+# -----------------------------------------------------------------------------
+ is($aurs->id,$aur->id,'Re-retrieved status-enhanced user request');
+ is($aurs->request_status,2,'Request Status = Pending');
+ is($aurs->lineitem,$jub_id,'Lineitem matches');
+ }
+}
+
+my $purchase_order_id;
+my $purchase_order = Fieldmapper::acq::purchase_order->new;
+$purchase_order->owner(1); # admin
+$purchase_order->create_time('now');
+$purchase_order->edit_time('now');
+$purchase_order->provider(2); # BRODART
+$purchase_order->state('pending');
+$purchase_order->ordering_agency(4); # BR1
+$purchase_order->creator(1); # admin
+$purchase_order->editor(1); # admin
+$purchase_order->name( $script->authtoken ); # $purchase_order->name('22-acq-requests.t');
+$purchase_order->isnew(1);
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.purchase_order.create',
+ $script->authtoken, $purchase_order, { 'lineitems' => [$jub_id] });
+if (my $resp = $req->recv) {
+ if (my $return = $resp->content) {
+#FIXME: open-ils.acq.purchase_order.create docs needs to be updated with correct return value
+#FIXME: open-ils.acq.purchase_order.create docs needs to be updated for lineitem_ids argument
+# -----------------------------------------------------------------------------
+# 17. Check for created purchase_order
+# -----------------------------------------------------------------------------
+ $purchase_order_id = $$return{'purchase_order'}->id;
+ ok($purchase_order_id > 0,'Created purchase_order');
+ diag('Purchase Order ID = ' . $purchase_order_id);
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurs',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if (my $aurs = $resp->content) {
+# -----------------------------------------------------------------------------
+# 18, 19. Check user request status is still Pending
+# -----------------------------------------------------------------------------
+ is($aurs->id,$aur->id,'Re-retrieved status-enhanced user request');
+ is($aurs->request_status,2,'Request Status = Pending');
+ }
+}
+
+
+# open-ils.acq.purchase_order.assets.create
+my $vlArgs = {
+ 'vandelay' => {
+ 'auto_overlay_1match' => 0,
+ 'match_quality_ratio' => '0.0',
+ 'queue_name' => $script->authtoken, #'queue_name' => '22-acq-requests.t',
+ 'import_no_match' => 'on',
+ 'bib_source' => '',
+ 'fall_through_merge_profile' => '',
+ 'merge_profile' => '',
+ 'auto_overlay_best_match' => 0,
+ 'strip_field_groups' => [],
+ 'auto_overlay_exact' => 0,
+ 'existing_queue' => '',
+ 'match_set' => ''
+ }
+};
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.purchase_order.assets.create',
+ $script->authtoken, $purchase_order_id, $vlArgs);
+if (my $resp = $req->recv) {
+ if (my $return = $resp->content) {
+# -----------------------------------------------------------------------------
+# 20. Check for created assets
+# -----------------------------------------------------------------------------
+ is($return->{'complete'},1,'Assets created');
+ }
+}
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.purchase_order.activate',
+ $script->authtoken, $purchase_order_id, {
+ 'no_assets' => 0, 'zero_copy_activate' => 0});
+if (my $resp = $req->recv) {
+ if (my $return = $resp->content) {
+# -----------------------------------------------------------------------------
+# 21. Check for activated purchase order
+# -----------------------------------------------------------------------------
+ is($return,1,'Purchase order activated');
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurs',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if (my $aurs = $resp->content) {
+# -----------------------------------------------------------------------------
+# 22, 23. Check user request status Ordered, No Hold Placed
+# -----------------------------------------------------------------------------
+ is($aurs->id,$aur->id,'Re-retrieved status-enhanced user request');
+ is($aurs->request_status,3,'Request Status = Ordered, Hold Not Placed');
+ }
+}
+
+$req = $script->session('open-ils.acq')->request(
+ 'open-ils.acq.user_request.cancel.batch.atomic',
+ $script->authtoken, [ $aur_id ], 1015); # Canceled: Fulfilled
+if (my $resp = $req->recv) {
+ if (my $return = $resp->content) {
+# -----------------------------------------------------------------------------
+# 24. Check for activated purchase order
+# -----------------------------------------------------------------------------
+ is($return->[1]->{'complete'},1,'User request canceled with Canceled: Fulfilled');
+ }
+}
+
+$req = $script->session('open-ils.pcrud')->request(
+ 'open-ils.pcrud.retrieve.aurs',
+ $script->authtoken, $aur->id);
+if (my $resp = $req->recv) {
+ if (my $aurs = $resp->content) {
+# -----------------------------------------------------------------------------
+# 25, 26. Check user request status Ordered, No Hold Placed
+# -----------------------------------------------------------------------------
+ is($aurs->id,$aur->id,'Re-retrieved status-enhanced user request');
+ is($aurs->request_status,7,'Request Status = Canceled');
+ }
+}
+
label TEXT NOT NULL UNIQUE -- i18n-ize
);
+CREATE TABLE acq.user_request_status_type (
+ id SERIAL PRIMARY KEY
+ ,label TEXT
+);
+
+INSERT INTO acq.user_request_status_type (id,label) VALUES
+ (0,oils_i18n_gettext(0,'Error','aurst','label'))
+ ,(1,oils_i18n_gettext(1,'New','aurst','label'))
+ ,(2,oils_i18n_gettext(2,'Pending','aurst','label'))
+ ,(3,oils_i18n_gettext(3,'Ordered, Hold Not Placed','aurst','label'))
+ ,(4,oils_i18n_gettext(4,'Ordered, Hold Placed','aurst','label'))
+ ,(5,oils_i18n_gettext(5,'Received','aurst','label'))
+ ,(6,oils_i18n_gettext(6,'Fulfilled','aurst','label'))
+ ,(7,oils_i18n_gettext(7,'Canceled','aurst','label'))
+;
+
+SELECT SETVAL('acq.user_request_status_type_id_seq'::TEXT, 100);
+
CREATE TABLE acq.user_request (
id SERIAL PRIMARY KEY,
usr INT NOT NULL REFERENCES actor.usr (id), -- requesting user
request_type INT NOT NULL REFERENCES acq.user_request_type (id),
isxn TEXT,
+ upc TEXT,
title TEXT,
volume TEXT,
author TEXT,
mentioned TEXT,
other_info TEXT,
cancel_reason INT REFERENCES acq.cancel_reason( id )
- DEFERRABLE INITIALLY DEFERRED
+ DEFERRABLE INITIALLY DEFERRED,
+ cancel_time TIMESTAMPTZ
);
+ALTER TABLE action.hold_request ADD COLUMN acq_request INT REFERENCES acq.user_request (id);
-- Functions
(608, 'APPLY_WORKSTATION_SETTING',
oils_i18n_gettext(608, 'APPLY_WORKSTATION_SETTING', 'ppl', 'description')),
( 609, 'MANAGE_CUSTOM_PERM_GRP_TREE', oils_i18n_gettext( 609,
- 'Allows a user to manage custom permission group lists.', 'ppl', 'description' ))
+ 'Allows a user to manage custom permission group lists.', 'ppl', 'description' )),
+ ( 610, 'CLEAR_PURCHASE_REQUEST', oils_i18n_gettext(610,
+ 'Clear Completed User Purchase Requests', 'ppl', 'description'))
;
aout.name = 'Consortium' AND
perm.code IN (
'ALLOW_ALT_TCN',
+ 'CLEAR_PURCHASE_REQUEST',
'CREATE_BIB_IMPORT_QUEUE',
'CREATE_IMPORT_ITEM',
'CREATE_INVOICE',
INSERT INTO acq.user_request_type (id,label) VALUES (1, oils_i18n_gettext('1', 'Books', 'aurt', 'label'));
-INSERT INTO acq.user_request_type (id,label) VALUES (2, oils_i18n_gettext('2', 'Journal/Magazine & Newspaper Articles', 'aurt', 'label'));
+INSERT INTO acq.user_request_type (id,label) VALUES (2, oils_i18n_gettext('2', 'Articles', 'aurt', 'label'));
INSERT INTO acq.user_request_type (id,label) VALUES (3, oils_i18n_gettext('3', 'Audiobooks', 'aurt', 'label'));
INSERT INTO acq.user_request_type (id,label) VALUES (4, oils_i18n_gettext('4', 'Music', 'aurt', 'label'));
INSERT INTO acq.user_request_type (id,label) VALUES (5, oils_i18n_gettext('5', 'DVDs', 'aurt', 'label'));
+INSERT INTO acq.user_request_type (id,label) VALUES (6, oils_i18n_gettext('6', 'Other', 'aurt', 'label'));
-SELECT SETVAL('acq.user_request_type_id_seq'::TEXT, 6);
+SELECT SETVAL('acq.user_request_type_id_seq'::TEXT, 7);
-- org_unit setting types
'coust', 'description'),
'integer', null)
-,( 'acq.holds.allow_holds_from_purchase_request', 'acq',
- oils_i18n_gettext('acq.holds.allow_holds_from_purchase_request',
- 'Allows patrons to create automatic holds from purchase requests.',
- 'coust', 'label'),
- oils_i18n_gettext('acq.holds.allow_holds_from_purchase_request',
- 'Allows patrons to create automatic holds from purchase requests.',
- 'coust', 'description'),
- 'bool', null)
-
,( 'acq.tmp_barcode_prefix', 'acq',
oils_i18n_gettext('acq.tmp_barcode_prefix',
'Temporary barcode prefix',
,( 'circ.holds.canceled.display_age', 'holds',
oils_i18n_gettext('circ.holds.canceled.display_age',
- 'Canceled holds display age',
+ 'Canceled holds/requests display age',
'coust', 'label'),
oils_i18n_gettext('circ.holds.canceled.display_age',
- 'Show all canceled holds that were canceled within this amount of time',
+ 'Show all canceled entries in patron holds and patron acquisition requests interfaces that were canceled within this amount of time',
'coust', 'description'),
'interval', null)
,( 'circ.holds.canceled.display_count', 'holds',
oils_i18n_gettext('circ.holds.canceled.display_count',
- 'Canceled holds display count',
+ 'Canceled holds/requests display count',
'coust', 'label'),
oils_i18n_gettext('circ.holds.canceled.display_count',
- 'How many canceled holds to show in patron holds interfaces',
+ 'How many canceled entries to show in patron holds and patron acquisition requests interfaces',
'coust', 'description'),
'integer', null)
oils_i18n_gettext(1007, 'This line item is not accepted by the seller.', 'acqcr', 'description')),
('f',( 10+1000), 1, oils_i18n_gettext(1010, 'Canceled: Not Found', 'acqcr', 'label'),
oils_i18n_gettext(1010, 'This line item is not found in the referenced message.', 'acqcr', 'description')),
+('f',( 15+1000), 1, oils_i18n_gettext(1015, 'Canceled: Fulfilled', 'acqcr', 'label'),
+ oils_i18n_gettext(1015, 'This acquisition request has been fulfilled.', 'acqcr', 'description')),
('t',( 24+1000), 1, oils_i18n_gettext(1024, 'Delayed: Accepted with amendment', 'acqcr', 'label'),
oils_i18n_gettext(1024, 'Accepted with changes which require no confirmation.', 'acqcr', 'description'));
--- /dev/null
+BEGIN;
+
+--SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+ALTER TABLE acq.user_request ADD COLUMN cancel_time TIMESTAMPTZ;
+ALTER TABLE acq.user_request ADD COLUMN upc TEXT;
+ALTER TABLE action.hold_request ADD COLUMN acq_request INT REFERENCES acq.user_request (id);
+
+UPDATE
+ config.org_unit_setting_type
+SET
+ label = oils_i18n_gettext(
+ 'circ.holds.canceled.display_age',
+ 'Canceled holds/requests display age',
+ 'coust', 'label'),
+ description = oils_i18n_gettext(
+ 'circ.holds.canceled.display_age',
+ 'Show all canceled entries in patron holds and patron acquisition requests interfaces that were canceled within this amount of time',
+ 'coust', 'description')
+WHERE
+ name = 'circ.holds.canceled.display_age'
+;
+
+UPDATE
+ config.org_unit_setting_type
+SET
+ label = oils_i18n_gettext(
+ 'circ.holds.canceled.display_count',
+ 'Canceled holds/requests display count',
+ 'coust', 'label'),
+ description = oils_i18n_gettext(
+ 'circ.holds.canceled.display_count',
+ 'How many canceled entries to show in patron holds and patron acquisition requests interfaces',
+ 'coust', 'description')
+WHERE
+ name = 'circ.holds.canceled.display_count'
+;
+
+INSERT INTO acq.cancel_reason (org_unit, keep_debits, id, label, description)
+ VALUES (
+ 1, 'f', 1015,
+ oils_i18n_gettext(1015, 'Canceled: Fulfilled', 'acqcr', 'label'),
+ oils_i18n_gettext(1015, 'This acquisition request has been fulfilled.', 'acqcr', 'description')
+ )
+;
+
+UPDATE
+ acq.user_request_type
+SET
+ label = oils_i18n_gettext('2', 'Articles', 'aurt', 'label')
+WHERE
+ id = 2
+;
+
+INSERT INTO acq.user_request_type (id,label)
+ SELECT 6, oils_i18n_gettext('6', 'Other', 'aurt', 'label');
+
+SELECT SETVAL('acq.user_request_type_id_seq'::TEXT, (SELECT MAX(id)+1 FROM acq.user_request_type));
+
+INSERT INTO permission.perm_list ( id, code, description ) VALUES
+ ( 610, 'CLEAR_PURCHASE_REQUEST', oils_i18n_gettext(610,
+ 'Clear Completed User Purchase Requests', 'ppl', 'description'))
+;
+
+CREATE TABLE acq.user_request_status_type (
+ id SERIAL PRIMARY KEY
+ ,label TEXT
+);
+
+INSERT INTO acq.user_request_status_type (id,label) VALUES
+ (0,oils_i18n_gettext(0,'Error','aurst','label'))
+ ,(1,oils_i18n_gettext(1,'New','aurst','label'))
+ ,(2,oils_i18n_gettext(2,'Pending','aurst','label'))
+ ,(3,oils_i18n_gettext(3,'Ordered, Hold Not Placed','aurst','label'))
+ ,(4,oils_i18n_gettext(4,'Ordered, Hold Placed','aurst','label'))
+ ,(5,oils_i18n_gettext(5,'Received','aurst','label'))
+ ,(6,oils_i18n_gettext(6,'Fulfilled','aurst','label'))
+ ,(7,oils_i18n_gettext(7,'Canceled','aurst','label'))
+;
+
+SELECT SETVAL('acq.user_request_status_type_id_seq'::TEXT, 100);
+
+-- not used
+DELETE FROM actor.org_unit_setting WHERE name = 'acq.holds.allow_holds_from_purchase_request';
+DELETE FROM config.org_unit_setting_type_log WHERE field_name = 'acq.holds.allow_holds_from_purchase_request';
+DELETE FROM config.org_unit_setting_type WHERE name = 'acq.holds.allow_holds_from_purchase_request';
+
+COMMIT;
--- /dev/null
+[%
+ WRAPPER "staff/base.tt2";
+ ctx.page_title = l("Acquisition Patron Requests");
+ ctx.page_app = "egAcqRequestsApp";
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/acq/services/requests.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/acq/requests/list.js"></script>
+<script>
+angular.module('egCoreMod').run(['egStrings', function(s) {
+ s.CREATE_USER_REQUEST_SUCCESS = "[% l('Created Acquisition Patron Request') %]";
+ s.CREATE_USER_REQUEST_FAIL = "[% l('Failed to Create Acquisition Patron Request') %]";
+ s.EDIT_USER_REQUEST_SUCCESS = "[% l('Edited Acquisition Patron Request') %]";
+ s.EDIT_USER_REQUEST_FAIL = "[% l('Failed to Edit Acquisition Patron Request') %]";
+}]);
+</script>
+<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/circ.css" />
+[% END %]
+
+<div ng-view></div>
+
+[% END %]
--- /dev/null
+[% ctx.page_title = l("Cancel Selected Patron Requests"); %]
+<!-- use <form> so we get submit-on-enter for free -->
+<form class="form-validated" novalidate name="form" ng-submit="ok(cancel_reason)">
+ <div> <!-- modal-content -->
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="cancel()"
+ aria-hidden="true">×</button>
+ <h4 class="modal-title">
+ [% l('Cancel Selected Patron Requests') %]</h4>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label for="ids">[% l('Request IDs') %]</label>
+ <input type="text" class="form-control"
+ id="ids" ng-model="ids" ng-disabled="true"/>
+ </div>
+ <div class="form-group">
+ <label for="cancel-reason-selector">[% l('Cancel Reason') %]</label>
+ <select id="cancel-reason-selector" class="form-control" required
+ ng-model="cancel_reason"
+ ng-options="rt.label() for rt in cancel_reasons"/>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <input type="submit" ng-disabled="form.$invalid"
+ class="btn btn-primary" value="[% l('Cancel Requests') %]"/>
+ <button class="btn btn-warning"
+ ng-click="cancel()">[% l('Abort Cancellation') %]</button>
+ </div>
+ </div> <!-- modal-content -->
+</form>
--- /dev/null
+[% ctx.page_title = l("Clear Completed Patron Requests"); %]
+<!-- use <form> so we get submit-on-enter for free -->
+<form class="form-validated" novalidate name="form" ng-submit="ok(true)">
+ <div> <!-- modal-content -->
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="cancel()"
+ aria-hidden="true">×</button>
+ <h4 class="modal-title">
+ [% l('Clear Completed Patron Requests') %]</h4>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label for="ids">[% l('Request IDs') %]</label>
+ <input type="text" class="form-control"
+ id="ids" ng-model="ids" ng-disabled="true"/>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <input type="submit" ng-disabled="form.$invalid"
+ class="btn btn-primary" value="[% l('Clear Requests') %]"/>
+ <button class="btn btn-warning"
+ ng-click="cancel()">[% l('Abort Clear Requests') %]</button>
+ </div>
+ </div> <!-- modal-content -->
+</form>
--- /dev/null
+[% ctx.page_title = l("Create/Edit/View patron Request"); %]
+<!-- use <form> so we get submit-on-enter for free -->
+<form class="form-validated" novalidate name="form"
+ ng-submit="ok(request,extra)">
+ <div> <!-- modal-content -->
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="cancel()"
+ aria-hidden="true">×</button>
+ <h4 ng-if="mode=='create'" class="modal-title">
+ [% l('Create Patron Request') %]</h4>
+ <h4 ng-if="mode=='edit'" class="modal-title">
+ [% l('Edit Patron Request') %]</h4>
+ <h4 ng-if="mode=='view'" class="modal-title">
+ [% l('View Patron Request') %]</h4>
+ </div>
+ <div class="modal-header">
+ <div class="row">
+ <div class="form-group col-sm-6">
+ <label for="edit-request-usr">
+ [% l('User Barcode') %]</label>
+ <input type="text" ng-model="extra.barcode" id="barcode"
+ class="form-control" focus-me="focusMe"
+ ng-model-options="{ debounce: 1000 }"
+ ng-disabled="mode=='view'"
+ placeholder="[% l('Barcode...') %]"/>
+ <span ng-show="extra.barcode && request.usr">
+ [% l('[_1], [_2] [_3] : [_4]',
+ '{{extra.user_obj.family_name}}'
+ '{{extra.user_obj.first_given_name}}'
+ '{{extra.user_obj.second_given_name}}'
+ '{{extra.user_obj.home_ou.shortname}}') %]
+ </span>
+ </div>
+ <div class="form-group col-sm-6">
+ <label for="edit-request-usr">[% l('User ID') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-usr" ng-model="request.usr"
+ required ng-disabled="true"/>
+ <span class="alert-info pull-right"
+ ng-show="extra.barcode && !request.usr">
+ [% l('Not Found') %]
+ </span>
+ </div>
+ </div>
+ <div class="form-group" ng-show="request.cancel_reason">
+ <label for="edit-request-id">[% l('Cancel Reason') %]</label>
+ <div class="form-control" ng-disabled="true">
+ {{request.cancel_reason.label()}}
+ </div>
+ </div>
+ <div class="row">
+ <div class="form-group col-sm-6">
+ <label>[% l('Request Date/Time') %]</label>
+ <div class="form-control" ng-disabled="true">
+ {{request.request_date | date:$root.egDateAndTimeFormat}}
+ </div>
+ </div>
+ <div class="form-group col-sm-6">
+ <label for="edit-request-need-before">
+ [% l('Need Before Date/Time') %]</label>
+ <eg-date-input id="edit-request-need-before"
+ show-time-picker ng-disabled="mode=='view'"
+ ng-model="request.need_before" min-date="minDate"/>
+ </div>
+ </div>
+ <div class="row" ng-show="mode=='view'">
+ <div class="form-group col-sm-6">
+ <label for="edit-request-bib-record">
+ [% l('Bib Record') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-bib-record" ng-disabled="true"
+ ng-model="request.eg_bib"/>
+ </div>
+ <div class="form-group col-sm-6">
+ <label for="edit-request-lineitem">
+ [% l('PO Line Item') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-lineitem" ng-disabled="true"
+ ng-model="request.lineitem.id"/>
+ </div>
+ </div>
+ <div class="row">
+ <div class="form-group col-sm-6">
+ <label for="edit-request-place-hold">
+ <input type="checkbox" id="edit-request-place-hold"
+ ng-disabled="mode=='view'" ng-model="request.hold"/>
+ [% l('Place Hold?') %]
+ </label>
+ </div>
+ <div class="form-group col-sm-6">
+ <label for="edit-request-pickup-lib">
+ [% l('Pickup Library') %]</label>
+ <eg-org-selector id="edit-request-pickup-lib"
+ ng-hide="mode=='view'" selected="request.pickup_lib"
+ disable-test="cant_have_vols"/>
+ <span ng-show="mode=='view'">
+ {{request.pickup_lib.shortname()}}
+ </span>
+ </div>
+ </div>
+ <div class="row">
+ <div class="form-group col-sm-6">
+ <label for="edit-request-email-notify">
+ <input type="checkbox" id="edit-request-email-notify"
+ ng-disabled="mode=='view'"
+ ng-model="request.email_notify"/>
+ [% l('Notify By Email When Hold Ready?') %]
+ </label>
+ </div>
+ <div class="form-group col-sm-6">
+ <label for="edit-extra-phone-notify">
+ <input type="checkbox" id="edit-extra-phone-notify"
+ ng-disabled="mode=='view'"
+ ng-model="extra.phone_notify"/>
+ [% l('Notify By Phone When Hold Ready?') %]
+ </label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-phone-notify"
+ ng-disabled="mode=='view'"
+ ng-model="request.phone_notify"/>
+ </div>
+ </div>
+ </div>
+ <div class="modal-body">
+ <div class="row" ng-if="mode!='create'">
+ <div class="form-group col-sm-6"">
+ <label for="edit-request-id">[% l('Request ID') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-id" ng-model="request.id" ng-disabled="true"/>
+ </div>
+ <div class="form-group col-sm-6"">
+ <label for="edit-request-status">[% l('Request Status') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-status" ng-model="request.request_status.label" ng-disabled="true"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="request-type-selector">[% l('Request Type') %]</label>
+ <select id="request-type-selector" class="form-control" required
+ ng-model="extra.selected_request_type"
+ ng-disabled="mode=='view'"
+ ng-options="rt.label() for rt in request_types"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-isxn">[% l('ISxN') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-isxn" ng-model="request.isxn"
+ ng-disabled="mode=='view'" placeholder="[% l('ISxN...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-upc">[% l('UPC') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-upc" ng-model="request.upc"
+ ng-disabled="mode=='view'" placeholder="[% l('UPC...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-title">[% l('Title') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-title" ng-model="request.title"
+ ng-disabled="mode=='view'" placeholder="[% l('Title...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-volume">[% l('Volume') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-volume" ng-model="request.volume"
+ ng-disabled="mode=='view'" placeholder="[% l('Volume...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-author">[% l('Author') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-author" ng-model="request.author"
+ ng-disabled="mode=='view'" placeholder="[% l('Author...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-publisher">[% l('Publisher') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-publisher" ng-model="request.publisher"
+ ng-disabled="mode=='view'" placeholder="[% l('Publisher...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-publication-location">
+ [% l('Publication Location') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-publication-location"
+ ng-model="request.location"
+ ng-disabled="mode=='view'"
+ placeholder="[% l('Publication Location...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-publication-date">
+ [% l('Publication Date') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-publication-date"
+ ng-model="request.pubdate"
+ ng-disabled="mode=='view'"
+ placeholder="[% l('Publication Date...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-article-title">
+ [% l('Article Title') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ ng-disabled="mode=='view' || request.request_type != '2'"
+ id="edit-request-article-title" ng-model="request.article_title"
+ placeholder="[% l('Article Title...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-article-pages">
+ [% l('Article Pages') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ ng-disabled="mode=='view' || request.request_type != '2'"
+ id="edit-request-article-pages" ng-model="request.article_pages"
+ placeholder="[% l('Article Pages...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-mentioned-in">
+ [% l('Mentioned In') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-mentioned-in"
+ ng-model="request.mentioned"
+ ng-disabled="mode=='view'"
+ placeholder="[% l('Mentioned In...') %]"/>
+ </div>
+ <div class="form-group">
+ <label for="edit-request-other-info">
+ [% l('Other Info') %]</label>
+ <input type="text" class="form-control" focus-me='focusMe'
+ id="edit-request-other-info"
+ ng-model="request.other_info"
+ ng-disabled="mode=='view'"
+ placeholder="[% l('Other Info...') %]"/>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <input type="submit" ng-hide="mode=='view'" ng-disabled="form.$invalid"
+ class="btn btn-primary" value="[% l('Save') %]"/>
+ <button class="btn btn-warning"
+ ng-click="cancel()">[% l('Cancel') %]</button>
+ </div>
+ </div> <!-- modal-content -->
+</form>
--- /dev/null
+<div class="container-fluid" style="text-align:center">
+ <div class="alert alert-info alert-less-pad strong-text-2">
+ <span>[% l('Acquisition Patron Requests') %]</span>
+ </div>
+</div>
+
+<div>
+ <div class="form-group">
+ <div class="row">
+ <span ng-hide="context_user || context_lineitem">
+ <label for="select-request-ou">[% l('Patron Home Library: ' ) %]</label>
+ <eg-org-selector id="select-request-ou" selected="context_ou"></eg-org-selector>
+ <span> </span>
+ </span>
+ <span ng-show="context_user">[% l('User ID: [_1]','{{context_user}}') %]</span>
+ <span ng-show="context_lineitem">[% l('PO Line Item ID: [_1]','{{context_lineitem}}') %]</span>
+ </div>
+ </div>
+</div>
+
+<hr/>
+
+<eg-grid
+ id-field="id"
+ idl-class="aurs"
+ features="-sort,-multisort"
+ grid-controls="grid_controls"
+ persist-key="acq.requests.list"
+ dateformat="{{$root.egDateAndTimeFormat}}">
+
+ <eg-grid-menu-item handler="create_request"
+ label="[% l('Create Request') %]"></eg-grid-menu-item>
+
+ <eg-grid-menu-item handler="canceled_requests_checkbox_handler"
+ label="[% l('Show Canceled Requests') %]"
+ checkbox="requests_show_canceled"
+ checked="requests_show_canceled"/>
+
+ <eg-grid-menu-item handler="clear_requests" disabled="need_one_and_all_uncanceled"
+ label="[% l('Clear Completed Requests') %]"></eg-grid-menu-item>
+
+ <eg-grid-action handler="edit_request" disabled="need_one_uncanceled"
+ label="[% l('Edit Request') %]"></eg-grid-action>
+ <eg-grid-action handler="view_request" disabled="need_one_selected"
+ label="[% l('View Request') %]"></eg-grid-action>
+ <eg-grid-action handler="retrieve_user" disabled="need_one_selected"
+ label="[% l('Retrieve Patron') %]"></eg-grid-action>
+ <eg-grid-action handler="add_request_to_picklist" disabled="need_one_uncanceled_no_lineitem"
+ label="[% l('Add Request to Selection List') %]"></eg-grid-action>
+ <eg-grid-action handler="view_picklist" disabled="need_one_lineitem"
+ label="[% l('View Selection List') %]"></eg-grid-action>
+ <eg-grid-action handler="set_yes_hold_requests" disabled="need_one_and_all_new_or_pending"
+ label="[% l('Set Hold on Requests') %]"></eg-grid-action>
+ <eg-grid-action handler="set_no_hold_requests" disabled="need_one_and_all_new_or_pending"
+ label="[% l('Set No Hold on Requests') %]"></eg-grid-action>
+ <eg-grid-action handler="cancel_requests" disabled="need_one_and_all_uncanceled"
+ label="[% l('Cancel Requests') %]"></eg-grid-action>
+
+ <eg-grid-field path='id' hidden required sortable></eg-grid-field>
+ <eg-grid-field path='request_status.label' sortable label="[% l('Request Status') %]"></eg-grid-field>
+ <eg-grid-field path='request_status.id' required hidden sortable label="[% l('Request Status ID') %]"></eg-grid-field>
+ <eg-grid-field path='request_date' sortable label="[% l('Request Date/Time') %]"
+ datatype="timestamp"></eg-grid-field>
+ <eg-grid-field path='need_before' sortable label="[% l('Need Before Date/Time') %]"
+ datatype="timestamp"></eg-grid-field>
+ <eg-grid-field path='request_type.label' required sortable label="[% l('Request Type') %]"></eg-grid-field>
+ <eg-grid-field path='hold' sortable></eg-grid-field>
+ <eg-grid-field path='pickup_lib.shortname' required sortable label="[% l('Pickup Lib') %]"></eg-grid-field>
+ <eg-grid-field path='isxn' sortable></eg-grid-field>
+ <eg-grid-field path='upc' sortable></eg-grid-field>
+ <eg-grid-field path='title' sortable></eg-grid-field>
+ <eg-grid-field path='article_title' sortable></eg-grid-field>
+ <eg-grid-field path='lineitem.id' required sortable label="[% l('Lineitem ID') %]" hidden></eg-grid-field>
+ <eg-grid-field path='lineitem.picklist' sortable required label="[% l('Selection List ID') %]" hidden></eg-grid-field>
+ <eg-grid-field path='usr.id' required sortable label="[% l('User ID') %]" hidden></eg-grid-field>
+ <eg-grid-field path='usr.card.barcode' sortable required label="[% l('User Barcode') %]"></eg-grid-field>
+ <eg-grid-field path='usr.family_name' sortable required label="[% l('User Family Name') %]" hidden></eg-grid-field>
+ <eg-grid-field path='usr.home_ou.shortname' required sortable label="[% l('User Home Library') %]" hidden></eg-grid-field>
+ <eg-grid-field path='cancel_reason.label' sortable required label="[% l('Cancel Reason') %]" hidden></eg-grid-field>
+ <eg-grid-field path='*' required hidden></eg-grid-field>
+</eg-grid>
+
--- /dev/null
+[% ctx.page_title = l('Set "No Hold" on Selected Patron Requests'); %]
+<!-- use <form> so we get submit-on-enter for free -->
+<form class="form-validated" novalidate name="form" ng-submit="ok(true)">
+ <div> <!-- modal-content -->
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="cancel()"
+ aria-hidden="true">×</button>
+ <h4 class="modal-title">
+ [% l('Set "No Hold" on Selected Patron Requests') %]</h4>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label for="ids">[% l('Request IDs') %]</label>
+ <input type="text" class="form-control"
+ id="ids" ng-model="ids" ng-disabled="true"/>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <input type="submit" ng-disabled="form.$invalid"
+ class="btn btn-primary" value="[% l('Update Requests') %]"/>
+ <button class="btn btn-warning"
+ ng-click="cancel()">[% l('Abort Update') %]</button>
+ </div>
+ </div> <!-- modal-content -->
+</form>
--- /dev/null
+[% ctx.page_title = l('Set "Hold" on Selected Patron Requests'); %]
+<!-- use <form> so we get submit-on-enter for free -->
+<form class="form-validated" novalidate name="form" ng-submit="ok(true)">
+ <div> <!-- modal-content -->
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="cancel()"
+ aria-hidden="true">×</button>
+ <h4 class="modal-title">
+ [% l('Set "Hold" on Selected Patron Requests') %]</h4>
+ </div>
+ <div class="modal-body">
+ <div class="form-group">
+ <label for="ids">[% l('Request IDs') %]</label>
+ <input type="text" class="form-control"
+ id="ids" ng-model="ids" ng-disabled="true"/>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <input type="submit" ng-disabled="form.$invalid"
+ class="btn btn-primary" value="[% l('Update Requests') %]"/>
+ <button class="btn btn-warning"
+ ng-click="cancel()">[% l('Abort Update') %]</button>
+ </div>
+ </div> <!-- modal-content -->
+</form>
</a>
</li>
<li>
+ <a href="./acq/requests/user/{{patron().id()}}" target="_top">
+ [% l('Acquisition Patron Requests') %]
+ </a>
+ </li>
+ <li>
<a href="./booking/legacy/booking/reservation?patron_barcode={{patron().card().barcode()}}" target="_top">
[% l('Booking: Create or Cancel Reservations') %]
</a>
</a>
</li>
<li>
- <a href="./acq/legacy/picklist/user_request" target="_self">
+ <a href="./acq/requests/list" target="_self">
<span class="glyphicon glyphicon-thumbs-up"></span>
[% l('Patron Requests') %]
</a>
oilsBasePath + "/acq/lineitem/worksheet/" + li.id() +
'?source=' + encodeURIComponent(location.pathname + location.search)
- nodeByName("show_requests_link", row).href =
- oilsBasePath + "/acq/picklist/user_request?lineitem=" + li.id() +
- '?source=' + encodeURIComponent(location.pathname + location.search)
+ if (!IAMBROWSER) {
+ nodeByName("show_requests_link", row).href =
+ oilsBasePath + "/acq/picklist/user_request?lineitem=" + li.id() +
+ '?source=' + encodeURIComponent(location.pathname + location.search);
+ } else {
+ nodeByName("show_requests_link", row).href =
+ "/eg/staff/acq/requests/lineitem/" + li.id();
+ nodeByName("show_requests_link", row).setAttribute('target','_top');
+ }
dojo.query('[attr=title]', row)[0].onclick = function() {self.drawInfo(li.id())};
dojo.query('[name=copieslink]', row)[0].onclick = function() {self.drawCopies(li.id())};
pcrud.update( aur_obj, {
'oncomplete' : function(r, cudResults) {
// Goes back to the list view
- location.href = oilsBasePath + '/acq/picklist/user_request';
+ if (!window.IAMBROWSER) {
+ location.href = oilsBasePath + '/acq/picklist/user_request';
+ } else {
+ window.top.location.href = '/eg/staff/acq/requests/list';
+ }
}
});
} else {
--- /dev/null
+angular.module('egAcqRequestsApp',
+ ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUserMod', 'egUiMod', 'egGridMod'])
+
+.config(function($routeProvider, $locationProvider, $compileProvider) {
+ $locationProvider.html5Mode(true);
+ // grid export
+ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|blob):/);
+
+ var resolver = {delay :
+ ['egStartup', function(egStartup) {return egStartup.go()}]}
+
+ $routeProvider.when('/acq/requests/list', {
+ templateUrl: './acq/requests/t_list',
+ controller: 'AcqRequestsCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.when('/acq/requests/user/:user', {
+ templateUrl: './acq/requests/t_list',
+ controller: 'AcqRequestsCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.when('/acq/requests/lineitem/:lineitem', {
+ templateUrl: './acq/requests/t_list',
+ controller: 'AcqRequestsCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.otherwise({redirectTo : '/acq/requests/list'});
+})
+
+.controller('AcqRequestsCtrl',
+ ['$scope','$q','$routeParams','$window','egCore','egAcqRequests','egUser',
+ 'egGridDataProvider','$uibModal','$timeout',
+function($scope , $q , $routeParams , $window , egCore , egAcqRequests , egUser ,
+ egGridDataProvider , $uibModal , $timeout) {
+
+ var cancel_age;
+ var cancel_count;
+ $scope.context_user = $routeParams.user;
+ $scope.context_lineitem = $routeParams.lineitem;
+
+ egCore.startup.go().then(function() {
+ // org settings for constraining display of canceled requests
+ egCore.org.settings([
+ 'circ.holds.canceled.display_age',
+ 'circ.holds.canceled.display_count' // FIXME Don't know how to use this with egGrid
+ ]).then(function(set) {
+ cancel_age = set['circ.holds.canceled.display_age'];
+ cancel_count = set['circ.holds.canceled.display_count'];
+ if (!cancel_age && !cancel_count) {
+ cancel_count = 10; // default to last 10 canceled requests
+ }
+ });
+ });
+
+ $scope.need_one_selected = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 1) return false;
+ return true;
+ }
+
+ $scope.need_one_uncanceled = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 1) {
+ return requests[0]['cancel_reason.label'] ? true : false;
+ }
+ return true;
+ }
+
+ $scope.need_one_lineitem = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 1) {
+ return ! requests[0]['lineitem.id'];
+ }
+ return true;
+ }
+
+ $scope.need_one_uncanceled_no_lineitem = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 1) {
+ if (! requests[0]['lineitem.id']) {
+ return requests[0]['cancel_reason.label'] ? true : false;
+ }
+ }
+ return true;
+ }
+
+ $scope.need_one_and_all_uncanceled = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 0) return true;
+ var found_canceled = false;
+ angular.forEach(requests,function(v,k) {
+ if (v['cancel_reason.label']) { found_canceled = true; }
+ });
+ return found_canceled;
+ }
+
+ $scope.need_one_and_all_new_or_pending = function() {
+ var requests = $scope.grid_controls.selectedItems();
+ if (requests.length == 0) return true;
+ var found_bad = false;
+ angular.forEach(requests,function(v,k) {
+ if (v['request_status.id'] != 2 // Pending
+ && v['request_status.id'] != 1) { // New
+ found_bad = true;
+ }
+ });
+ return found_bad;
+ }
+
+ $scope.create_request = function(rows) {
+ var row = {};
+ if ($scope.context_user) {
+ row.usr = $scope.context_user;
+ }
+ egAcqRequests.handle_request(row,'create',$scope.context_ou,refresh_page);
+ }
+
+ $scope.edit_request = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.handle_request(rows[0],'edit',$scope.context_ou,refresh_page);
+ }
+
+ $scope.view_request = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.handle_request(rows[0],'view',$scope.context_ou,refresh_page);
+ }
+
+ $scope.add_request_to_picklist = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.add_request_to_picklist(rows[0]);
+ }
+
+ $scope.view_picklist = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.view_picklist(rows[0]);
+ }
+
+ $scope.retrieve_user = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ location.href = "/eg/staff/circ/patron/" + rows[0]['usr.id'] + "/checkout";
+ }
+
+ $scope.clear_requests = function(rows) {
+ rows = $scope.grid_controls.selectedItems(); // remove this if we move the grid action into the menu
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.clear_requests( rows, refresh_page );
+ }
+
+ $scope.set_no_hold_requests = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.set_no_hold_requests( rows, refresh_page );
+ }
+
+ $scope.set_yes_hold_requests = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.set_yes_hold_requests( rows, refresh_page );
+ }
+
+ $scope.cancel_requests = function(rows) {
+ if (!rows) return;
+ if (!angular.isArray(rows)) rows = [rows];
+ if (rows.length == 0) return;
+ egAcqRequests.cancel_requests( rows, refresh_page );
+ }
+
+ $scope.canceled_requests_checkbox_handler = function (item) {
+ $scope.canceled_requests_cb_changed(item.checkbox,item.checked);
+ }
+
+ $scope.canceled_requests_cb_changed = function(cb,newVal,norefresh) {
+ $scope[cb] = newVal;
+ egCore.hatch.setItem('eg.acq.' + cb, newVal);
+ if (!norefresh) {
+ refresh_page();
+ }
+ }
+
+ function current_query() {
+ var filter = {}
+ if ($scope.context_user) {
+ filter.usr = $scope.context_user;
+ } else if ($scope.context_lineitem) {
+ filter.lineitem = $scope.context_lineitem;
+ } else {
+ filter.home_ou = egCore.org.descendants($scope.context_ou.id(), true)
+ }
+ if ($scope['requests_show_canceled']) {
+ filter.cancel_reason = { '!=' : null };
+ if (cancel_age) {
+ var seconds = egCore.date.intervalToSeconds(cancel_age);
+ var now_epoch = new Date().getTime();
+ var cancel_date = new Date(
+ now_epoch - (seconds * 1000 /* milliseconds */)
+ );
+ filter.cancel_time = { '>=' : cancel_date.toISOString() };
+ }
+
+ } else {
+ filter.cancel_reason = { '=' : null };
+ }
+ return filter;
+ }
+
+ $scope.grid_controls = {
+ activateItem : $scope.view_request,
+ setQuery : current_query
+ }
+
+ function refresh_page() {
+ $scope.grid_controls.setQuery(current_query());
+ $scope.grid_controls.refresh();
+ }
+
+ $scope.context_ou = egCore.org.get(egCore.auth.user().ws_ou());
+ $scope.$watch('context_ou', function(newVal, oldVal) {
+ if (newVal && newVal != oldVal) refresh_page();
+ });
+
+}])
+
--- /dev/null
+/**
+ * AcqRequests, yo
+ */
+
+angular.module('egCoreMod')
+
+.factory('egAcqRequests',
+
+ ['$uibModal','$q','egCore','egOrg','ngToast',
+function($uibModal , $q , egCore , egOrg , ngToast) {
+
+ var service = {};
+
+ var aur_fleshing = {
+
+ flesh : 2,
+ // aur -> cancel_reason
+ // aur -> lineitem
+ // aur -> pickup_lib
+ // aur -> request_type
+ // aur -> usr
+ // aur -> usr -> card
+
+ flesh_fields : {
+ 'aur' : [
+ 'cancel_reason'
+ ,'lineitem'
+ ,'pickup_lib'
+ ,'request_type'
+ ,'usr'
+ ]
+ ,'au' : [
+ 'card'
+ ,'home_ou'
+ ,'mailing_address'
+ ,'billing_address'
+ ,'settings'
+ ]
+ }
+ };
+
+ var aurs_fleshing = {
+
+ flesh : 2,
+ // aurs -> cancel_reason
+ // aurs -> lineitem
+ // aurs -> pickup_lib
+ // aurs -> request_type
+ // aurs -> request_status
+ // aurs -> usr
+ // aurs -> usr -> card
+
+ flesh_fields : {
+ 'aurs' : [
+ 'cancel_reason'
+ ,'lineitem'
+ ,'pickup_lib'
+ ,'request_type'
+ ,'request_status'
+ ,'usr'
+ ]
+ ,'au' : [
+ 'card'
+ ,'home_ou'
+ ,'mailing_address'
+ ,'billing_address'
+ ,'settings'
+ ]
+ }
+ };
+
+ service.aur_fleshing = function(newvalue) {
+ if (newvalue) {
+ aur_fleshing = newvalue;
+ }
+ return angular.copy(aur_fleshing);
+ }
+
+ service.aurs_fleshing = function(newvalue) {
+ if (newvalue) {
+ aurs_fleshing = newvalue;
+ }
+ return angular.copy(aurs_fleshing);
+ }
+
+ service.fetch_request = function(aur_id) {
+ var deferred = $q.defer();
+ egCore.pcrud.search(
+ 'aur', { id : aur_id }, aur_fleshing, { atomic : true, authoritative : true }
+ ).then(function(requests) {
+ deferred.resolve(requests[0]);
+ });
+ return deferred.promise;
+ }
+
+ service.fetch_request_with_status = function(aur_id) {
+ var deferred = $q.defer();
+ egCore.pcrud.search(
+ 'aurs', { id : aur_id }, aurs_fleshing, { atomic : true, authoritative : true }
+ ).then(function(requests) {
+ deferred.resolve(requests[0]);
+ });
+ return deferred.promise;
+ }
+
+ service.fetch_cancel_reasons = function() {
+ var deferred = $q.defer();
+ egCore.pcrud.retrieveAll(
+ 'acqcr', {}, {atomic : true, authoritative : true}
+ ).then(function(cancel_reasons) {
+ deferred.resolve(cancel_reasons);
+ });
+ return deferred.promise;
+ }
+
+ service.fetch_request_types = function() {
+ var deferred = $q.defer();
+ egCore.pcrud.retrieveAll(
+ 'aurt', {}, {atomic : true, authoritative : true}
+ ).then(function(request_types) {
+ deferred.resolve(request_types);
+ });
+ return deferred.promise;
+ }
+
+ service.fetch_request_status_types = function() {
+ var deferred = $q.defer();
+ egCore.pcrud.retrieveAll(
+ 'aurst', {}, {atomic : true, authoritative : true}
+ ).then(function(request_status_types) {
+ deferred.resolve(request_status_types);
+ });
+ return deferred.promise;
+ }
+
+ service.add_request_to_picklist = function (row) {
+ egCore.pcrud.search('aurs', {
+ id : row['id']
+ }, aurs_fleshing, {
+ atomic : true
+ }
+ ).then(function(requests) {
+ var aur_obj = requests[0];
+ var prepop = { // based on acq.lineitem_marc_attr_definition
+ "1": [aur_obj.title(), aur_obj.article_title(), aur_obj.volume()].join(' '),
+ "2": aur_obj.author(),
+ "4": aur_obj.article_pages(),
+ "7": aur_obj.upc(),
+ "10": aur_obj.publisher(),
+ "11": aur_obj.pubdate()
+ }
+ if (aur_obj.request_type().id() == "2") { /* Articles */
+ prepop["6"] = aur_obj.isxn();
+ } else {
+ prepop["5"] = aur_obj.isxn();
+ }
+ location.href = "/eg/staff/acq/legacy/picklist/brief_record?ur="
+ + aur_obj.id() + "&prepop=" + encodeURIComponent(js2JSON(prepop));
+ });
+ }
+
+ service.view_picklist = function (row) {
+ location.href = "/eg/staff/acq/legacy/picklist/view/" + row['lineitem.picklist'];
+ }
+
+ service.handle_request = function(row,mode,context_ou,callback) {
+ if (mode!='create' && !row) { return; }
+ return $uibModal.open({
+ templateUrl: './acq/requests/t_edit',
+ backdrop: 'static',
+ controller: ['$scope', '$uibModalInstance','egCore',
+ 'request_and_extra','request_types','request_status_types',
+ function($m_scope , $uibModalInstance , egCore ,
+ request_and_extra , request_types , request_status_types ) {
+ var request = request_and_extra.request;
+ var extra = request_and_extra.extra || {};
+ var today = new Date();
+ today.setHours(0);
+ today.setMinutes(0);
+ today.setSeconds(0);
+ today.setMilliseconds(0);
+ $m_scope.minDate = today;
+ $m_scope.mode = mode;
+ $m_scope.request = request;
+ $m_scope.request_types = request_types;
+ $m_scope.extra = extra;
+ $m_scope.extra.user_obj = request.usr;
+ angular.forEach(['hold', 'email_notify'], function(field) {
+ if (request[field] == 't') {
+ request[field] = true;
+ } else if (request[field] == 'f' || typeof request[field] == 'undefined') {
+ request[field] = false;
+ }
+ });
+ if (request.request_type) {
+ if (typeof request.request_type.id != 'undefined') {
+ request.request_type = request.request_type.id;
+ }
+ angular.forEach(request_types,function(v,k) {
+ if (v.id() == request.request_type) {
+ $m_scope.extra.selected_request_type = v;
+ }
+ });
+ }
+ if (request.need_before) {
+ request.need_before = new Date(request.need_before);
+ }
+ if (request.pickup_lib) {
+ $m_scope.request.pickup_lib =
+ egCore.idl.fromHash('aou',request.pickup_lib);
+ } else {
+ $m_scope.request.pickup_lib =
+ egOrg.CanHaveVolumes(context_ou)
+ ? context_ou
+ : egOrg.get( egCore.auth.user().ws_ou() );
+ }
+ if (request.cancel_reason) {
+ $m_scope.request.cancel_reason =
+ egCore.idl.fromHash('acqcr',request.cancel_reason);
+ $m_scope.mode = 'view'; // TODO: want explicit uncancel?
+ }
+ if (request.request_status && request.request_status.id != 1) { // New
+ $m_scope.mode = 'view';
+ }
+ if (request.usr) {
+ if (typeof request.usr.id != 'undefined') {
+ $m_scope.extra.barcode = request.usr.card.barcode;
+ request.usr = request.usr.id;
+ }
+ }
+ $m_scope.cancel = function () {
+ $uibModalInstance.dismiss('canceled');
+ }
+ $m_scope.ok = function(request2,extra2) {
+ $uibModalInstance.close({
+ 'request':request2
+ ,'extra':extra2
+ });
+ }
+ $m_scope.model_has_changed = false;
+ $m_scope.cant_have_vols = function (id) {
+ return !egCore.org.CanHaveVolumes(id);
+ }
+ $m_scope.find_user = function () {
+
+ $m_scope.request.usr = null;
+ $m_scope.extra.user_obj = null;
+ if (!$m_scope.extra.barcode) return;
+
+ egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.get_barcodes',
+ egCore.auth.token(), egCore.auth.user().ws_ou(),
+ 'actor', $m_scope.extra.barcode)
+
+ .then(function(resp) { // get_barcodes
+
+ if (evt = egCore.evt.parse(resp)) {
+ console.error(evt.toString());
+ return;
+ }
+
+ if (!resp || !resp[0]) {
+ $m_scope.request.usr = null;
+ return;
+ }
+
+ egCore.pcrud.search('au', {
+ id : resp[0].id
+ }, {
+ flesh : 1,
+ flesh_fields : {
+ 'au' : [
+ 'card'
+ ,'home_ou'
+ ,'mailing_address'
+ ,'billing_address'
+ ,'settings'
+ ]
+ }
+ },
+ { atomic : true }
+ ).then(function(users) {
+ var usr = egCore.idl.toHash(users[0]);
+ $m_scope.extra.user_obj = usr;
+ $m_scope.request.usr = usr.id;
+ $m_scope.request.pickup_lib = egOrg.get(usr.home_ou.id);
+ $m_scope.request.phone_notify = usr.day_phone;
+ angular.forEach(usr.settings, function(s) {
+ if (s.name == 'opac.hold_notify') {
+ if (s.value.match('phone')) {
+ $m_scope.extra.phone_notify = true;
+ }
+ if (s.value.match('email')) {
+ $m_scope.request.email_notify = true;
+ }
+ }
+ if (s.name == 'opac.default_phone') {
+ $m_scope.request.phone_notify = s.value.replace(/^"/,'').replace(/"$/,'');
+ }
+ if (s.name == 'opac.default_pickup_location') {
+ $m_scope.request.pickup_lib =
+ egOrg.get(s.value);
+ }
+ });
+ return $m_scope.request;
+ });
+ });
+ }
+ $m_scope.$watch("extra.barcode", function(newVal, oldVal) {
+ if (newVal && newVal != oldVal) {
+ $m_scope.find_user();
+ }
+ });
+ $m_scope.$watch("extra.selected_request_type",
+ function(newVal, oldVal) {
+ if (newVal && newVal != oldVal) {
+ $m_scope.request.request_type = newVal.id();
+ }
+ }
+ );
+ }],
+ resolve : {
+ request_and_extra : function() {
+ if (mode=='create') {
+ var aur_obj = egCore.idl.toHash(new egCore.idl.aurs());
+ var extra = {};
+ if (row['usr']) {
+ return egCore.pcrud.search('au', {
+ id : row['usr']
+ }, {
+ flesh : 1,
+ flesh_fields : {
+ 'au' : [
+ 'card'
+ ,'home_ou'
+ ,'mailing_address'
+ ,'billing_address'
+ ,'settings'
+ ]
+ }
+ },
+ { atomic : true }
+ ).then(function(users) {
+ if (users.length > 0) {
+ var usr = egCore.idl.toHash(users[0]);
+ aur_obj.usr = usr.id;
+ aur_obj.pickup_lib = egCore.idl.toHash(
+ egOrg.get(usr.home_ou.id)
+ );
+ aur_obj.phone_notify = usr.day_phone;
+ angular.forEach(usr.settings, function(s) {
+ if (s.name == 'opac.hold_notify') {
+ if (s.value.match('phone')) {
+ extra.phone_notify = true;
+ }
+ if (s.value.match('email')) {
+ aur_obj.email_notify = true;
+ }
+ }
+ if (s.name == 'opac.default_phone') {
+ aur_obj.phone_notify = s.value.replace(/^"/,'').replace(/"$/,'');
+ }
+ if (s.name == 'opac.default_pickup_location') {
+ aur_obj.pickup_lib = egCore.idl.toHash(
+ egOrg.get(s.value)
+ );
+ }
+ });
+ }
+ return { 'request' : aur_obj, 'extra' : extra };
+ });
+ } else {
+ console.log('here');
+ return { 'request' : aur_obj, 'extra': extra };
+ }
+ } else {
+ return egCore.pcrud.search('aurs', {
+ id : row['id']
+ }, aurs_fleshing, {
+ atomic : true
+ }
+ ).then(function(requests) {
+ var aur_obj = egCore.idl.toHash(requests[0]);
+ var extra = {};
+ if (aur_obj.phone_notify) {
+ extra.phone_notify = true;
+ }
+ return { 'request' : aur_obj, 'extra' : extra };
+ });
+ }
+ }
+ ,request_types : function() {
+ return service.fetch_request_types();
+ }
+ ,request_status_types : function() {
+ return service.fetch_request_status_types();
+ }
+ }
+ }).result.then(function(data) {
+ delete data.request.request_status;
+ delete data.request.home_ou;
+ var aur_obj = new egCore.idl.fromHash('aur',data.request);
+ if (aur_obj.need_before() && typeof aur_obj.need_before() == 'object') {
+ aur_obj.need_before( aur_obj.need_before().toISOString() );
+ }
+ if (!data.extra.phone_notify) {
+ aur_obj.phone_notify(null);
+ }
+ if (mode=='create') {
+ aur_obj.isnew('t');
+ aur_obj.pickup_lib( aur_obj.pickup_lib().id() );
+ return egCore.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.user_request.create',
+ egCore.auth.token(), egCore.idl.toHash(aur_obj)
+ ).then(function(resp) {
+ var evt = egCore.evt.parse(resp);
+ if (evt) {
+ ngToast.danger(egCore.strings.CREATE_USER_REQUEST_FAIL + ' : ' + evt.desc);
+ } else {
+ ngToast.success(egCore.strings.CREATE_USER_REQUEST_SUCCESS);
+ }
+ callback(resp);
+ });
+ } else {
+ aur_obj.ischanged('t');
+ return egCore.pcrud.apply(aur_obj).then(function(resp) {
+ var evt = egCore.evt.parse(resp);
+ if (evt) {
+ ngToast.danger(egCore.strings.EDIT_USER_REQUEST_FAIL + ' : ' + evt.desc);
+ } else {
+ ngToast.success(egCore.strings.EDIT_USER_REQUEST_SUCCESS);
+ }
+ callback(resp);
+ });
+ }
+ }).catch(function(e) {
+ console.log('caught',e);
+ });
+ }
+
+ service.set_no_hold_requests = function(rows,callback) {
+ var ids = rows.map(function(v,i,a) {
+ return v.id;
+ });
+ return $uibModal.open({
+ templateUrl: './acq/requests/t_set_no_hold',
+ backdrop: 'static',
+ controller: ['$scope', '$uibModalInstance','egCore',
+ function($m_scope , $uibModalInstance , egCore ) {
+ $m_scope.ids = ids;
+ $m_scope.cancel = function () {
+ $uibModalInstance.dismiss('canceled');
+ }
+ $m_scope.ok = function(doit) {
+ $uibModalInstance.close(doit);
+ }
+ }],
+ resolve : {}
+ }).result.then(function(cancel_reason) {
+ return egCore.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.user_request.set_no_hold.batch',
+ egCore.auth.token(), ids
+ ).then(function(obj) {
+ if (callback) {
+ callback(obj);
+ }
+ });
+ }).catch(function(e) {
+ console.log('caught',e);
+ });
+ }
+
+ service.set_yes_hold_requests = function(rows,callback) {
+ var ids = rows.map(function(v,i,a) {
+ return v.id;
+ });
+ return $uibModal.open({
+ templateUrl: './acq/requests/t_set_yes_hold',
+ backdrop: 'static',
+ controller: ['$scope', '$uibModalInstance','egCore',
+ function($m_scope , $uibModalInstance , egCore ) {
+ $m_scope.ids = ids;
+ $m_scope.cancel = function () {
+ $uibModalInstance.dismiss('canceled');
+ }
+ $m_scope.ok = function(doit) {
+ $uibModalInstance.close(doit);
+ }
+ }],
+ resolve : {}
+ }).result.then(function(cancel_reason) {
+ return egCore.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.user_request.set_yes_hold.batch',
+ egCore.auth.token(), ids
+ ).then(function(obj) {
+ if (callback) {
+ callback(obj);
+ }
+ });
+ }).catch(function(e) {
+ console.log('caught',e);
+ });
+ }
+
+ service.cancel_requests = function(rows,callback) {
+ var ids = rows.map(function(v,i,a) {
+ return v.id;
+ });
+ return $uibModal.open({
+ templateUrl: './acq/requests/t_cancel',
+ backdrop: 'static',
+ controller: ['$scope', '$uibModalInstance','egCore','cancel_reasons',
+ function($m_scope , $uibModalInstance , egCore , cancel_reasons ) {
+ $m_scope.ids = ids;
+ $m_scope.cancel_reasons = cancel_reasons;
+ $m_scope.cancel = function () {
+ $uibModalInstance.dismiss('canceled');
+ }
+ $m_scope.ok = function(cancel_reason) {
+ $uibModalInstance.close(cancel_reason);
+ }
+ }],
+ resolve : {
+ cancel_reasons : function() {
+ return service.fetch_cancel_reasons();
+ }
+ }
+ }).result.then(function(cancel_reason) {
+ return egCore.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.user_request.cancel.batch.atomic',
+ egCore.auth.token(), ids, cancel_reason.id()
+ ).then(function(obj) {
+ if (callback) {
+ callback(obj);
+ }
+ });
+ }).catch(function(e) {
+ console.log('caught',e);
+ });
+ }
+
+ service.clear_requests = function(rows,callback) {
+ var ids = rows.map(function(v,i,a) {
+ return v.id;
+ });
+ return $uibModal.open({
+ templateUrl: './acq/requests/t_clear',
+ backdrop: 'static',
+ controller: ['$scope', '$uibModalInstance','egCore',
+ function($m_scope , $uibModalInstance , egCore) {
+ $m_scope.ids = ids;
+ $m_scope.cancel = function () {
+ $uibModalInstance.dismiss('canceled');
+ }
+ $m_scope.ok = function(cancel_reason) {
+ $uibModalInstance.close(true);
+ }
+ }],
+ resolve : {}
+ }).result.then(function(doit) {
+ return egCore.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.clear_completed_user_requests',
+ egCore.auth.token(), ids
+ ).then(function(obj) {
+ if (callback) {
+ callback(obj);
+ }
+ });
+ }).catch(function(e) {
+ console.log('caught',e);
+ });
+ }
+
+ return service;
+}])
+;