示例#1
0
 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 */
 }