1 package OpenILS::Application::Acq::Lineitem;
2 use base qw/OpenILS::Application/;
3 use strict; use warnings;
6 use OpenSRF::Utils::Logger qw(:logger);
7 use OpenILS::Utils::Fieldmapper;
8 use OpenILS::Utils::CStoreEditor q/:funcs/;
9 use OpenILS::Const qw/:const/;
10 use OpenSRF::Utils::SettingsClient;
11 use OpenILS::Application::AppUtils;
12 use OpenILS::Application::Acq::Financials;
13 use OpenILS::Application::Cat::BibCommon;
14 use OpenILS::Application::Cat::AssetCommon;
15 use OpenILS::Application::Acq::Lineitem::BatchUpdate;
16 use OpenILS::Application::Acq::Common;
17 my $U = 'OpenILS::Application::AppUtils';
18 my $AC = 'OpenILS::Application::Acq::Common';
21 __PACKAGE__->register_method(
22 method => 'create_lineitem',
23 api_name => 'open-ils.acq.lineitem.create',
25 desc => 'Creates a lineitem',
27 {desc => 'Authentication token', type => 'string'},
28 {desc => 'The lineitem object to create', type => 'object'},
30 return => {desc => 'ID of newly created lineitem on success, Event on error'}
35 my($self, $conn, $auth, $li) = @_;
36 my $e = new_editor(xact=>1, authtoken=>$auth);
37 return $e->die_event unless $e->checkauth;
41 my $picklist = $e->retrieve_acq_picklist($li->picklist)
42 or return $e->die_event;
44 if($picklist->owner != $e->requestor->id) {
45 return $e->die_event unless
46 $e->allowed('CREATE_PICKLIST', $picklist->org_unit, $picklist);
49 # indicate the picklist was updated
50 $picklist->edit_time('now');
51 $picklist->editor($e->requestor->id);
52 $e->update_acq_picklist($picklist) or return $e->die_event;
56 if($li->purchase_order) {
57 $po = $e->retrieve_acq_purchase_order([
59 {flesh => 1, flesh_fields => {acqpo => ['provider']}}
60 ]) or return $e->die_event;
61 return $e->die_event unless
62 $e->allowed('MANAGE_PROVIDER', $po->ordering_agency, $po);
64 $li->provider($po->provider) unless defined $li->provider;
67 $li->selector($e->requestor->id);
68 $li = $e->create_acq_lineitem($li) or return $e->die_event;
70 # if no price is set, see if it can be extracted from the price attribute.
71 if (not defined $li->estimated_unit_price) { # '0' is valid
72 my $evt = set_li_price_from_attr($e, $li);
77 # apply the default number of copies for this provider
78 for (1 .. $po->provider->default_copy_count) {
79 my $lid = Fieldmapper::acq::lineitem_detail->new;
80 $lid->lineitem($li->id);
81 $lid->owning_lib($e->requestor->ws_ou);
82 $e->create_acq_lineitem_detail($lid) or return $e->die_event;
90 # See if we have a value for the price attribute. If so, apply the price
91 # value to the lineitem.
92 # Returns undef on success, Event on error.
93 sub set_li_price_from_attr {
96 my $attr = $e->search_acq_lineitem_attr({
98 attr_type => 'lineitem_marc_attr_definition',
104 my $val = $attr->attr_value;
106 return unless defined $val; # '0' is valid
108 $li->estimated_unit_price($val);
110 if (!$e->update_acq_lineitem($li)) {
112 return OpenILS::Event->new('BAD_PARAMS',
113 desc => "Invalid lineitem price value: '$val'") ;
120 __PACKAGE__->register_method(
121 method => 'retrieve_lineitem',
122 api_name => 'open-ils.acq.lineitem.retrieve',
125 desc => 'Retrieves a lineitem',
127 {desc => 'Authentication token', type => 'string'},
128 {desc => 'lineitem ID to retrieve', type => 'number'},
129 {options => q/Hash of options, including:
130 flesh_attrs : for attributes,
131 flesh_notes : for notes,
132 flesh_cancel_reason : for cancel reason,
133 flesh_li_details : for order details objects,
134 flesh_provider : for provider,
135 flesh_claim_policy : for claim policy,
136 flesh_queued_record : for queued bib record from Vandelay,
137 clear_marc : to clear marcxml from lineitem/, type => 'hash'},
139 return => {desc => 'lineitem object on success, Event on error'}
144 sub retrieve_lineitem {
145 my($self, $conn, $auth, $li_id, $options) = @_;
146 my $e = new_editor(authtoken=>$auth);
147 return $e->die_event unless $e->checkauth;
148 return retrieve_lineitem_impl($e, $li_id, $options);
151 sub retrieve_lineitem_impl {
152 my ($e, $li_id, $options, $no_auth) = @_; # no_auth needed for EDI scripts
158 jub => ['purchase_order', 'picklist'], # needed for permission check
164 my $fields = $flesh->{flesh_fields};
166 push(@{$fields->{jub} }, 'attributes') if $$options{flesh_attrs};
167 push(@{$fields->{jub} },'lineitem_notes') if $$options{flesh_notes};
168 push(@{$fields->{acqlin}}, 'alert_text') if $$options{flesh_notes};
169 push(@{$fields->{jub} }, 'order_summary') if $$options{flesh_order_summary};
170 push(@{$fields->{jub} }, 'cancel_reason') if $$options{flesh_cancel_reason};
171 push(@{$fields->{jub} }, 'provider') if $$options{flesh_provider};
172 push(@{$fields->{jub} }, 'claim_policy') if $$options{flesh_claim_policy};
173 push(@{$fields->{jub} }, 'queued_record') if $$options{flesh_queued_record};
174 push(@{$fields->{jub} }, 'creator') if $$options{flesh_creator};
175 push(@{$fields->{jub} }, 'editor') if $$options{flesh_editor};
176 push(@{$fields->{jub} }, 'selector') if $$options{flesh_selector};
178 if ($$options{flesh_formulas}) {
179 push(@{$fields->{jub}}, 'distribution_formulas');
180 push(@{$fields->{acqdfa}}, 'formula');
181 push(@{$fields->{acqdfa}}, 'creator');
184 if($$options{flesh_li_details}) {
185 push(@{$fields->{jub} }, 'lineitem_details');
186 push(@{$fields->{acqlid}}, 'fund' ) if $$options{flesh_fund};
187 push(@{$fields->{acqlid}}, 'fund_debit' ) if $$options{flesh_fund_debit};
188 push(@{$fields->{acqlid}}, 'cancel_reason') if $$options{flesh_cancel_reason};
189 push(@{$fields->{acqlid}}, 'circ_modifier') if $$options{flesh_circ_modifier};
190 push(@{$fields->{acqlid}}, 'location') if $$options{flesh_location};
191 push(@{$fields->{acqlid}}, 'eg_copy_id') if $$options{flesh_copies};
194 if($$options{clear_marc}) { # avoid fetching marc blob
195 my @fields = grep { $_ ne 'marc' } Fieldmapper::acq::lineitem->new->real_fields;
196 $flesh->{select} = {jub => [@fields]};
199 my $li = $e->retrieve_acq_lineitem([$li_id, $flesh]) or return $e->event;
201 # collect the # of lids
202 if($$options{flesh_li_details}) {
203 $li->item_count(scalar(@{$li->lineitem_details}));
205 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id}, {idlist=>1});
206 $li->item_count(scalar(@$details));
209 # attach claims to LIDs
210 if($$options{flesh_li_details}) {
211 foreach (@{$li->lineitem_details}) {
213 $e->search_acq_claim([
214 {"lineitem_detail", $_->id}, {
215 "flesh" => 1, "flesh_fields" => {"acqcl" => ["type"]}
222 return $e->event unless ((
223 $li->purchase_order and
224 ($no_auth or $e->allowed(['VIEW_PURCHASE_ORDER', 'CREATE_PURCHASE_ORDER'],
225 $li->purchase_order->ordering_agency, $li->purchase_order))
227 $li->picklist and !$li->purchase_order and # user doesn't have view_po perms
228 ($no_auth or $e->allowed(['VIEW_PICKLIST', 'CREATE_PICKLIST'],
229 $li->picklist->org_unit, $li->picklist))
232 unless ($$options{flesh_po}) {
234 $li->purchase_order ? $li->purchase_order->id : undef
237 unless ($$options{flesh_pl}) {
238 $li->picklist($li->picklist ? $li->picklist->id : undef);
243 __PACKAGE__->register_method(
244 method => 'retrieve_lineitem_batch',
245 api_name => 'open-ils.acq.lineitem.retrieve.batch',
247 max_bundle_count => 1,
250 Retrieves a set of lineitems.
251 See open-ils.acq.lineitem.retrieve/,
253 {desc => 'Authentication token', type => 'string'},
254 {desc => 'Array of lineitem IDs to retrieve', type => 'array'},
255 {options => q/See open-ils.acq.lineitem.retrieve/}
257 return => {desc => 'Stream of lineitems, Event on error'}
262 sub retrieve_lineitem_batch {
263 my($self, $client, $auth, $li_ids, $options) = @_;
264 my $e = new_editor(authtoken => $auth, xact => 1);
265 return $e->die_event unless $e->checkauth;
267 for my $li_id (@$li_ids) {
270 lineitem => retrieve_lineitem_impl($e, $li_id, $options),
271 existing_copies => $AC->li_existing_copies($e, $li_id)
282 __PACKAGE__->register_method(
283 method => 'delete_lineitem',
284 api_name => 'open-ils.acq.lineitem.delete',
286 desc => 'Deletes a lineitem',
288 {desc => 'Authentication token', type => 'string'},
289 {desc => 'lineitem ID to delete', type => 'number'},
291 return => {desc => '1 on success, Event on error'}
295 __PACKAGE__->register_method(
296 method => 'delete_lineitem',
297 api_name => 'open-ils.acq.purchase_order.lineitem.delete',
299 desc => 'Deletes a lineitem from a purchase order',
301 {desc => 'Authentication token', type => 'string'},
302 {desc => 'lineitem ID to delete', type => 'number'},
304 return => {desc => '1 on success, Event on error'}
308 __PACKAGE__->register_method(
309 method => 'delete_lineitem',
310 api_name => 'open-ils.acq.picklist.lineitem.delete',
312 desc => 'Deletes a lineitem from a picklist',
314 {desc => 'Authentication token', type => 'string'},
315 {desc => 'lineitem ID to delete', type => 'number'},
317 return => {desc => '1 on success, Event on error'}
321 sub delete_lineitem {
322 my($self, $conn, $auth, $li_id) = @_;
323 my $e = new_editor(xact=>1, authtoken=>$auth);
324 return $e->die_event unless $e->checkauth;
326 my $li = $e->retrieve_acq_lineitem($li_id)
327 or return $e->die_event;
332 my $picklist = $e->retrieve_acq_picklist($li->picklist)
333 or return $e->die_event;
334 return OpenILS::Event->new('BAD_PARAMS')
335 if $picklist->owner != $e->requestor->id;
340 # once a LI is attached to a PO, deleting it
341 # from a picklist means *detaching* it from the picklist
342 if ($self->api_name =~ /picklist/ && $li->purchase_order) {
344 my $evt = update_lineitem_impl($e, $li);
350 # delete the attached lineitem_details
351 my $lid_ids = $e->search_acq_lineitem_detail(
352 {lineitem => $li_id}, {idlist=>1});
354 for my $lid_id (@$lid_ids) {
355 $e->delete_acq_lineitem_detail(
356 $e->retrieve_acq_lineitem_detail($lid_id))
357 or return $e->die_event;
360 $e->delete_acq_lineitem($li) or return $e->die_event;
366 __PACKAGE__->register_method(
367 method => 'update_lineitem',
368 api_name => 'open-ils.acq.lineitem.update',
370 desc => 'Update one or many lineitems',
372 {desc => 'Authentication token', type => 'string'},
373 {desc => 'lineitem object update', type => 'object'}
375 return => {desc => '1 on success, Event on error'}
379 sub update_lineitem {
380 my($self, $conn, $auth, $li) = @_;
381 my $e = new_editor(xact=>1, authtoken=>$auth);
382 return $e->die_event unless $e->checkauth;
384 $li = [$li] unless ref $li eq "ARRAY";
386 my $evt = update_lineitem_impl($e, $_);
394 sub update_lineitem_impl {
397 my $orig_li = $e->retrieve_acq_lineitem([
399 { flesh => 1, # grab the lineitem with picklist attached
400 flesh_fields => {jub => ['picklist', 'purchase_order']}
402 ]) or return $e->die_event;
404 # the marc may have been cleared on retrieval...
405 $li->marc($orig_li->marc) unless $li->marc;
407 $li->editor($e->requestor->id);
408 $li->edit_time('now');
409 $e->update_acq_lineitem($li) or return $e->die_event;
413 __PACKAGE__->register_method(
414 method => 'lineitem_search',
415 api_name => 'open-ils.acq.lineitem.search',
418 desc => 'Searches lineitems',
420 {desc => 'Authentication token', type => 'string'},
421 {desc => 'Search definition', type => 'object'},
422 {desc => 'Options hash. idlist=true', type => 'object'},
423 {desc => 'List of lineitems', type => 'object/number'},
428 sub lineitem_search {
429 my($self, $conn, $auth, $search, $options) = @_;
430 my $e = new_editor(authtoken=>$auth);
431 return $e->event unless $e->checkauth;
432 return $e->event unless $e->allowed('CREATE_PICKLIST');
433 # XXX needs permissions consideration
434 my $lis = $e->search_acq_lineitem($search, {idlist=>1});
435 for my $li_id (@$lis) {
436 if($$options{idlist}) {
437 $conn->respond($li_id);
439 my $res = retrieve_lineitem($self, $conn, $auth, $li_id, $options);
440 $conn->respond($res) unless $U->event_code($res);
446 __PACKAGE__->register_method (
447 method => 'lineitems_related_by_bib',
448 api_name => 'open-ils.acq.lineitems_for_bib.by_bib_id',
451 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the bib id.
452 @param authtoken Login session key
453 @param bib_id Id for the pertinent bib record.
454 @param options Object for tweaking the selection criteria and fleshing options.
458 __PACKAGE__->register_method (
459 method => 'lineitems_related_by_bib',
460 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id',
463 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the id for any of the pertinent lineitems.
464 @param authtoken Login session key
465 @param bib_id Id for a pertinent lineitem.
466 @param options Object for tweaking the selection criteria and fleshing options.
470 __PACKAGE__->register_method (
471 method => 'lineitems_related_by_bib',
472 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id.count',
474 signature => q/See open-ils.acq.lineitems_for_bib.by_lineitem_id. This version returns numbers of lineitems only (XXX may count lineitems we don't actually have permission to retrieve)/
477 sub lineitems_related_by_bib {
478 my($self, $conn, $auth, $test_value, $options) = @_;
479 my $e = new_editor(authtoken => $auth);
480 return $e->event unless $e->checkauth;
482 my $perm_orgs = $U->user_has_work_perm_at($e, 'VIEW_PURCHASE_ORDER', {descendants =>1}, $e->requestor->id);
485 "select"=>{"jub"=>["id"]},
486 "from"=>{"jub" => {"acqpo" => {type => 'left'}, "acqpl" => {type => 'left'}}},
489 { "+acqpo"=>{ "ordering_agency" => $perm_orgs } },
490 { '+acqpl' => { org_unit => $perm_orgs } }
493 "order_by"=>[{"class"=>"jub", "field"=>"create_time", "direction"=>"desc"}]
496 # Be sure we just return the original LI if no related bibs
497 if ($self->api_name =~ /by_lineitem_id/) {
498 my $orig = retrieve_lineitem($self, $conn, $auth, $test_value) or
499 return $e->die_event;
500 if ($test_value = $orig->eg_bib_id) {
501 $query->{"where"}->{"eg_bib_id"} = $test_value;
503 $query->{"where"}->{"id"} = $orig->id;
505 } elsif ($test_value) {
506 $query->{"where"}->{"eg_bib_id"} = $test_value;
509 return new OpenILS::Event("BAD_PARAMS", "Null bib id");
512 if ($options && defined $options->{lineitem_state}) {
513 $query->{'where'}{'jub'}{'state'} = $options->{lineitem_state};
516 if ($options && defined $options->{po_state}) {
517 $query->{'where'}{'+acqpo'}{'state'} = $options->{po_state};
520 if ($options && defined $options->{order_by}) {
521 $query->{'order_by'} = $options->{order_by};
524 my $results = $e->json_query($query);
525 if ($self->api_name =~ /count$/) {
526 return scalar(@$results);
528 for my $result (@$results) {
529 # retrieve_lineitem takes care of POs and PLs and also handles
530 # options like flesh_notes and permissions checking.
532 retrieve_lineitem($self, $conn, $auth, $result->{"id"}, $options)
541 __PACKAGE__->register_method(
542 method => "lineitem_search_by_attributes",
543 api_name => "open-ils.acq.lineitem.search.by_attributes",
546 desc => "Performs a search against lineitem_attrs",
548 {desc => "Authentication token", type => "string"},
551 attr_value_pairs : list of pairs of (attr definition ID, attr value) where value can be scalar (fuzzy match) or array (exact match)
552 li_states : list of lineitem states
553 po_agencies : list of purchase order ordering agencies (org) ids
555 At least one of these search terms is required.
560 idlist : if set, only return lineitem IDs
561 clear_marc : if set, strip the MARC xml from the lineitem before delivery
562 flesh_attrs : flesh lineitem attributes;
569 __PACKAGE__->register_method(
570 method => "lineitem_search_by_attributes",
571 api_name => "open-ils.acq.lineitem.search.by_attributes.ident",
574 desc => "Performs a search against lineitem_attrs where ident is true. ".
575 "See open-ils.acq.lineitem.search.by_attributes for params."
579 sub lineitem_search_by_attributes {
580 my ($self, $conn, $auth, $search, $options) = @_;
582 my $e = new_editor(authtoken => $auth, xact => 1);
583 return $e->die_event unless $e->checkauth;
584 # XXX needs permissions consideration
586 return [] unless $search;
587 my $attr_value_pairs = $search->{attr_value_pairs};
588 my $li_states = $search->{li_states};
589 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
592 "select" => {"acqlia" =>
593 [{"column" => "lineitem", "transform" => "distinct"}]
597 "acqliad" => {"field" => "id", "fkey" => "definition"},
600 "fkey" => "lineitem",
605 "fkey" => "purchase_order"
614 $where->{"+acqliad"} = {"ident" => "t"}
615 if $self->api_name =~ /\.ident/;
617 my $searched_for_something = 0;
619 if (ref $attr_value_pairs eq "ARRAY") {
620 $where->{"-or"} = [];
621 foreach (@$attr_value_pairs) {
623 my ($def, $value) = @$_;
624 push @{$where->{"-or"}}, {
626 "attr_value" => (ref $value) ?
627 $value : {"ilike" => "%" . $value . "%"},
632 $searched_for_something = 1;
635 if ($li_states and @$li_states) {
636 $where->{"+jub"} = {"state" => $li_states};
637 $searched_for_something = 1;
640 if ($po_agencies and @$po_agencies) {
641 $where->{"+acqpo"} = {"ordering_agency" => $po_agencies};
642 $searched_for_something = 1;
645 if (not $searched_for_something) {
647 return new OpenILS::Event(
648 "BAD_PARAMS", note => "You have provided no search terms."
652 $query->{"where"} = $where;
653 my $lis = $e->json_query($query);
655 for my $li_id_obj (@$lis) {
656 my $li_id = $li_id_obj->{"lineitem"};
657 if($options->{"idlist"}) {
658 $conn->respond($li_id);
661 retrieve_lineitem($self, $conn, $auth, $li_id, $options)
669 __PACKAGE__->register_method(
670 method => 'lineitem_search_ident',
671 api_name => 'open-ils.acq.lineitem.search.ident',
674 desc => 'Performs a search against lineitem_attrs where ident is true',
676 {desc => 'Authentication token', type => 'string'},
677 { desc => q/Search definition. Options are:
678 attr_values : list of attribute values (required)
679 li_states : list of lineitem states
680 po_agencies : list of purchase order ordering agencies (org) ids
685 Options hash. Options are:
686 idlist : if set, only return lineitem IDs
687 clear_marc : if set, strip the MARC xml from the lineitem before delivery
688 flesh_attrs : flesh lineitem attributes;
696 my $LI_ATTR_SEARCH = {
697 select => { acqlia => ['lineitem'] },
710 fkey => 'purchase_order'
718 sub lineitem_search_ident {
719 my($self, $conn, $auth, $search, $options) = @_;
720 my $e = new_editor(authtoken=>$auth, xact=>1);
721 return $e->event unless $e->checkauth;
722 # XXX needs permissions consideration
724 return [] unless $search;
725 my $attr_values = $search->{attr_values};
726 my $li_states = $search->{li_states};
727 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
732 '+acqliad' => {ident => 't'},
736 push(@{$where_clause->{'-or'}}, {attr_value => {ilike => "%$_%"}}) for @$attr_values;
738 $where_clause->{'+jub'} = {state => {in => $li_states}}
739 if $li_states and @$li_states;
741 $where_clause->{'+acqpo'} = {ordering_agency => $po_agencies}
742 if $po_agencies and @$po_agencies;
744 $LI_ATTR_SEARCH->{where} = $where_clause;
746 my $lis = $e->json_query($LI_ATTR_SEARCH);
748 for my $li_id_obj (@$lis) {
749 my $li_id = $li_id_obj->{lineitem};
750 if($$options{idlist}) {
751 $conn->respond($li_id);
754 if($$options{flesh_attrs}) {
755 $li = $e->retrieve_acq_lineitem([
756 $li_id, {flesh => 1, flesh_fields => {jub => ['attributes']}}])
758 $li = $e->retrieve_acq_lineitem($li_id);
760 $li->clear_marc if $$options{clear_marc};
768 __PACKAGE__->register_method(
769 method => 'retrieve_lineitem_detail',
770 api_name => 'open-ils.acq.lineitem_detail.retrieve',
773 desc => q/Updates a lineitem detail/,
775 { desc => 'Authentication token', type => 'string' },
776 { desc => 'id of lineitem_detail to retrieve', type => 'number' },
778 return => { desc => 'object on success, Event on failure' }
781 sub retrieve_lineitem_detail {
782 my($self, $conn, $auth, $li_detail_id) = @_;
783 my $e = new_editor(authtoken=>$auth);
784 return $e->event unless $e->checkauth;
786 my $li_detail = $e->retrieve_acq_lineitem_detail($li_detail_id)
789 if($li_detail->fund) {
790 my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->event;
791 return $e->event unless
792 $e->allowed('MANAGE_FUND', $fund->org, $fund);
795 # XXX check lineitem perms
800 __PACKAGE__->register_method(
801 method => 'approve_lineitem',
802 api_name => 'open-ils.acq.lineitem.approve',
804 desc => 'Mark a lineitem as approved',
806 { desc => 'Authentication token', type => 'string' },
807 { desc => 'lineitem ID', type => 'number' }
809 return => { desc => '1 on success, Event on error' }
812 sub approve_lineitem {
813 my($self, $conn, $auth, $li_id) = @_;
814 my $e = new_editor(xact=>1, authtoken=>$auth);
815 return $e->die_event unless $e->checkauth;
817 # XXX perm checks for each lineitem detail
819 my $li = $e->retrieve_acq_lineitem($li_id)
820 or return $e->die_event;
822 return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li_id)
823 if $li->state eq 'approved';
825 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id});
826 return OpenILS::Event->new('ACQ_LINEITEM_NO_COPIES', payload => $li_id)
827 unless scalar(@$details) > 0;
829 for my $detail (@$details) {
830 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_FUND', payload => $detail->id)
831 unless $detail->fund;
833 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_ORG', payload => $detail->id)
834 unless $detail->owning_lib;
837 $li->state('approved');
838 $li->edit_time('now');
839 $e->update_acq_lineitem($li) or return $e->die_event;
847 __PACKAGE__->register_method(
848 method => 'set_lineitem_attr',
849 api_name => 'open-ils.acq.lineitem_usr_attr.set',
851 desc => 'Sets a lineitem_usr_attr value',
853 { desc => 'Authentication token', type => 'string' },
854 { desc => 'Lineitem ID', type => 'number' },
855 { desc => 'Attr name', type => 'string' },
856 { desc => 'Attr value', type => 'string' }
858 return => { desc => '1 on success, Event on error' }
862 __PACKAGE__->register_method(
863 method => 'set_lineitem_attr',
864 api_name => 'open-ils.acq.lineitem_local_attr.set',
866 desc => 'Sets a lineitem_local_attr value',
868 { desc => 'Authentication token', type => 'string' },
869 { desc => 'Lineitem ID', type => 'number' },
870 { desc => 'Attr name', type => 'string' },
871 { desc => 'Attr value', type => 'string' }
873 return => { desc => 'ID of the attr object on success, Event on error' }
878 sub set_lineitem_attr {
879 my($self, $conn, $auth, $li_id, $attr_name, $attr_value) = @_;
880 my $e = new_editor(xact=>1, authtoken=>$auth);
881 return $e->die_event unless $e->checkauth;
885 my $attr_type = $self->api_name =~ /local_attr/ ?
886 'lineitem_local_attr_definition' : 'lineitem_usr_attr_definition';
888 my $attr = $e->search_acq_lineitem_attr({
890 attr_type => $attr_type,
891 attr_name => $attr_name})->[0];
893 my $find = "search_acq_$attr_type";
896 $attr->attr_value($attr_value);
897 $e->update_acq_lineitem_attr($attr) or return $e->die_event;
899 $attr = Fieldmapper::acq::lineitem_attr->new;
900 $attr->lineitem($li_id);
901 $attr->attr_type($attr_type);
902 $attr->attr_name($attr_name);
903 $attr->attr_value($attr_value);
905 my $attr_def_id = $e->$find({code => $attr_name}, {idlist=>1})->[0]
906 or return $e->die_event;
907 $attr->definition($attr_def_id);
908 $e->create_acq_lineitem_attr($attr) or return $e->die_event;
915 __PACKAGE__->register_method(
916 method => 'get_lineitem_attr_defs',
917 api_name => 'open-ils.acq.lineitem_attr_definition.retrieve.all',
920 desc => 'Retrieve lineitem attr definitions',
921 params => [ { desc => 'Authentication token', type => 'string' }, ],
922 return => { desc => 'List of attr definitions' }
926 sub get_lineitem_attr_defs {
927 my($self, $conn, $auth) = @_;
928 my $e = new_editor(authtoken=>$auth);
929 return $e->event unless $e->checkauth;
931 for my $type (qw/generated marc local usr provider/) {
932 my $call = "retrieve_all_acq_lineitem_${type}_attr_definition";
933 $results{$type} = $e->$call;
939 __PACKAGE__->register_method(
940 method => 'lineitem_note_CUD_batch',
941 api_name => 'open-ils.acq.lineitem_note.cud.batch',
944 desc => q/Manage lineitem notes/,
946 { desc => 'Authentication token', type => 'string' },
947 { desc => 'List of lineitem_notes to manage', type => 'array' },
950 { desc => 'Streaming response of current position in the array' }
954 sub lineitem_note_CUD_batch {
955 my($self, $conn, $auth, $li_notes) = @_;
957 my $e = new_editor(xact=>1, authtoken=>$auth);
958 return $e->die_event unless $e->checkauth;
961 my $total = @$li_notes;
964 for my $note (@$li_notes) {
966 $note->editor($e->requestor->id);
967 $note->edit_time('now');
970 $note->creator($e->requestor->id);
971 $note = $e->create_acq_lineitem_note($note) or return $e->die_event;
973 } elsif($note->isdeleted) {
974 $e->delete_acq_lineitem_note($note) or return $e->die_event;
976 } elsif($note->ischanged) {
977 $e->update_acq_lineitem_note($note) or return $e->die_event;
980 if(!$note->isdeleted) {
981 $note = $e->retrieve_acq_lineitem_note([
983 "flesh" => 1, "flesh_fields" => {"acqlin" => ["alert_text"]}
988 $conn->respond({maximum => $total, progress => ++$count, note => $note});
992 return {complete => 1};
995 __PACKAGE__->register_method(
996 method => 'ranged_line_item_alert_text',
997 api_name => 'open-ils.acq.line_item_alert_text.ranged.retrieve.all'); # TODO: signature
999 sub ranged_line_item_alert_text {
1000 my($self, $conn, $auth, $org_id, $depth) = @_;
1001 my $e = new_editor(authtoken => $auth);
1002 return $e->event unless $e->checkauth;
1003 return $e->event unless $e->allowed('ADMIN_ACQ_LINEITEM_ALERT_TEXT', $org_id);
1004 return $e->search_acq_lineitem_alert_text(
1005 {owning_lib => $U->get_org_full_path($org_id, $depth)});
1009 __PACKAGE__->register_method(
1010 method => "retrieve_lineitem_by_copy_id",
1011 api_name => "open-ils.acq.lineitem.retrieve.by_copy_id",
1014 desc => q/Manage lineitem notes/,
1016 {desc => "Authentication token", type => "string"},
1017 {desc => "Evergreen internal copy ID", type => "number"},
1018 {desc => "Hash of options (see open-ils.acq.lineitem.retrieve",
1022 desc => "Lineitem associated with given copy",
1023 type => "object", class => "jub"
1028 sub retrieve_lineitem_by_copy_id {
1029 my ($self, $conn, $auth, $object_id, $options) = @_;
1031 my $e = new_editor("authtoken" => $auth);
1032 return $e->die_event unless $e->checkauth;
1034 my $result = $e->json_query({
1035 "select" => {"acqlid" => ["lineitem"]},
1037 "where" => {"eg_copy_id" => $object_id}
1040 return new OpenILS::Event("ACQ_LINEITEM_NOT_FOUND");
1043 my $li = retrieve_lineitem_impl($e, $result->{"lineitem"}, $options) or
1044 return $e->die_event;