<?php

namespace Core\Librerias;

use App\Controladores\TarifasControlador;
use App\Modelos\AlmacenUbicacion;
use App\Modelos\CarritoVentasModel;
use App\Modelos\ProductoUbicacion;
use App\Modelos\Proveedor;
use Core\Helpers\Moneda;

final class CarritoCompras
{
    private $carrito = [];
    private $array_errors = [];
    private $divisa_master;
    private $carritoModel;

    public function __construct()
    {
        $this->carritoModel = new CarritoVentasModel();
        $this->divisa_master = Moneda::Predeterminada();
    }

    public function obtenerDivisaFacturar(): array
    {
        return $this->carritoModel->obtenerDivisaFacturar();
    }

    public function obtenerDivisasParaFacturar(): array
    {
        $data_divisa = $this->carritoModel->obtenerDivisaEmpleado($_SESSION['user_data']['emp_id']);

        if ($data_divisa) {
            $divisas = $data_divisa;
        } else {
            $divisas = $this->carritoModel->obtenerDivisas();
        }

        return $divisas;
    }

    public function obtenerAlmacen(int $id_almacen)
    {
        return $this->carritoModel->obtenerAlmacen($id_almacen);
    }

    public function chuequearStock(int $id_producto, int $id_almacen)
    {
        return $this->carritoModel->chuequearStock($id_producto, $id_almacen);
    }

    public function obtenerProducto(int $id_producto)
    {
        return $this->carritoModel->obtenerProducto($id_producto);
    }

    public function obtenerDivisa(int $id_divisa)
    {
        return $this->carritoModel->obtenerDivisa($id_divisa);
    }

    public function obtenerSerie(int $id_serie)
    {
        return $this->carritoModel->obtenerSerie($id_serie);
    }

    public function obtenerCliente(int $id_cliente)
    {
        return $this->carritoModel->obtenerCliente($id_cliente);
    }

    public function obtenerEmpleados()
    {
        return $this->carritoModel->obtenerEmpleados();
    }

    public function obtenerDatosEmpresa()
    {
        return $this->carritoModel->obtenerDatosEmpresa();
    }

    public function obternerTiposDeDocumentos()
    {
        return $this->carritoModel->obternerTiposDeDocumentos();
    }

    public function obtenerImpuestos()
    {
        return $this->carritoModel->obtenerImpuestos();
    }

    public function obtenerPaises()
    {
        return $this->carritoModel->obtenerPaises();
    }

    public function obtenerAlmacenesEmpleado()
    {
        return $this->carritoModel->obtenerAlmacenesEmpleado();
    }

    public function obtenerSeriesEmpleado()
    {
        return $this->carritoModel->obtenerSeriesEmpleado();
    }

    public function chuequearCorrelativo(int $id_serie, int $id_documento)
    {
        return $this->carritoModel->chuequearCorrelativo($id_serie, $id_documento);
    }

    public function actualizarCorrelativo(int $id_serie, int $id_documento, int $correlativo)
    {
        return $this->carritoModel->actualizarCorrelativo($id_serie, $id_documento, $correlativo);
    }

    public function contenidoCarrito(string $_nombre_carrito_, int $id_cliente)
    {
        $this->carrito = [];
        $this->carrito = $_SESSION["$_nombre_carrito_$id_cliente"];
        unset($this->carrito['articulos_cantidad']);
        unset($this->carrito['subtotal']);
        unset($this->carrito['descuento']);
        unset($this->carrito['neto']);
        unset($this->carrito['iva']);
        unset($this->carrito['total']);
        unset($this->carrito['divisa']);
        unset($this->carrito['id_almacen']);
        return $this->carrito;
    }

    public function predeterminarDivisa(string $_nombre_carrito_, int $id_cliente, int $id_divisa, string $descuento_global)
    {
        $divisa = Moneda::obtenerDivisa($id_divisa);

        if ($divisa) {
            if ($divisa['id'] !== $this->divisa_master['id']) {
                $div_master = $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] ?? $this->divisa_master['id'];
                if (!$this->carritoModel->obtenerDivisaAlCambio($div_master, $divisa['id'])) {
                    $this->array_errors[] = 'Lo siento no se encuentra algun valor establecido para la conversión con la moneda predetermminada';
                }
            }
        } else {
            $this->array_errors[] = 'Divisa predeterminada no establecisa o divisa no enontrada';
        }

