/**
  *
  *Iniciar una orden de consignaci?n. La fecha sera tomada del servidor.
  *
  * @param productos json Objeto que contendra los ids de los productos que se daran a consignacion a ese cliente con sus cantidades. Se incluira el id del almacen del cual seran tomados para determinar a que empresa pertenece esta consignacion
  * @param id_consignatario int Id del cliente al que se le hace la consignacion
  * @return id_consignacion int Id de la consignacion autogenerado por la insercion.
  **/
 public static function Nueva($fecha_termino, $folio, $id_consignatario, $productos, $tipo_consignacion, $fecha_envio_programada = null)
 {
     Logger::log("Creando nueva consignacion");
     //Se valida al consignatario
     $e = self::validarConsignatario($id_consignatario);
     if (is_string($e)) {
         Logger::error($e);
         throw new Exception($e);
     }
     $consignatario = UsuarioDAO::getByPK($id_consignatario);
     //Se obtiene al usuario de la sesion actual
     $id_usuario = LoginController::getCurrentUser();
     if (is_null($id_usuario)) {
         Logger::error("No se pudo obtener al usuario de la sesion, ya inicio sesion?");
         throw new Exception("No se pudo obtener al usuario de la sesion, ya inicio sesion?");
     }
     //Valida el parametro tipo de consignacion
     if ($tipo_consignacion != "credito" && $tipo_consignacion != "contado") {
         Logger::error("El parametro tipo de consignacion (" . $tipo_consignacion . ") es invalido");
         throw new Exception("El parametro tipo de consignacion (" . $tipo_consignacion . ") es invalido");
     }
     //Si no se recibio fecha de envio, se toma la fecha actual
     if (is_null($fecha_envio_programada)) {
         $fecha_envio_programada = date("Y-m-d H:i:s");
     }
     $consignacion = new Consignacion(array("id_cliente" => $id_consignatario, "id_usuario" => $id_usuario, "fecha_creacion" => date("Y-m-d H:i:s"), "activa" => 1, "cancelada" => 0, "folio" => $folio, "fecha_termino" => $fecha_termino, "saldo" => 0, "tipo_consignacion" => $tipo_consignacion));
     //Se agrupan los productos que vienen del mismo almacen en subarreglos para
     //programar un solo traspaso por almacen.
     $productos_por_almacen = array();
     $num_productos = count($productos);
     for ($i = 0; $i < $num_productos; $i++) {
         if ($productos[i] == null) {
             continue;
         }
         $temp = array();
         array_push($temp, $productos[i]);
         for ($j = $i + 1; $j < $num_productos; $j++) {
             if ($productos[$i]["id_almacen"] == $productos[$j]["id_almacen"]) {
                 array_push($temp, $productos[$j]);
                 $productos[$j] = null;
             }
         }
         $productos[$i] = null;
         array_push($productos_por_almacen, $temp);
     }
     DAO::transBegin();
     try {
         ConsignacionDAO::save($consignacion);
         $consignacion_producto = new ConsignacionProducto(array("id_consignacion" => $consignacion->getIdConsignacion()));
         foreach ($productos_por_almacen as $producto_por_almacen) {
             //Se validan los parametros obtenidos del arreglo de productos
             foreach ($producto_por_almacen as $producto) {
                 $validar = self::validarConsignacionProducto($producto["id_producto"], $producto["id_unidad"], $producto["cantidad"], $producto["impuesto"], $producto["descuento"], $producto["retencion"], $producto["precio"]);
                 if (is_string($validar)) {
                     throw new Exception($validar);
                 }
                 $validar = self::validarAlmacen($producto["id_almacen"]);
                 if (is_string($validar)) {
                     throw new Eception($validar);
                 }
             }
             /*
              * El consignatario puede contar con algún o ningún almacen de tipo consignacion,
              * pero solo tendra uno por empresa, esto quiere decir que todos los productos recibidos
              * seran repartidos en estos almacenes de acuerdo a la empresa a la que pertenece
              * el almacen de donde son extraidos.
              * 
              * Si el consignatario no cuenta con un almacen para la empresa de ese producto, se creara uno
              * nuevo y se realizara la transferencia.
              */
             //Se obtiene el id de la empresa de la cual vienen los productos
             $id_empresa = AlmacenDAO::getByPK($producto_por_almacen[0]["id_almacen"])->getIdEmpresa();
             //Se busca el almacen de consignacion de este cliente para esta empresa
             $almacen = null;
             $almacenes = AlmacenDAO::search(new Almacen(array("id_empresa" => $id_empresa, "nombre" => $consignatario->getCodigoUsuario(), "id_sucursal" => 0)));
             //Si no existe, se crea
             if (empty($almacenes)) {
                 $almacen = new Almacen(array("id_sucursal" => 0, "id_empresa" => $id_empresa, "id_tipo_almacen" => 2, "nombre" => $consignatario->getCodigoUsuario(), "descripcion" => "Almacen de consignacion del usuario " . $consignatario->getNombre() . " con clave " . $consignatario->getCodigoUsuario() . " para la empresa " . $id_empresa, "activo" => 1));
                 AlmacenDAO::save($almacen);
             } else {
                 $almacen = $almacenes[0];
             }
             //Se prepara el arreglo de productos para crear el traspaso de un almacen a otro
             $productos_para_traspaso = array();
             foreach ($producto_por_almacen as $producto) {
                 $p = array("id_producto" => $producto["id_producto"], "id_unidad" => $producto["id_unidad"], "cantidad" => $producto["cantidad"]);
                 array_push($productos_para_traspaso, $p);
             }
             //Se programa el traspaso del almacen de donde se tomaron estos productos al almacen de consignacion
             SucursalesController::ProgramarTraspasoAlmacen($almacen->getIdAlmacen(), $producto_por_almacen[0]["id_almacen"], $fecha_envio_programada, $productos_para_traspaso);
         }
     } catch (Exception $e) {
         DAO::transRollback();
         Logger::error("No se pudo crear la nueva consignacion: " . $e);
         throw new Exception("No se pudo crear la nueva consignacion");
     }
     DAO::transEnd();
     Logger::log("Consignacion creada exitosamente");
     return array("id_consignacion" => $consignacion->getIdConsignacion());
 }
 /**
  *
  *Creara un nuevo almacen en una sucursal, este almacen contendra lotes.
  *
  * @param id_empresa int Id de la empresa a la que pertenecen los productos de este almacen
  * @param id_sucursal int El id de la sucursal a la que pertenecera este almacen.
  * @param id_tipo_almacen int Id del tipo de almacen 
  * @param nombre string nombre del almacen
  * @param descripcion string Descripcion extesa del almacen
  * @return id_almacen int el id recien generado
  **/
 static function Nuevo($id_empresa, $id_sucursal, $id_tipo_almacen, $nombre, $descripcion = null)
 {
     //verificamos que exista la empresa
     if (!is_null($id_empresa) && !($empresa = EmpresaDAO::getByPK($id_empresa))) {
         throw new Exception("No se tiene registro de la empresa {$id_empresa}");
     }
     //verificamos que exista la sucursal
     if (!is_null($id_sucursal) && !($sucursal = SucursalDAO::getByPK($id_sucursal))) {
         throw new Exception("No se tiene registro de la sucursal {$id_sucursal}");
     }
     //verificamos que exista el tipo de almacen
     if (!is_null($id_tipo_almacen) && !($almacen = TipoAlmacenDAO::getByPK($id_tipo_almacen))) {
         throw new Exception("No se tiene registro del tipo de almacen {$id_tipo_almacen}");
     }
     //verificamos que se haya especificado el nombre
     if (!ValidacionesController::validarLongitudDeCadena(trim($nombre), 2, 100)) {
         throw new Exception("El nombre debe ser una cadena entre 2 y 100 caracteres, se encontro \"" . trim($nombre) . "\" ");
     }
     //Se valida si hay un almacen con ese mimso nombre en esta sucursal
     $almacenes = AlmacenDAO::search(new Almacen(array("id_sucursal" => $id_sucursal)));
     foreach ($almacenes as $almacen) {
         if ($almacen->getNombre() == trim($nombre) && $almacen->getActivo()) {
             Logger::log("El nombre (" . $nombre . ") ya esta siendo usado por el almacen: " . $almacen->getIdAlmacen());
             throw new Exception("El nombre ya esta en uso");
         }
     }
     //Si se recibe un tipo de almacen de consignacion, se manda una excepcion, pues no se puede crear un almacen
     //de consignacion con este metodo.
     if ($id_tipo_almacen == 2) {
         Logger::error("No se puede crear un almacen de consignacion con este metodo");
         throw new Exception("No se puede crear un almacen de consignacion con este metodo");
     }
     //Solo puede haber un almacen por tipo por cada empresa en una sucursal.
     $almacenes = AlmacenDAO::search(new Almacen(array("id_sucursal" => $id_sucursal, "id_empresa" => $id_empresa, "id_tipo_almacen" => $id_tipo_almacen)));
     if (!empty($almacenes)) {
         Logger::error("Ya existe un almacen (" . $almacenes[0]->getIdAlmacen() . ") de este tipo (" . $id_tipo_almacen . ") en esta sucursal (" . $id_sucursal . ") para esta empresa (" . $id_empresa . ")");
         throw new Exception("Ya existe un almacen de este tipo en esta sucursal para esta empresa");
     }
     //Se inicializa el registro a guardar con los datos obtenidos.
     $almacen = new Almacen();
     $almacen->setNombre(trim($nombre));
     $almacen->setDescripcion($descripcion);
     $almacen->setIdSucursal($id_sucursal);
     $almacen->setIdEmpresa($id_empresa);
     $almacen->setIdTipoAlmacen($id_tipo_almacen);
     $almacen->setActivo(1);
     DAO::transBegin();
     try {
         AlmacenDAO::save($almacen);
     } catch (Exception $e) {
         DAO::transRollback();
         Logger::error("No se pudo crear el nuevo almacen");
         throw new Exception("No se pudo crear el nuevo almacen");
     }
     DAO::transEnd();
     Logger::log("Almacen " . $almacen->getIdAlmacen() . " creado exitosamente");
     return array("id_almacen" => (int) $almacen->getIdAlmacen());
 }