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 my $U = 'OpenILS::Application::AppUtils';
18 __PACKAGE__->register_method(
19 method => 'create_lineitem',
20 api_name => 'open-ils.acq.lineitem.create',
22 desc => 'Creates a lineitem',
24 {desc => 'Authentication token', type => 'string'},
25 {desc => 'The lineitem object to create', type => 'object'},
27 return => {desc => 'ID of newly created lineitem on success, Event on error'}
32 my($self, $conn, $auth, $li) = @_;
33 my $e = new_editor(xact=>1, authtoken=>$auth);
34 return $e->die_event unless $e->checkauth;
38 my $picklist = $e->retrieve_acq_picklist($li->picklist)
39 or return $e->die_event;
41 if($picklist->owner != $e->requestor->id) {
42 return $e->die_event unless
43 $e->allowed('CREATE_PICKLIST', $picklist->org_unit, $picklist);
46 # indicate the picklist was updated
47 $picklist->edit_time('now');
48 $picklist->editor($e->requestor->id);
49 $e->update_acq_picklist($picklist) or return $e->die_event;
52 if($li->purchase_order) {
53 my $po = $e->retrieve_acq_purchase_order($li->purchase_order)
54 or return $e->die_event;
55 return $e->die_event unless
56 $e->allowed('MANAGE_PROVIDER', $po->ordering_agency, $po);
58 $li->provider($po->provider) unless defined $li->provider;
61 $li->selector($e->requestor->id);
62 $e->create_acq_lineitem($li) or return $e->die_event;
69 __PACKAGE__->register_method(
70 method => 'retrieve_lineitem',
71 api_name => 'open-ils.acq.lineitem.retrieve',
73 desc => 'Retrieves a lineitem',
75 {desc => 'Authentication token', type => 'string'},
76 {desc => 'lineitem ID to retrieve', type => 'number'},
77 {options => q/Hash of options, including:
78 flesh_attrs : for attributes,
79 flesh_notes : for notes,
80 flesh_cancel_reason : for cancel reason,
81 flesh_li_details : for order details objects,
82 clear_marc : to clear marcxml from lineitem/, type => 'hash'},
84 return => {desc => 'lineitem object on success, Event on error'}
89 sub retrieve_lineitem {
90 my($self, $conn, $auth, $li_id, $options) = @_;
91 my $e = new_editor(authtoken=>$auth);
92 return $e->die_event unless $e->checkauth;
93 return retrieve_lineitem_impl($e, $li_id, $options);
96 sub retrieve_lineitem_impl {
97 my ($e, $li_id, $options) = @_;
103 jub => ['purchase_order', 'picklist'], # needed for permission check
109 my $fields = $flesh->{flesh_fields};
111 push(@{$fields->{jub} }, 'attributes') if $$options{flesh_attrs};
112 push(@{$fields->{jub} },'lineitem_notes') if $$options{flesh_notes};
113 push(@{$fields->{acqlin}}, 'alert_text') if $$options{flesh_notes};
114 push(@{$fields->{jub} }, 'order_summary') if $$options{flesh_order_summary};
115 push(@{$fields->{acqlin}}, 'cancel_reason') if $$options{flesh_cancel_reason};
117 if($$options{flesh_li_details}) {
118 push(@{$fields->{jub} }, 'lineitem_details');
119 push(@{$fields->{acqlid}}, 'fund' ) if $$options{flesh_fund};
120 push(@{$fields->{acqlid}}, 'fund_debit' ) if $$options{flesh_fund_debit};
121 push(@{$fields->{acqlid}}, 'cancel_reason') if $$options{flesh_cancel_reason};
124 if($$options{clear_marc}) { # avoid fetching marc blob
125 my @fields = grep { $_ ne 'marc' } Fieldmapper::acq::lineitem->new->real_fields;
126 $flesh->{select} = {jub => [@fields]};
129 my $li = $e->retrieve_acq_lineitem([$li_id, $flesh]) or return $e->event;
131 # collect the # of lids
132 if($$options{flesh_li_details}) {
133 $li->item_count(scalar(@{$li->lineitem_details}));
135 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id}, {idlist=>1});
136 $li->item_count(scalar(@$details));
139 # attach claims to LIDs
140 if($$options{flesh_li_details}) {
141 foreach (@{$li->lineitem_details}) {
143 $e->search_acq_claim([
144 {"lineitem_detail", $_->id}, {
145 "flesh" => 1, "flesh_fields" => {"acqcl" => ["type"]}
152 return $e->event unless (
153 $li->purchase_order and
154 $e->allowed(['VIEW_PURCHASE_ORDER', 'CREATE_PURCHASE_ORDER'],
155 $li->purchase_order->ordering_agency, $li->purchase_order)
157 $li->picklist and !$li->purchase_order and # user doesn't have view_po perms
158 $e->allowed(['VIEW_PICKLIST', 'CREATE_PICKLIST'],
159 $li->picklist->org_unit, $li->picklist)
162 unless ($$options{flesh_po}) {
164 $li->purchase_order ? $li->purchase_order->id : undef
167 unless ($$options{flesh_pl}) {
168 $li->picklist($li->picklist ? $li->picklist->id : undef);
175 __PACKAGE__->register_method(
176 method => 'delete_lineitem',
177 api_name => 'open-ils.acq.lineitem.delete',
179 desc => 'Deletes a lineitem',
181 {desc => 'Authentication token', type => 'string'},
182 {desc => 'lineitem ID to delete', type => 'number'},
184 return => {desc => '1 on success, Event on error'}
188 sub delete_lineitem {
189 my($self, $conn, $auth, $li_id) = @_;
190 my $e = new_editor(xact=>1, authtoken=>$auth);
191 return $e->die_event unless $e->checkauth;
193 my $li = $e->retrieve_acq_lineitem($li_id)
194 or return $e->die_event;
199 my $picklist = $e->retrieve_acq_picklist($li->picklist)
200 or return $e->die_event;
201 return OpenILS::Event->new('BAD_PARAMS')
202 if $picklist->owner != $e->requestor->id;
207 # delete the attached lineitem_details
208 my $lid_ids = $e->search_acq_lineitem_detail(
209 {lineitem => $li_id}, {idlist=>1});
211 for my $lid_id (@$lid_ids) {
212 $e->delete_acq_lineitem_detail(
213 $e->retrieve_acq_lineitem_detail($lid_id))
214 or return $e->die_event;
217 $e->delete_acq_lineitem($li) or return $e->die_event;
223 __PACKAGE__->register_method(
224 method => 'update_lineitem',
225 api_name => 'open-ils.acq.lineitem.update',
227 desc => 'Update one or many lineitems',
229 {desc => 'Authentication token', type => 'string'},
230 {desc => 'lineitem object update', type => 'object'}
232 return => {desc => '1 on success, Event on error'}
236 sub update_lineitem {
237 my($self, $conn, $auth, $li) = @_;
238 my $e = new_editor(xact=>1, authtoken=>$auth);
239 return $e->die_event unless $e->checkauth;
241 $li = [$li] unless ref $li eq "ARRAY";
243 my $evt = update_lineitem_impl($e, $_);
251 sub update_lineitem_impl {
254 my $orig_li = $e->retrieve_acq_lineitem([
256 { flesh => 1, # grab the lineitem with picklist attached
257 flesh_fields => {jub => ['picklist', 'purchase_order']}
259 ]) or return $e->die_event;
261 # the marc may have been cleared on retrieval...
262 $li->marc($orig_li->marc) unless $li->marc;
264 $li->editor($e->requestor->id);
265 $li->edit_time('now');
266 $e->update_acq_lineitem($li) or return $e->die_event;
270 __PACKAGE__->register_method(
271 method => 'lineitem_search',
272 api_name => 'open-ils.acq.lineitem.search',
275 desc => 'Searches lineitems',
277 {desc => 'Authentication token', type => 'string'},
278 {desc => 'Search definition', type => 'object'},
279 {desc => 'Options hash. idlist=true', type => 'object'},
280 {desc => 'List of lineitems', type => 'object/number'},
285 sub lineitem_search {
286 my($self, $conn, $auth, $search, $options) = @_;
287 my $e = new_editor(authtoken=>$auth);
288 return $e->event unless $e->checkauth;
289 return $e->event unless $e->allowed('CREATE_PICKLIST');
290 # XXX needs permissions consideration
291 my $lis = $e->search_acq_lineitem($search, {idlist=>1});
292 for my $li_id (@$lis) {
293 if($$options{idlist}) {
294 $conn->respond($li_id);
296 my $res = retrieve_lineitem($self, $conn, $auth, $li_id, $options);
297 $conn->respond($res) unless $U->event_code($res);
303 __PACKAGE__->register_method (
304 method => 'lineitems_related_by_bib',
305 api_name => 'open-ils.acq.lineitems_for_bib.by_bib_id',
308 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the bib id.
309 @param authtoken Login session key
310 @param bib_id Id for the pertinent bib record.
311 @param options Object for tweaking the selection criteria and fleshing options.
315 __PACKAGE__->register_method (
316 method => 'lineitems_related_by_bib',
317 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id',
320 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the id for any of the pertinent lineitems.
321 @param authtoken Login session key
322 @param bib_id Id for a pertinent lineitem.
323 @param options Object for tweaking the selection criteria and fleshing options.
327 __PACKAGE__->register_method (
328 method => 'lineitems_related_by_bib',
329 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id.count',
331 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)/
334 sub lineitems_related_by_bib {
335 my($self, $conn, $auth, $test_value, $options) = @_;
336 my $e = new_editor(authtoken => $auth);
337 return $e->event unless $e->checkauth;
339 my $perm_orgs = $U->user_has_work_perm_at($e, 'VIEW_PURCHASE_ORDER', {descendants =>1}, $e->requestor->id);
342 "select"=>{"jub"=>["id"]},
343 "from"=>{"jub" => {"acqpo" => {type => 'left'}, "acqpl" => {type => 'left'}}},
346 { "+acqpo"=>{ "ordering_agency" => $perm_orgs } },
347 { '+acqpl' => { org_unit => $perm_orgs } }
350 "order_by"=>[{"class"=>"jub", "field"=>"create_time", "direction"=>"desc"}]
353 # Be sure we just return the original LI if no related bibs
354 if ($self->api_name =~ /by_lineitem_id/) {
355 my $orig = retrieve_lineitem($self, $conn, $auth, $test_value) or
356 return $e->die_event;
357 if ($test_value = $orig->eg_bib_id) {
358 $query->{"where"}->{"eg_bib_id"} = $test_value;
360 $query->{"where"}->{"id"} = $orig->id;
362 } elsif ($test_value) {
363 $query->{"where"}->{"eg_bib_id"} = $test_value;
366 return new OpenILS::Event("BAD_PARAMS", "Null bib id");
369 if ($options && defined $options->{lineitem_state}) {
370 $query->{'where'}{'jub'}{'state'} = $options->{lineitem_state};
373 if ($options && defined $options->{po_state}) {
374 $query->{'where'}{'+acqpo'}{'state'} = $options->{po_state};
377 if ($options && defined $options->{order_by}) {
378 $query->{'order_by'} = $options->{order_by};
381 my $results = $e->json_query($query);
382 if ($self->api_name =~ /count$/) {
383 return scalar(@$results);
385 for my $result (@$results) {
386 # retrieve_lineitem takes care of POs and PLs and also handles
387 # options like flesh_notes and permissions checking.
389 retrieve_lineitem($self, $conn, $auth, $result->{"id"}, $options)
398 __PACKAGE__->register_method(
399 method => "lineitem_search_by_attributes",
400 api_name => "open-ils.acq.lineitem.search.by_attributes",
403 desc => "Performs a search against lineitem_attrs",
405 {desc => "Authentication token", type => "string"},
408 attr_value_pairs : list of pairs of (attr definition ID, attr value) where value can be scalar (fuzzy match) or array (exact match)
409 li_states : list of lineitem states
410 po_agencies : list of purchase order ordering agencies (org) ids
412 At least one of these search terms is required.
417 idlist : if set, only return lineitem IDs
418 clear_marc : if set, strip the MARC xml from the lineitem before delivery
419 flesh_attrs : flesh lineitem attributes;
426 __PACKAGE__->register_method(
427 method => "lineitem_search_by_attributes",
428 api_name => "open-ils.acq.lineitem.search.by_attributes.ident",
431 desc => "Performs a search against lineitem_attrs where ident is true. ".
432 "See open-ils.acq.lineitem.search.by_attributes for params."
436 sub lineitem_search_by_attributes {
437 my ($self, $conn, $auth, $search, $options) = @_;
439 my $e = new_editor(authtoken => $auth, xact => 1);
440 return $e->die_event unless $e->checkauth;
441 # XXX needs permissions consideration
443 return [] unless $search;
444 my $attr_value_pairs = $search->{attr_value_pairs};
445 my $li_states = $search->{li_states};
446 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
449 "select" => {"acqlia" =>
450 [{"column" => "lineitem", "transform" => "distinct"}]
454 "acqliad" => {"field" => "id", "fkey" => "definition"},
457 "fkey" => "lineitem",
462 "fkey" => "purchase_order"
471 $where->{"+acqliad"} = {"ident" => "t"}
472 if $self->api_name =~ /\.ident/;
474 my $searched_for_something = 0;
476 if (ref $attr_value_pairs eq "ARRAY") {
477 $where->{"-or"} = [];
478 foreach (@$attr_value_pairs) {
480 my ($def, $value) = @$_;
481 push @{$where->{"-or"}}, {
483 "attr_value" => (ref $value) ?
484 $value : {"ilike" => "%" . $value . "%"},
489 $searched_for_something = 1;
492 if ($li_states and @$li_states) {
493 $where->{"+jub"} = {"state" => $li_states};
494 $searched_for_something = 1;
497 if ($po_agencies and @$po_agencies) {
498 $where->{"+acqpo"} = {"ordering_agency" => $po_agencies};
499 $searched_for_something = 1;
502 if (not $searched_for_something) {
504 return new OpenILS::Event(
505 "BAD_PARAMS", note => "You have provided no search terms."
509 $query->{"where"} = $where;
510 my $lis = $e->json_query($query);
512 for my $li_id_obj (@$lis) {
513 my $li_id = $li_id_obj->{"lineitem"};
514 if($options->{"idlist"}) {
515 $conn->respond($li_id);
518 retrieve_lineitem($self, $conn, $auth, $li_id, $options)
526 __PACKAGE__->register_method(
527 method => 'lineitem_search_ident',
528 api_name => 'open-ils.acq.lineitem.search.ident',
531 desc => 'Performs a search against lineitem_attrs where ident is true',
533 {desc => 'Authentication token', type => 'string'},
534 { desc => q/Search definition. Options are:
535 attr_values : list of attribute values (required)
536 li_states : list of lineitem states
537 po_agencies : list of purchase order ordering agencies (org) ids
542 Options hash. Options are:
543 idlist : if set, only return lineitem IDs
544 clear_marc : if set, strip the MARC xml from the lineitem before delivery
545 flesh_attrs : flesh lineitem attributes;
553 my $LI_ATTR_SEARCH = {
554 select => { acqlia => ['lineitem'] },
567 fkey => 'purchase_order'
575 sub lineitem_search_ident {
576 my($self, $conn, $auth, $search, $options) = @_;
577 my $e = new_editor(authtoken=>$auth, xact=>1);
578 return $e->event unless $e->checkauth;
579 # XXX needs permissions consideration
581 return [] unless $search;
582 my $attr_values = $search->{attr_values};
583 my $li_states = $search->{li_states};
584 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
589 '+acqliad' => {ident => 't'},
593 push(@{$where_clause->{'-or'}}, {attr_value => {ilike => "%$_%"}}) for @$attr_values;
595 $where_clause->{'+jub'} = {state => {in => $li_states}}
596 if $li_states and @$li_states;
598 $where_clause->{'+acqpo'} = {ordering_agency => $po_agencies}
599 if $po_agencies and @$po_agencies;
601 $LI_ATTR_SEARCH->{where} = $where_clause;
603 my $lis = $e->json_query($LI_ATTR_SEARCH);
605 for my $li_id_obj (@$lis) {
606 my $li_id = $li_id_obj->{lineitem};
607 if($$options{idlist}) {
608 $conn->respond($li_id);
611 if($$options{flesh_attrs}) {
612 $li = $e->retrieve_acq_lineitem([
613 $li_id, {flesh => 1, flesh_fields => {jub => ['attributes']}}])
615 $li = $e->retrieve_acq_lineitem($li_id);
617 $li->clear_marc if $$options{clear_marc};
627 # this call duplicates a call in Order.pm and makes references to subs that don't exist.
628 # TODO: Verify then remove.
629 __PACKAGE__->register_method(
630 method => 'lineitem_detail_CUD_batch',
631 api_name => 'open-ils.acq.lineitem_detail.cud.batch_',
634 desc => q/Creates a new purchase order line item detail.
635 Additionally creates the associated fund_debit/,
637 {desc => 'Authentication token', type => 'string'},
638 {desc => 'List of lineitem_details to create', type => 'array'},
640 return => {desc => 'Streaming response of current position in the array'}
644 sub lineitem_detail_CUD_batch {
645 my($self, $conn, $auth, $li_details, $options) = @_;
646 my $e = new_editor(xact=>1, authtoken=>$auth);
647 return $e->die_event unless $e->checkauth;
649 my $total = scalar(@$li_details);
650 for my $li_detail (@$li_details) {
654 $logger->info(Dumper($li_detail));
655 $logger->info('lid id ' . $li_detail->id);
656 $logger->info('lineitem ' . $li_detail->lineitem);
658 if($li_detail->isnew) {
659 $res = create_lineitem_detail_impl($self, $conn, $e, $li_detail, $options);
660 } elsif($li_detail->ischanged) {
661 $res = update_lineitem_detail_impl($self, $conn, $e, $li_detail);
662 } elsif($li_detail->isdeleted) {
663 $res = delete_lineitem_detail_impl($self, $conn, $e, $li_detail->id);
665 return $e->event if $e->died;
666 $conn->respond({maximum => $total, progress => $pos++, li => $res});
669 return {complete => 1};
673 sub create_lineitem_detail_impl {
674 my($self, $conn, $e, $li_detail, $options) = @_;
677 my $li = $e->retrieve_acq_lineitem($li_detail->lineitem)
678 or return $e->die_event;
680 my $evt = update_li_edit_time($e, $li);
683 # XXX check lineitem provider perms
685 if($li_detail->fund) {
686 my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->die_event;
687 return $e->die_event unless
688 $e->allowed('MANAGE_FUND', $fund->org, $fund);
691 $e->create_acq_lineitem_detail($li_detail) or return $e->die_event;
693 unless($li_detail->barcode) {
694 my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_barcode_prefix') || 'ACQ';
695 $li_detail->barcode($pfx.$li_detail->id);
697 unless($li_detail->cn_label) {
698 my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_callnumber_prefix') || 'ACQ';
699 $li_detail->cn_label($pfx.$li_detail->id);
702 if(my $loc = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.default_copy_location')) {
703 $li_detail->location($loc);
706 $e->update_acq_lineitem_detail($li_detail) or return $e->die_event;
708 return $li_detail if $$options{return_obj};
709 return $li_detail->id
713 sub update_li_edit_time {
715 # some lineitem edits are allowed after approval time...
716 # return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li->id)
717 # if $li->state eq 'approved';
718 $li->edit_time('now');
719 $li->editor($e->requestor->id);
720 $e->update_acq_lineitem($li) or return $e->die_event;
725 __PACKAGE__->register_method(
726 method => 'retrieve_lineitem_detail',
727 api_name => 'open-ils.acq.lineitem_detail.retrieve',
729 desc => q/Updates a lineitem detail/,
731 { desc => 'Authentication token', type => 'string' },
732 { desc => 'id of lineitem_detail to retrieve', type => 'number' },
734 return => { desc => 'object on success, Event on failure' }
737 sub retrieve_lineitem_detail {
738 my($self, $conn, $auth, $li_detail_id) = @_;
739 my $e = new_editor(authtoken=>$auth);
740 return $e->event unless $e->checkauth;
742 my $li_detail = $e->retrieve_acq_lineitem_detail($li_detail_id)
745 if($li_detail->fund) {
746 my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->event;
747 return $e->event unless
748 $e->allowed('MANAGE_FUND', $fund->org, $fund);
751 # XXX check lineitem perms
756 __PACKAGE__->register_method(
757 method => 'approve_lineitem',
758 api_name => 'open-ils.acq.lineitem.approve',
760 desc => 'Mark a lineitem as approved',
762 { desc => 'Authentication token', type => 'string' },
763 { desc => 'lineitem ID', type => 'number' }
765 return => { desc => '1 on success, Event on error' }
768 sub approve_lineitem {
769 my($self, $conn, $auth, $li_id) = @_;
770 my $e = new_editor(xact=>1, authtoken=>$auth);
771 return $e->die_event unless $e->checkauth;
773 # XXX perm checks for each lineitem detail
775 my $li = $e->retrieve_acq_lineitem($li_id)
776 or return $e->die_event;
778 return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li_id)
779 if $li->state eq 'approved';
781 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id});
782 return OpenILS::Event->new('ACQ_LINEITEM_NO_COPIES', payload => $li_id)
783 unless scalar(@$details) > 0;
785 for my $detail (@$details) {
786 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_FUND', payload => $detail->id)
787 unless $detail->fund;
789 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_ORG', payload => $detail->id)
790 unless $detail->owning_lib;
793 $li->state('approved');
794 $li->edit_time('now');
795 $e->update_acq_lineitem($li) or return $e->die_event;
803 __PACKAGE__->register_method(
804 method => 'set_lineitem_attr',
805 api_name => 'open-ils.acq.lineitem_usr_attr.set',
807 desc => 'Sets a lineitem_usr_attr value',
809 { desc => 'Authentication token', type => 'string' },
810 { desc => 'Lineitem ID', type => 'number' },
811 { desc => 'Attr name', type => 'string' },
812 { desc => 'Attr value', type => 'string' }
814 return => { desc => '1 on success, Event on error' }
818 __PACKAGE__->register_method(
819 method => 'set_lineitem_attr',
820 api_name => 'open-ils.acq.lineitem_local_attr.set',
822 desc => 'Sets a lineitem_local_attr value',
824 { desc => 'Authentication token', type => 'string' },
825 { desc => 'Lineitem ID', type => 'number' },
826 { desc => 'Attr name', type => 'string' },
827 { desc => 'Attr value', type => 'string' }
829 return => { desc => 'ID of the attr object on success, Event on error' }
834 sub set_lineitem_attr {
835 my($self, $conn, $auth, $li_id, $attr_name, $attr_value) = @_;
836 my $e = new_editor(xact=>1, authtoken=>$auth);
837 return $e->die_event unless $e->checkauth;
841 my $attr_type = $self->api_name =~ /local_attr/ ?
842 'lineitem_local_attr_definition' : 'lineitem_usr_attr_definition';
844 my $attr = $e->search_acq_lineitem_attr({
846 attr_type => $attr_type,
847 attr_name => $attr_name})->[0];
849 my $find = "search_acq_$attr_type";
852 $attr->attr_value($attr_value);
853 $e->update_acq_lineitem_attr($attr) or return $e->die_event;
855 $attr = Fieldmapper::acq::lineitem_attr->new;
856 $attr->lineitem($li_id);
857 $attr->attr_type($attr_type);
858 $attr->attr_name($attr_name);
859 $attr->attr_value($attr_value);
861 my $attr_def_id = $e->$find({code => $attr_name}, {idlist=>1})->[0]
862 or return $e->die_event;
863 $attr->definition($attr_def_id);
864 $e->create_acq_lineitem_attr($attr) or return $e->die_event;
871 __PACKAGE__->register_method(
872 method => 'get_lineitem_attr_defs',
873 api_name => 'open-ils.acq.lineitem_attr_definition.retrieve.all',
875 desc => 'Retrieve lineitem attr definitions',
876 params => [ { desc => 'Authentication token', type => 'string' }, ],
877 return => { desc => 'List of attr definitions' }
881 sub get_lineitem_attr_defs {
882 my($self, $conn, $auth) = @_;
883 my $e = new_editor(authtoken=>$auth);
884 return $e->event unless $e->checkauth;
886 for my $type (qw/generated marc local usr provider/) {
887 my $call = "retrieve_all_acq_lineitem_${type}_attr_definition";
888 $results{$type} = $e->$call;
894 __PACKAGE__->register_method(
895 method => 'lineitem_note_CUD_batch',
896 api_name => 'open-ils.acq.lineitem_note.cud.batch',
899 desc => q/Manage lineitem notes/,
901 { desc => 'Authentication token', type => 'string' },
902 { desc => 'List of lineitem_notes to manage', type => 'array' },
905 { desc => 'Streaming response of current position in the array' }
909 sub lineitem_note_CUD_batch {
910 my($self, $conn, $auth, $li_notes) = @_;
912 my $e = new_editor(xact=>1, authtoken=>$auth);
913 return $e->die_event unless $e->checkauth;
916 my $total = @$li_notes;
919 for my $note (@$li_notes) {
921 $note->editor($e->requestor->id);
922 $note->edit_time('now');
925 $note->creator($e->requestor->id);
926 $note = $e->create_acq_lineitem_note($note) or return $e->die_event;
928 } elsif($note->isdeleted) {
929 $e->delete_acq_lineitem_note($note) or return $e->die_event;
931 } elsif($note->ischanged) {
932 $e->update_acq_lineitem_note($note) or return $e->die_event;
935 if(!$note->isdeleted) {
936 $note = $e->retrieve_acq_lineitem_note([
938 "flesh" => 1, "flesh_fields" => {"acqlin" => ["alert_text"]}
943 $conn->respond({maximum => $total, progress => ++$count, note => $note});
947 return {complete => 1};
950 __PACKAGE__->register_method(
951 method => 'ranged_line_item_alert_text',
952 api_name => 'open-ils.acq.line_item_alert_text.ranged.retrieve.all'); # TODO: signature
954 sub ranged_line_item_alert_text {
955 my($self, $conn, $auth, $org_id, $depth) = @_;
956 my $e = new_editor(authtoken => $auth);
957 return $e->event unless $e->checkauth;
958 return $e->event unless $e->allowed('ADMIN_ACQ_LINEITEM_ALERT_TEXT', $org_id);
959 return $e->search_acq_lineitem_alert_text(
960 {owning_lib => $U->get_org_full_path($org_id, $depth)});
964 __PACKAGE__->register_method(
965 method => "retrieve_lineitem_by_copy_id",
966 api_name => "open-ils.acq.lineitem.retrieve.by_copy_id",
968 desc => q/Manage lineitem notes/,
970 {desc => "Authentication token", type => "string"},
971 {desc => "Evergreen internal copy ID", type => "number"},
972 {desc => "Hash of options (see open-ils.acq.lineitem.retrieve",
976 desc => "Lineitem associated with given copy",
977 type => "object", class => "jub"
982 sub retrieve_lineitem_by_copy_id {
983 my ($self, $conn, $auth, $object_id, $options) = @_;
985 my $e = new_editor("authtoken" => $auth);
986 return $e->die_event unless $e->checkauth;
988 my $result = $e->json_query({
989 "select" => {"acqlid" => ["lineitem"]},
991 "where" => {"eg_copy_id" => $object_id}
994 return new OpenILS::Event("ACQ_LINEITEM_NOT_FOUND");
997 my $li = retrieve_lineitem_impl($e, $result->{"lineitem"}, $options) or
998 return $e->die_event;