return $li;
}
+# lineitem_batch_update_perm_test()
+#
+# Returns undef on success, event on perm failure.
+# Responsible for calling $e->die_event.
+# Also sanitizes values in $target.
+#
+sub lineitem_batch_update_perm_test {
+ my ($e, $target) = @_;
+
+ return $e->die_event(new OpenILS::Event("BAD_PARAMS", note => "target"))
+ unless ref $target eq "HASH";
+
+ my $perm_for = {
+ ordering_agency => "CREATE_PURCHASE_ORDER",
+ org_unit => "UPDATE_PICKLIST"
+ };
+
+ if (ref $target->{lineitems} eq "ARRAY") {
+ # Sanitization
+ $target->{lineitems} = [ map { int $_ } @{$target->{lineitems}} ];
+
+ return $e->die_event(
+ new OpenILS::Event(
+ "BAD_PARAMS", note => "target (lineitems list empty)"
+ )
+ ) unless @{$target->{lineitems}};
+
+ # Get all PO & picklist linkings from lineitems in question.
+ my $li_rows = $e->json_query({
+ select => {
+ jub => ["id"],
+ acqpo => ["ordering_agency"],
+ acqpl => ["org_unit"]
+ },
+ from => {
+ jub => {acqpl => {type => "left"}, acqpo => {type => "left"}}
+ },
+ where => {
+ "+jub" => {id => $target->{lineitems}}
+ }
+ }) or return $e->die_event;
+
+ # Fail loudly rather than giving user any surprises if they asked to
+ # update lineitems that don't exist. This is an asymmetric difference
+ # calculation.
+ my %present = map { $_->{id} => 1 } @$li_rows;
+ my @missing = grep { not exists $present{$_} } @{$target->{lineitems}};
+ return $e->die_event(
+ new OpenILS::Event(
+ "ACQ_LINEITEM_NOT_FOUND", payload => \@missing
+ )
+ ) if @missing;
+
+ # To avoid repetition of perm tests, track them here.
+ my $already_done = {
+ ordering_agency => {},
+ org_unit => {}
+ };
+
+ # Test all lineitems based on the context OU of all linked POs AND PLs.
+ foreach my $row (@$li_rows) {
+ foreach my $field (keys %$already_done) {
+ if ($row->{$field}) {
+ if (not $already_done->{$row}{$field}) {
+ my $perm = $perm_for->{$field};
+ my $context = $row->{$field};
+
+ if (not $e->allowed($perm, $context)) {
+ my $evt = $e->die_event;
+
+ # Take the PERM_FAILURE event and annotate it with
+ # a list of the targeted lineitems that would fail
+ # the same permission check (i.e. that have the
+ # same context).
+ $evt->{payload} = [
+ map { $_->{id} } (
+ grep { $_->{$field} == $context } @$li_rows
+ )
+ ];
+ return $evt;
+ } else {
+ $already_done->{$row}{$field} = 1;
+ }
+ }
+ }
+ }
+ }
+ } elsif ($target->{purchase_order}) {
+ $target->{purchase_order} = int($target->{purchase_order});
+
+ my $po = $e->retrieve_acq_purchase_order($target->{purchase_order}) or
+ return $e->die_event;
+
+ return $e->die_event unless
+ $e->allowed($perm_for->{ordering_agency}, $po->ordering_agency);
+ } elsif ($target->{picklist}) {
+ $target->{picklist} = int($target->{picklist});
+
+ my $pl = $e->retrieve_acq_picklist($target->{picklist}) or
+ return $e->die_event;
+
+ return $e->die_event unless
+ $e->allowed($perm_for->{org_unit}, $pl->org_unit);
+ } else {
+ return $e->die_event(
+ new OpenILS::Event("BAD_PARAMS", note => "target")
+ );
+ }
+
+ return; # perm check pass
+}
+
+__PACKAGE__->register_method(
+ method => "lineitem_batch_update_api",
+ api_name => "open-ils.acq.lineitem.batch_update",
+ signature => {
+ desc => "Apply changes to lineitems in batch",
+ params => [
+ {desc => "Authentication token", type => "string"},
+ {desc => "Target. Object key must be one of lineitems, purchase_order or picklist. The value for 'lineitems' must be an array of IDs, and the values for either of the other two must be single IDs.", type => "object"},
+ {desc => "Changes (optional). If these changes conflict with distribution formula, these changes win.", type => "object"},
+ {desc => "Distribution formula ID (optional)", type => "number"}
+ ],
+ return => {
+ # XXX TODO
+ }
+ }
+);
+
+sub lineitem_batch_update_api {
+ my ($self, $conn, $auth, $target, $changes, $dist_formula) = @_;
+
+ my $e = new_editor("authtoken" => $auth, xact => 1);
+ return $e->die_event unless $e->checkauth;
+
+ # lineitem_batch_update_perm_test() will call die_event() for us if needed.
+ my $evt = lineitem_batch_update_perm_test($e, $target);
+ return $evt if $U->event_code($evt);
+
+ $e->rollback;
+
+ return 1;
+}
+
1;