        if (empty($this->array_errors)) {

            if (!is_null($_SESSION["$_nombre_carrito_$id_cliente"])) {

                $descuento_global = convertir_a_float($descuento_global);
                $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);

                foreach ($contenido_carrito as $row) {
                    $precio = $this->obtenerPrecioSegunDivisa($_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['costo'], $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'], $id_divisa);
                    $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['costo'] = $precio['precio'];
                    $pc = $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['cantidad'] * $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['costo'];
                    $precio = $this->obtenerDescuentoMasIvaProducto($pc, $row['iva'], 'pvp', $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['descuento']);
                    $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['iva_total']     = $precio['iva'];
                    $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['neto']          = $precio['neto'];
                    $_SESSION["$_nombre_carrito_$id_cliente"][$row['unique']]['total']         = $precio['total'];
                }

                $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] = $id_divisa;

                return [
                    'divisa' => $divisa,
                    'data_carrito' => $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global)
                ];
            } else {
                return [
                    'divisa' => $divisa,
                    'data_carrito' => []
                ];
            }
        }

        return ['errors' => $this->array_errors];
    }

    public function buscarProducto(string $producto, int $id_divisa, int $id_almacen)
    {
        $divisa = Moneda::obtenerDivisa($id_divisa);

        if ($divisa) {
            if ($divisa['id'] !== $this->divisa_master['id']) {
                $divisa_factor = $this->carritoModel->obtenerDivisaAlCambio($this->divisa_master['id'], $divisa['id']);
                if (!$divisa_factor) {
                    $this->array_errors[] = 'Lo siento no se encuentra algun valor establecido para la conversión con la moneda predetermminada.';
                } else {
                    $factor = $divisa_factor['df_factor'];
                }
            } else {
                $factor = 1;
            }
        } else {
            $this->array_errors[] = 'Divisa predeterminada no establecisa o divisa no encontrada';
        }

        if (empty($this->array_errors)) {

            $array_productos = [];

            if (strlen($producto) > 0) {

                $productos = $this->carritoModel->buscarProductosCompras($producto);

                if (is_countable($productos) && count($productos)) {
                    foreach ($productos as $row) {
                        $imagen = null;
                        if (($row['pi_imagen'] != null || $row['pi_imagen'] != '') && file_exists(constant('UPLOADS_URI') . 'productos/' . $row['pi_imagen'])) {
                            $imagen = constant('IMG_URI') . 'productos/' . $row['pi_imagen'];
                        }
                        $array_productos[] = [
                            'pro_id'            => $row['pro_id'],
                            'pro_descripcion'   => "({$row['pro_codigo']}) {$row['pro_descripcion']}",
                            'pro_costo'         => Moneda::moneda(($row['pro_costo'] * $factor), $divisa['locale'], $divisa['symbol']),
                            'ps_cantidad'       => $row['ps_cantidad'] ?? 0,
                            'id_almacen'        => $id_almacen,
                            'fabricante'        => $row['fa_nombre'],
                            'imagen'            => $imagen
                        ];
                    }
                }
            }

            return $array_productos;
        }

        return ['errors' => $this->array_errors];
    }

    public function actualizarPrecioTotalYCantidad(string $_nombre_carrito_, int $id_cliente, $descuento = null)
    {
        $this->carrito = $_SESSION["$_nombre_carrito_$id_cliente"];
        unset($this->carrito['articulos_cantidad']);
        unset($this->carrito['subtotal']);
        unset($this->carrito['descuento']);
        unset($this->carrito['neto']);
        unset($this->carrito['iva']);
        unset($this->carrito['total']);
        unset($this->carrito['divisa']);
        unset($this->carrito['id_almacen']);

        $subtotal = $total_iva = $neto = $total = $articulos_cantidad = 0;

        if ($descuento > 0) {
            foreach ($this->carrito as $row) {
                $articulos_cantidad += 1;
                $subtotal += $row['neto'];
                $precio = $this->obtenerDescuentoMasIvaProducto($row['neto'], $row['iva'], 'pvp', $descuento, 0);
                $neto += $precio['neto'];
                $total_iva += $precio['iva'];
                $total += $precio['total'];
            }
        } else {
            foreach ($this->carrito as $row) {
                $articulos_cantidad += 1;
                $neto += $row['neto'];
                $total_iva += $row['iva_total'];
                $total += $row['total'];
            }
            $subtotal = $neto;
        }

        $_SESSION["$_nombre_carrito_$id_cliente"]['articulos_cantidad']   = $articulos_cantidad;
        $_SESSION["$_nombre_carrito_$id_cliente"]['subtotal']             = $subtotal;
        $_SESSION["$_nombre_carrito_$id_cliente"]['descuento']            = $descuento;
        $_SESSION["$_nombre_carrito_$id_cliente"]['neto']                 = $neto;
        $_SESSION["$_nombre_carrito_$id_cliente"]['iva']                  = $total_iva;
        $_SESSION["$_nombre_carrito_$id_cliente"]['total']                = $neto + $total_iva;
    }

    public function obtenerCarritoCliente(string $_nombre_carrito_, int $id_cliente, $descuento = null)
    {
        $this->actualizarPrecioTotalYCantidad($_nombre_carrito_, $id_cliente, $descuento);

        $div_format = Moneda::obtenerDivisa($_SESSION["$_nombre_carrito_$id_cliente"]['divisa']);

        $carrito_c = [];
        $carrito_c = $_SESSION["$_nombre_carrito_$id_cliente"];
        unset($carrito_c['articulos_cantidad']);
        unset($carrito_c['subtotal']);
        unset($carrito_c['descuento']);
        unset($carrito_c['neto']);
        unset($carrito_c['iva']);
        unset($carrito_c['total']);
        unset($carrito_c['divisa']);
        unset($carrito_c['id_almacen']);

        foreach ($carrito_c as $row) {
            $carrito_c[$row['unique']]['costo'] = number_format($row['costo'], $div_format['precision'], $div_format['decimal'], $div_format['thousands']);
            $carrito_c[$row['unique']]['iva'] = number_format($row['iva'], $div_format['precision'], $div_format['decimal'], $div_format['thousands']);
            $carrito_c[$row['unique']]['iva_total'] = number_format($row['iva_total'], $div_format['precision'], $div_format['decimal'], $div_format['thousands']);
            $carrito_c[$row['unique']]['neto'] = number_format($row['neto'], $div_format['precision'], $div_format['decimal'], $div_format['thousands']);
            $carrito_c[$row['unique']]['total'] = number_format($row['total'], $div_format['precision'], $div_format['decimal'], $div_format['thousands']);
        }

        return [
            'articulos_cantidad'    => round($_SESSION["$_nombre_carrito_$id_cliente"]['articulos_cantidad'] ?? 0, 2),
            'subtotal'              => number_format($_SESSION["$_nombre_carrito_$id_cliente"]['subtotal'] ?? 0, $div_format['precision'], $div_format['decimal'], $div_format['thousands']),
            'descuento'             => round($_SESSION["$_nombre_carrito_$id_cliente"]['descuento'] ?? 0, 2),
            'neto'                  => number_format($_SESSION["$_nombre_carrito_$id_cliente"]['neto'] ?? 0, $div_format['precision'], $div_format['decimal'], $div_format['thousands']),
            'iva'                   => number_format($_SESSION["$_nombre_carrito_$id_cliente"]['iva'] ?? 0, $div_format['precision'], $div_format['decimal'], $div_format['thousands']),
            'total'                 => number_format($_SESSION["$_nombre_carrito_$id_cliente"]['total'] ?? 0, $div_format['precision'], $div_format['decimal'], $div_format['thousands']),
            'carrito'               => $carrito_c
        ];
    }

    private function obtenerDescuentoMasIvaProducto(float $precio, float $iva, string $tipo_tarifa, float $tarifa)
    {
        if ($tarifa > 0) {
            $precio = TarifasControlador::aplicar(null, $precio, $tipo_tarifa, $tarifa, 0); //DESCUENTO PRODUCTO
        }

        $iva = $precio * ($iva / 100);

        return [
            'iva' => $iva,
            'neto' => $precio,
            'total' => $precio + $iva,
        ];
    }

    public function obtenerPrecioSegunDivisa(float $precio, int $id_divisa_master, int $id_divisa_buscada)
    {
        $divisa_factor = $this->carritoModel->obtenerDivisaAlCambio($id_divisa_master, $id_divisa_buscada);

        if ($divisa_factor) {
            $precio *= $divisa_factor['df_factor'];
            $factor = $divisa_factor['df_factor'];
        } else {
            $precio = $precio;
            $factor = 1;
        }

        return [
            'precio' => $precio,
            'factor' => $factor
        ];
    }

    public function agregarProductoBarcode(string $_nombre_carrito_, int $id_cliente, string $producto, int $id_almacen, int $id_divisa, string $descuento_global, bool $chequear_stock = true)
    {
        $producto = $this->carritoModel->buscarProductoBarcode($id_almacen, $producto);
        $divisa   = Moneda::obtenerDivisa($id_divisa);

        $imp_data = $this->carritoModel->obtenerImpuesto(2);

        if (!$producto || !$divisa)
            $this->array_errors[] = 'Producto o Divisa no disponibles';

        if ($_SESSION["$_nombre_carrito_$id_cliente"] != null) {
            if ($_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'] != $id_almacen)
                $this->array_errors[] = 'No puede seleccionar otro almacén diferente';
            if ($_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] != $id_divisa)
                $this->array_errors[] = 'No puede seleccionar otra divisa diferente';
        }

        if ($divisa['id'] !== $this->divisa_master['id']) {
            $divisa_factor = $this->carritoModel->obtenerDivisaAlCambio($this->divisa_master['id'], $divisa['id']);
            if (!$divisa_factor)
                $this->array_errors[] = 'Lo siento no se encuentra el valor establecido para la conversión con la moneda predeterminada.';
        }

        if (empty($this->array_errors)) {

            $descuento_global = convertir_a_float($descuento_global);
            $unique = md5($producto['pro_id']);

            if (isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
                $id_divisa_master   = $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'];
                $costo              = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['costo'];
                $id_iva             = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['id_iva'];
                $iva                = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva'];
                $nombre             = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['nombre'];
            } else {
                $id_divisa_master   = $this->divisa_master['id'];
                $costo             = $producto['pro_costo'];
                $id_iva             = $imp_data['imp_id'];
                $iva                = $imp_data['imp_valor'];
                $nombre             = $producto['pro_descripcion'];
            }

            $costo = $this->obtenerPrecioSegunDivisa($costo, $id_divisa_master, $divisa['id']);

            $articulo = [
                'id'                => $producto['pro_id'],
                'codigo'            => $producto['pro_codigo'],
                'nombre'            => $nombre,
                'costo'             => $costo['precio'],
                'id_iva'            => $id_iva,
                'iva'               => $iva,
                'id_almacen'        => $id_almacen,
                'descuento'         => 0.00,
                'cantidad'          => 1.00,
            ];

            $articulo['unique'] = $unique;

            $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);

            if (!empty($contenido_carrito)) {
                foreach ($contenido_carrito as $row) {
                    if ($row['id'] === $articulo['id']) {
                        $articulo['cantidad'] += $row['cantidad'];
                    }
                }
            }

            $precio = $this->obtenerDescuentoMasIvaProducto(($articulo['cantidad'] * $articulo['costo']), $articulo['iva'], 'pvp', 0);

            $articulo['iva_total']  = $precio['iva'];
            $articulo['neto']       = $precio['neto'];
            $articulo['total']      = $precio['total'];

            $_SESSION["$_nombre_carrito_$id_cliente"][$unique] = $articulo;
            $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] = $id_divisa;
            $_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'] = $id_almacen;

            return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
        }

        return ['errors' => $this->array_errors];
    }

    public function agregarProducto(string $_nombre_carrito_, int $id_cliente, int $id_producto, int $id_almacen, int $id_divisa, string $descuento_global)
    {
        $producto = $this->carritoModel->obtenerProducto($id_producto);
        $divisa   = Moneda::obtenerDivisa($id_divisa);

        if (!$producto || !$divisa)
            $this->array_errors[] = 'Producto o Divisa no disponibles';

        if ($_SESSION["$_nombre_carrito_$id_cliente"] != null) {
            if ($_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'] != $id_almacen)
                $this->array_errors[] = 'No puede seleccionar otro almacen diferente';
            if ($_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] != $id_divisa)
                $this->array_errors[] = 'No puede seleccionar otra divisa diferente';
        }

        if ($divisa['id'] !== $this->divisa_master['id']) {
            $divisa_factor = $this->carritoModel->obtenerDivisaAlCambio($this->divisa_master['id'], $divisa['id']);
            if (!$divisa_factor)
                $this->array_errors[] = 'Lo siento no se encuentra el valor establecido para la conversión con la moneda predeterminada.';
        }

        if (empty($this->array_errors)) {

            $imp_data = $this->carritoModel->obtenerImpuesto(2);
            $descuento_global = convertir_a_float($descuento_global);
            $unique = md5($producto['pro_id']);

            if (isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
                $id_divisa_master   = $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'];
                $costo              = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['costo'];
                $id_iva             = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['id_iva'];
                $iva                = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva'];
                $nombre             = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['nombre'];
            } else {
                $id_divisa_master   = $this->divisa_master['id'];
                $costo              = $producto['pro_costo'];
                $id_iva             = $imp_data['imp_id'];
                $iva                = $imp_data['imp_valor'];
                $nombre             = $producto['pro_descripcion'];
            }

            $costo = $this->obtenerPrecioSegunDivisa($costo, $id_divisa_master, $divisa['id']);

            $articulo = [
                'id'            => $producto['pro_id'],
                'codigo'        => $producto['pro_codigo'],
                'nombre'        => $nombre,
                'costo'         => $costo['precio'],
                'id_iva'        => $id_iva,
                'iva'           => $iva,
                'id_almacen'    => $id_almacen,
                'descuento'     => 0.00,
                'cantidad'      => 1.00,
            ];

            $articulo['unique'] = $unique;

            $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);

            if (!empty($contenido_carrito)) {
                foreach ($contenido_carrito as $row) {
                    if ($row['id'] === $articulo['id']) {
                        $articulo['cantidad'] += $row['cantidad'];
                    }
                }
            }

            $precio = $this->obtenerDescuentoMasIvaProducto(($articulo['cantidad'] * $articulo['costo']), $articulo['iva'], 'pvp', 0);

            $articulo['iva_total']  = $precio['iva'];
            $articulo['neto']       = $precio['neto'];
            $articulo['total']      = $precio['total'];

            $_SESSION["$_nombre_carrito_$id_cliente"][$unique] = $articulo;
            $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] = $id_divisa;
            $_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'] = $id_almacen;

            return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
        }

        return ['errors' => $this->array_errors];
    }

    public function actualizarPrecio(string $_nombre_carrito_, int $id_cliente, string $unique, string $precio, string $descuento_global)
    {
        if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
            $this->array_errors[] = 'Acción prohibida';
        } else {

            $precio = convertir_a_float($precio);
            $descuento_global = convertir_a_float($descuento_global);
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['costo'] = $precio;
            $pc = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['cantidad'] * $precio;
            $precio = $this->obtenerDescuentoMasIvaProducto($pc, $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva'], 'pvp', $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['descuento']);
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva_total']   = $precio['iva'];
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto']        = $precio['neto'];
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['total']       = $precio['total'];

            return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
        }

        return ['errors' => $this->array_errors];
    }

    public function actualizarCantidad(string $_nombre_carrito_, int $id_cliente, int $id_producto, float $cantidad, string $descuento_global)
    {
        $producto = $this->carritoModel->obtenerProducto($id_producto);

        if (!$producto)
            $this->array_errors[] = 'Producto no disponible';

        if (empty($this->array_errors)) {

            $unique = md5($id_producto);
            $cantidad = round($cantidad, constant('EMP_CANTIDAD'));

            if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
                $this->array_errors[] = 'Producto no disponible';
            } else {
                $descuento_global = convertir_a_float($descuento_global);
                $pc = $cantidad * $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['costo'];
                $precio = $this->obtenerDescuentoMasIvaProducto($pc, $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva'], 'pvp', $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['descuento']);
                $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['cantidad']    = $cantidad;
                $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva_total']   = $precio['iva'];
                $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto']        = $precio['neto'];
                $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['total']       = $precio['total'];
                return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
            }
        }

        return ['errors' => $this->array_errors];
    }

    public function actualizarDescripcion(string $_nombre_carrito_, int $id_cliente, string $unique, string $descripcion)
    {
        if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
            $this->array_errors[] = 'Producto no disponible';
        } else {
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['nombre'] = $descripcion;
            return true;
        }

        return ['errors' => $this->array_errors];
    }

    public function aplicarNuevoIva(string $_nombre_carrito_, int $id_cliente, string $unique, int $id_iva, string $descuento_global)
    {
        $iva = $this->carritoModel->obtenerImpuesto($id_iva);

        if (!$iva) {
            $this->array_errors[] = 'IVA no disponible';
        } else {
            if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
                $this->array_errors[] = 'Producto no disponible';
            } else {

                $descuento_global = convertir_a_float($descuento_global);
                $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['id_iva'] = $iva['imp_id'];
                $iva_total = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto'] * ($iva['imp_valor'] / 100);

                if ($iva['imp_valor'] > 0) {
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva']         = $iva['imp_valor'];
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva_total']   = $iva_total;
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['total']       = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto'] + $iva_total;
                } else {
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva']         = 0.00;
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva_total']   = 0.00;
                    $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['total']       = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto'];
                }

                return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
            }
        }

        return ['errors' => $this->array_errors];
    }

    public function aplicarDescuentoProducto(string $_nombre_carrito_, int $id_cliente, string $unique, string $descuento, string $descuento_global)
    {
        if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
            $this->array_errors[] = 'Producto no disponible';
        } else {
            $descuento = convertir_a_float($descuento);
            $descuento_global = convertir_a_float($descuento_global);
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['descuento'] = $descuento;
            $precio_total = $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['cantidad'] * $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['costo'];
            $precio = $this->obtenerDescuentoMasIvaProducto($precio_total, $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva'], 'pvp', $descuento);
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['iva_total']   = $precio['iva'];
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['neto']        = $precio['neto'];
            $_SESSION["$_nombre_carrito_$id_cliente"][$unique]['total']       = $precio['total'];
            return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
        }

        return ['errors' => $this->array_errors];
    }

    public function aplicarDescuentoAdicional(string $_nombre_carrito_, int $id_cliente, string $descuento_global)
    {
        $descuento = convertir_a_float($descuento_global);
        return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento);
    }

    public function eliminarProducto(string $_nombre_carrito_, int $id_cliente, string $unique, string $descuento_global)
    {
        if (!isset($_SESSION["$_nombre_carrito_$id_cliente"][$unique])) {
            $this->array_errors[] = 'Producto no disponible';
        } else {
            $descuento_global = convertir_a_float($descuento_global);
            unset($_SESSION["$_nombre_carrito_$id_cliente"][$unique]);
            return $this->obtenerCarritoCliente($_nombre_carrito_, $id_cliente, $descuento_global);
        }

        return ['errors' => $this->array_errors];
    }

    public function editarDetallesCliente(int $prov_id, array $data)
    {
        $new_proveedor = new Proveedor();

        if ($new_proveedor->where(['prov_id!=' => $prov_id, 'prov_cifnif' => $data['prov_cifnif']], true))
            $this->array_errors[] = 'El DNI ya se encuentra en uso';

        if (empty($this->array_errors)) {
            return $new_proveedor->editar($prov_id, [
                'prov_tipoidfiscal'     => $data['prov_tipoidfiscal'],
                'prov_cifnif'           => $data['prov_cifnif'],
                'prov_razonsocial'      => $data['prov_razonsocial'],
                'prov_direccion'        => $data['prov_direccion'],
                'prov_paisid'           => $data['prov_paisid'],
                'prov_estado'           => $data['prov_estado'],
                'prov_ciudad'           => $data['prov_ciudad'],
                'prov_codigo_postal'    => $data['prov_codigo_postal']
            ]);
        }

        return ['errors' => $this->array_errors];
    }

    public function guardarCompra(string $tabla_db, string $_nombre_carrito_, int $id_cliente, int $id_serie, string $fecha, string $observaciones, int $descuento_global, bool $afectar_precio, bool $afectar_stock)
    {
        $proveedor          = $this->carritoModel->obtenerProveedor($id_cliente);
        $serie              = $this->carritoModel->obtenerSerie($id_serie);
        $divisa_facturar    = Moneda::facturarPredeterminada();

        switch ($tabla_db) {
            case 'app_compras':
                $tipo_doc = 8;
                $tabla_db_articulos = 'app_compras_articulos';
                $uri = 'cmpfacturaeditar/verFactura/';
                break;
            case 'app_compras_notas':
                $tipo_doc = 9;
                $tabla_db_articulos = 'app_compras_notas_articulos';
                $uri = 'cmpnotaseditar/verFactura/';
                break;
            case 'app_cmppedidos':
                $tipo_doc = 10;
                $tabla_db_articulos = 'app_cmppedidos_articulos';
                $uri = 'cmppedidoseditar/verFactura/';
                break;
        }

        $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);
        $correlativo = $this->carritoModel->chuequearCorrelativo($id_serie, $tipo_doc);

        if (!$correlativo) {
            $this->array_errors[] = 'No existe correlativo entre la serie seleccionada y el documento Factura por favor dirijase a Modulo Configuración -> correlativos';
        } else {
            //REALIZAR CONVERSION A DIVISA PREDETERMINADA PARA FACTURAR
            if ($tabla_db == 'app_factura_master' && $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] != $divisa_facturar['id']) {
                $result = $this->predeterminarDivisa('factura', $id_cliente, $divisa_facturar['id'], $descuento_global);
                if (isset($result['errors'])) {
                    $this->array_errors[] = 'Error al convertir a la divisa predeterminada para facturar';
                }
            }
        }

        if (empty($this->array_errors)) {

            $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);
            $fecha = date('Y-m-d', strtotime($fecha)) . ' ' . date('H:i:s');
            $factor = 1;

            if ($this->divisa_master['id'] != $_SESSION["$_nombre_carrito_$id_cliente"]['divisa']) {
                $factor_div = $this->carritoModel->obtenerDivisaAlCambio($_SESSION["$_nombre_carrito_$id_cliente"]['divisa'], $this->divisa_master['id']);
                $factor = $factor_div['df_factor'];
            }

            switch ($tabla_db) {
                case 'app_compras':
                    $data_form_master = [
                        'cmp_subtotal'          => $_SESSION["$_nombre_carrito_$id_cliente"]['subtotal'],
                        'cmp_descuento'         => $_SESSION["$_nombre_carrito_$id_cliente"]['descuento'],
                        'cmp_neto'              => $_SESSION["$_nombre_carrito_$id_cliente"]['neto'],
                        'cmp_iva'               => $_SESSION["$_nombre_carrito_$id_cliente"]['iva'],
                        'cmp_total'             => $_SESSION["$_nombre_carrito_$id_cliente"]['total'],
                        'cmp_articulos_total'   => $_SESSION["$_nombre_carrito_$id_cliente"]['articulos_cantidad'],
                        'cmp_divid'             => $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'],
                        'cmp_almid'             => $_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'],
                        'cmp_empleadoid'        => $_SESSION['user_data']['einfo_id'],
                        'cmp_correlativo'       => $correlativo['cor_correlativo'] + 1,
                        'cmp_serid'             => $serie['ser_id'],
                        'cmp_serie'             => $serie['ser_descripcion'],
                        'cmp_cliid'             => $proveedor['prov_id'],
                        'cmp_env_nombres'       => $proveedor['prov_razonsocial'],
                        'cmp_env_direccion'     => $proveedor['prov_direccion'],
                        'cmp_env_pais'          => $proveedor['prov_paisid'],
                        'cmp_env_estado'        => $proveedor['prov_estado'],
                        'cmp_env_ciudad'        => $proveedor['prov_ciudad'],
                        'cmp_env_codigo_postal' => $proveedor['prov_codigo_postal'],
                        'cmp_fecha'             => $fecha,
                        'cmp_empresaid'         => 1,
                        'cmp_estatus'           => 2,
                        'cmp_observaciones'     => $observaciones,
                        'cmp_agregado'          => ($afectar_stock == 'true') ? 1 : 0,
                        'cmp_precio'            => ($afectar_precio == 'true') ? 1 : 0,
                    ];
                    $data_form_articulos = [
                        'cmpart_cmpid', 'cmpart_proid', 'cmpart_procodigo', 'cmpart_propnombre', 'cmpart_proprecio', 'cmpart_procantidad',
                        'cmpart_prodescuento', 'cmpart_proneto', 'cmpart_idiva', 'cmpart_almid', 'cmpart_proiva', 'cmpart_ivatotal',
                        'cmpart_prototal', 'cmpart_agregar_inventario'
                    ];
                    break;
                case 'app_compras_notas':
                    $data_form_master = [
                        'cmpn_subtotal'          => $_SESSION["$_nombre_carrito_$id_cliente"]['subtotal'],
                        'cmpn_descuento'         => $_SESSION["$_nombre_carrito_$id_cliente"]['descuento'],
                        'cmpn_neto'              => $_SESSION["$_nombre_carrito_$id_cliente"]['neto'],
                        'cmpn_iva'               => $_SESSION["$_nombre_carrito_$id_cliente"]['iva'],
                        'cmpn_total'             => $_SESSION["$_nombre_carrito_$id_cliente"]['total'],
                        'cmpn_articulos_total'   => $_SESSION["$_nombre_carrito_$id_cliente"]['articulos_cantidad'],
                        'cmpn_divid'             => $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'],
                        'cmpn_almid'             => $_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'],
                        'cmpn_empleadoid'        => $_SESSION['user_data']['einfo_id'],
                        'cmpn_correlativo'       => $correlativo['cor_correlativo'] + 1,
                        'cmpn_serid'             => $serie['ser_id'],
                        'cmpn_serie'             => $serie['ser_descripcion'],
                        'cmpn_cliid'             => $proveedor['prov_id'],
                        'cmpn_env_nombres'       => $proveedor['prov_razonsocial'],
                        'cmpn_env_direccion'     => $proveedor['prov_direccion'],
                        'cmpn_env_pais'          => $proveedor['prov_paisid'],
                        'cmpn_env_estado'        => $proveedor['prov_estado'],
                        'cmpn_env_ciudad'        => $proveedor['prov_ciudad'],
                        'cmpn_env_codigo_postal' => $proveedor['prov_codigo_postal'],
                        'cmpn_fecha'             => $fecha,
                        'cmpn_empresaid'         => 1,
                        'cmpn_estatus'           => 2,
                        'cmpn_observaciones'     => $observaciones,
                        'cmpn_agregado'          => ($afectar_stock == 'true') ? 1 : 0,
                        'cmpn_precio'            => ($afectar_precio == 'true') ? 1 : 0,
                    ];
                    $data_form_articulos = [
                        'cmpnart_cmpnid', 'cmpnart_proid', 'cmpnart_procodigo', 'cmpnart_propnombre', 'cmpnart_proprecio', 'cmpnart_procantidad',
                        'cmpnart_prodescuento', 'cmpnart_proneto', 'cmpnart_idiva', 'cmpnart_almid', 'cmpnart_proiva', 'cmpnart_ivatotal',
                        'cmpnart_prototal', 'cmpnart_agregar_inventario'
                    ];
                    break;
                case 'app_cmppedidos':
                    $data_form_master = [
                        'cmppe_subtotal'           => $_SESSION["$_nombre_carrito_$id_cliente"]['subtotal'],
                        'cmppe_descuento'          => $_SESSION["$_nombre_carrito_$id_cliente"]['descuento'],
                        'cmppe_neto'               => $_SESSION["$_nombre_carrito_$id_cliente"]['neto'],
                        'cmppe_iva'                => $_SESSION["$_nombre_carrito_$id_cliente"]['iva'],
                        'cmppe_total'              => $_SESSION["$_nombre_carrito_$id_cliente"]['total'],
                        'cmppe_articulos_total'    => $_SESSION["$_nombre_carrito_$id_cliente"]['articulos_cantidad'],
                        'cmppe_divid'              => $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'],
                        'cmppe_almid'              => $_SESSION["$_nombre_carrito_$id_cliente"]['id_almacen'],
                        'cmppe_empleadoid'         => $_SESSION['user_data']['einfo_id'],
                        'cmppe_correlativo'        => $correlativo['cor_correlativo'] + 1,
                        'cmppe_serid'              => $serie['ser_id'],
                        'cmppe_serie'              => $serie['ser_descripcion'],
                        'cmppe_cliid'              => $proveedor['prov_id'],
                        'cmppe_env_nombres'       => $proveedor['prov_razonsocial'],
                        'cmppe_env_direccion'     => $proveedor['prov_direccion'],
                        'cmppe_env_pais'          => $proveedor['prov_paisid'],
                        'cmppe_env_estado'        => $proveedor['prov_estado'],
                        'cmppe_env_ciudad'        => $proveedor['prov_ciudad'],
                        'cmppe_env_codigo_postal' => $proveedor['prov_codigo_postal'],
                        'cmppe_fecha'              => $fecha,
                        'cmppe_observaciones'      => $observaciones,
                        'cmppe_estatus'            => 2,
                        'cmppe_empresaid'          => 1,
                        'cmppe_descontado'         => 0,
                    ];
                    $data_form_articulos = [
                        'cmppeart_peid', 'cmppeart_proid', 'cmppeart_procodigo', 'cmppeart_propnombre',
                        'cmppeart_proprecio', 'cmppeart_procantidad', 'cmppeart_prodescuento',
                        'cmppeart_proneto', 'cmppeart_idiva', 'cmppeart_almid', 'cmppeart_proiva', 'cmppeart_ivatotal',
                        'cmppeart_prototal', 'cmppeart_descontar_inventario'
                    ];
                break;
            }

            try {

                $this->carritoModel->transactionBegin();

                $id_venta = $this->carritoModel->guardar($data_form_master, false, $tabla_db);

                $this->carritoModel->actualizarCorrelativo($serie['ser_id'], $tipo_doc);

                foreach ($contenido_carrito as $row) {

                    $almacen    = $this->carritoModel->obtenerAlmacen($row['id_almacen']);
                    $cantidad   = $this->carritoModel->chuequearStock($row['id'], $row['id_almacen']);

                    $this->carritoModel->guardar([
                        $data_form_articulos[0] => $id_venta,
                        $data_form_articulos[1] => $row['id'],
                        $data_form_articulos[2] => $row['codigo'],
                        $data_form_articulos[3] => $row['nombre'],
                        $data_form_articulos[4] => $row['costo'],
                        $data_form_articulos[5] => $row['cantidad'],
                        $data_form_articulos[6] => $row['descuento'],
                        $data_form_articulos[7] => $row['neto'],
                        $data_form_articulos[8] => $row['id_iva'],
                        $data_form_articulos[9] => $row['id_almacen'],
                        $data_form_articulos[10] => $row['iva'],
                        $data_form_articulos[11] => $row['iva_total'],
                        $data_form_articulos[12] => $row['total'],
                        $data_form_articulos[13] => ($afectar_stock=='true') ? $row['cantidad'] : 0,
                    ], true, $tabla_db_articulos);

                    if ($afectar_stock) {
                        if ($cantidad) {
                            if ($this->carritoModel->restablecerStock($row['id'], $row['id_almacen'], $row['cantidad'])) {
                                $this->carritoModel->guardar([
                                    'bsp_proid'     => $row['id'],
                                    'bsp_almacen'   => $almacen['alm_nombre'],
                                    'bsp_modulo'    => 'compras',
                                    'bsp_empleado'  => $_SESSION['user_data']['einfo_nombres'] . ' ' . $_SESSION['user_data']['einfo_apellidos'],
                                    'bsp_habia'     => $cantidad['ps_cantidad'],
                                    'bsp_sube'      => $row['cantidad'],
                                    'bsp_baja'      => 0,
                                    'bsp_total'     => $cantidad['ps_cantidad'] + $row['cantidad'],
                                    'bsp_facid'     => $id_venta,
                                    'bsp_docid'     => $tipo_doc
                                ], true, 'app_bitacora_stock_producto');
                            }
                        } else {
                            if ($this->carritoModel->guardar([
                                'ps_cantidad'   => $row['cantidad'],
                                'ps_almid'      => $row['id_almacen'],
                                'ps_disponible' => $row['cantidad'],
                                'ps_proid'      => $row['id'],
                                'ps_stockmax'   => $row['cantidad'],
                                'ps_stockmin'   => $row['cantidad']
                            ], true, 'app_productos_stocks')) {
                                $this->carritoModel->guardar([
                                    'bsp_proid'     => $row['id'],
                                    'bsp_almacen'   => $almacen['alm_nombre'],
                                    'bsp_modulo'    => 'compras',
                                    'bsp_empleado'  => $_SESSION['user_data']['einfo_nombres'] . ' ' . $_SESSION['user_data']['einfo_apellidos'],
                                    'bsp_habia'     => 0,
                                    'bsp_sube'      => $row['cantidad'],
                                    'bsp_baja'      => 0,
                                    'bsp_total'     => $row['cantidad'],
                                    'bsp_facid'     => $id_venta,
                                    'bsp_docid'     => $tipo_doc
                                ], true, 'app_bitacora_stock_producto');
                            }
                        }
                    }

                    if ($afectar_precio == true) {
                        $precio = TarifasControlador::aplicar(null, $row['costo'], "pvp", $row['descuento'], 0); //DESCUENTO PRODUCTO
                        if ($_SESSION["$_nombre_carrito_$id_cliente"]['divisa'] != $this->divisa_master['id']) {
                            $factor =  $this->obtenerPrecioSegunDivisa($precio, $_SESSION["$_nombre_carrito_$id_cliente"]['divisa'], $this->divisa_master['id']);
                            $this->carritoModel->editar($row['id'], [
                                'pro_costo' => $factor['precio'],
                                //'pro_impid' => $row['id_iva']
                            ], 'app_productos', 'pro_id');
                        } else {
                            $this->carritoModel->editar($row['id'], [
                                'pro_costo' => $precio,
                                //'pro_impid' => $row['id_iva']
                            ], 'app_productos', 'pro_id');
                        }
                    }
                }
                $this->carritoModel->transactionCommit();
            } catch (\Throwable $th) {
                $this->carritoModel->transactionRollBack();
                $this->array_errors[] = 'Error en transacción'.$th;
            }

            if (empty($this->array_errors)) {
                return ruta_base() . $uri . $id_venta;
            }
        }

        return ['errors' => $this->array_errors];
    }

    public function obtenerUbicacionesProducto(string $_nombre_carrito_, int $id_cliente)
    {
        $newProUbi = new ProductoUbicacion();
        $newAU = new AlmacenUbicacion();
        $tipo_de_escalon = [];
        $lista = [];
        $array_tipo = [
            'Zonas' => 'Zona',
            'Pasillos' => 'Pasillo',
            'Armarios' => 'Armario',
            'Secciones' => 'Sección',
            'Cajones' => 'Cajón'
        ];

        $contenido_carrito = $this->contenidoCarrito($_nombre_carrito_, $id_cliente);

        if (!empty($contenido_carrito)) {

            foreach ($contenido_carrito as $car) {

                $ubicacion = $newProUbi->obtenerubicacionProductoAlmacen($car['id'], $car['id_almacen']);

                if (is_countable($ubicacion) && count($ubicacion)) {

                    foreach ($ubicacion as $row) {

                        $tipo_de_escalon = [];
                        $padre = $row['au_padre'];

                        $tipo_de_escalon[] = [
                            'id' => $row['au_id'],
                            'tipo' => $array_tipo[$row['au_tipo']],
                            'descripcion' => $row['au_descripcion']
                        ];

                        while ($padre != 0) {
                            $escalon = $newAU->obtenerUbicacion($padre);
                            if ($escalon) {
                                $tipo_de_escalon[] = [
                                    'id' => $escalon['au_id'],
                                    'tipo' => $array_tipo[$escalon['au_tipo']],
                                    'descripcion' => $escalon['au_descripcion']
                                ];
                                $padre = $escalon['au_padre'];
                            } else {
                                $padre = 0;
                            }
                        }

                        $lista[] = [
                            'almacen' => [
                                'id' => $row['alm_id'],
                                'descripcion' => $row['alm_nombre']
                            ],
                            'producto' => [
                                'id' => $row['pro_id'],
                                'codigo' => $row['pro_codigo'],
                                'descripcion' => $row['pro_descripcion']
                            ],
                            'ubicacion' => $tipo_de_escalon
                        ];
                    }
                }
            }
        }

        return $lista;
    }
}
