commit 1bbcb32cff12865da20d6f2dabc85d7683dca31e
Author: Bernd Bleßmann <bernd@kivitendo-premium.de>
Date:   Wed Dec 20 15:16:24 2017 +0100

    Inventur: Inventurzählungen mit Lagerbewegungen im Backend SL::WH speichern können

diff --git a/SL/WH.pm b/SL/WH.pm
index e596abc94..3c3f65420 100644
--- a/SL/WH.pm
+++ b/SL/WH.pm
@@ -80,7 +80,8 @@ sub transfer {
   my $db = SL::DB::Inventory->new->db;
   $db->with_transaction(sub{
     while (my $transfer = shift @args) {
-      my ($trans_id) = selectrow_query($::form, $::form->get_standard_dbh, qq|SELECT nextval('id')|);
+      my $trans_id;
+      ($trans_id) = selectrow_query($::form, $::form->get_standard_dbh, qq|SELECT nextval('id')|) if $transfer->{qty};
 
       my $part          = $objectify->($transfer, 'parts',         'SL::DB::Part');
       my $unit          = $objectify->($transfer, 'unit',          'SL::DB::Unit',         name => $transfer->{unit});
@@ -101,6 +102,8 @@ sub transfer {
       my $transfer_type = $objectify->($transfer, 'transfer_type', 'SL::DB::TransferType', direction   => $directions[$direction],
                                                                                            description => $transfer->{transfer_type});
 
+      my $stocktaking_qty = $transfer->{stocktaking_qty};
+
       my %params = (
           part             => $part,
           employee         => $employee,
@@ -113,13 +116,15 @@ sub transfer {
       );
 
       if ($unit) {
-        $qty = $unit->convert_to($qty, $part->unit_obj);
+        $qty             = $unit->convert_to($qty,             $part->unit_obj);
+        $stocktaking_qty = $unit->convert_to($stocktaking_qty, $part->unit_obj);
       }
 
       $params{chargenumber} ||= '';
 
-      if ($direction & 1) {
-        SL::DB::Inventory->new(
+      my @inventories;
+      if ($qty && $direction & 1) {
+        push @inventories, SL::DB::Inventory->new(
           %params,
           warehouse => $src_wh,
           bin       => $src_bin,
@@ -127,8 +132,8 @@ sub transfer {
         )->save;
       }
 
-      if ($direction & 2) {
-        SL::DB::Inventory->new(
+      if ($qty && $direction & 2) {
+        push @inventories, SL::DB::Inventory->new(
           %params,
           warehouse => $dst_wh->id,
           bin       => $dst_bin->id,
@@ -140,6 +145,30 @@ sub transfer {
         }
       }
 
+      # Record stocktaking if requested.
+      # This is only possible if transfer was a stock in or stock out,
+      # but not both (transfer).
+      if ($transfer->{record_stocktaking}) {
+        die 'Stocktaking can only be recorded for stock in or stock out, but not on a transfer.' if scalar @inventories > 1;
+
+        my $inventory_id;
+        $inventory_id = $inventories[0]->id if $inventories[0];
+
+        SL::DB::Stocktaking->new(
+          inventory_id => $inventory_id,
+          warehouse    => $src_wh  || $dst_wh,
+          bin          => $src_bin || $dst_bin,
+          parts_id     => $part->id,
+          employee_id  => $employee->id,
+          qty          => $stocktaking_qty,
+          comment      => $transfer->{comment},
+          cutoff_date  => $transfer->{stocktaking_cutoff_date},
+          chargenumber => $transfer->{chargenumber},
+          bestbefore   => $transfer->{bestbefore},
+        )->save;
+
+      }
+
       push @trans_ids, $trans_id;
     }
 
@@ -1133,6 +1162,13 @@ transfer accepts more than one transaction parameter, each being a hash ref. If
 more than one is supplied, it is guaranteed, that all are processed in the same
 transaction.
 
+It is possible to record stocktakings within this transaction as well.
+This is useful if the transfer is the result of stocktaking (see also
+C<SL::Controller::Inventory>). To do so the parameters C<record_stocktaking>,
+C<stocktaking_qty> and C<stocktaking_cutoff_date> hava to be given.
+If stocktaking should be saved, then the transfer quantity can be zero. In this
+case no entry in inventory will be made, but only the stocktaking entry.
+
 Here is a full list of parameters. All "_id" parameters except oe and
 orderitems can be called without id with RDB objects as well.
 
@@ -1199,6 +1235,18 @@ An optional comment.
 
 An expiration date. Note that this is not by default used by C<warehouse_report>.
 
+=item record_stocktaking
+
+A boolean flag to indicate that a stocktaking entry should be saved.
+
+=item stocktaking_qty
+
+The quantity for the stocktaking entry.
+
+=item stocktaking_cutoff_date
+
+The cutoff date for the stocktaking entry.
+
 =back
 
 =head2 create_assembly \%PARAMS, [ \%PARAMS, ... ]
