Acq: lineitem batch updater - more perm checks, working on implementation
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 12 Feb 2013 22:42:56 +0000 (17:42 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Mon, 11 Mar 2013 18:00:48 +0000 (14:00 -0400)
Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm

index e96f30e..4fdc0aa 100644 (file)
@@ -954,8 +954,9 @@ sub retrieve_lineitem_by_copy_id {
     return $li;
 }
 
-# lineitem_batch_update_perm_test()
+# lineitem_batch_update_perm_test(), helper for lineitem_batch_update_api()
 #
+# Tests permissions on targeted lineitems, purchase orders, and picklists.
 # Returns undef on success, event on perm failure.
 # Responsible for calling $e->die_event.
 # Also sanitizes values in $target.
@@ -1066,6 +1067,71 @@ sub lineitem_batch_update_perm_test {
     return; # perm check pass
 }
 
+# lineitem_batch_update_impl() should be handed everything pre-perm-checked
+# and ready-to-go. $e is in a transaction.
+sub lineitem_batch_update_impl {
+    my ($e, $target, $changes, $dist_formula) = @_;
+
+    # First, retrieve existing lineitem details.
+
+    # The right ordering is important for adjusting lineitem detail counts.
+    my %order_by = (order_by => [
+        {class => "acqlid", field => "lineitem"},
+        {class => "acqlid", field => "id"}
+    ]);
+
+    my $lineitem_details;
+
+    if ($target->{lineitems}) {
+        $lineitem_details = $e->search_acq_lineitem_detail(
+            {lineitem => $target->{lineitems}}, \%order_by
+        ) or return $e->die_event;
+    } else {
+        my $where;
+
+        if ($target->{purchase_order}) {
+            $where = {"+jub" => {purchase_order => $target->{purchase_order}}};
+        } else {    # picklist
+            $where = {"+jub" => {picklist => $target->{picklist}}};
+        }
+
+        $lineitem_details = $e->search_acq_lineitem_detail(
+            $where, {join => "jub", %order_by}
+        ) or return $e->die_event;
+    }
+
+    # XXX Here, send one of those opensrf continue thingers in case (or substream on previous search_*()? ask berick 
+
+    # XXX TODO
+    # Count how many lineitem details we have per lineitem, and for each
+    # lineitem add or remove lineitems to match $changes->{count}, as needed.
+
+    # Now, going through all our lineitem details, make the updates called for
+    # in $changes, other than the 'count' field (handled above).
+
+    foreach my $lid (@$lineitem_details) {
+        foreach my $field (qw/owning_lib fund location collection_code circ_modifer/) {
+            # undef value in $changes should clear a field.
+            # Absence of value should do nothing to a field.
+
+            if (exists $changes->{$field}) {
+                if (not defined $changes->{$field}) {
+                    my $meth = "clear_$field";
+                    $lid->$meth;
+                } else {
+                    $lid->$field($changes->{$field});
+                }
+            }
+        }
+
+        # XXX TODO cstore update, and send client a response per LI (not per
+        # LID I think...)
+    }
+
+    $e->commit;
+}
+
+
 __PACKAGE__->register_method(
     method => "lineitem_batch_update_api",
     api_name => "open-ils.acq.lineitem.batch_update",
@@ -1086,16 +1152,53 @@ __PACKAGE__->register_method(
 sub lineitem_batch_update_api {
     my ($self, $conn, $auth, $target, $changes, $dist_formula) = @_;
 
-    my $e = new_editor("authtoken" => $auth, xact => 1);
+    # Make sure that $changes->{count}, if it exists, is a natural number.
+    # Other things in $change are safe to treat somewhat more casually,
+    # except fund, which is handled later.
+    $changes ||= {};
+    if (exists $changes->{count}) {
+        $changes->{count} = int($changes->{count});
+        return new OpenILS::Event("BAD_PARAMS", note => "changes (count)")
+            unless $changes->{count} >= 0;
+    }
+
+    # We want to do our perm tests and everything within a transaction.
+
+    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.
+    # If any distribution formula ID is given, fetch distribution formula
+    # (with entries fleshed) early so we can get a quick permission check
+    # out of the way.
+    if ($dist_formula) {
+        $dist_formula = $e->acq->retrieve_acq_dist_formula([
+            int($dist_formula), {flesh=>1, flesh_fields=>["entries","fund"]}
+        ]) or return $e->die_event;
+
+        return $e->die_event unless
+            $e->allowed("ADMIN_ACQ_DISTRIB_FORMULA", $dist_formula->owner);
+
+        # If the distribution formula has a fund, there's an additional perm
+        # test to do before proceeding.
+        if ($dist_formula->fund) {
+            return $e->die_event unless $e->allowed(
+                ["ADMIN_FUND", "MANAGE_FUND"],
+                $dist_formula->fund->org, $dist_formula->fund
+            );
+        }
+    }
+
+    # Next, test permissions on fund to set, if any, from $changes.
+    # XXX TODO
+
+    # Now test permissions on the targets.  lineitem_batch_update_perm_test()
+    # calls die_event() for us if needed.  Has side-effect of target
+    # sanitization.
     my $evt = lineitem_batch_update_perm_test($e, $target);
     return $evt if $U->event_code($evt);
 
-    $e->rollback;
-
-    return 1;
+    # Now do the actual work.
+    return lineitem_batch_update_impl($e, $target, $changes, $dist_formula);
 }
 
 1;