I think I found the bug in the packing algorithm (the one Thomas was talking about)
in line 450:
$productsRemaining = array_slice($productsRemaining, $p + 1);
it should be
$productsRemaining = array_slice($productsRemaining, $p);
because the $productsRemaining[$p] product has not been packed yet and shouldn't be taken out of the array.
Furthermore, packProducts function treats downloadable software as physical objects to be packed so I added this codes to eliminate such products from the list.
for ($i = 0; $i < count($productsArray); $i++) {
$product = $productsArray[$i];
$downloadableflag = false;
if (is_array($product['attributes'])) {
reset($product['attributes']);
while (list($opt, $value) = each($product['attributes'])) {
$virtual_check_query = tep_db_query("select count(*) as from " . TABLE_PRODUCTS_ATTRIBUTES . " pa, " . TABLE_PRODUCTS_ATTRIBUTES_DOWNLOAD . " pad where pa.products_id = '" . $product['id'] . "' and pa.options_id = '" . $opt . "' and pa.options_values_id = '" . $value . "' and pa.products_attributes_id = pad.products_attributes_id");
$virtual_check = tep_db_fetch_array($virtual_check_query);
if ($virtual_check['total'] > 0) $downloadableflag = true;
}
}
if (!$downloadableflag) {
for ($j = 0; $j < $productsArray[$i]['quantity']; $j++) {
$productsRemaining[] = $product;
}
}
}
in replace of :
for ($i = 0; $i < count($productsArray); $i++) {
$product = $productsArray[$i];
for ($j = 0; $j < $productsArray[$i]['quantity']; $j++) {
$productsRemaining[] = $product;
}
}
I hope that works.