- my $fill_up_doi_query = $self->require_stock_out ? $stock_fill_up_doi_query : $no_stock_fill_up_doi_query;
-
- my $oi_query = sprintf $fill_up_oi_query, join (', ', ('?')x@oe_ids);
- my $doi_query = sprintf $fill_up_doi_query, join (', ', ('?')x@oe_ids);
- my $rl_query = sprintf $oe_do_record_links, join (', ', ('?')x@oe_ids);
-
- my $oi = selectall_hashref_query($::form, $self->dbh, $oi_query, @oe_ids);
-
- return unless @$oi;
-
- my $doi = selectall_hashref_query($::form, $self->dbh, $doi_query, @oe_ids);
- my $rl = selectall_hashref_query($::form, $self->dbh, $rl_query, @oe_ids);
-
- my %oi_by_identity = partition_by { $self->item_identity($_) } @$oi;
- my %doi_by_id = partition_by { $_->{delivery_order_id} } @$doi;
- my %doi_by_trans_id;
- push @{ $doi_by_trans_id{$_->{from_id}} //= [] }, @{ $doi_by_id{$_->{to_id}} }
- for grep { exists $doi_by_id{$_->{to_id}} } @$rl;
-
- my %doi_by_identity = partition_by { $self->item_identity($_) } @$doi;
-
- for my $match (sort keys %oi_by_identity) {
- next unless exists $doi_by_identity{$match};
-
- my %oi_by_oe = partition_by { $_->{trans_id} } @{ $oi_by_identity{$match} };
- for my $trans_id (sort { $a <=> $b } keys %oi_by_oe) {
- next unless my @sorted_doi = _intersect($doi_by_identity{$match}, $doi_by_trans_id{$trans_id});
-
- # sorting should be quite fast here, because there are usually only a handful of matches
- next unless my @sorted_oi = sort { $a->{position} <=> $b->{position} } @{ $oi_by_oe{$trans_id} };
-
- # parallel walk through sorted oi/doi entries
- my $oi_i = my $doi_i = 0;
- my ($oi, $doi) = ($sorted_oi[$oi_i], $sorted_doi[$doi_i]);
- while ($oi_i < @sorted_oi && $doi_i < @sorted_doi) {
- $oi = $sorted_oi[++$oi_i], next if $oi->{qty} <= $self->shipped_qty->{$oi->{id}};
- $doi = $sorted_doi[++$doi_i], next if 0 == $doi->{qty};
-
- my $factor = AM->convert_unit($doi->{unit} => $oi->{unit});
- my $min_qty = min($oi->{qty} - $self->shipped_qty->{$oi->{id}}, $doi->{qty} * $factor);
-
- # min_qty should never be 0 now. the first part triggers the first next,
- # the second triggers the second next and factor must not be 0
- # but it would lead to an infinite loop, so catch that.
- die 'panic! invalid shipping quantity' unless $min_qty;
-
- $self->shipped_qty->{$oi->{id}} += $min_qty;
- $doi->{qty} -= $min_qty / $factor; # TODO: find a way to avoid float rounding
- }
- }