+#
+# Eingabe:  Teilenummer, Lagerplatz_Id (bin_id)
+# Ausgabe:  Die maximale Anzahl der Teile in diesem Lagerplatz
+#           Bzw. Fehler, falls Chargen oder bestbefore
+#           bei eingelagerten Teilen definiert sind.
+#
+sub get_max_qty_parts_bin {
+$main::lxdebug->enter_sub();
+
+  my $self     = shift;
+  my %params   = @_;
+
+  Common::check_params(\%params, qw(parts_id bin_id)); #die brauchen wir
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $dbh      = $params{dbh} || $form->get_standard_dbh();
+
+  my $query = qq| SELECT SUM(qty), chargenumber, bestbefore  FROM inventory where parts_id = ?
+                            AND bin_id = ? GROUP BY chargenumber, bestbefore|;
+
+  my $sth_QTY      = prepare_execute_query($form, $dbh, $query, ,$params{parts_id}, $params{bin_id}); #info: aufruf an DBUtils.pm
+
+  my $max_qty_parts = 0; #Initialisierung mit 0
+  # falls derselbe artikel mehrmals eingelagert ist
+  # chargennummer, muss entsprechend händisch agiert werden
+  my $i = 0;
+  my $error;
+  while (my $ref = $sth_QTY->fetchrow_hashref()) {  # wir laufen über alle Haltbarkeiten und Chargen(s.a. SQL-Query oben)
+    $max_qty_parts += $ref->{sum};
+    $i++;
+    if (($ref->{chargenumber} || $ref->{bestbefore}) && $ref->{sum} != 0){
+      $error = 1;
+    }
+  }
+  $main::lxdebug->leave_sub();
+
+  return ($max_qty_parts, $error);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+SL::WH - Warehouse backend
+
+=head1 SYNOPSIS
+
+  use SL::WH;
+  WH->transfer(\%params);
+
+=head1 DESCRIPTION
+
+Backend for kivitendo warehousing functions.
+
+=head1 FUNCTIONS
+
+=head2 transfer \%PARAMS, [ \%PARAMS, ... ]
+
+This is the main function to manipulate warehouse contents. A typical transfer
+is called like this:
+
+  WH->transfer->({
+    parts_id         => 6342,
+    qty              => 12.45,
+    transfer_type    => 'transfer',
+    src_warehouse_id => 12,
+    src_bin_id       => 23,
+    dst_warehouse_id => 25,
+    dst_bin_id       => 167,
+  });
+
+It will generate an entry in inventory representing the transfer. Note that
+parts_id, qty, and transfer_type are mandatory. Depending on the transfer_type
+a destination or a src is mandatory.
+
+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.
+
+Here is a full list of parameters. All "_id" parameters except oe and
+orderitems can be called without id with RDB objects as well.
+
+=over 4
+
+=item parts_id
+
+The id of the article transferred. Does not check if the article is a service.
+Mandatory.
+
+=item qty
+
+Quantity of the transaction.  Mandatory.
+
+=item unit
+
+Unit of the transaction. Optional.
+
+=item transfer_type
+
+=item transfer_type_id
+
+The type of transaction. The first version is a string describing the
+transaction (the types 'transfer' 'in' 'out' and a few others are present on
+every system), the id is the hard id of a transfer_type from the database.
+
+Depending of the direction of the transfer_type, source and/or destination must
+be specified.
+
+One of transfer_type or transfer_type_id is mandatory.
+
+=item src_warehouse_id
+
+=item src_bin_id
+
+Warehouse and bin from which to transfer. Mandatory in transfer and out
+directions. Ignored in in directions.
+
+=item dst_warehouse_id
+
+=item dst_bin_id
+
+Warehouse and bin to which to transfer. Mandatory in transfer and in
+directions. Ignored in out directions.
+
+=item chargenumber
+
+If given, the transfer will transfer only articles with this chargenumber.
+Optional.
+
+=item orderitem_id
+
+Reference to an orderitem for which this transfer happened. Optional
+
+=item oe_id
+
+Reference to an order for which this transfer happened. Optional
+
+=item comment
+
+An optional comment.
+
+=item best_before
+
+An expiration date. Note that this is not by default used by C<warehouse_report>.
+
+=back
+
+=head2 create_assembly \%PARAMS, [ \%PARAMS, ... ]
+
+Creates an assembly if all defined items are available.
+
+Assembly item(s) will be stocked out and the assembly will be stocked in,
+taking into account the qty and units which can be defined for each
+assembly item separately.
+
+The calling params originate from C<transfer> but only parts_id with the
+attribute assembly are processed.
+
+The typical params would be:
+
+  my %TRANSFER = (
+    'login'            => $::myconfig{login},
+    'dst_warehouse_id' => $form->{warehouse_id},
+    'dst_bin_id'       => $form->{bin_id},
+    'chargenumber'     => $form->{chargenumber},
+    'bestbefore'       => $form->{bestbefore},
+    'assembly_id'      => $form->{parts_id},
+    'qty'              => $form->{qty},
+    'comment'          => $form->{comment}
+  );
+
+=head3 Prerequisites
+
+All of these prerequisites have to be trueish, otherwise the function will exit
+unsuccessfully with a return value of undef.
+
+=over 4
+
+=item Mandantory params
+
+  assembly_id, qty, login, dst_warehouse_id and dst_bin_id are mandatory.
+
+=item Subset named 'Assembly' of data set 'Part'
+
+  assembly_id has to be an id in the table parts with the valid subset assembly.
+
+=item Assembly is composed of assembly item(s)
+
+  There has to be at least one data set in the table assembly referenced to this assembly_id.
+
+=item Assembly cannot be destroyed or disassembled
+
+  Assemblies are like cakes. You cannot disassemble it. NEVER.
+  No negative nor zero qty's are valid inputs.
+
+=item The assembly item(s) have to be in the same warehouse
+
+  inventory.warehouse_id equals dst_warehouse_id (client configurable).
+
+=item The assembly item(s) have to be in stock with the qty needed
+
+  I can only make a cake by receipt if I have ALL ingredients and
+  in the needed stock amount.
+  The qty of stocked in assembly item(s) has to fit into the
+  number of the qty of the assemblies, which are going to be created (client configurable).
+
+=item assembly item(s) with the parts set 'service' are ignored
+
+  The subset 'Services' of part will not transferred for assembly item(s).
+
+=back
+
+Client configurable prerequisites can be changed with different
+prerequisites as described in client_config (s.a. next chapter).
+
+
+=head2 default creation of assembly
+
+The valid state of the assembly item(s) used for the assembly process are
+'out' for the general direction and 'used' as the specific reason.
+The valid state of the assembly is 'in' for the direction and 'assembled'
+as the specific reason.
+
+The method is transaction safe, in case of errors not a single entry will be made
+in inventory.
+
+Two prerequisites can be changed with this global parameters
+
+=over 2
+
+=item  $::instance_conf->get_transfer_default_warehouse_for_assembly
+
+  If trueish we try to get all the items form the default bins defined in parts
+  and do not try to find them in the destination warehouse. Returns an
+  error if not all items have set a default bin in parts.
+
+=item  $::instance_conf->get_bin_id_ignore_onhand
+
+  If trueish we can create assemblies even if we do not have enough items in stock.
+  The needed qty will be booked in a special bin, which has to be configured in
+  the client config.
+
+=back
+
+
+
+
+=head1 BUGS
+
+None yet.
+
+=head1 AUTHOR