in reply to deleting key/value from hashref

If I'm reading it correctly, your problem is that in your second block you're deleting $sale_items->{$salesKey}, and then in the condition to the third block you're checking $sale_items->{$salesKey}{amount}, which is recreating $sale_items->{$salesKey}. Probably the easiest way would be to next things a little, and reduce some of the repetition (like having exactly the same conditions on the warn and delete. In particular, doing the check for the amounts in an else (or elsif) will make sure you don't try to check something you've already deleted.
foreach my $paymentRow ( @$payments ) { foreach my $salesKey ( keys %$sale_items ) { ### make sure we're applying the right line items ... next if ( $paymentRow->{creditacct} != $sale_items->{$salesKey}{debitacct} ); next unless $paymentRow->{ppid} == $sale_items->{$salesKey}{ppid}; ## if payment can be applied, ## apply it and delete the row from payments/credits array if ( $paymentRow->{amount} == $sale_items->{$salesKey}{amount}){ warn "DELETING ... {$salesKey} "; delete $sale_items->{$salesKey}; undef( $paymentRow ); } elsif ($paymentRow->{amount} < $sale_items->{$salesKey}{amount}){ $sale_items->{$salesKey}{amount} -= $paymentRow->{amount}; } } }