dba843cd88b523c22ffde27a39942f92c1ab65a9
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Acq / Claims.pm
1 package OpenILS::Application::Acq::Claims;
2 use base qw/OpenILS::Application/;
3 use strict; use warnings;
4
5 use OpenSRF::Utils::Logger qw(:logger);
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Utils::CStoreEditor q/:funcs/;
8 use OpenILS::Application::AppUtils;
9 use OpenILS::Event;
10 my $U = 'OpenILS::Application::AppUtils';
11
12
13 __PACKAGE__->register_method(
14         method => 'claim_ready_items',
15         api_name        => 'open-ils.acq.claim.eligible.lineitem_detail',
16     stream => 1,
17         signature => {
18         desc => q/Locates lineitem_details that are eligible for claiming/,
19         params => [
20             {desc => 'Authentication token', type => 'string'},
21             {   desc => q/
22                     Filter object.  Filter keys include 
23                     purchase_order
24                     lineitem
25                     lineitem_detail
26                     claim_policy_action
27                     ordering_agency
28                 /, 
29                 type => 'object'
30             },
31             {   desc => q/
32                     Flesh fields.  Which fields to flesh on the response object.  
33                     For valid options, see the filter object
34                 q/, 
35                 type => 'array'
36             }
37         ],
38         return => {desc => 'Claim ready data', type => 'object', class => 'acrlid'}
39     }
40 );
41
42 sub claim_ready_items {
43     my($self, $conn, $auth, $filters, $flesh_fields, $limit, $offset) = @_;
44
45     my $e = new_editor(authtoken=>$auth);
46     return $e->event unless $e->checkauth;
47
48     $filters ||= {};
49     $flesh_fields ||= [];
50     $limit ||= 50;
51     $offset ||= 0;
52
53     if(defined $filters->{ordering_agency}) {
54         return $e->event unless $e->allowed('VIEW_PURCHASE_ORDER', $filters->{ordering_agency});
55     } else {
56         $filters->{ordering_agency} = $U->user_has_work_perm_at($e, 'VIEW_PURCHASE_ORDER', {descendants => 1});
57     }
58
59     my $items = $e->search_acq_claim_ready_lineitem_detail([$filters, {limit => $limit, offset => $offset}]);
60
61     my %cache;
62     for my $item (@$items) {
63
64         # flesh from the flesh fields, using the cache when we can
65         foreach (@$flesh_fields) {
66             my $retrieve = "retrieve_acq_${_}";
67             $cache{$_} = {} unless $cache{$_};
68             $item->$_( 
69                 $cache{$_}{$item->$_} || 
70                 ($cache{$_}{$item->$_} = $e->$retrieve($item->$_))
71             );
72         }
73
74         $conn->respond($item);
75     }
76
77     return undef;
78 }
79
80 __PACKAGE__->register_method(
81     method => "claim_item",
82     api_name => "open-ils.acq.claim.lineitem",
83     stream => 1,
84     signature => {
85         desc => q/Initiates a claim for a lineitem/,
86         params => [
87             {desc => "Authentication token", type => "string"},
88             {desc => "Lineitem ID", type => "number"},
89             {desc => q/Claim (acqcl) ID.  If defined, attach new claim
90                 events to this existing claim object/, type => "number"},
91             {desc => q/Claim Type (acqclt) ID.  If defined (and no claim is
92                 defined), create a new claim with this type/, type => "number"},
93             {desc => "Note for the claim event", type => "string"},
94             {desc => q/Optional: Claim Policy Actions.  If not present,
95                 claim events for all eligible claim policy actions will be
96                 created.  This is an array of acqclpa IDs./,
97                 type => "array"},
98         ],
99         return => {
100             desc => "The claim voucher events on success, Event on error",
101             type => "object", class => "acrlid"
102         }
103     }
104 );
105
106 __PACKAGE__->register_method(
107         method => 'claim_item',
108         api_name        => 'open-ils.acq.claim.lineitem_detail',
109     stream => 1,
110         signature => {
111         desc => q/Initiates a claim for an individual lineitem_detail/,
112         params => [
113             {desc => 'Authentication token', type => 'string'},
114             {desc => 'Lineitem Detail ID', type => 'number'},
115             {desc => 'Claim (acqcl) ID.  If defined, attach new claim events to this existing claim object', type => 'number'},
116             {desc => 'Claim Type (acqclt) ID.  If defined (and no claim is defined), create a new claim with this type', type => 'number'},
117             {desc => "Note for the claim event", type => "string"},
118             {   desc => q/
119                 
120                     Optional: Claim Policy Actions.  If not present, claim events 
121                     for all eligible claim policy actions will be created.  This is
122                     an array of acqclpa ID's.
123                 /, 
124                 type => 'array'
125             },
126             {   desc => q/
127                     Optional: Claim Event Types.  If present, we bypass any policy configuration
128                     and use the specified event types.  This is useful for manual claiming against
129                     items that have no claim policy.
130                 /,
131                 type => 'array'
132             }
133         ],
134         return => {
135             desc => "The claim voucher events on success, Event on error",
136             type => "object", class => "acrlid"
137         }
138     }
139 );
140
141 sub claim_item {
142     my $self = shift;
143     my $conn = shift;
144     my $auth = shift;
145     my $object_id = shift;
146     my $claim_id = shift;
147     my $claim_type_id = shift;
148     my $note = shift;
149     my $policy_actions = shift;
150
151     # if this claim occurs outside of a policy, allow the caller to specificy the event type
152     my $claim_event_types = shift; 
153
154     my $e = new_editor(xact => 1, authtoken=>$auth);
155     return $e->die_event unless $e->checkauth;
156
157     my $evt;
158     my $claim;
159     my $claim_type;
160     my $claim_events = {
161         events => [],
162         trigger_stuff => []
163     };
164
165     my $lid_flesh = {
166         "flesh" => 2,
167         "flesh_fields" => {
168             "acqlid" => ["lineitem"], "jub" => ["purchase_order"],
169         }
170     };
171
172     if($claim_id) {
173         $claim = $e->retrieve_acq_claim($claim_id) or return $e->die_event;
174     } elsif($claim_type_id) {
175         $claim_type = $e->retrieve_acq_claim_type($claim_type_id) or return $e->die_event;
176     } else {
177         $e->rollback;
178         return OpenILS::Event->new('BAD_PARAMS');
179     }
180
181
182     my $lids;
183     if($self->api_name =~ /claim.lineitem_detail/) {
184
185         $lids = $e->search_acq_lineitem_detail([
186             {"id" => $object_id, "cancel_reason" => undef},
187             $lid_flesh
188         ]) or return $e->die_event;
189
190     } elsif($self->api_name =~ /claim.lineitem/) {
191         $lids = $e->search_acq_lineitem_detail([
192             {"lineitem" => $object_id, "cancel_reason" => undef},
193             $lid_flesh
194         ]) or return $e->die_event;
195     }
196
197     foreach my $lid (@$lids) {
198         return $evt if
199             $evt = claim_lineitem_detail(
200                 $e, $lid, $claim, $claim_type, $policy_actions,
201                 $note, $claim_events, $claim_event_types
202             );
203     }
204
205     $e->commit;
206
207     # create related A/T events
208     $U->create_events_for_hook('claim_event.created', $_->[0], $_->[1]) for @{$claim_events->{trigger_stuff}};
209
210     # do voucher rendering and return result
211     $conn->respond($U->fire_object_event(
212         undef, "format.acqcle.html", $_->[0], $_->[1], "print-on-demand"
213     )) foreach @{$claim_events->{trigger_stuff}};
214     return undef;
215 }
216
217 sub claim_lineitem_detail {
218     my($e, $lid, $claim, $claim_type, $policy_actions, $note, $claim_events, $claim_event_types) = @_;
219
220     # Create the claim object
221     unless($claim) {
222         $claim = Fieldmapper::acq::claim->new;
223         $claim->lineitem_detail($lid->id);
224         $claim->type($claim_type->id);
225         $e->create_acq_claim($claim) or return $e->die_event;
226     }
227
228     unless($claim_event_types) {
229         # user did not specify explicit event types
230
231         unless($policy_actions) {
232             # user did not specifcy policy actions.  find all eligible.
233
234             my $list = $e->json_query({
235                 select => {acrlid => ['claim_policy_action']},
236                 from => 'acrlid',
237                 where => {lineitem_detail => $lid->id}
238             });
239     
240             $policy_actions = [map { $_->{claim_policy_action} } @$list];
241         }
242
243         # from the set of policy_action's, locate the related event types
244         # IOW, the policy action's action
245         $claim_event_types = [];
246         for my $act_id (@$policy_actions) {
247             my $action = $e->retrieve_acq_claim_policy_action($act_id) or return $e->die_event;
248             push(@$claim_event_types, $action->action);
249         }
250     }
251
252     # for each eligible (or chosen) policy actions, create a claim_event
253     for my $event_type (@$claim_event_types) {
254         my $event = Fieldmapper::acq::claim_event->new;
255         $event->claim($claim->id);
256         $event->type($event_type);
257         $event->creator($e->requestor->id);
258         $event->note($note);
259         $e->create_acq_claim_event($event) or return $e->die_event;
260         push(@{$claim_events->{events}}, $event);
261         push(@{$claim_events->{trigger_stuff}}, [$event, $lid->lineitem->purchase_order->ordering_agency]);
262     }
263
264     return undef;
265 }
266
267
268 __PACKAGE__->register_method(
269     method => "get_claim_voucher_by_lid",
270     api_name => "open-ils.acq.claim.voucher.by_lineitem_detail",
271     stream => 1,
272     signature => {
273         desc => q/Retrieve existing claim vouchers by lineitem detail ID/,
274         params => [
275             {desc => "Authentication token", type => "string"},
276             {desc => "Lineitem detail ID", type => "number"}
277         ],
278         return => {
279             desc => "Claim ready data", type => "object", class => "atev"
280         }
281     }
282 );
283
284 sub get_claim_voucher_by_lid {
285     my ($self, $conn, $auth, $lid_id) = @_;
286
287     my $e = new_editor("authtoken" => $auth);
288     return $e->die_event unless $e->checkauth;
289
290     my $lid = $e->retrieve_acq_lineitem_detail([
291         $lid_id, {
292             "flesh" => 2,
293             "flesh_fields" => {
294                 "acqlid" => ["lineitem"], "jub" => ["purchase_order"]
295             }
296         }
297     ]);
298
299     return $e->die_event unless $e->allowed(
300         "VIEW_PURCHASE_ORDER", $lid->lineitem->purchase_order->ordering_agency
301     );
302
303     my $id_list = $e->json_query({
304         "select" => {"atev" => ["id"]},
305         "from" => {
306             "atev" => {
307                 "atevdef" => {"field" => "id", "fkey" => "event_def"},
308                 "acqcle" => {
309                     "field" => "id", "fkey" => "target",
310                     "join" => {
311                         "acqcl" => {
312                             "field" => "id", "fkey" => "claim",
313                             "join" => {
314                                 "acqlid" => {
315                                     "fkey" => "lineitem_detail",
316                                     "field" => "id"
317                                 }
318                             }
319                         }
320                     }
321                 }
322             }
323         },
324         "where" => {
325             "-and" => {
326                 "+atevdef" => {"hook" => "format.acqcle.html"},
327                 "+acqlid" => {"id" => $lid_id}
328             }
329         }
330     }) or return $e->die_event;
331
332     if ($id_list && @$id_list) {
333         foreach (@$id_list) {
334             $conn->respond(
335                 $e->retrieve_action_trigger_event([
336                     $_->{"id"}, {
337                         "flesh" => 1,
338                         "flesh_fields" => {"atev" => ["template_output"]}
339                     }
340                 ])
341             );
342         }
343     }
344
345     $e->disconnect;
346     undef;
347 }
348
349 1;