X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/blobdiff_plain/3b322be491a2d7e9a042a2e208793218e1188b93..15176cbb3b162a07a055dbe6cfc0f98f9d65d0df:/SL/Helper/Inventory.pm diff --git a/SL/Helper/Inventory.pm b/SL/Helper/Inventory.pm index c26d855c9..a1a142803 100644 --- a/SL/Helper/Inventory.pm +++ b/SL/Helper/Inventory.pm @@ -7,6 +7,7 @@ use Exporter qw(import); 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); @@ -23,7 +24,10 @@ sub _get_stock_onhand { my $onhand_mode = !!$params{onhand}; - my @selects = ('SUM(qty) as qty'); + my @selects = ( + 'SUM(qty) AS qty', + 'MIN(EXTRACT(epoch FROM inventory.itime)) AS itime', + ); my @values; my @where; my @groups; @@ -167,9 +171,9 @@ sub allocate { return () if $qty <= 0; my $results = get_stock(part => $part, by => 'for_allocate'); - my %bin_whitelist = map { (ref $_ ? $_->id : $_) => 1 } listify($params{bin}); - my %wh_whitelist = map { (ref $_ ? $_->id : $_) => 1 } listify($params{warehouse}); - my %chargenumbers = map { (ref $_ ? $_->id : $_) => 1 } listify($params{chargenumber}); + my %bin_whitelist = map { (ref $_ ? $_->id : $_) => 1 } grep defined, listify($params{bin}); + my %wh_whitelist = map { (ref $_ ? $_->id : $_) => 1 } grep defined, listify($params{warehouse}); + my %chargenumbers = map { (ref $_ ? $_->id : $_) => 1 } grep defined, listify($params{chargenumber}); my %reserve_whitelist; if ($params{reserve_for}) { $reserve_whitelist{ $_->meta->table }{ $_->id } = 1 for listify($params{reserve_for}); @@ -191,6 +195,7 @@ sub allocate { || exists $chargenumbers{$b->{chargenumber}} <=> exists $chargenumbers{$a->{chargenumber}} # then prefer wanted chargenumbers || exists $bin_whitelist{$b->{bin_id}} <=> exists $bin_whitelist{$a->{bin_id}} # then prefer wanted bins || exists $wh_whitelist{$b->{warehouse_id}} <=> exists $wh_whitelist{$a->{warehouse_id}} # then prefer wanted bins + || $a->{itime} <=> $b->{itime} # and finally prefer earlier charges } @filtered_results; my @allocations; my $rest_qty = $qty; @@ -208,17 +213,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 => 'not enough to allocate', - msg => t8("can not allocate #1 units of #2, missing #3 units", $qty, $part->displayable_name, $rest_qty), + msg => t8("can not allocate #1 units of #2, missing #3 units", _qty($qty), $part->displayable_name, _qty($rest_qty)), ); } else { if ($params{constraints}) { @@ -239,8 +244,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; @@ -317,7 +327,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}; @@ -348,6 +358,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, @@ -355,7 +366,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, ); } @@ -376,7 +387,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 { @@ -390,7 +401,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) { @@ -422,32 +433,32 @@ SL::WH - Warehouse and Inventory API # See description for an intro to the concepts used here. - use SL::Helper::Inventory; + use SL::Helper::Inventory qw(:ALL); # stock, get "what's there" for a part with various conditions: - my $qty = SL::Helper::Inventory->get_stock(part => $part); # how much is on stock? - my $qty = SL::Helper::Inventory->get_stock(part => $part, date => $date); # how much was on stock at a specific time? - my $qty = SL::Helper::Inventory->get_stock(part => $part, bin => $bin); # how is on stock in a specific bin? - my $qty = SL::Helper::Inventory->get_stock(part => $part, warehouse => $warehouse); # how is on stock in a specific warehouse? - my $qty = SL::Helper::Inventory->get_stock(part => $part, chargenumber => $chargenumber); # how is on stock of a specific chargenumber? + my $qty = get_stock(part => $part); # how much is on stock? + my $qty = get_stock(part => $part, date => $date); # how much was on stock at a specific time? + my $qty = get_stock(part => $part, bin => $bin); # how is on stock in a specific bin? + my $qty = get_stock(part => $part, warehouse => $warehouse); # how is on stock in a specific warehouse? + my $qty = get_stock(part => $part, chargenumber => $chargenumber); # how is on stock of a specific chargenumber? # onhand, get "what's available" for a part with various conditions: - my $qty = SL::Helper::Inventory->get_onhand(part => $part); # how much is available? - my $qty = SL::Helper::Inventory->get_onhand(part => $part, date => $date); # how much was available at a specific time? - my $qty = SL::Helper::Inventory->get_onhand(part => $part, bin => $bin); # how much is available in a specific bin? - my $qty = SL::Helper::Inventory->get_onhand(part => $part, warehouse => $warehouse); # how much is available in a specific warehouse? - my $qty = SL::Helper::Inventory->get_onhand(part => $part, chargenumber => $chargenumber); # how much is availbale of a specific chargenumber? - my $qty = SL::Helper::Inventory->get_onhand(part => $part, reserve_for => $order); # how much is available if you include this reservation? + my $qty = get_onhand(part => $part); # how much is available? + my $qty = get_onhand(part => $part, date => $date); # how much was available at a specific time? + my $qty = get_onhand(part => $part, bin => $bin); # how much is available in a specific bin? + my $qty = get_onhand(part => $part, warehouse => $warehouse); # how much is available in a specific warehouse? + my $qty = get_onhand(part => $part, chargenumber => $chargenumber); # how much is availbale of a specific chargenumber? + my $qty = get_onhand(part => $part, reserve_for => $order); # how much is available if you include this reservation? # onhand batch mode: - my $data = SL::Helper::Inventory->get_onhand( + my $data = get_onhand( warehouse => $warehouse, by => [ qw(bin part chargenumber reserve_for) ], with_objects => [ qw(bin part) ], ); # allocate: - my @allocations, SL::Helper::Inventory->allocate( + my @allocations, allocate( part => $part, # part_id works too qty => $qty, # must be positive chargenumber => $chargenumber, # optional, may be arrayref. if provided these charges will be used first @@ -457,7 +468,7 @@ SL::WH - Warehouse and Inventory API ); # shortcut to allocate all that is needed for producing an assembly, will use chargenumbers as appropriate - my @allocations, SL::Helper::Inventory->allocate_for_assembly( + my @allocations, allocate_for_assembly( part => $assembly, # part_id works too qty => $qty, # must be positive ); @@ -472,11 +483,11 @@ 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: - SL::Helper::Inventory->produce_assembly( + produce_assembly( part => $part, # target assembly qty => $qty, # qty allocations => \@allocations, # allocations to use. alternatively use "auto_allocate => 1," @@ -760,15 +771,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