X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/blobdiff_plain/0f19ca7ee7e34f2598e8fd59053abd59b40311ac..155b8aa4f756d7cd34a2b26a65207cbacce40ec3:/SL/Helper/Inventory.pm diff --git a/SL/Helper/Inventory.pm b/SL/Helper/Inventory.pm index 9d4ee96a0..14d4d1619 100644 --- a/SL/Helper/Inventory.pm +++ b/SL/Helper/Inventory.pm @@ -4,14 +4,16 @@ use strict; use Carp; use DateTime; use Exporter qw(import); -use List::Util qw(min); +use List::Util qw(min sum); use List::UtilsBy qw(sort_by); use List::MoreUtils qw(any); +use POSIX qw(ceil); use SL::Locale::String qw(t8); use SL::MoreCommon qw(listify); use SL::DBUtils qw(selectall_hashref_query selectrow_query); use SL::DB::TransferType; +use SL::Helper::Number qw(_round_qty _qty); use SL::X; our @EXPORT_OK = qw(get_stock get_onhand allocate allocate_for_assembly produce_assembly check_constraints); @@ -207,17 +209,17 @@ sub allocate { bestbefore => $chunk->{bestbefore}, reserve_for_id => $chunk->{reserve_for_id}, reserve_for_table => $chunk->{reserve_for_table}, - oe_id => undef, + for_object_id => undef, ); - $rest_qty -= $qty; + $rest_qty -= _round_qty($qty); } - + $rest_qty = _round_qty($rest_qty); last if $rest_qty == 0; } if ($rest_qty > 0) { die SL::X::Inventory::Allocation->new( - error => t8('not enough to allocate'), - msg => t8("can not allocate #1 units of #2, missing #3 units", $qty, $part->displayable_name, $rest_qty), + error => 'not enough to allocate', + msg => t8("can not allocate #1 units of #2, missing #3 units", _qty($qty), $part->displayable_name, _qty($rest_qty)), ); } else { if ($params{constraints}) { @@ -238,8 +240,13 @@ sub allocate_for_assembly { my %parts_to_allocate; for my $assembly ($part->assemblies) { + next if $assembly->part->dispotype eq 'no_stock'; + + my $tmpqty = $assembly->assembly_part->is_recipe ? $assembly->qty * $qty / $assembly->assembly_part->scalebasis + : $assembly->part->unit eq 'Stck' ? ceil($assembly->qty * $qty) + : $assembly->qty * $qty; $parts_to_allocate{ $assembly->part->id } //= 0; - $parts_to_allocate{ $assembly->part->id } += $assembly->qty * $qty; # TODO recipe factor + $parts_to_allocate{ $assembly->part->id } += $tmpqty; } my @allocations; @@ -282,12 +289,16 @@ sub check_constraints { warehouse_id => t8('Warehouses'), chargenumber => t8('Chargenumbers'), ); - my @allocs = grep { !$whitelist{$_->$accessor} } @$allocations; + my @allocs = grep { $whitelist{$_->$accessor} } @$allocations; + my $needed = sum map { $_->qty } grep { !$whitelist{$_->$accessor} } @$allocations; + my $err = t8("Cannot allocate parts."); + $err .= ' '.t8('part \'#\'1 in bin \'#2\' only with qty #3 (need additional #4) and chargenumber \'#5\'.', + SL::DB::Part->load_cached($_->parts_id)->description, + SL::DB::Bin->load_cached($_->bin_id)->full_description, + _qty($_->qty), _qty($needed), $_->chargenumber ? $_->chargenumber : '--') for @allocs; die SL::X::Inventory::Allocation->new( - accessor => $accessor, - allocations => \@allocs, - error => 'allocation constraints failure', - msg => t8("Allocations didn't pass constraints for #1",$error_constraints{$_}), + error => 'allocation constraints failure', + msg => $err, ); } } @@ -312,7 +323,7 @@ sub produce_assembly { my $bin = $params{bin} or Carp::croak("need target bin"); my $chargenumber = $params{chargenumber}; my $bestbefore = $params{bestbefore}; - my $oe_id = $params{oe_id}; + my $for_object_id = $params{for_object_id}; my $comment = $params{comment} // ''; my $production_order_item = $params{production_order_item}; @@ -343,6 +354,7 @@ sub produce_assembly { my @transfers; for my $allocation (@$allocations) { + my $oe_id = delete $allocation->{for_object_id}; push @transfers, SL::DB::Inventory->new( trans_id => $trans_id, %$allocation, @@ -350,7 +362,7 @@ sub produce_assembly { trans_type => $trans_type_out, shippingdate => $shippingdate, employee => SL::DB::Manager::Employee->current, - oe_id => $allocation->oe_id, + oe_id => $allocation->for_object_id, ); } @@ -371,7 +383,7 @@ sub produce_assembly { comment => $comment, prod => $production_order_item, employee => SL::DB::Manager::Employee->current, - oe_id => $oe_id, + oe_id => $for_object_id, ); SL::DB->client->with_transaction(sub { @@ -385,7 +397,7 @@ sub produce_assembly { } package SL::Helper::Inventory::Allocation { - my @attributes = qw(parts_id qty bin_id warehouse_id chargenumber bestbefore comment reserve_for_id reserve_for_table oe_id); + my @attributes = qw(parts_id qty bin_id warehouse_id chargenumber bestbefore comment reserve_for_id reserve_for_table for_object_id); my %attributes = map { $_ => 1 } @attributes; for my $name (@attributes) { @@ -467,7 +479,7 @@ SL::WH - Warehouse and Inventory API bestbefore => undef, reserve_for_id => undef, reserve_for_table => undef, - oe_id => $my_document, + for_object_id => $order->id, ); # produce_assembly: @@ -755,15 +767,18 @@ each of the following attributes to be set at creation time: =item * reserve_for_table -=item * oe_id +=item * for_object_id -Must be explicit set if the allocation needs also an (other) document. +If set the allocations will be marked as allocated for the given object. +If these allocations are later used to produce an assembly, the resulting +consuming transactions will be marked as belonging to the given object. +The object may be an order, productionorder or other objects =back -C, C, C, C and oe_id may -be C (but must still be present at creation time). Instances are -considered immutable. +C, C, C, C and +C may be C (but must still be present at creation time). +Instances are considered immutable. =head1 CONSTRAINTS