private static function DescontarDeAlmacenes2(VentaProducto $detalle_producto, $id_sucursal) { Logger::log("DescontarDeAlmacenes( Sucursal={$id_sucursal} )"); //se buscan los almacenes de la sucursal $almacenes = AlmacenDAO::search(new Almacen(array("id_sucursal" => $id_sucursal))); Logger::log("\tExisten " . count($almacenes) . " almacenes en esta sucursa."); //Arreglo que contendra los almacenes con el producto que buscamos. $productos_almacen = array(); //El total de productos en existencia en todos los almacenes $total = 0; //por cada almacen en la sucursal que no sea de consignacion se busca el producto en dicho almacen, //si el producto fue encontrado se ingresa en el arreglo de productos_almacen y si su existencia es mayor a 0 //se lleva incrementa el total de productos en existencia por parte de todos los almacenes foreach ($almacenes as $almacen) { if ($almacen->getIdTipoAlmacen() == 2) { continue; } $producto_almacen = ProductoAlmacenDAO::getByPK($detalle_producto->getIdProducto(), $almacen->getIdAlmacen(), $detalle_producto->getIdUnidad()); if (!is_null($producto_almacen)) { if ($producto_almacen->getCantidad() > 0) { $total += $producto_almacen->getCantidad(); } array_push($productos_almacen, $producto_almacen); } } //Si productos_almacen queda vacío, quiere decir que no se encontro el producto en ningún almacen de esta sucursal if (empty($productos_almacen)) { Logger::log("No se encontro el producto en los almacenes de esta sucursal"); throw new BusinessLogicException("No se encontro el producto en los almacenes de esta sucursal"); } //La cantidad de producto que estamos buscando vender $n = $detalle_producto->getCantidad(); //El numero de almacenes que cuentan con el producto $n_almacenes = count($productos_almacen); /* * Este algoritmo se basa en dos casos posibles * * 1. Que el numero de elementos vendidos sea mayor o igual al total de elementos encontrados en los almacenes * * 2. Que el numero de elementos vendidos sean menor al total de elementos encontrados * * Caso 1: * * Dejamos la posibilidad abierta de que los almacenes queden con cantidad negativa, pues como es una * venta en mostrador, para vender el producto tiene que estar fisicamente ahi, y no se pretende evitar la venta * de un producto que fisicamente esta presente pero no lo esta en el sistema. * * Así pues, como de cualqueir manera todos los almacenes van a quedar con ese elemento en cantidades negativas o en ceros * cuando el numero de elementos sea igual al total, dejamos en ceros las existencias y empezamos a restar uniformemente * en cada almacen hasta cubrir la diferencia entre el numero de elementos vendidos con el numero de elementos encontrados. * * Caso 2: * * Se tiene que empezar a descontar del almacen que cuenta con mas existencia del elemento vendido * hasta que su existencia sea igual a la del segundo almacen que cuenta con mas existencia. A partir de ahi * se descontara de dos almacenes en lugar de uno, y asi hasta llegar al almacen co nmenos existencia. * * Para lograr esto, se ordena el arreglo de almacenes con sus productos y se guarda un arreglo de diferencias, * que indicara cuantas veces podremos restar de un almacen hasta tener que pasar al siguiente y restar de ambos. * Un contador nos indica a cuantos almacenes le estamso restando producto hasta que se cubre la demanda de elementos. * * En ambos casos se mantiene la uniformidad de existencia del elemento en los almacenes. El metodo funciona tanto para * las unidades que aceptan decimales como aquellas que solo son enteros. */ //caso 1 if ($n >= $total) { $n -= $total; if ($unidad->getEsEntero()) { $mod = $n % $n_almacenes; $cantidad = floor($n / $n_almacenes); } else { $mod = 0; $cantidad = $n / $n_almacenes; } DAO::transBegin(); try { foreach ($productos_almacen as $p) { $temp = $cantidad; if ($mod > 0) { $temp++; $mod--; } $p->setCantidad(0 - $temp); ProductoAlmacenDAO::save($p); } } catch (Exception $e) { DAO::transRollback(); Logger::error("No se pudo actualizar la cantidad de producto en almacen: " . $e); throw new Exception("No se pudo actualizar la cantidad de producto en almacen"); } DAO::transEnd(); } else { $productos_almacen = self::OrdenarProductosAlmacen($productos_almacen); $diferencia = array(); for ($i = 0; $i < $n_almacenes - 1; $i++) { $diferencia[$i] = $productos_almacen[$i]->getCantidad() - $productos_almacen[$i + 1]->getCantidad(); } $diferencia[$i] = $productos_almacen[$i]->getCantidad(); for ($i = 0; $n > 0 && $i < $n_almacenes; $i++) { if ($n / ($i + 1) <= $diferencia[$i] * ($i + 1)) { if ($unidad->getEsEntero()) { $mod = $n % ($i + 1); $cantidad = floor($n / ($i + 1)); } else { $mod = 0; $cantidad = $n / ($i + 1); } DAO::transBegin(); try { for ($j = $i; $j >= 0; $j--) { $temp = $cantidad; if ($mod > 0) { $temp++; $mod--; } $productos_almacen[$j]->setCantidad($productos_almacen[$j]->getCantidad() - $temp); ProductoAlmacenDAO::save($productos_almacen[$j]); } } catch (Exception $e) { DAO::transRollback(); Logger::error("No se pudo actualizar la cantidad de producto en almacen: " . $e); throw new Exception("No se pudo actualizar la cantidad de producto en almacen"); } DAO::transEnd(); } else { for ($j = $i; $j >= 0; $j--) { $productos_almacen[$j]->setCantidad($productos_almacen[$j]->getCantidad() - $diferencia[$i]); } } $n -= $diferencia[$i] * ($i + 1); } /* Fin del for */ } /* Fin del caso 2 */ }