]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Acq/Lineitem.pm
using new common cat code to in-transactoin bib/volume/copy creation. created stream...
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Acq / Lineitem.pm
1 package OpenILS::Application::Acq::Picklist;
2 use base qw/OpenILS::Application/;
3 use strict; use warnings;
4
5 use OpenILS::Event;
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::Cat::BibCommon;
13 use OpenILS::Application::Cat::AssetCommon;
14 my $U = 'OpenILS::Application::AppUtils';
15
16
17 __PACKAGE__->register_method(
18         method => 'create_lineitem',
19         api_name        => 'open-ils.acq.lineitem.create',
20         signature => {
21         desc => 'Creates a lineitem',
22         params => [
23             {desc => 'Authentication token', type => 'string'},
24             {desc => 'The lineitem object to create', type => 'object'},
25         ],
26         return => {desc => 'ID of newly created lineitem on success, Event on error'}
27     }
28 );
29
30 sub create_lineitem {
31     my($self, $conn, $auth, $li) = @_;
32     my $e = new_editor(xact=>1, authtoken=>$auth);
33     return $e->die_event unless $e->checkauth;
34
35
36     if($li->picklist) {
37         my $picklist = $e->retrieve_acq_picklist($li->picklist)
38             or return $e->die_event;
39
40         if($picklist->owner != $e->requestor->id) {
41             return $e->die_event unless 
42                 $e->allowed('CREATE_PICKLIST', $picklist->org_unit, $picklist);
43         }
44     
45         # indicate the picklist was updated
46         $picklist->edit_time('now');
47         $picklist->editor($e->requestor->id);
48         $e->update_acq_picklist($picklist) or return $e->die_event;
49     }
50
51     if($li->purchase_order) {
52         my $po = $e->retrieve_acq_purchase_order($li->purchase_order)
53             or return $e->die_event;
54         return $e->die_event unless 
55             $e->allowed('MANAGE_PROVIDER', $po->ordering_agency, $po);
56     }
57
58     $li->selector($e->requestor->id);
59     $e->create_acq_lineitem($li) or return $e->die_event;
60
61     $e->commit;
62     return $li->id;
63 }
64
65
66 __PACKAGE__->register_method(
67         method => 'retrieve_lineitem',
68         api_name        => 'open-ils.acq.lineitem.retrieve',
69         signature => {
70         desc => 'Retrieves a lineitem',
71         params => [
72             {desc => 'Authentication token', type => 'string'},
73             {desc => 'lineitem ID to retrieve', type => 'number'},
74             {options => q/Hash of options, including 
75                 "flesh_attrs", which fleshes the attributes; 
76                 "flesh_li_details", which fleshes the order details objects/, type => 'hash'},
77         ],
78         return => {desc => 'lineitem object on success, Event on error'}
79     }
80 );
81
82
83 sub retrieve_lineitem {
84     my($self, $conn, $auth, $li_id, $options) = @_;
85     my $e = new_editor(authtoken=>$auth);
86     return $e->die_event unless $e->checkauth;
87     $options ||= {};
88
89     # XXX finer grained perms...
90
91     my $li;
92
93     if($$options{flesh_attrs}) {
94         $li = $e->retrieve_acq_lineitem([
95             $li_id, {flesh => 1, flesh_fields => {jub => ['attributes']}}])
96             or return $e->event;
97     } else {
98         $li = $e->retrieve_acq_lineitem($li_id) or return $e->event;
99     }
100
101     if($$options{flesh_li_details}) {
102         my $ops = {
103             flesh => 1,
104             flesh_fields => {acqlid => []}
105         };
106         push(@{$ops->{flesh_fields}->{acqlid}}, 'fund') if $$options{flesh_fund};
107         push(@{$ops->{flesh_fields}->{acqlid}}, 'fund_debit') if $$options{flesh_fund_debit};
108         my $details = $e->search_acq_lineitem_detail([{lineitem => $li_id}, $ops]);
109         $li->lineitem_details($details);
110         $li->item_count(scalar(@$details));
111     } else {
112         my $details = $e->search_acq_lineitem_detail({lineitem => $li_id}, {idlist=>1});
113         $li->item_count(scalar(@$details));
114     }
115
116     if($li->picklist) {
117         my $picklist = $e->retrieve_acq_picklist($li->picklist)
118             or return $e->event;
119     
120         if($picklist->owner != $e->requestor->id) {
121             return $e->event unless 
122                 $e->allowed('VIEW_PICKLIST', undef, $picklist);
123         }
124     }
125
126     $li->clear_marc if $$options{clear_marc};
127
128     return $li;
129 }
130
131
132
133 __PACKAGE__->register_method(
134         method => 'delete_lineitem',
135         api_name        => 'open-ils.acq.lineitem.delete',
136         signature => {
137         desc => 'Deletes a lineitem',
138         params => [
139             {desc => 'Authentication token', type => 'string'},
140             {desc => 'lineitem ID to delete', type => 'number'},
141         ],
142         return => {desc => '1 on success, Event on error'}
143     }
144 );
145
146 sub delete_lineitem {
147     my($self, $conn, $auth, $li_id) = @_;
148     my $e = new_editor(xact=>1, authtoken=>$auth);
149     return $e->die_event unless $e->checkauth;
150
151     my $li = $e->retrieve_acq_lineitem($li_id)
152         or return $e->die_event;
153
154     # XXX check state
155
156     if($li->picklist) {
157         my $picklist = $e->retrieve_acq_picklist($li->picklist)
158             or return $e->die_event;
159         return OpenILS::Event->new('BAD_PARAMS') 
160             if $picklist->owner != $e->requestor->id;
161     } else {
162         # check PO perms
163     }
164
165     # delete the attached lineitem_details
166     my $lid_ids = $e->search_acq_lineitem_detail(
167         {lineitem => $li_id}, {idlist=>1});
168
169     for my $lid_id (@$lid_ids) {
170         $e->delete_acq_lineitem_detail(
171             $e->retrieve_acq_lineitem_detail($lid_id))
172             or return $e->die_event;
173     }
174
175     $e->delete_acq_lineitem($li) or return $e->die_event;
176     $e->commit;
177     return 1;
178 }
179
180
181 __PACKAGE__->register_method(
182         method => 'update_lineitem',
183         api_name        => 'open-ils.acq.lineitem.update',
184         signature => {
185         desc => 'Update a lineitem',
186         params => [
187             {desc => 'Authentication token', type => 'string'},
188             {desc => 'lineitem object update', type => 'object'}
189         ],
190         return => {desc => '1 on success, Event on error'}
191     }
192 );
193
194 sub update_lineitem {
195     my($self, $conn, $auth, $li) = @_;
196     my $e = new_editor(xact=>1, authtoken=>$auth);
197     return $e->die_event unless $e->checkauth;
198     my $evt = update_lineitem_impl($e, $li);
199     return $evt if $evt;
200     $e->commit;
201     return 1;
202 }
203
204 sub update_lineitem_impl {
205     my($e, $li) = @_;
206
207     my $orig_li = $e->retrieve_acq_lineitem([
208         $li->id,
209         {   flesh => 1, # grab the lineitem with picklist attached
210             flesh_fields => {jub => ['picklist', 'purchase_order']}
211         }
212     ]) or return $e->die_event;
213
214     # the marc may have been cleared on retrieval...
215     $li->marc($e->retrieve_acq_lineitem($li->id)->marc)
216         unless $li->marc;
217
218     $li->editor($e->requestor->id);
219     $li->edit_time('now');
220     $e->update_acq_lineitem($li) or return $e->die_event;
221     return undef;
222 }
223
224 __PACKAGE__->register_method(
225         method => 'lineitem_search',
226         api_name => 'open-ils.acq.lineitem.search',
227     stream => 1,
228         signature => {
229         desc => 'Searches lineitems',
230         params => [
231             {desc => 'Authentication token', type => 'string'},
232             {desc => 'Search definition', type => 'object'},
233             {desc => 'Optoins hash.  idlist=true', type => 'object'},
234             {desc => 'List of lineitems', type => 'object/number'},
235         ]
236     }
237 );
238
239 sub lineitem_search {
240     my($self, $conn, $auth, $search, $options) = @_;
241     my $e = new_editor(authtoken=>$auth, xact=>1);
242     return $e->event unless $e->checkauth;
243     return $e->event unless $e->allowed('CREATE_PICKLIST');
244     # XXX needs permissions consideration
245     my $lis = $e->search_acq_lineitem($search, {idlist=>1});
246     for my $li_id (@$lis) {
247         if($$options{idlist}) {
248             $conn->respond($li_id);
249         } else {
250             my $res = retrieve_lineitem($self, $conn, $auth, $li_id, $options);
251             $conn->respond($res) unless $U->event_code($res);
252         }
253     }
254     return undef;
255 }
256
257
258 __PACKAGE__->register_method(
259         method => 'lineitem_search_ident',
260         api_name => 'open-ils.acq.lineitem.search.ident',
261     stream => 1,
262         signature => {
263         desc => 'Performs a search against lineitem_attrs where ident is true',
264         params => [
265             {desc => 'Authentication token', type => 'string'},
266             {   desc => q/Search definition. Options are:
267                    attr_values : list of attribute values (required)
268                    li_states : list of lineitem states
269                    po_agencies : list of purchase order ordering agencies (org) ids
270                 /,
271                 type => 'object',
272             },
273             {   desc => q/
274                     Options hash.  Options are:
275                         idlist : if set, only return lineitem IDs
276                         clear_marc : if set, strip the MARC xml from the lineitem before delivery
277                         flesh_attrs : flesh lineitem attributes; 
278                 /,
279                 type => 'object',
280             }
281         ]
282     }
283 );
284
285 my $LI_ATTR_SEARCH = {
286     select => {acqlia => ['lineitem']},
287     from => {
288         acqlia => {
289             acqliad => {
290                 field => 'id',
291                 fkey => 'definition'
292             },
293             jub => {
294                 field => 'id',
295                 fkey => 'lineitem',
296                 join => {
297                     acqpo => {
298                         field => 'id',
299                         fkey => 'purchase_order'
300                     }
301                 }
302             }
303         }
304     }
305 };
306
307 sub lineitem_search_ident {
308     my($self, $conn, $auth, $search, $options) = @_;
309     my $e = new_editor(authtoken=>$auth, xact=>1);
310     return $e->event unless $e->checkauth;
311     # XXX needs permissions consideration
312
313     return [] unless $search;
314     my $attr_values = $search->{attr_values};
315     my $li_states = $search->{li_states};
316     my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
317
318     my $where_clause = {
319         '-or' => [],
320         '+acqlia' => {
321             '+acqliad' => {ident => 't'},
322         }
323     };
324
325     push(@{$where_clause->{'-or'}}, {attr_value => {ilike => "%$_%"}}) for @$attr_values;
326
327     $where_clause->{'+jub'} = {state => {in => $li_states}}
328         if $li_states and @$li_states;
329
330     $where_clause->{'+acqpo'} = {ordering_agency => $po_agencies} 
331         if $po_agencies and @$po_agencies;
332
333     $LI_ATTR_SEARCH->{where} = $where_clause;
334
335     my $lis = $e->json_query($LI_ATTR_SEARCH);
336
337     for my $li_id_obj (@$lis) {
338         my $li_id = $li_id_obj->{lineitem};
339         if($$options{idlist}) {
340             $conn->respond($li_id);
341         } else {
342             my $li;
343             if($$options{flesh_attrs}) {
344                 $li = $e->retrieve_acq_lineitem([
345                     $li_id, {flesh => 1, flesh_fields => {jub => ['attributes']}}])
346             } else {
347                 $li = $e->retrieve_acq_lineitem($li_id);
348             }
349             $li->clear_marc if $$options{clear_marc};
350             $conn->respond($li);
351         }
352     }
353     return undef;
354 }
355
356
357 __PACKAGE__->register_method(
358         method => 'create_lineitem_detail',
359         api_name        => 'open-ils.acq.lineitem_detail.create',
360         signature => {
361         desc => q/Creates a new purchase order line item detail.  
362             Additionally creates the associated fund_debit/,
363         params => [
364             {desc => 'Authentication token', type => 'string'},
365             {desc => 'lineitem_detail to create', type => 'object'},
366         ],
367         return => {desc => 'The purchase order line item detail id, Event on failure'}
368     }
369 );
370
371 sub create_lineitem_detail {
372     my($self, $conn, $auth, $li_detail, $options) = @_;
373     my $e = new_editor(xact=>1, authtoken=>$auth);
374     return $e->die_event unless $e->checkauth;
375     my $res = create_lineitem_detail_impl($self, $conn, $e, $li_detail, $options);
376     return $e->event if $e->died;
377     $e->commit;
378     return $res;
379 }
380
381
382 __PACKAGE__->register_method(
383         method => 'lineitem_detail_CUD_batch',
384         api_name => 'open-ils.acq.lineitem_detail.cud.batch',
385     stream => 1,
386         signature => {
387         desc => q/Creates a new purchase order line item detail.  
388             Additionally creates the associated fund_debit/,
389         params => [
390             {desc => 'Authentication token', type => 'string'},
391             {desc => 'List of lineitem_details to create', type => 'array'},
392         ],
393         return => {desc => 'Streaming response of current position in the array'}
394     }
395 );
396
397 sub lineitem_detail_CUD_batch {
398     my($self, $conn, $auth, $li_details, $options) = @_;
399     my $e = new_editor(xact=>1, authtoken=>$auth);
400     return $e->die_event unless $e->checkauth;
401     my $pos = 0;
402     my $total = scalar(@$li_details);
403     for my $li_detail (@$li_details) {
404         my $res;
405
406         use Data::Dumper;
407         $logger->info(Dumper($li_detail));
408         $logger->info('lid id ' . $li_detail->id);
409         $logger->info('lineitem ' . $li_detail->lineitem);
410
411         if($li_detail->isnew) {
412             $res = create_lineitem_detail_impl($self, $conn, $e, $li_detail, $options);
413         } elsif($li_detail->ischanged) {
414             $res = update_lineitem_detail_impl($self, $conn, $e, $li_detail);
415         } elsif($li_detail->isdeleted) {
416             $res = delete_lineitem_detail_impl($self, $conn, $e, $li_detail->id);
417         }
418         return $e->event if $e->died;
419         $conn->respond({maximum => $total, progress => $pos++, li => $res});
420     }
421     $e->commit;
422     return {complete => 1};
423 }
424
425
426 sub create_lineitem_detail_impl {
427     my($self, $conn, $e, $li_detail, $options) = @_;
428     $options ||= {};
429
430     my $li = $e->retrieve_acq_lineitem($li_detail->lineitem)
431         or return $e->die_event;
432
433     my $evt = update_li_edit_time($e, $li);
434     return $evt if $evt;
435
436     # XXX check lineitem provider perms
437
438     if($li_detail->fund) {
439         my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->die_event;
440         return $e->die_event unless 
441             $e->allowed('MANAGE_FUND', $fund->org, $fund);
442     }
443
444     $e->create_acq_lineitem_detail($li_detail) or return $e->die_event;
445
446     unless($li_detail->barcode) {
447         my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_barcode_prefix') || 'ACQ';
448         $li_detail->barcode($pfx.$li_detail->id);
449     }
450     unless($li_detail->cn_label) {
451         my $pfx = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.tmp_callnumber_prefix') || 'ACQ';
452         $li_detail->cn_label($pfx.$li_detail->id);
453     }
454
455     if(my $loc = $U->ou_ancestor_setting_value($li_detail->owning_lib, 'acq.default_copy_location')) {
456         $li_detail->location($loc);
457     }
458
459     $e->update_acq_lineitem_detail($li_detail) or return $e->die_event;
460
461     return $li_detail if $$options{return_obj};
462     return $li_detail->id
463 }
464
465
466
467 __PACKAGE__->register_method(
468         method => 'update_lineitem_detail',
469         api_name        => 'open-ils.acq.lineitem_detail.update',
470         signature => {
471         desc => q/Updates a lineitem detail/,
472         params => [
473             {desc => 'Authentication token', type => 'string'},
474             {desc => 'lineitem_detail to update', type => 'object'},
475         ],
476         return => {desc => '1 on success, Event on failure'}
477     }
478 );
479
480 sub update_lineitem_detail {
481     my($self, $conn, $auth, $li_detail) = @_;
482     my $e = new_editor(xact=>1, authtoken=>$auth);
483     return $e->die_event unless $e->checkauth;
484     my $res = update_lineitem_detail_impl($self, $conn, $e, $li_detail);
485     return $e->event if $e->died;
486     $e->commit;
487     return $res;
488 }
489
490 sub update_lineitem_detail_impl {
491     my($self, $conn, $e, $li_detail) = @_;
492
493     if($li_detail->fund) {
494         my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->die_event;
495         return $e->die_event unless 
496             $e->allowed('MANAGE_FUND', $fund->org, $fund);
497     }
498
499     # XXX check lineitem perms
500
501     my $li = $e->retrieve_acq_lineitem($li_detail->lineitem)
502         or return $e->die_event;
503     my $evt = update_li_edit_time($e, $li);
504     return $evt if $evt;
505
506     $e->update_acq_lineitem_detail($li_detail) or return $e->die_event;
507     return 1;
508 }
509
510 sub update_li_edit_time {
511     my ($e, $li) = @_;
512     # some lineitem edits are allowed after approval time...
513 #    return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li->id)
514 #        if $li->state eq 'approved';
515     $li->edit_time('now');
516     $li->editor($e->requestor->id);
517     $e->update_acq_lineitem($li) or return $e->die_event;
518     return undef;
519 }
520
521
522 __PACKAGE__->register_method(
523         method => 'delete_lineitem_detail',
524         api_name        => 'open-ils.acq.lineitem_detail.delete',
525         signature => {
526         desc => q/Deletes a lineitem detail/,
527         params => [
528             {desc => 'Authentication token', type => 'string'},
529             {desc => 'lineitem_detail ID to delete', type => 'number'},
530         ],
531         return => {desc => '1 on success, Event on failure'}
532     }
533 );
534
535 sub delete_lineitem_detail {
536     my($self, $conn, $auth, $li_detail_id) = @_;
537     my $e = new_editor(xact=>1, authtoken=>$auth);
538     return $e->die_event unless $e->checkauth;
539     my $res = delete_lineitem_detail_impl($self, $conn, $e, $li_detail_id);
540     return $e->event if $e->died;
541     $e->commit;
542     return $res;
543 }
544
545 sub delete_lineitem_detail_impl {
546     my($self, $conn, $e, $li_detail_id) = @_;
547
548     my $li_detail = $e->retrieve_acq_lineitem_detail([
549         $li_detail_id,
550         {   flesh => 1,
551             flesh_fields => {acqlid => ['lineitem']}
552         }
553     ]) or return $e->die_event;
554
555     my $li = $li_detail->lineitem;
556
557     my $evt = update_li_edit_time($e, $li);
558     return $evt if $evt;
559
560     return OpenILS::Event->new('BAD_PARAMS') unless 
561         $li->state =~ /new|approved/;
562
563     # XXX check lineitem perms
564
565     $e->delete_acq_lineitem_detail($li_detail) or return $e->die_event;
566     return 1;
567 }
568
569
570 __PACKAGE__->register_method(
571         method => 'retrieve_lineitem_detail',
572         api_name        => 'open-ils.acq.lineitem_detail.retrieve',
573         signature => {
574         desc => q/Updates a lineitem detail/,
575         params => [
576             {desc => 'Authentication token', type => 'string'},
577             {desc => 'id of lineitem_detail to retrieve', type => 'number'},
578         ],
579         return => {desc => 'object on success, Event on failure'}
580     }
581 );
582 sub retrieve_lineitem_detail {
583     my($self, $conn, $auth, $li_detail_id) = @_;
584     my $e = new_editor(authtoken=>$auth);
585     return $e->event unless $e->checkauth;
586
587     my $li_detail = $e->retrieve_acq_lineitem_detail($li_detail_id)
588         or return $e->event;
589
590     if($li_detail->fund) {
591         my $fund = $e->retrieve_acq_fund($li_detail->fund) or return $e->event;
592         return $e->event unless 
593             $e->allowed('MANAGE_FUND', $fund->org, $fund);
594     }
595
596     # XXX check lineitem perms
597     return $li_detail;
598 }
599
600
601
602 __PACKAGE__->register_method(
603         method => 'approve_lineitem',
604         api_name        => 'open-ils.acq.lineitem.approve',
605         signature => {
606         desc => 'Mark a lineitem as approved',
607         params => [
608             {desc => 'Authentication token', type => 'string'},
609             {desc => 'lineitem ID', type => 'number'}
610         ],
611         return => {desc => '1 on success, Event on error'}
612     }
613 );
614 sub approve_lineitem {
615     my($self, $conn, $auth, $li_id) = @_;
616     my $e = new_editor(xact=>1, authtoken=>$auth);
617     return $e->die_event unless $e->checkauth;
618
619     # XXX perm checks for each lineitem detail
620
621     my $li = $e->retrieve_acq_lineitem($li_id)
622         or return $e->die_event;
623
624     return OpenILS::Event->new('ACQ_LINEITEM_APPROVED', payload => $li_id)
625         if $li->state eq 'approved';
626
627     my $details = $e->search_acq_lineitem_detail({lineitem => $li_id});
628     return OpenILS::Event->new('ACQ_LINEITEM_NO_COPIES', payload => $li_id)
629         unless scalar(@$details) > 0;
630
631     for my $detail (@$details) {
632         return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_FUND', payload => $detail->id)
633             unless $detail->fund;
634
635         return OpenILS::Event->new('ACQ_LINEITEM_DETAIL_NO_ORG', payload => $detail->id)
636             unless $detail->owning_lib;
637     }
638     
639     $li->state('approved');
640     $li->edit_time('now');
641     $e->update_acq_lineitem($li) or return $e->die_event;
642
643     $e->commit;
644     return 1;
645 }
646
647
648 __PACKAGE__->register_method(
649         method => 'receive_lineitem_detail',
650         api_name        => 'open-ils.acq.lineitem_detail.receive',
651         signature => {
652         desc => 'Mark a lineitem_detail as received',
653         params => [
654             {desc => 'Authentication token', type => 'string'},
655             {desc => 'lineitem detail ID', type => 'number'}
656         ],
657         return => {desc => '1 on success, Event on error'}
658     }
659 );
660 sub receive_lineitem_detail {
661     my($self, $conn, $auth, $lid_id) = @_;
662     my $e = new_editor(xact=>1, authtoken=>$auth);
663     return $e->die_event unless $e->checkauth;
664     my $resp = receive_lineitem_detail_impl($e, $lid_id);
665     if($resp) {$e->rollback; return $resp;}
666     $e->commit;
667     return 1;
668 }
669
670 sub receive_lineitem_detail_impl {
671     my($e, $lid_id) = @_;
672
673     my $lid = $e->retrieve_acq_lineitem_detail([
674         $lid_id,
675         {   flesh => 1,
676             flesh_fields => {
677                 acqlid => ['fund_debit']
678             }
679         }
680     ]) or return $e->die_event;
681
682     return OpenILS::Event->new(
683         'ACQ_LINEITEM_DETAIL_RECEIVED') if $lid->recv_time;
684
685     $lid->recv_time('now');
686     $e->update_acq_lineitem_detail($lid) or return $e->die_event;
687
688     my $copy = $e->retrieve_asset_copy($lid->eg_copy_id)
689         or return $e->die_event;
690
691     $copy->status(OILS_COPY_STATUS_IN_PROCESS);
692     $copy->edit_date('now');
693     $copy->editor($e->requestor->id);
694     $e->update_asset_copy($copy) or return $e->die_event;
695
696     if($lid->fund_debit) {
697         $lid->fund_debit->encumbrance('f');
698         $e->update_acq_fund_debit($lid->fund_debit) or return $e->die_event;
699     }
700
701     # -------------------------------------------------------------
702     # if all of the lineitem details for this lineitem have 
703     # been received, mark the lineitem as received
704     # -------------------------------------------------------------
705     my $non_recv = $e->search_acq_lineitem_detail(
706         {recv_time => undef, lineitem => $lid->lineitem}, {idlist=>1});
707
708     return undef if @$non_recv;
709
710     my $li = $e->retrieve_acq_lineitem($lid->lineitem);
711     $li->state('received');
712     $li->edit_time('now');
713     $e->update_acq_lineitem($li) or return $e->die_event;
714
715     # -------------------------------------------------------------
716     # if all of the lineitems for this PO are received,
717     # mark the PO as received
718     # -------------------------------------------------------------
719     my $non_recv_li = $e->search_acq_lineitem(
720         {   purchase_order => $li->purchase_order, 
721             state => {'!=' => 'received'}
722         }, {idlist=>1});
723
724     return undef if @$non_recv_li;
725
726     my $po = $e->retrieve_acq_purchase_order($li->purchase_order);
727     $po->state('received');
728     $po->edit_time('now');
729     $e->update_acq_purchase_order($po) or return $e->die_event;
730
731     return undef;
732 }
733
734
735 __PACKAGE__->register_method(
736         method => 'set_lineitem_attr',
737         api_name        => 'open-ils.acq.lineitem_usr_attr.set',
738         signature => {
739         desc => 'Sets a lineitem_usr_attr value',
740         params => [
741             {desc => 'Authentication token', type => 'string'},
742             {desc => 'Lineitem ID', type => 'number'},
743             {desc => 'Attr name', type => 'string'},
744             {desc => 'Attr value', type => 'string'}
745         ],
746         return => {desc => '1 on success, Event on error'}
747     }
748 );
749
750 __PACKAGE__->register_method(
751         method => 'set_lineitem_attr',
752         api_name        => 'open-ils.acq.lineitem_local_attr.set',
753         signature => {
754         desc => 'Sets a lineitem_local_attr value',
755         params => [
756             {desc => 'Authentication token', type => 'string'},
757             {desc => 'Lineitem ID', type => 'number'},
758             {desc => 'Attr name', type => 'string'},
759             {desc => 'Attr value', type => 'string'}
760         ],
761         return => {desc => 'ID of the attr object on success, Event on error'}
762     }
763 );
764
765
766 sub set_lineitem_attr {
767     my($self, $conn, $auth, $li_id, $attr_name, $attr_value) = @_;
768     my $e = new_editor(xact=>1, authtoken=>$auth);
769     return $e->die_event unless $e->checkauth;
770
771     # XXX perm
772
773     my $attr_type = $self->api_name =~ /local_attr/ ?
774         'lineitem_local_attr_definition' : 'lineitem_usr_attr_definition';
775
776     my $attr = $e->search_acq_lineitem_attr({
777         lineitem => $li_id, 
778         attr_type => $attr_type,
779         attr_name => $attr_name})->[0];
780
781     my $find = "search_acq_$attr_type";
782
783     if($attr) {
784         $attr->attr_value($attr_value);
785         $e->update_acq_lineitem_attr($attr) or return $e->die_event;
786     } else {
787         $attr = Fieldmapper::acq::lineitem_attr->new;
788         $attr->lineitem($li_id);
789         $attr->attr_type($attr_type);
790         $attr->attr_name($attr_name);
791         $attr->attr_value($attr_value);
792
793         my $attr_def_id = $e->$find({code => $attr_name}, {idlist=>1})->[0] 
794             or return $e->die_event;
795         $attr->definition($attr_def_id);
796         $e->create_acq_lineitem_attr($attr) or return $e->die_event;
797     }
798
799     $e->commit;
800     return $attr->id;
801 }
802
803 __PACKAGE__->register_method(
804         method => 'get_lineitem_attr_defs',
805         api_name        => 'open-ils.acq.lineitem_attr_definition.retrieve.all',
806         signature => {
807         desc => 'Retrieve lineitem attr definitions',
808         params => [
809             {desc => 'Authentication token', type => 'string'},
810         ],
811         return => {desc => 'List of attr definitions'}
812     }
813 );
814
815 sub get_lineitem_attr_defs {
816     my($self, $conn, $auth) = @_;
817     my $e = new_editor(authtoken=>$auth);
818     return $e->event unless $e->checkauth;
819     my %results;
820     for my $type (qw/generated marc local usr provider/) {
821         my $call = "retrieve_all_acq_lineitem_${type}_attr_definition";
822         $results{$type} = $e->$call;
823     }
824     return \%results;
825 }
826
827
828 1;