#!/usr/bin/perl require "parser.pl"; require "misc.pl"; $mult = shift(@ARGV); &parse; sub number { local ($id) = @_; my $s = $inv{$id}[0]; my $n = $want{$id}*$mult; return $n < $s ? $n : $s; } # # The heuristics here aren't very nice. We give zero-cost stock priority over # any other stock, when we go by stock size up to the quantity we need. The # idea is to exhause local stock (zero-cost) first, then try to obtain the # parts with as few orders as possible. # # It would be better to have some sort of priority, so that we can express a # preference among stock we already own. Also, if non-zero-cost stock has widly # different prices, the smallest order cost may not be a good indicator of # which source we prefer. # # Furthermore, the algorithm doesn't consider the number of sources we use in # total or things like lead time, shipping cost, customs, etc. # sub rank { local ($a, $b) = @_; my $na = &number($a); # min(number wanted, available) my $nb = &number($b); my $pa = $inv{$a}[3]; # per unit price for smallest quantum my $pb = $inv{$b}[3]; #print STDERR "a=$a b=$b na=$na nb=$nb pa=$pa pb=$pb\n"; return 1 if $na && !$pa && $pb; return -1 if $nb && $pa && !$pb; return $na <=> $nb if $na != $nb; return $pb <=> $pa; } for (keys %parts) { $parts++; } print "#ORD\n"; for (sort { &rank($b, $a) } keys %want) { my $n = &number($_); $n -= $n % $mult; next unless $n; my @f = @{ $inv{$_} }; my $max = shift @f; my $currency = shift @f; my @qty; my @price; my %index; my $best_qty; my $best_price = undef; while (@f) { my $q = shift @f; my $p = shift @f; if (defined $index{$q}) { $price[$index{$q}] = $p; } else { push(@qty, $q); push(@price, $p); $index{$q} = $#qty; # @@@ this fails if smaller quantities following a large quantity # differ from the quantities preceding them. E.g., 1 10 100 25 # wouldn't yield correct results. } for (my $i = $#qty; $i >= 0; $i--) { my $order = 0; my $price = 0; my $left = $n; for (my $j = $#qty; $j >= $i; $j--) { while ($left >= ($j == $i ? 1 : $qty[$j])) { $left -= $qty[$j]; $order += $qty[$j]; $price += $price[$j]*$qty[$j]; } } next if $order > $max; if (!defined $best_price || $price < $best_price) { $best_price = $price; $best_qty = $order; } } } next if !defined $best_price; print "$_ $best_qty $currency $best_price"; my $id = $_; while (keys %{ $comps{$id} }) { last if $best_qty < $mult; $best_qty -= $mult; my $ref = (sort { &cmp_cref($a, $b); } keys %{ $comps{$id} })[0]; #print STDERR "$id: $ref + ", join("|", keys %{ $comps{$id} }), "\n"; my @f = @{ $parts{$ref} }; while (@f) { my @id2 = splice(@f, 0, 2); my $id2 = "$id2[0] $id2[1]"; $want{$id2}--; delete $comps{$id2}{$ref}; } print " $ref"; } print "\n"; } for my $id (sort { $want{$b} <=> $want{$a} } keys %want) { next unless $want{$id}; print STDERR "$id"; for (&eq($id)) { # next unless $want{$_}; die "\n$_ ($want{$_}) vs. $id want ($want{$id})" unless $want{$_} == $want{$id}; print STDERR " $_"; $want{$_} = 0; } print STDERR ": want $want{$id}\n"; $want{$id} = 0; }