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);
59 $li->selector($e->requestor->id);
60 $e->create_acq_lineitem($li) or return $e->die_event;
67 __PACKAGE__->register_method(
68 method => 'retrieve_lineitem',
69 api_name => 'open-ils.acq.lineitem.retrieve',
71 desc => 'Retrieves a lineitem',
73 {desc => 'Authentication token', type => 'string'},
74 {desc => 'lineitem ID to retrieve', type => 'number'},
75 {options => q/Hash of options, including
76 "flesh_attrs", which fleshes the attributes;
77 "flesh_li_details", which fleshes the order details objects/, type => 'hash'},
79 return => {desc => 'lineitem object on success, Event on error'}
84 sub retrieve_lineitem {
85 my($self, $conn, $auth, $li_id, $options) = @_;
86 my $e = new_editor(authtoken=>$auth);
87 return $e->die_event unless $e->checkauth;
88 return retrieve_lineitem_impl($e, $li_id, $options);
91 sub retrieve_lineitem_impl {
92 my ($e, $li_id, $options) = @_;
95 # XXX finer grained perms...
98 if($$options{flesh_attrs} or $$options{flesh_notes}) {
99 $flesh = {flesh => 2, flesh_fields => {jub => []}};
100 if($$options{flesh_notes}) {
101 push(@{$flesh->{flesh_fields}->{jub}}, 'lineitem_notes');
102 $flesh->{flesh_fields}->{acqlin} = ['alert_text'];
104 if($$options{"flesh_cancel_reason"}) {
105 push @{$flesh->{flesh_fields}->{jub}}, "cancel_reason";
107 push(@{$flesh->{flesh_fields}->{jub}}, 'attributes') if $$options{flesh_attrs};
110 my $li = $e->retrieve_acq_lineitem([$li_id, $flesh]) or return $e->die_event;
112 if($$options{flesh_li_details}) {
115 flesh_fields => {acqlid => ["cancel_reason"]} #XXX cancel_reason? always? really?
117 push(@{$ops->{flesh_fields}->{acqlid}}, 'fund') if $$options{flesh_fund};
118 push(@{$ops->{flesh_fields}->{acqlid}}, 'fund_debit') if $$options{flesh_fund_debit};
119 if (my $details = $e->search_acq_lineitem_detail([{lineitem => $li_id}, $ops])) {
120 $li->lineitem_details($details);
121 $li->item_count(scalar(@$details));
123 $li->lineitem_count(0);
126 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id}, {idlist=>1});
127 $li->item_count(scalar(@$details));
130 if($li->purchase_order) {
132 $e->retrieve_acq_purchase_order($li->purchase_order)
135 if($purchase_order->owner != $e->requestor->id) {
136 return $e->event unless
137 $e->allowed('VIEW_PURCHASE_ORDER', undef, $purchase_order);
139 } elsif($li->picklist) {
140 my $picklist = $e->retrieve_acq_picklist($li->picklist)
143 if($picklist->owner != $e->requestor->id) {
144 return $e->event unless
145 $e->allowed('VIEW_PICKLIST', undef, $picklist);
149 $li->clear_marc if $$options{clear_marc};
154 __PACKAGE__->register_method(
155 method => 'cancel_lineitem',
156 api_name => 'open-ils.acq.lineitem.cancel',
158 desc => 'Cancels a lineitem, any of its detail entries and corresponding copies and call numbers, and potentially related holds (if the bib becomes empty).',
160 {desc => 'Authentication token', type => 'string'},
161 {desc => 'lineitem ID to cancel', type => 'number'},
163 return => {desc => '1 on success, Event on error'}
167 sub cancel_lineitem {
168 my($self, $conn, $auth, $li_id, $cancel_reason) = @_;
169 my $e = new_editor(xact=>1, authtoken=>$auth);
170 return $e->die_event unless $e->checkauth;
172 $cancel_reason = $e->retrieve_acq_cancel_reason($cancel_reason);
173 if (!$cancel_reason) {
175 return new OpenILS::Event(
177 "note" => "Provide cancel reason ID" # let client handle I18N for such events?
181 my $li = $e->retrieve_acq_lineitem($li_id)
182 or return $e->die_event;
183 $li->cancel_reason( $cancel_reason);
185 # cancel the attached lineitem_details and gather corresponding copies
186 my $lids = $e->search_acq_lineitem_detail({
190 flesh_fields => { acqlid => ['eg_copy_id'] }
194 for my $lid (@$lids) {
195 $lid->cancel_reason( $cancel_reason );
196 $e->update_acq_lineitem_detail( $lid );
197 $lid->eg_copy_id->isdeleted('t');
198 push @$copies, $lid->eg_copy_id;
201 # attempt to delete the gathered copies (will this may handle volume deletion and do hold retargeting for us?)
202 my $cat = OpenSRF::AppSession->create('open-ils.cat');
204 my $req = $cat->request('open-ils.cat.asset.copy.fleshed.batch.update', $auth, $copies);
205 my $result = $req->recv;
207 if ($result != 1) { # failed to delete copies
212 $e->update_acq_lineitem($li) or return $e->die_event;
217 __PACKAGE__->register_method(
218 method => 'delete_lineitem',
219 api_name => 'open-ils.acq.lineitem.delete',
221 desc => 'Deletes a lineitem',
223 {desc => 'Authentication token', type => 'string'},
224 {desc => 'lineitem ID to delete', type => 'number'},
226 return => {desc => '1 on success, Event on error'}
230 sub delete_lineitem {
231 my($self, $conn, $auth, $li_id) = @_;
232 my $e = new_editor(xact=>1, authtoken=>$auth);
233 return $e->die_event unless $e->checkauth;
235 my $li = $e->retrieve_acq_lineitem($li_id)
236 or return $e->die_event;
241 my $picklist = $e->retrieve_acq_picklist($li->picklist)
242 or return $e->die_event;
243 return OpenILS::Event->new('BAD_PARAMS')
244 if $picklist->owner != $e->requestor->id;
249 # delete the attached lineitem_details
250 my $lid_ids = $e->search_acq_lineitem_detail(
251 {lineitem => $li_id}, {idlist=>1});
253 for my $lid_id (@$lid_ids) {
254 $e->delete_acq_lineitem_detail(
255 $e->retrieve_acq_lineitem_detail($lid_id))
256 or return $e->die_event;
259 $e->delete_acq_lineitem($li) or return $e->die_event;
265 __PACKAGE__->register_method(
266 method => 'update_lineitem',
267 api_name => 'open-ils.acq.lineitem.update',
269 desc => 'Update a lineitem',
271 {desc => 'Authentication token', type => 'string'},
272 {desc => 'lineitem object update', type => 'object'}
274 return => {desc => '1 on success, Event on error'}
278 sub update_lineitem {
279 my($self, $conn, $auth, $li) = @_;
280 my $e = new_editor(xact=>1, authtoken=>$auth);
281 return $e->die_event unless $e->checkauth;
282 my $evt = update_lineitem_impl($e, $li);
288 sub update_lineitem_impl {
291 my $orig_li = $e->retrieve_acq_lineitem([
293 { flesh => 1, # grab the lineitem with picklist attached
294 flesh_fields => {jub => ['picklist', 'purchase_order']}
296 ]) or return $e->die_event;
298 # the marc may have been cleared on retrieval...
299 $li->marc($e->retrieve_acq_lineitem($li->id)->marc)
302 $li->editor($e->requestor->id);
303 $li->edit_time('now');
304 $e->update_acq_lineitem($li) or return $e->die_event;
308 __PACKAGE__->register_method(
309 method => 'lineitem_search',
310 api_name => 'open-ils.acq.lineitem.search',
313 desc => 'Searches lineitems',
315 {desc => 'Authentication token', type => 'string'},
316 {desc => 'Search definition', type => 'object'},
317 {desc => 'Options hash. idlist=true', type => 'object'},
318 {desc => 'List of lineitems', type => 'object/number'},
323 sub lineitem_search {
324 my($self, $conn, $auth, $search, $options) = @_;
325 my $e = new_editor(authtoken=>$auth, xact=>1);
326 return $e->event unless $e->checkauth;
327 return $e->event unless $e->allowed('CREATE_PICKLIST');
328 # XXX needs permissions consideration
329 my $lis = $e->search_acq_lineitem($search, {idlist=>1});
330 for my $li_id (@$lis) {
331 if($$options{idlist}) {
332 $conn->respond($li_id);
334 my $res = retrieve_lineitem($self, $conn, $auth, $li_id, $options);
335 $conn->respond($res) unless $U->event_code($res);
341 __PACKAGE__->register_method (
342 method => 'lineitems_related_by_bib',
343 api_name => 'open-ils.acq.lineitems_for_bib.by_bib_id',
346 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the bib id.
347 @param authtoken Login session key
348 @param bib_id Id for the pertinent bib record.
349 @param options Object for tweaking the selection criteria and fleshing options.
353 __PACKAGE__->register_method (
354 method => 'lineitems_related_by_bib',
355 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id',
358 Retrieves lineitems attached to same bib record, subject to the PO ordering agency. This variant takes the id for any of the pertinent lineitems.
359 @param authtoken Login session key
360 @param bib_id Id for a pertinent lineitem.
361 @param options Object for tweaking the selection criteria and fleshing options.
365 __PACKAGE__->register_method (
366 method => 'lineitems_related_by_bib',
367 api_name => 'open-ils.acq.lineitems_for_bib.by_lineitem_id.count',
369 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)/
372 sub lineitems_related_by_bib {
373 my($self, $conn, $auth, $test_value, $options) = @_;
374 my $e = new_editor(authtoken => $auth);
375 return $e->event unless $e->checkauth;
377 my $perm_orgs = $U->user_has_work_perm_at($e, 'VIEW_PURCHASE_ORDER', {descendants =>1}, $e->requestor->id);
380 "select"=>{"jub"=>["id"]},
381 "from"=>{"jub"=>"acqpo"},
389 "order_by"=>[{"class"=>"jub", "field"=>"create_time", "direction"=>"desc"}]
392 # Be sure we just return the original LI if no related bibs
393 if ($self->api_name =~ /by_lineitem_id/) {
394 my $orig = retrieve_lineitem($self, $conn, $auth, $test_value) or
395 return $e->die_event;
396 if ($test_value = $orig->eg_bib_id) {
397 $query->{"where"}->{"eg_bib_id"} = $test_value;
399 $query->{"where"}->{"id"} = $orig->id;
401 } elsif ($test_value) {
402 $query->{"where"}->{"eg_bib_id"} = $test_value;
405 return new OpenILS::Event("BAD_PARAMS", "Null bib id");
408 if ($options && defined $options->{lineitem_state}) {
409 $query->{'where'}{'jub'}{'state'} = $options->{lineitem_state};
412 if ($options && defined $options->{po_state}) {
413 $query->{'where'}{'+acqpo'}{'state'} = $options->{po_state};
416 if ($options && defined $options->{order_by}) {
417 $query->{'order_by'} = $options->{order_by};
420 my $results = $e->json_query($query);
421 if ($self->api_name =~ /count$/) {
422 return scalar(@$results);
424 for my $result (@$results) {
425 # retrieve_lineitem takes care of POs and PLs and also handles
426 # options like flesh_notes and permissions checking.
428 retrieve_lineitem($self, $conn, $auth, $result->{"id"}, $options)
437 __PACKAGE__->register_method(
438 method => "lineitem_search_by_attributes",
439 api_name => "open-ils.acq.lineitem.search.by_attributes",
442 desc => "Performs a search against lineitem_attrs",
444 {desc => "Authentication token", type => "string"},
447 attr_value_pairs : list of pairs of (attr definition ID, attr value) where value can be scalar (fuzzy match) or array (exact match)
448 li_states : list of lineitem states
449 po_agencies : list of purchase order ordering agencies (org) ids
451 At least one of these search terms is required.
456 idlist : if set, only return lineitem IDs
457 clear_marc : if set, strip the MARC xml from the lineitem before delivery
458 flesh_attrs : flesh lineitem attributes;
465 __PACKAGE__->register_method(
466 method => "lineitem_search_by_attributes",
467 api_name => "open-ils.acq.lineitem.search.by_attributes.ident",
470 desc => "Performs a search against lineitem_attrs where ident is true.".
471 "See open-ils.acq.lineitem.search.by_attributes for params."
475 sub lineitem_search_by_attributes {
476 my ($self, $conn, $auth, $search, $options) = @_;
478 my $e = new_editor(authtoken => $auth, xact => 1);
479 return $e->die_event unless $e->checkauth;
480 # XXX needs permissions consideration
482 return [] unless $search;
483 my $attr_value_pairs = $search->{attr_value_pairs};
484 my $li_states = $search->{li_states};
485 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
488 "select" => {"acqlia" =>
489 [{"column" => "lineitem", "transform" => "distinct"}]
493 "acqliad" => {"field" => "id", "fkey" => "definition"},
496 "fkey" => "lineitem",
501 "fkey" => "purchase_order"
510 $where->{"+acqliad"} = {"ident" => "t"}
511 if $self->api_name =~ /\.ident/;
513 my $searched_for_something = 0;
515 if (ref $attr_value_pairs eq "ARRAY") {
516 $where->{"-or"} = [];
517 foreach (@$attr_value_pairs) {
519 my ($def, $value) = @$_;
520 push @{$where->{"-or"}}, {
522 "attr_value" => (ref $value) ?
523 $value : {"ilike" => "%" . $value . "%"},
528 $searched_for_something = 1;
531 if ($li_states and @$li_states) {
532 $where->{"+jub"} = {"state" => $li_states};
533 $searched_for_something = 1;
536 if ($po_agencies and @$po_agencies) {
537 $where->{"+acqpo"} = {"ordering_agency" => $po_agencies};
538 $searched_for_something = 1;
541 if (not $searched_for_something) {
543 return new OpenILS::Event(
544 "BAD_PARAMS", note => "You have provided no search terms."
548 $query->{"where"} = $where;
549 my $lis = $e->json_query($query);
551 for my $li_id_obj (@$lis) {
552 my $li_id = $li_id_obj->{"lineitem"};
553 if($options->{"idlist"}) {
554 $conn->respond($li_id);
557 retrieve_lineitem($self, $conn, $auth, $li_id, $options)
565 __PACKAGE__->register_method(
566 method => 'lineitem_search_ident',
567 api_name => 'open-ils.acq.lineitem.search.ident',
570 desc => 'Performs a search against lineitem_attrs where ident is true',
572 {desc => 'Authentication token', type => 'string'},
573 { desc => q/Search definition. Options are:
574 attr_values : list of attribute values (required)
575 li_states : list of lineitem states
576 po_agencies : list of purchase order ordering agencies (org) ids
581 Options hash. Options are:
582 idlist : if set, only return lineitem IDs
583 clear_marc : if set, strip the MARC xml from the lineitem before delivery
584 flesh_attrs : flesh lineitem attributes;
592 my $LI_ATTR_SEARCH = {
593 select => {acqlia => ['lineitem']},
606 fkey => 'purchase_order'
614 sub lineitem_search_ident {
615 my($self, $conn, $auth, $search, $options) = @_;
616 my $e = new_editor(authtoken=>$auth, xact=>1);
617 return $e->event unless $e->checkauth;
618 # XXX needs permissions consideration
620 return [] unless $search;
621 my $attr_values = $search->{attr_values};
622 my $li_states = $search->{li_states};
623 my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
628 '+acqliad' => {ident => 't'},
632 push(@{$where_clause->{'-or'}}, {attr_value => {ilike => "%$_%"}}) for @$attr_values;
634 $where_clause->{'+jub'} = {state => {in => $li_states}}
635 if $li_states and @$li_states;
637 $where_clause->{'+acqpo'} = {ordering_agency => $po_agencies}
638 if $po_agencies and @$po_agencies;
640 $LI_ATTR_SEARCH->{where} = $where_clause;
642 my $lis = $e->json_query($LI_ATTR_SEARCH);
644 for my $li_id_obj (@$lis) {
645 my $li_id = $li_id_obj->{lineitem};
646 if($$options{idlist}) {
647 $conn->respond($li_id);
650 if($$options{flesh_attrs}) {
651 $li = $e->retrieve_acq_lineitem([
652 $li_id, {flesh => 1, flesh_fields => {jub => ['attributes']}}])
654 $li = $e->retrieve_acq_lineitem($li_id);
656 $li->clear_marc if $$options{clear_marc};
665 __PACKAGE__->register_method(
666 method => 'lineitem_detail_CUD_batch',
667 api_name => 'open-ils.acq.lineitem_detail.cud.batch',
670 desc => q/Creates a new purchase order line item detail.
671 Additionally creates the associated fund_debit/,
673 {desc => 'Authentication token', type => 'string'},
674 {desc => 'List of lineitem_details to create', type => 'array'},
676 return => {desc => 'Streaming response of current position in the array'}
680 sub lineitem_detail_CUD_batch {
681 my($self, $conn, $auth, $li_details, $options) = @_;
682 my $e = new_editor(xact=>1, authtoken=>$auth);
683 return $e->die_event unless $e->checkauth;
685 my $total = scalar(@$li_details);
686 for my $li_detail (@$li_details) {
690 $logger->info(Dumper($li_detail));
691 $logger->info('lid id ' . $li_detail->id);
692 $logger->info('lineitem ' . $li_detail->lineitem);
694 if($li_detail->isnew) {
695 $res = create_lineitem_detail_impl($self, $conn, $e, $li_detail, $options);
696 } elsif($li_detail->ischanged) {
697 $res = update_lineitem_detail_impl($self, $conn, $e, $li_detail);
698 } elsif($li_detail->isdeleted) {
699 $res = delete_lineitem_detail_impl($self, $conn, $e, $li_detail->id);
701 return $e->event if $e->died;
702 $conn->respond({maximum => $total, progress => $pos++, li => $res});
705 return {complete => 1};
709 sub create_lineitem_detail_impl {
710 my($self, $conn, $e, $li_detail, $options) = @_;
713 my $li = $e->retrieve_acq_lineitem($li_detail->lineitem)
714 or return $e->die_event;
716 my $evt = update_li_edit_time($e, $li);
719 # XXX check lineitem provider perms
721 if($li_detail->fund) {
722 my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->die_event;
723 return $e->die_event unless
724 $e->allowed('MANAGE_FUND', $fund->org, $fund);
727 $e->create_acq_lineitem_detail($li_detail) or return $e->die_event;
729 unless($li_detail->barcode) {
730 my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_barcode_prefix') || 'ACQ';
731 $li_detail->barcode($pfx.$li_detail->id);
733 unless($li_detail->cn_label) {
734 my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_callnumber_prefix') || 'ACQ';
735 $li_detail->cn_label($pfx.$li_detail->id);
738 if(my $loc = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.default_copy_location')) {
739 $li_detail->location($loc);
742 $e->update_acq_lineitem_detail($li_detail) or return $e->die_event;
744 return $li_detail if $$options{return_obj};
745 return $li_detail->id
749 sub update_li_edit_time {
751 # some lineitem edits are allowed after approval time...
752 # return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li->id)
753 # if $li->state eq 'approved';
754 $li->edit_time('now');
755 $li->editor($e->requestor->id);
756 $e->update_acq_lineitem($li) or return $e->die_event;
761 __PACKAGE__->register_method(
762 method => 'retrieve_lineitem_detail',
763 api_name => 'open-ils.acq.lineitem_detail.retrieve',
765 desc => q/Updates a lineitem detail/,
767 {desc => 'Authentication token', type => 'string'},
768 {desc => 'id of lineitem_detail to retrieve', type => 'number'},
770 return => {desc => 'object on success, Event on failure'}
773 sub retrieve_lineitem_detail {
774 my($self, $conn, $auth, $li_detail_id) = @_;
775 my $e = new_editor(authtoken=>$auth);
776 return $e->event unless $e->checkauth;
778 my $li_detail = $e->retrieve_acq_lineitem_detail($li_detail_id)
781 if($li_detail->fund) {
782 my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->event;
783 return $e->event unless
784 $e->allowed('MANAGE_FUND', $fund->org, $fund);
787 # XXX check lineitem perms
793 __PACKAGE__->register_method(
794 method => 'approve_lineitem',
795 api_name => 'open-ils.acq.lineitem.approve',
797 desc => 'Mark a lineitem as approved',
799 {desc => 'Authentication token', type => 'string'},
800 {desc => 'lineitem ID', type => 'number'}
802 return => {desc => '1 on success, Event on error'}
805 sub approve_lineitem {
806 my($self, $conn, $auth, $li_id) = @_;
807 my $e = new_editor(xact=>1, authtoken=>$auth);
808 return $e->die_event unless $e->checkauth;
810 # XXX perm checks for each lineitem detail
812 my $li = $e->retrieve_acq_lineitem($li_id)
813 or return $e->die_event;
815 return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li_id)
816 if $li->state eq 'approved';
818 my $details = $e->search_acq_lineitem_detail({lineitem => $li_id});
819 return OpenILS::Event->new('ACQ_LINEITEM_NO_COPIES', payload => $li_id)
820 unless scalar(@$details) > 0;
822 for my $detail (@$details) {
823 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_FUND', payload => $detail->id)
824 unless $detail->fund;
826 return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_ORG', payload => $detail->id)
827 unless $detail->owning_lib;
830 $li->state('approved');
831 $li->edit_time('now');
832 $e->update_acq_lineitem($li) or return $e->die_event;
840 __PACKAGE__->register_method(
841 method => 'set_lineitem_attr',
842 api_name => 'open-ils.acq.lineitem_usr_attr.set',
844 desc => 'Sets a lineitem_usr_attr value',
846 {desc => 'Authentication token', type => 'string'},
847 {desc => 'Lineitem ID', type => 'number'},
848 {desc => 'Attr name', type => 'string'},
849 {desc => 'Attr value', type => 'string'}
851 return => {desc => '1 on success, Event on error'}
855 __PACKAGE__->register_method(
856 method => 'set_lineitem_attr',
857 api_name => 'open-ils.acq.lineitem_local_attr.set',
859 desc => 'Sets a lineitem_local_attr value',
861 {desc => 'Authentication token', type => 'string'},
862 {desc => 'Lineitem ID', type => 'number'},
863 {desc => 'Attr name', type => 'string'},
864 {desc => 'Attr value', type => 'string'}
866 return => {desc => 'ID of the attr object on success, Event on error'}
871 sub set_lineitem_attr {
872 my($self, $conn, $auth, $li_id, $attr_name, $attr_value) = @_;
873 my $e = new_editor(xact=>1, authtoken=>$auth);
874 return $e->die_event unless $e->checkauth;
878 my $attr_type = $self->api_name =~ /local_attr/ ?
879 'lineitem_local_attr_definition' : 'lineitem_usr_attr_definition';
881 my $attr = $e->search_acq_lineitem_attr({
883 attr_type => $attr_type,
884 attr_name => $attr_name})->[0];
886 my $find = "search_acq_$attr_type";
889 $attr->attr_value($attr_value);
890 $e->update_acq_lineitem_attr($attr) or return $e->die_event;
892 $attr = Fieldmapper::acq::lineitem_attr->new;
893 $attr->lineitem($li_id);
894 $attr->attr_type($attr_type);
895 $attr->attr_name($attr_name);
896 $attr->attr_value($attr_value);
898 my $attr_def_id = $e->$find({code => $attr_name}, {idlist=>1})->[0]
899 or return $e->die_event;
900 $attr->definition($attr_def_id);
901 $e->create_acq_lineitem_attr($attr) or return $e->die_event;
908 __PACKAGE__->register_method(
909 method => 'get_lineitem_attr_defs',
910 api_name => 'open-ils.acq.lineitem_attr_definition.retrieve.all',
912 desc => 'Retrieve lineitem attr definitions',
914 {desc => 'Authentication token', type => 'string'},
916 return => {desc => 'List of attr definitions'}
920 sub get_lineitem_attr_defs {
921 my($self, $conn, $auth) = @_;
922 my $e = new_editor(authtoken=>$auth);
923 return $e->event unless $e->checkauth;
925 for my $type (qw/generated marc local usr provider/) {
926 my $call = "retrieve_all_acq_lineitem_${type}_attr_definition";
927 $results{$type} = $e->$call;
933 __PACKAGE__->register_method(
934 method => 'lineitem_note_CUD_batch',
935 api_name => 'open-ils.acq.lineitem_note.cud.batch',
938 desc => q/Manage lineitem notes/,
940 {desc => 'Authentication token', type => 'string'},
941 {desc => 'List of lineitem_notes to manage', type => 'array'},
943 return => {desc => 'Streaming response of current position in the array'}
947 sub lineitem_note_CUD_batch {
948 my($self, $conn, $auth, $li_notes) = @_;
950 my $e = new_editor(xact=>1, authtoken=>$auth);
951 return $e->die_event unless $e->checkauth;
954 my $total = @$li_notes;
957 for my $note (@$li_notes) {
959 $note->editor($e->requestor->id);
960 $note->edit_time('now');
963 $note->creator($e->requestor->id);
964 $note = $e->create_acq_lineitem_note($note) or return $e->die_event;
966 } elsif($note->isdeleted) {
967 $e->delete_acq_lineitem_note($note) or return $e->die_event;
969 } elsif($note->ischanged) {
970 $e->update_acq_lineitem_note($note) or return $e->die_event;
973 if(!$note->isdeleted) {
974 $note = $e->retrieve_acq_lineitem_note([
976 "flesh" => 1, "flesh_fields" => {"acqlin" => ["alert_text"]}
981 $conn->respond({maximum => $total, progress => ++$count, note => $note});
985 return {complete => 1};
988 __PACKAGE__->register_method(
989 method => 'ranged_line_item_alert_text',
990 api_name => 'open-ils.acq.line_item_alert_text.ranged.retrieve.all');
992 sub ranged_line_item_alert_text {
993 my($self, $conn, $auth, $org_id, $depth) = @_;
994 my $e = new_editor(authtoken => $auth);
995 return $e->event unless $e->checkauth;
996 return $e->event unless $e->allowed('ADMIN_ACQ_LINEITEM_ALERT_TEXT', $org_id);
997 return $e->search_acq_lineitem_alert_text(
998 {owning_lib => $U->get_org_full_path($org_id, $depth)});