<?php
class Venta_model extends CI_Model {

/********************************** Funciones de Consulta **************************************/

	/**
	 * Entrega listado de ventas en estados vendido:
	 * Entregado, enviado, Disponible para retiro, En preparación y Pago Aceptado
	 * @param $idt id_transportista
	 * @param $ida id_asignado
	*/
	/*public function get_all($type = 1, $idt = 0, $ida = '-1') {
		$this->db->select('v.*, ev.color, ev.fondo');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('v.deleted', 0);
		if ($type == 1) {
			$this->db->where_in('v.id_tipo_venta', [1, 5, 7, 8, 9, 11, 12]);
		}
		else if ($type == 4) {
			$this->db->where_in('v.id_tipo_venta', [4, 6]);
		}
		else {
			$this->db->where_in('v.id_tipo_venta', [$type]);
		}
		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}

		$this->db->where('v.vendido', 1);

		$this->db->order_by('DATE_FORMAT(fecha, \'%Y%m\') DESC');
		$this->db->order_by('CASE WHEN id_tipo_venta = 5 THEN 1 ELSE 0 END', 'DESC', FALSE);
		$this->db->order_by('CASE WHEN boleta > 0 THEN 1 ELSE 0 END', 'ASC', FALSE);
		$this->db->order_by('v.boleta', 'DESC');
		$this->db->order_by('v.fecha', 'DESC');
		$this->db->order_by('v.ps_id', 'DESC');
		$result = $this->db->get()->result_array();
		$tmp_ventas = [];
		foreach ($result as &$venta) {
			$venta['mes'] = date('Ym', strtotime($venta['fecha']));
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}
			$tmp_ventas[$venta['mes']][] = $venta;
			//prx($venta);
		}

		$result = $tmp_ventas;
		return $result;
	}*/
	public function get_all($type = 1, $idt = 0, $ida = '-1') {
		// =======================
		// 1. QUERY PRINCIPAL DE VENTAS
		// =======================
		$this->db->select('
			v.*, 
			ev.color, 
			ev.fondo,
			c.nombre AS cliente_nombre,
			c.email  AS cliente_email,
			t.nombre AS transportista
		');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.deleted', 0);

		if ($type == 1) {
			$this->db->where_in('v.id_tipo_venta', [1, 5, 7, 8, 9, 11, 12]);
		} else if ($type == 4) {
			$this->db->where_in('v.id_tipo_venta', [4, 6]);
		} else {
			$this->db->where_in('v.id_tipo_venta', [$type]);
		}

		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}

		$this->db->where('v.vendido', 1);

		// Ordenamiento
		$this->db->order_by('DATE_FORMAT(fecha, \'%Y%m\') DESC');
		$this->db->order_by('CASE WHEN id_tipo_venta = 5 THEN 1 ELSE 0 END', 'DESC', FALSE);
		$this->db->order_by('CASE WHEN boleta > 0 THEN 1 ELSE 0 END', 'ASC', FALSE);
		$this->db->order_by('v.boleta', 'DESC');
		$this->db->order_by('v.fecha', 'DESC');
		$this->db->order_by('v.ps_id', 'DESC');

		$ventas = $this->db->get()->result_array();

		// =======================
		// 2. MAPEO DE PRODUCTOS
		// =======================
		$ventas_ids = array_column($ventas, 'id');
		$productos_map = [];

		if (!empty($ventas_ids)) {
			$this->db->select('pv.id_venta, p.id, p.nombre, pv.cantidad');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p', 'pv.id_producto = p.id', 'left');
			$this->db->where_in('pv.id_venta', $ventas_ids);
			$this->db->where('pv.deleted', 0);
			$productos = $this->db->get()->result_array();

			foreach ($productos as $prod) {
				$productos_map[$prod['id_venta']][] = [
					'id'       => $prod['id'],
					'nombre'   => $prod['nombre'],
					'cantidad' => $prod['cantidad']
				];
			}
		}

		// =======================
		// 3. PROCESAMIENTO Y AGRUPACIÓN POR MES
		// =======================
		$tmp_ventas = [];
		foreach ($ventas as &$venta) {
			// Agregar productos
			$venta['productos'] = $productos_map[$venta['id']] ?? [];

			$venta['mes'] = date('Ym', strtotime($venta['fecha']));

			// Estado externo
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}

			// Agrupar por mes
			$tmp_ventas[$venta['mes']][] = $venta;
		}

		return $tmp_ventas;
	}


	public function get($id) {
		$this->db->select('v.*, c.nombre, t.nombre as transportista, t.color');
		$this->db->from('ventas v');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.id', $id);
		$this->db->where('v.deleted', 0);
		$query = $this->db->get();
		$venta = $query->row_array();
		
		if (!empty($venta)) {
			$this->db->select('*, pv.id as id, pv.precio as precio_unitario');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p','pv.id_producto = p.id');
			$this->db->where('pv.id_venta', $id);
			$this->db->where('pv.deleted', 0);
			$query = $this->db->get();
			$productosVentas = $query->result_array();

			$CI =& get_instance();
			$CI->load->model('producto_model');
			foreach ($productosVentas as &$pv) {
				$pv['id_image'] = $CI->producto_model->get_ps_image($pv['ps_id']);
			}

			$venta['fecha'] = date('Y-m-d', strtotime($venta['fecha']));
			if ($venta['fecha_venta']) {
				$venta['fecha_venta'] = date('Y-m-d', strtotime($venta['fecha_venta'])) . 'T' . date('H:i:s', strtotime($venta['fecha_venta']));
			}
			if ($venta['nombre'] != '') {
				$venta['cliente'] = $venta['nombre'];
			}
			$venta['productos_ventas'] = $productosVentas;
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}

			$venta['puntos'] = $this->get_points($venta['id'], $venta['ps_id']);

			return $venta;
		}
		else{
			return [];
		}
	}


	/**
	 * Entrega listado de ventas en los estados solicitados, independiente de su tipo
	 * @param array $states estados solicitados
	 * @param int $idt id de transportista
	 * @param int $ida id de usuario asignado (armador)
	 * @param string $ida campo or el cual se ordenan los resultados
	*/
	/*public function get_by_state($estados, $idt = 0, $ida = 0, $idc = 0, $orden = 'fecha') {
		$this->db->select('v.*, t.nombre as transportista');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.deleted', 0);
		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}
		if ($idc > 0) {
			$this->db->where('v.id_canal', $idc);
		}
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->order_by('v.ps_id_asociado', 'DESC');
		$this->db->order_by('v.' . $orden, 'ASC');
		$this->db->order_by('v.id', 'ASC');
		$ventas = $this->db->get()->result_array();

		$asociados = [];
		foreach ($ventas as $key => &$venta) {
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}
			if ($venta['ps_id_asociado'] != 0) {
				$asociados[$venta['ps_id_asociado']][] = $venta;
				unset($ventas[$key]);
			}
			else if (!empty($asociados[$venta['ps_id']])) {
				$venta['asociados'] = $asociados[$venta['ps_id']];
				unset($asociados[$venta['ps_id']]);
			}
		}

		// Revisa si queda alguna venta en asociados que no haya sido asociada a otra ventas
		// Y la retorna al arreglo de ventas
		foreach ($asociados as $va){
			foreach ($va as $v){
				$ventas[] = $v;
			}
		}

		return $ventas;
	}*/

	public function get_by_state($estados, $idt = 0, $ida = 0, $idc = 0, $orden = 'fecha') {
		// =======================
		// 1. QUERY PRINCIPAL
		// =======================
		$this->db->select('
			v.*, 
			t.nombre as transportista,
			c.nombre AS cliente_nombre, 
			c.email  AS cliente_email
		');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->where('v.deleted', 0);

		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}
		if ($idc > 0) {
			$this->db->where('v.id_canal', $idc);
		}

		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->order_by('v.ps_id_asociado', 'DESC');
		$this->db->order_by('v.' . $orden, 'ASC');
		$this->db->order_by('v.id', 'ASC');
		
		$ventas = $this->db->get()->result_array();

		// =======================
		// 2. MAPEO DE PRODUCTOS
		// =======================
		$ventas_ids = array_column($ventas, 'id');
		$productos_map = [];

		if (!empty($ventas_ids)) {
			$this->db->select('pv.id_venta, p.id, p.nombre, pv.cantidad');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p', 'pv.id_producto = p.id', 'left');
			$this->db->where_in('pv.id_venta', $ventas_ids);
			$this->db->where('pv.deleted', 0);
			$productos = $this->db->get()->result_array();

			foreach ($productos as $prod) {
				$productos_map[$prod['id_venta']][] = [
					'id'       => $prod['id'],
					'nombre'   => $prod['nombre'],
					'cantidad' => $prod['cantidad']
				];
			}
		}

		// =======================
		// 3. PROCESAR VENTAS
		// =======================
		$asociados = [];
		foreach ($ventas as $key => &$venta) {
			// Agregar productos
			$venta['productos'] = $productos_map[$venta['id']] ?? [];

			// Estado PS
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}

			// Asociados
			if ($venta['ps_id_asociado'] != 0) {
				$asociados[$venta['ps_id_asociado']][] = $venta;
				unset($ventas[$key]);
			}
			else if (!empty($asociados[$venta['ps_id']])) {
				$venta['asociados'] = $asociados[$venta['ps_id']];
				unset($asociados[$venta['ps_id']]);
			}
		}

		// Reinyectar ventas asociadas no utilizadas
		foreach ($asociados as $va) {
			foreach ($va as $v) {
				$ventas[] = $v;
			}
		}

		return $ventas;
	}



	/**
	 * Entrega listado de ventas según documento, para emitir o ya emitidos
	 * Entregado, enviado, Disponible para retiro
	 * @param $tipo_venta
	 * @param $periodo id_transportista
	 * @param $canal id_asignado
	 * @param $emision
	*/
	/*
	public function get_documentos($tipo = [], $periodo = '', $canal = 0, $emision = 0) {

		$this->db->select('v.*, ev.color, ev.fondo');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('v.deleted', 0);
		if ($emision == 0) {
			$this->db->where('v.boleta', 0);
		}
		if ($emision == 1) {
			$this->db->where('v.boleta >', 0);
		}
		if (!is_array($tipo)) {
			$tipo = [0 => $tipo];
		}
		$this->db->where_in('v.id_tipo_documento', $tipo);
		$this->db->group_start();
			$this->db->where_in('v.id_estado_venta', [4, 5, 18]);
			$this->db->or_where('boleta >', 0);
		$this->db->group_end();
		if ($periodo == date('Ym')) {
			$this->db->group_start();
			$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = ', $periodo);
			$this->db->or_where('boleta', 0);
			$this->db->group_end();
		}
		else {
			$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = ', $periodo);
		}
		if ($canal) {
			$this->db->where('v.id_canal', $canal);
		}

		$this->db->order_by('CASE WHEN boleta > 0 THEN 1 ELSE 0 END', 'ASC', FALSE);
		$this->db->order_by('v.fecha_boleta', 'DESC');
		$this->db->order_by('v.fecha_venta', 'DESC');
		$this->db->order_by('v.boleta', 'DESC');
		if (count($tipo) > 1) {
			$this->db->order_by('CASE WHEN id_tipo_venta = 5 THEN 1 ELSE 0 END', 'DESC', FALSE);
		}
		$this->db->order_by('v.ps_id', 'DESC');		
		$results = $this->db->get()->result_array();

		$boletas = 0;
		$totalBoletas = 0;
		$sinBoleta = 0;
		$totalSinBoleta = 0;
		$contadas = [];
		$ventas = ['cantidad' => 0, 'monto' => 0];
		foreach ($results as &$result) {
			if ($result['ps_id'] != 0) {
				$result['ps_state'] = $this->get_order_state($result['ps_id']);
			}
			if (empty($result['ps_state'])) {
				$result['ps_state'] = 0;
			}
			$ventas['ventas'][] = $result;
			$ventas['cantidad']++;
			$ventas['monto'] += $result['total'];
		}

		// Calcula total de boletas independiente del tipo
		$this->db->select('SUM(CASE WHEN boleta = 0 THEN 1 ELSE 0 END) AS sin_boleta, SUM(CASE WHEN boleta = 0 THEN 0 ELSE 1 END) AS boletas, SUM(CASE WHEN boleta = 0 THEN total ELSE 0 END) AS total_sin_boleta, SUM(CASE WHEN boleta = 0 THEN 0 ELSE total END) AS total_boletas');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where_in('v.id_tipo_documento', $tipo);
		$this->db->group_start();
			$this->db->where_in('v.id_estado_venta', [4, 5, 18]);
			$this->db->or_where('boleta >', 0);
		$this->db->group_end();
		if ($periodo == date('Ym')) {
			$this->db->group_start();
			$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = ', $periodo);
			$this->db->or_where('boleta', 0);
			$this->db->group_end();
		}
		else {
			$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = ', $periodo);
		}
		$result = $this->db->get()->row_array();

		$ventas['total_boletas'] = $result['total_boletas'];
		$ventas['total_sin_boleta'] = $result['total_sin_boleta'];
		$ventas['boletas'] = $result['boletas'];
		$ventas['sin_boleta'] = $result['sin_boleta'];

		return $ventas;
	}*/
	public function get_documentos($tipo = [], $periodo = '', $canal = 0, $emision = 0, $transportista = 0) {
		// Asegurar que $tipo siempre sea array
		if (!is_array($tipo)) {
			$tipo = [$tipo];
		}

		// =======================
		// 1. QUERY PRINCIPAL
		// =======================
		$this->db->select('
			v.*, 
			ev.color, 
			ev.fondo, 
			c.nombre AS cliente_nombre, 
			c.email  AS cliente_email
		');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->join('clientes c','v.id_cliente = c.id','left');
		$this->db->where('v.deleted', 0);

		// Filtro emisión
		if ($emision == 0) {
			$this->db->where('v.boleta', 0);
		} elseif ($emision == 1) {
			$this->db->where('v.boleta >', 0);
		}

		// Filtro tipo documento
		if (!empty($tipo)) {
			$this->db->where_in('v.id_tipo_documento', $tipo);
		}

		// Estado de venta o boleta emitida
		$this->db->group_start()
				->where_in('v.id_estado_venta', [4, 5, 18])
				->or_where('boleta >', 0)
				->group_end();

		// Filtro periodo
		$this->db->group_start();
			$this->db->where("DATE_FORMAT(fecha_boleta, '%Y%m') =", $periodo);
			if ($periodo == date('Ym')) {
				$this->db->or_where('boleta', 0);
			}
		$this->db->group_end();

		// Filtro canal
		if ($canal) {
			$this->db->where('v.id_canal', $canal);
		}

		// Filtro Transportista
		if ($transportista) {
			$this->db->where('v.id_transportista', $transportista);
		}

		// Ordenamientos
		if ($emision == 1) {

			if (count($tipo) === 1) {

				$docs_fiscales = [1, 2, 3, 5];

				if (in_array($tipo[0], $docs_fiscales)) {
					// Para documentos fiscales (boleta, factura, NC, e-boleta):
					// Ordenar por número correlativo ascendente
					$this->db->order_by('v.boleta', 'ASC');
				} else {
					// Para documentos NO fiscales (TBK, ML, Webpay, etc.)
					// Ordenar por fecha de venta DESC
					$this->db->order_by('v.fecha_venta', 'DESC');
				}
			}
			else {
				// para emitidas se traen de forma ascendente por número de documento
				$this->db->order_by('v.id_tipo_documento', 'ASC')
					->order_by('v.boleta', 'ASC');
			}
		}
		else {
			$this->db->order_by('CASE WHEN boleta > 0 THEN 1 ELSE 0 END', 'ASC', FALSE)
				->order_by('v.fecha_boleta', 'DESC')
				->order_by('v.fecha_venta', 'DESC')
				->order_by('v.boleta', 'DESC');
		}

		if (count($tipo) > 1) {
			$this->db->order_by('CASE WHEN id_tipo_venta = 5 THEN 1 ELSE 0 END', 'DESC', FALSE);
		}

		$this->db->order_by('v.ps_id', 'DESC');

		$results = $this->db->get()->result_array();

		// =======================
		// 2. PRODUCTOS DE VENTAS
		// =======================
		$ventas_ids = array_column($results, 'id');
		$productos_map = [];

		if (!empty($ventas_ids)) {
			$this->db->select('pv.id_venta, p.id, p.nombre, pv.cantidad');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p', 'pv.id_producto = p.id', 'left');
			$this->db->where_in('pv.id_venta', $ventas_ids);
			$productos = $this->db->get()->result_array();

			foreach ($productos as $prod) {
				$productos_map[$prod['id_venta']][] = [
					'id'       => $prod['id'],
					'nombre'   => $prod['nombre'],
					'cantidad' => $prod['cantidad']
				];
			}
		}

		// =======================
		// 3. ARMAR RESULTADOS
		// =======================
		$ventas = ['cantidad' => 0, 'monto' => 0, 'ventas' => []];

		foreach ($results as &$result) {
			// Agregar productos
			$result['productos'] = $productos_map[$result['id']] ?? [];

			$result['ps_state'] = $result['ps_id'] != 0 ? $this->get_order_state($result['ps_id']) : 0;
			if (empty($result['ps_state'])) {
				$result['ps_state'] = 0;
			}

			// Cliente ya viene por el JOIN (cliente_nombre, cliente_email)
			$ventas['ventas'][] = $result;
			$ventas['cantidad']++;
			$ventas['monto'] += $result['total'];
		}

		// =======================
		// 4. CALCULAR TOTALES
		// =======================
		$this->db->select('
			SUM(CASE WHEN boleta = 0 THEN 1 ELSE 0 END) AS sin_boleta,
			SUM(CASE WHEN boleta = 0 THEN 0 ELSE 1 END) AS boletas,
			SUM(CASE WHEN boleta = 0 THEN total ELSE 0 END) AS total_sin_boleta,
			SUM(CASE WHEN boleta = 0 THEN 0 ELSE total END) AS total_boletas
		');
		$this->db->from('ventas v');
		$this->db->where('v.deleted', 0);
		$this->db->where_in('v.id_tipo_documento', $tipo);
		$this->db->group_start()
				->where_in('v.id_estado_venta', [4, 5, 18])
				->or_where('boleta >', 0)
				->group_end();

		$this->db->group_start();
			$this->db->where("DATE_FORMAT(fecha_boleta, '%Y%m') =", $periodo);
			if ($periodo == date('Ym')) {
				$this->db->or_where('boleta', 0);
			}
		$this->db->group_end();

		$totales = $this->db->get()->row_array();

		$ventas['total_boletas']    = $totales['total_boletas'];
		$ventas['total_sin_boleta'] = $totales['total_sin_boleta'];
		$ventas['boletas']          = $totales['boletas'];
		$ventas['sin_boleta']       = $totales['sin_boleta'];

		return $ventas;
	}






	/**
	 * Entrega listado de ventas del periodo y canal indicado
	 * @param $periodo id_transportista
	 * @param $idCanal canal de venta
	*/
	public function get_by_channel_old($periodo = '', $idCanal = 2, $idPuntoVenta = '') {
		$this->db->select('v.*, ev.color, ev.fondo, DATE_FORMAT(fecha_venta, "%Y%m%d") as dia');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_canal', $idCanal);
		$this->db->where_in('v.id_tipo_venta', [1, 2, 5, 7, 8, 9]);
		if ($periodo == 'hoy') {
			$this->db->where('fecha_venta >=', date('Y-m-d 00:00:00'));
			$this->db->where('fecha_venta <', date('Y-m-d 23:59:59'));
		}
		else if ($periodo == 'semana') {
			if (date("D") == "Mon"){
				$lunes = date("Y-m-d");
			} else {
				$lunes = date("Y-m-d", strtotime('last Monday', time()));
			}
			$domingo = date('Y-m-d', strtotime('+7 days', strtotime($lunes)));
			$this->db->where('fecha_venta >=', $lunes . ' 00:00:00');
			$this->db->where('fecha_venta <=', $domingo . ' 23:59:59');
		}
		else {
			$this->db->where('DATE_FORMAT(fecha_venta, "%Y%m") = ', $periodo);
		}
		if ($idPuntoVenta != '') {
			$this->db->where('v.id_punto_venta', $idPuntoVenta);
		}
		$this->db->order_by('v.fecha_venta', 'DESC');
		$results = $this->db->get()->result_array();

		$dias = [];
		$acumulado = 0;
		$idSinCliente = 184;
		foreach ($results as &$result) {
			$dias['ventas'][$result['dia']][] = $result;
			if (empty($dias['total'][$result['dia']])) {
				$dias['total'][$result['dia']] = 0;
			}
			$dias['total'][$result['dia']] += $result['total'];
			$acumulado += $result['total'];

			//Si venta tiene cliente registrado le suma al total del día
			if (empty($dias['registrados'][$result['dia']])) {
				$dias['registrados'][$result['dia']] = 0;
			}

			if ($result['id_cliente'] != $idSinCliente) {
				$dias['registrados'][$result['dia']]++;
			}
		}
		$dias['total_periodo'] = $acumulado;
		return $dias;
	}


	public function get_by_channel($periodo = '', $idCanal = 2, $idPuntoVenta = '') {
		$idSinCliente = 184;

		$dbps = (ENVIRONMENT == 'production') ? 'dementeg_presta' : 'dementelocal';
		// Query base
		$this->db->select('v.*, ev.color, ev.fondo, c.ps_id as cliente_ps_id, c.nombre as cliente_nombre, c.email as cliente_email, psc.newsletter as cliente_newsletter, DATE_FORMAT(v.fecha_venta, "%Y%m%d") as dia');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left'); // JOIN con clientes
		$this->db->join($dbps.'.ps_customer psc','ON c.ps_id = psc.id_customer', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_canal', $idCanal);
		$this->db->where_in('v.id_tipo_venta', [1, 2, 5, 7, 8, 9]);

		// Filtrado por periodo
		$hoy = date('Y-m-d');
		if ($periodo == 'hoy') {
			$this->db->where('v.fecha_venta >=', "$hoy 00:00:00");
			$this->db->where('v.fecha_venta <=', "$hoy 23:59:59");
		} elseif ($periodo == 'semana') {
			$lunes = date("Y-m-d", strtotime('Monday this week'));
			$domingo = date("Y-m-d", strtotime('Sunday this week'));
			$this->db->where('v.fecha_venta >=', "$lunes 00:00:00");
			$this->db->where('v.fecha_venta <=', "$domingo 23:59:59");
		} elseif (!empty($periodo)) {
			// Asume formato YYYYMM
			$year = substr($periodo, 0, 4); // 2025
			$month = substr($periodo, 4, 2); // 08
			$start = "$year-$month-01 00:00:00";
			$end = date('Y-m-t', strtotime($start)) . ' 23:59:59';
			$this->db->where('v.fecha_venta >=', $start);
			$this->db->where('v.fecha_venta <=', $end);
		}

		// Filtrado por punto de venta
		if (!empty($idPuntoVenta)) {
			$this->db->where('v.id_punto_venta', $idPuntoVenta);
		}

		$this->db->order_by('v.fecha_venta', 'DESC');

		$results = $this->db->get()->result_array();

		// Procesamiento en PHP
		$dias = [
			'ventas' => [],
			'total' => [],
			'registrados' => [],
		];
		$acumulado = 0;

		if (!empty($results)) {
			// Traer productos de todas las ventas de una sola vez
			$ids_ventas = array_column($results, 'id');
			$this->db->select('pv.id_venta, pv.id_producto, pv.cantidad, p.nombre');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p','pv.id_producto = p.id','left');
			$this->db->where_in('pv.id_venta', $ids_ventas);
			$productos_data = $this->db->get()->result_array();

			// Agrupar productos por id_venta
			$productos_por_venta = [];
			foreach ($productos_data as $pd) {
				$productos_por_venta[$pd['id_venta']][] = [
					'id' => $pd['id_producto'],
					'nombre' => $pd['nombre'],
					'cantidad' => $pd['cantidad']
				];
			}

			// Recorrer ventas y agregar productos
			foreach ($results as $result) {
				$dia = $result['dia'];

				// Agregar array de productos a cada venta
				$result['productos'] = $productos_por_venta[$result['id']] ?? [];

				$dias['ventas'][$dia][] = $result;

				$dias['total'][$dia] = ($dias['total'][$dia] ?? 0) + $result['total'];
				$acumulado += $result['total'];

				if (!isset($dias['registrados'][$result['dia']])) {
					$dias['nuevos'][$result['dia']] = 0;
					$dias['registrados'][$result['dia']] = 0;
					$dias['suscritos'][$result['dia']] = 0;
					$dias['estrellas'][$result['dia']] = 0;
				}

				// Clientes que llegaron sin registro
				if ($result['id_cliente'] == $idSinCliente) {
					$dias['nuevos'][$result['dia']]++;
				}

				// Clientes que se registraron durante la venta
				if ($result['nuevo_cliente'] == 1) {
					$dias['nuevos'][$result['dia']]++;
					$dias['registrados'][$result['dia']]++;
					$dias['estrellas'][$result['dia']]++;

					// Contar cuántos de esos se suscribieron al newsletter
					if ($result['newsletter'] == 1) {
						$dias['suscritos'][$result['dia']]++;
						$dias['estrellas'][$result['dia']]++;
					}
				}
			}
		}

		$dias['total_periodo'] = $acumulado;
		return $dias;
	}


	public function search($b = '') {
		$ventas = [];
		if (!empty($b) && is_numeric($b)) {
			$this->db->select('
				v.*, 
				c.nombre AS cliente_nombre,
				c.email  AS cliente_email
			');
			$this->db->from('ventas v');
			$this->db->join('clientes c','v.id_cliente = c.id', 'left');
			$this->db->where('v.deleted', 0);
			$this->db->order_by('v.boleta', 'DESC');
			$this->db->group_start();
				$this->db->where('v.boleta', $b);
				$this->db->or_where('v.id', $b);
				$this->db->or_where('v.ps_id', $b);
			$this->db->group_end();
			$ventas = $this->db->get()->result_array();

			// Mapeo de productos
			$ventas_ids = array_column($ventas, 'id');
			$productos_map = [];

			if (!empty($ventas_ids)) {
				$this->db->select('pv.id_venta, p.id, p.nombre, pv.cantidad');
				$this->db->from('productos_ventas pv');
				$this->db->join('productos p', 'pv.id_producto = p.id', 'left');
				$this->db->where_in('pv.id_venta', $ventas_ids);
				$this->db->where('pv.deleted', 0);
				$productos = $this->db->get()->result_array();

				foreach ($productos as $prod) {
					$productos_map[$prod['id_venta']][] = [
						'id'       => $prod['id'],
						'nombre'   => $prod['nombre'],
						'cantidad' => $prod['cantidad']
					];
				}
			}

			foreach ($ventas as &$venta) {
				// Agregar productos
				$venta['productos'] = $productos_map[$venta['id']] ?? [];

				if ($venta['ps_id'] != 0) {
					$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
				}
				if (empty($venta['ps_state'])) {
					$venta['ps_state'] = 0;
				}
			}
		}
		return $ventas;
	}

	/**
	 * Entrega todas las ventas asociadas al id indicado
	 */
	public function get_asociadas($id = 0) {
		// trae venta
		$principal = $this->get($id);

		// si tiene id asociado trae la principal
		if (!empty($principal['ps_id_asociado'])) {
			$this->db->select('v.id');
			$this->db->from('ventas v');
			$this->db->where('v.ps_id', $principal['ps_id_asociado']);
			$this->db->where('v.deleted', 0);
			$query = $this->db->get();
			$id_principal = $query->row_array();
			$principal = $this->get($id_principal['id']);
		}

		$ventas[] = $principal;

		if (!empty($principal['ps_id'])){
			//trae todas las ventas asociadas a la principal
			$this->db->select('v.id');
			$this->db->from('ventas v');
			$this->db->where('v.ps_id_asociado', $principal['ps_id']);
			$this->db->where('v.deleted', 0);
			$query = $this->db->get();
			$asociadas = $query->result_array();


			foreach ($asociadas as $a){
				$ventas[] = $this->get($a['id']);
			}
		}

		//devuelve un arreglo de ventas
		return $ventas;
	}


		/**
	 * Entrega listado de ventas en estados en espera:
	 * Todos los distintos a: Entregado, enviado, Disponible para retiro, En preparación y Pago Aceptado
	 * @param $idt id_transportista
	 * @param $ida id_asignado
	*/
	/*
	public function get_processing($idt = 0, $ida = 0, $orden = 'fecha') {
		$this->db->select('*');
		$this->db->from('estados_ventas ev');
		$this->db->where('ev.deleted', 0);
		$this->db->where('ev.vendido !=', 1);
		$this->db->order_by('ev.orden', 'ASC');

		$estados_ventas = $this->db->get()->result_array();
		foreach ($estados_ventas as $estado_venta) {
			$estado_venta['total'] = 0;
			$newestados_ventas[$estado_venta['id']] = $estado_venta;
		}
		$estados_ventas = $newestados_ventas;

		$this->db->select('v.*, t.nombre as transportista');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.vendido !=', 1);
		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}
		// Trae primero las ventas con padre asignado
		$this->db->order_by('v.ps_id_asociado', 'DESC');
		//$this->db->order_by('v.fecha', 'ASC');
		$this->db->order_by('v.'.$orden, 'ASC');
		$ventas = $this->db->get()->result_array();

		$asociados = [];
		foreach ($ventas as $key => &$venta) {
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}

			if ($venta['ps_id_asociado'] != 0) {
				$asociados[$venta['ps_id_asociado']][] = $venta;
				unset($ventas[$key]);
			}
			else {
				if (!empty($asociados[$venta['ps_id']])) {
					$venta['asociados'] = $asociados[$venta['ps_id']];
					unset($asociados[$venta['ps_id']]);
				}

				if (isset($estados_ventas[$venta['id_estado_venta']]['total'])) {
					$estados_ventas[$venta['id_estado_venta']]['ventas'][] = $venta;
					$estados_ventas[$venta['id_estado_venta']]['total'] += $venta['total'];
				}
			}
		}

		// Revisa si queda alguna venta en asociados que no haya sido asociada a otra ventas
		// Y la retorna al arreglo de ventas
		foreach ($asociados as $va){
			foreach ($va as $v){
				$ventas[] = $v;
				$estados_ventas[$v['id_estado_venta']]['ventas'][] = $v;
				$estados_ventas[$v['id_estado_venta']]['total'] += $v['total'];
			}
		}

		return $estados_ventas;
	}
	*/
	public function get_processing($idt = 0, $ida = 0, $orden = 'fecha') {
		// =======================
		// 1. ESTADOS DE VENTA
		// =======================
		$this->db->select('*');
		$this->db->from('estados_ventas ev');
		$this->db->where('ev.deleted', 0);
		$this->db->where('ev.vendido !=', 1);
		$this->db->order_by('ev.orden', 'ASC');

		$estados_ventas = $this->db->get()->result_array();
		foreach ($estados_ventas as $estado_venta) {
			$estado_venta['total'] = 0;
			$estado_venta['ventas'] = []; // inicializar array de ventas
			$newestados_ventas[$estado_venta['id']] = $estado_venta;
		}
		$estados_ventas = $newestados_ventas;

		// =======================
		// 2. QUERY PRINCIPAL DE VENTAS
		// =======================
		$this->db->select('
			v.*, 
			t.nombre AS transportista,
			c.nombre AS cliente_nombre,
			c.email  AS cliente_email
		');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.vendido !=', 1);

		if (!empty($idt)) {
			$this->db->where('v.id_transportista', $idt);
		}
		if ($ida >= 0) {
			$this->db->where('v.id_asignado', $ida);
		}

		// Trae primero las ventas con padre asignado
		$this->db->order_by('v.ps_id_asociado', 'DESC');
		$this->db->order_by('v.'.$orden, 'ASC');
		$ventas = $this->db->get()->result_array();

		// =======================
		// 3. MAPEO DE PRODUCTOS
		// =======================
		$ventas_ids = array_column($ventas, 'id');
		$productos_map = [];

		if (!empty($ventas_ids)) {
			$this->db->select('pv.id_venta, p.id, p.nombre, pv.cantidad');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p', 'pv.id_producto = p.id', 'left');
			$this->db->where_in('pv.id_venta', $ventas_ids);
			$this->db->where('pv.deleted', 0);
			$productos = $this->db->get()->result_array();

			foreach ($productos as $prod) {
				$productos_map[$prod['id_venta']][] = [
					'id'       => $prod['id'],
					'nombre'   => $prod['nombre'],
					'cantidad' => $prod['cantidad']
				];
			}
		}

		// =======================
		// 4. PROCESAR VENTAS Y AGRUPAR POR ESTADO
		// =======================
		$asociados = [];
		foreach ($ventas as $key => &$venta) {
			// Agregar productos
			$venta['productos'] = $productos_map[$venta['id']] ?? [];

			// Estado PS
			if ($venta['ps_id'] != 0) {
				$venta['ps_state'] = $this->get_order_state($venta['ps_id']);
			}
			if (empty($venta['ps_state'])) {
				$venta['ps_state'] = 0;
			}

			// Asociados
			if ($venta['ps_id_asociado'] != 0) {
				$asociados[$venta['ps_id_asociado']][] = $venta;
				unset($ventas[$key]);
			} else {
				if (!empty($asociados[$venta['ps_id']])) {
					$venta['asociados'] = $asociados[$venta['ps_id']];
					unset($asociados[$venta['ps_id']]);
				}

				if (isset($estados_ventas[$venta['id_estado_venta']]['total'])) {
					$estados_ventas[$venta['id_estado_venta']]['ventas'][] = $venta;
					$estados_ventas[$venta['id_estado_venta']]['total'] += $venta['total'];
				}
			}
		}

		// Reinyectar ventas asociadas que quedaron sueltas
		foreach ($asociados as $va) {
			foreach ($va as $v) {
				$ventas[] = $v;
				$v['productos'] = $productos_map[$v['id']] ?? [];
				$estados_ventas[$v['id_estado_venta']]['ventas'][] = $v;
				$estados_ventas[$v['id_estado_venta']]['total'] += $v['total'];
			}
		}

		return $estados_ventas;
	}



	/**
	 * Entrega datos de direcciones de ventas por transportistas
	 */
	public function get_by_carrier($id_carrier = 0, $estados) {

		// Estados Por Enviar
		if (empty($estados)) {
			$estados = [2, 3, 18];
		}

		$this->db->select('v.id, v.ps_id, v.ps_id_asociado, v.boleta, v.dir_nombre, v.dir_apellidos, v.direccion, v.rut, v.telefono, v.despacho, r.nombre as region, c.nombre as comuna, v.total, v.email, v.id_transportista');
		$this->db->from('ventas v');
		$this->db->join('comunas c','v.id_comuna = c.id', 'left');
		$this->db->join('regiones r','v.id_region = r.id', 'left');
		$this->db->where('v.deleted', 0);
		if (!empty($id_carrier)) {
			$this->db->where('v.id_transportista', $id_carrier);
		}
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->order_by('v.id_transportista', 'ASC');
		$this->db->order_by('v.ps_id_asociado', 'ASC');
		$this->db->order_by('v.id', 'ASC');
		$ventas = $this->db->get()->result_array();

		foreach ($ventas as $venta) {
			// Define el orden de los campos
			$return = [
				'nombre' => '',
				'direccion' => '',
				'comuna' => '',
				'telefono' => '',
				'cantidad' => '1',
				'total' => '0',
				'observaciones' => ''
			];

			// Para Blue cambia el orden
			if ($venta['id_transportista'] == 12) {
				$return = [
					'nombre' => '',
					'apellido' => $venta['dir_apellidos'],
					'telefono' => '',
					'rut' => str_replace(['.','-'], ['',''], $venta['rut']),
					'email' => $venta['email'],
					'tipo_entrega' => 'Domicilio',
					'region' => $venta['region'],
					'comuna' => '',
					'direccion' => '',
					'numero' => '',
					'depto' => '',
					'observaciones' => '',
					'descripcion' => 'Juegos de mesa',
					'total' => $venta['total'],
					'garantia' => '',
					'boleta' => $venta['boleta']
				];
			}

			// Para Send Cargo cambia el orden
			if ($venta['id_transportista'] == 16) {
				$return = [
					'nombre' => '',
					'rut' => $venta['rut'],
					'direccion' => '',
					'numero' => '',
					'depto' => '',
					'telefono' => '',
					'email' => $venta['email'],
					'comuna' => '',
					'descripcion' => 'Juegos de mesa',
					'total' => $venta['total']
				];
			}

			// Para Recíbelo se cambia el orden
			if ($venta['id_transportista'] == 18) {
				$return = [
					'id_paquete' => 'DMG-' . $venta['id'] . '-0',
					'id_cp_retiro' => 337,
					'id_comuna' => '',
					'comuna' => '',
					'direccion' => '',
					'observaciones' => '',
					'nombre' => '',
					'apellido' => '',
					'email' => $venta['email'],
					'telefono' => ''
				];
			}

			// Para Fazt se cambia el orden
			if ($venta['id_transportista'] == 24) {
				$return = [
					'id_cp_retiro' => 275,
					'id_paquete' => 'DMG-' . $venta['id'],
					'direccion' => '',
					'observaciones' => '',
					'comuna' => '',
					'nombre' => '',
					'telefono' => '',
					'email' => $venta['email']
				];
			}

			// Para Bluvy se cambia el orden
			if ($venta['id_transportista'] == 33) {
				$return = [
					'delivery_date' => date('Y-m-d'),
					'logistic_type' => 'drop_off',
					'service_type' => 'ontime',
					'declared_value' => '0',
					'external_reference' => 'DMG-' . $venta['id'],
					'alt_external_reference' => '',
					'nombre' => '',
					'email' => $venta['email'],
					'telefono' => '',
					'to_instrucctions' => '',
					'to_address_type' => 'casa',
					'direccion' => '',
					'comuna' => '',
					'observaciones' => '',
					'to_address_comment' => '',
					'quantity_package' => '1'
				];
			}

			// Para AlphaGroup se cambia el orden
			if ($venta['id_transportista'] == 35) {
				$return = [
					'tracking' => 'DMG-' . $venta['id'],
					'fecha_de_venta' => date('d-m-Y'),
					'total' => '0',
					'peso_declarado' => '0',
					'nombre' => '',
					'telefono' => '',
					'direccion' => '',
					'comuna' => '',
					'observaciones' => '',
					'email' => $venta['email'],
					'referencia' => '',
					'total_a_cobrar' => '',
					'logistica_inversa' => '',
				];
			}

			$return['nombre'] = $venta['dir_nombre'] . ' ' . $venta['dir_apellidos'];
			$return['comuna'] = $venta['comuna'];
			$return['direccion'] = $venta['direccion'];
			$return['telefono'] = $venta['telefono'];
			$return['observaciones'] = $venta['despacho'];

			$return['total'] = round($venta['total']/10) * 10;

			// Correcciones para blue
			if ($venta['id_transportista'] == 12) {
				$return['nombre'] = $venta['dir_nombre'];
				$return['telefono'] = str_replace([' ','+'], ['',''], $venta['telefono']);
			}

			// Correcciones para recíbelo
			if ($venta['id_transportista'] == 18) {
				unset($return['total']);
				if ($return['comuna'] == 'Santiago') {
					$return['comuna'] = 'Santiago Centro';
				}
				$return['telefono'] = str_replace(['+'], [''], $venta['telefono']);

				// Consulta venta ps para traer nombre y apellido por separado
				if (!empty($venta['ps_id'])) {
					// Se deja nombre junto, pues Recibelo no considera apellido
					$return['apellido'] = '';

					// Agrega PS ID a id de paquete
					$return['id_paquete'] = 'DMG-' . $venta['id'] . '-' . $venta['ps_id'];
				}
			}

			// Correcciones para Fazt
			if ($venta['id_transportista'] == 24) {
				unset($return['total']);
				if ($return['comuna'] == 'Santiago Centro') {
					$return['comuna'] = 'Santiago';
				}
				$return['telefono'] = str_replace(['+'], [''], $venta['telefono']);

				if (!empty($venta['ps_id'])) {
					// Agrega PS ID a id de paquete
					$return['id_paquete'] = 'DMG-' . $venta['id'] . '-' . $venta['ps_id'];
				}
			}

			// Correcciones para Bluvy
			if ($venta['id_transportista'] == 33) {
				unset($return['total']);
				$return['telefono'] = str_replace(['+56'], [''], $venta['telefono']);
				$return['telefono'] = str_replace([' '], [''], $return['telefono']);

				if (!empty($venta['ps_id'])) {
					// Agrega PS ID a id de paquete
					$return['external_reference'] = 'DMG-' . $venta['id'] . '-' . $venta['ps_id'];
				}
			}

			// Correcciones para Alpha Group
			if ($venta['id_transportista'] == 35) {
				$return['telefono'] = str_replace(['+56'], [''], $venta['telefono']);
				$return['telefono'] = str_replace([' '], [''], $return['telefono']);
				if (!empty($venta['ps_id'])) {
					// Agrega PS ID a id de paquete
					$return['tracking'] = 'DMG-' . $venta['id'] . '-' . $venta['ps_id'];
				}
			}

			$venta['info'] = $return;

			if (!empty($venta['ps_id'])) {
				if (empty($venta['ps_id_asociado']) || empty($totales[$venta['ps_id_asociado']])) {
					$totales[$venta['ps_id']] = $venta;
				}
				else if(!empty($totales[$venta['ps_id_asociado']]['info']['total'])) {
					$totales[$venta['ps_id_asociado']]['info']['total'] += $venta['info']['total'];
				}
			}
		}

		foreach ($totales as $total) {
			$transportistas[$total['id_transportista']][] = $total;
		}
		//agregar ventas a transportistas
		return $transportistas;
	}

	/**
	 * Obtiene ventas en estado 3
	 */
	public function get_preparation($id = 0){
		$this->db->select("v.id");
		$this->db->from('ventas v');
		if (!empty($id)) {
			$this->db->where('v.id', $id);
		}
		else {
			$this->db->where('v.id_estado_venta', 3);
		}
		$this->db->where('v.deleted', 0);
		$this->db->order_by('v.cliente', 'ASC');
		$preparacion = $this->db->get()->result_array();
		$ventas = [];
		foreach($preparacion as $p) {
				$ventas[] = $this->get($p['id']);
		}
		return $ventas;
	}

	/**
	 * Obtiene datos para generar etiqueta de despacho
	 */
	public function get_delivery_info($id = 0) {
		$this->db->select('v.id, v.dir_nombre, v.dir_apellidos, v.rut, v.direccion, v.id_region, r.nombre as region, v.id_comuna, c.nombre as comuna, v.telefono, v.despacho, t.nombre as transportista, t.color');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->join('regiones r','v.id_region = r.id', 'left');
		$this->db->join('comunas c','v.id_comuna = c.id', 'left');
		if (!empty($id)) {
			$this->db->where('v.id', $id);
		}
		else {
			$this->db->where('v.id_estado_venta', 3);
		}
		$this->db->where('v.deleted', 0);
		$ventas = $this->db->get()->result_array();
		return $ventas;
	}


	public function get_last_survey($id = 0){
		$this->db->select("v.id, v.id_cliente, v.fecha_encuesta, v.email, c.nombre as cliente");
		$this->db->from('ventas v');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->where('v.id', $id);
		$this->db->where('v.deleted', 0);
		$this->db->limit(1);
		$venta = $this->db->get()->row_array();

		$idCliente = $venta['id_cliente'];

		$this->db->select("fecha_encuesta");
		$this->db->from('ventas');
		$this->db->where('id_cliente', $idCliente);
		$this->db->where('deleted', 0);
		$this->db->order_by('fecha_encuesta', 'DESC');
		$this->db->limit(1);
		$fecha = $this->db->get()->row_array();

		if (!empty($fecha['fecha_encuesta'])) {
			$venta['fecha_encuesta'] = $fecha['fecha_encuesta'];
			$dosMeses = strtotime(date("Y-m-d") . "- 2 months");
			$ventaTime = strtotime($fecha['fecha_encuesta']);
			if ($ventaTime < $dosMeses) {
				$venta['tiempo_espera'] = 1;
			}
			else {
				$venta['tiempo_espera'] = 0;
			}
		}
		else{
			$venta['tiempo_espera'] = 1;
		}
		return $venta;
	}

	/**
	 * Retorna un arreglo con las ventas asociadas (hijas)
	 */
	public function get_hijas($psId) {
		$asociadas = [];
		if (!empty($psId)) {
			$this->db->select("id, ps_id");
			$this->db->from('ventas');
			$this->db->where('deleted', 0);
			$this->db->where('ps_id_asociado', $psId);
			$tmp = $this->db->get()->result_array();

			foreach ($tmp as $v) {
				$asociadas[$v['id']] = $v['ps_id'];
			}
		}
		return $asociadas;
	}

	/**
	 * Entrega registros de Log de la venta
	 */
	public function get_log($id) {
		$this->db->select("*");
		$this->db->from('cambios_log');
		$this->db->where('tipo_entidad', 2);
		$this->db->where('id_entidad', $id);
		$this->db->order_by('created', 'DESC');
		$tmp = $this->db->get()->result_array();
		foreach ($tmp as &$l) {
			$l['cambios'] = json_decode($l['data'], TRUE);
		}
		return $tmp;
	}


	public function resumen_dia($dia, $idCanal = 2) {
		/*
		pr($dia);

		$this->db->select('SUM(total) AS total, id_medio_pago');
		$this->db->from('ventas');
		$this->db->where_in('id_tipo_venta', [2, 5]);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m%d") = ', $dia);
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_canal', 2);
		$this->db->group_by('id_medio_pago');
		$this->db->order_by('fecha_key', 'ASC');
		*/

		$this->db->select('id_medio_pago, id_punto_venta, mp.nombre as medio_pago, pv.nombre as punto_venta, count(v.id) as cantidad, SUM(total) AS total');
		$this->db->from('ventas v');
		$this->db->join('medios_pagos mp', 'v.id_medio_pago = mp.id', 'left');
		$this->db->join('puntos_ventas pv', 'v.id_punto_venta = pv.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_canal', $idCanal);
		$this->db->where_in('v.id_tipo_venta', [1, 2, 5, 7, 8, 9]);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m%d") = ', $dia);
		$this->db->group_by('v.id_medio_pago, v.id_punto_venta, mp.nombre, pv.nombre');
		$this->db->order_by('id_medio_pago, id_punto_venta', 'ASC');
		$result['medios_pagos'] = $this->db->get()->result_array();

		$this->db->select('DATE_FORMAT(v.fecha_venta, "%H") as hora, count(id) as cantidad, SUM(total) AS total');
		$this->db->from('ventas v');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_canal', $idCanal);
		$this->db->where_in('v.id_tipo_venta', [1, 2, 5, 7, 8, 9]);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m%d") = ', $dia);
		$this->db->group_by('DATE_FORMAT(v.fecha_venta, "%H")');
		$this->db->order_by('v.fecha_venta', 'ASC');
		$ventasHoras = $this->db->get()->result_array();

		$apertura = 10;
		$cierre = 21;
		for ($i = $apertura; $i <= $cierre; $i++) {
			$horas[$i] = [
				'hora' => '' . $i,
				'cantidad' => '0',
				'total' => '0'
			];
		}

		foreach ($ventasHoras as $ventasHora) {
			$h = (int) $ventasHora['hora'];
			$horaStr = str_pad($h, 2, '0', STR_PAD_LEFT);

			// Agregar horas faltantes entre la primera venta y la hora de apertura
			if ($h < $apertura) {
				for ($i = $h; $i < $apertura; $i++) {
					$intermedia = str_pad($i, 2, '0', STR_PAD_LEFT);
					if (!isset($horas[$intermedia])) {
						$horas[$intermedia] = [
							'hora' => $intermedia,
							'cantidad' => '0',
							'total' => '0'
						];
					}
				}
			}

			$horas[$horaStr] = $ventasHora;
		}
		ksort($horas);
		// Ordenamos para hacer array iterable en JS
		foreach ($horas as $hora) {
			$result['horas'][] = $hora;
		}

		return $result;
	}


	public function vendedor($data = [], $idVendedor = 0, $inicio = '', $fin = '') {
		$this->db->select('v.*, ev.color, ev.fondo');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('v.id_vendedor', $idVendedor);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y-%m-%d") >=', $inicio);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y-%m-%d") <=', $fin);
		$this->db->order_by('v.fecha_venta','ASC');

		$results = $this->db->get()->result_array();

		$cantidad = count($results);
		$total = 0;
		foreach ($results as $v){
			$total += $v['total'];
		}
		$data['ventas'] = $results;
		$data['cantidad'] = $cantidad;
		$data['total'] = $total;

		return $data;
	}

/*********************************************** Funciones de Edición ***************************************************************/

	/**
	 * Nueva función save que llama funciones pequeñas
	 * @param array data toda la info de venta que se debe guardar
	 */
	public function save($data){
		// Validaciones al crear y editar
		$data = $this->validations($data);

		// Validaciones al editar (solo si está editando)
		if (!empty($data['id'])){
			$data = $this->edit_validations($data);
		}
		if (!empty($data['validation_errors'])){
			$return['status'] = 'error';
			$return['message'] = implode('<br />', $data['validation_errors']);
			return $return;
		}

		if (!empty($data['errors'])) {
			$return['status'] = 'error';
			$return['message'] = $data['errors'];
			return $return;
		}

		//$this->db->trans_begin();
		$error = false;

		// Intenta crear Cliente en PS
		if (!empty($data['crea_cliente'])) {
			$clientePs = $this->Cliente->crea_ps($data['email'], $data['cliente'], $data['apellidos'] , $data['newsletter']);

			if (!empty($clientePs['id'])) {
				if (ENVIRONMENT == 'production') {
					// Solo envía email en producción
					$cliente['data'] = [
						'nombre' => $data['cliente'],
						'apellidos' => $data['apellidos'],
						'email' => $data['email'],
						'password' => $clientePs['password'],
						'id_canal' => $data['id_canal'],
					];

					$to = $data['email'];
					$subject = '¡Bienvenido a DeMente Games! Ya estás acumulando Puntos DeMente';
					$message = $this->load->view('clientes/email_bienvenida', $cliente , true);

					$this->load->model('Email_model', 'Email');
					$result = $this->Email->send_email($to, $subject, $message);
				}

				//Actualiza data con ps_id // Con esto se actualizará el cleinte de VDM
				$data['ps_id_cliente'] = $clientePs['id'];
			}
			$data['cliente'] = $data['cliente'] . ' ' . $data['apellidos'];
		}

		// Setea datos por defecto y otros
		$data = $this->set_data($data);

		$venta = $data;
		unset($venta['id_producto'], $venta['id_producto_venta'], $venta['producto'], $venta['cantidad'], $venta['precio']);
		unset($venta['precio_normal'], $venta['descuento_producto'], $venta['total_producto'], $venta['errors'], $venta['venta_anterior']);
		unset($venta['descuenta_stock'], $venta['acumular_puntos'], $venta['ps_id_cliente'], $venta['utiliza_puntos']);
		unset($venta['descuenta_almacenes'], $venta['numero_operacion']);
		unset($venta['apellidos'], $venta['crea_cliente']);

		// Crea Venta Nueva
		if (empty($data['id'])) {
			$venta = $this->create_sale($venta, $data);

			// Canjea puntos (Solo ventas nuevas)
			if (!empty($data['descuento_puntos'])) {
				// Si hay descuento por puntos, pasa todos los puntos a estado 6: Canjeados en tienda
				if (!$this->exchange_points($data['ps_id_cliente'], $data['descuento_puntos'])) {
					$data['errors'][] = 'Error al canjear puntos';
				}
			}

			// Carga puntos (Solo ventas nuevas)
			if (empty($data['ps_id']) && !empty($data['ps_id_cliente'])) {
				if (!$this->load_points($venta, $data)) {
					$data['errors'][] = 'Error al cargar puntos';
				}
			}
		}
		else {
			$venta = $this->update_sale($venta, $data);
		}

		// Guarda los cambios realizados en la venta
		if (!empty($venta['changes'])) {
			$log = [
				'tipo_entidad' => 2,
				'id_entidad' => $venta['id'],
				'id_usuario' => $_SESSION['usuario']['id'],
				'data' => json_encode($venta['changes'])
			];
			$this->db->insert('cambios_log', $log);
		}

		// Si no hay errores confirma el guardado de datos en DB
		if (empty($data['errors'])) {
			$this->db->trans_commit();

			// Descuenta stock // Si es full no descuenta stock de ps
			if (empty($data['id']) && $data['descuenta_stock'] && $data['id_transportista'] != 27) {
				foreach ($data['id_producto'] as $k => $idProducto) {
					$this->Producto->ps_descontar($idProducto, $data['cantidad'][$k], $data['id_canal']);
				}
			}

			$return['status'] = 'success';
			$return['id_venta'] = $venta['id'];
			return $return;
		}
		else{
			$this->db->trans_rollback();
			$return['status'] = 'error';
			$return['message'] = $data['errors'];
			return $return;
		}
	}


	public function update($id, $data) {
		if (!empty($id)) {
			$this->db->where('id', $id);
			$result = $this->db->update('ventas', $data);
		}
		return $result;
	}


	public function delete($id) {
		//revisar si viene id y si viene se hace update
		if (!empty($id)) {
			//Consulta datos de venta
			$this->db->select('boleta, total, vendido, reservado, enviado');
			$this->db->from('ventas v');
			$this->db->where('v.id', $id);
			$ventaAnterior = $this->db->get()->row_array();

			if ($ventaAnterior['boleta'] > 0) {
				$return['status'] = 'error';
				$return['message'] = 'No se puede eliminar una venta con boleta realizada';
				return $return;
			}

			//Elimina venta
			$this->db->set('deleted', 1, FALSE);
			$this->db->where('id', $id);
			$this->db->update('ventas');

			//Solo ajusta saldo si la venta estaba en estado vendido
			if ($ventaAnterior['vendido'] == 1) {
				$this->ajusta_saldo(0, $ventaAnterior['total']);
			}

			//Ajusta stock indicando datos anteriores
			$data['id'] = $id;
			$data['vendido_anterior'] = $ventaAnterior['vendido'];
			$data['reservado_anterior'] = $ventaAnterior['reservado'];
			$data['enviado_anterior'] = $ventaAnterior['enviado'];
			$this->ajusta_stock($data);
		}

		$return['status'] = 'success';
		return $return;
	}

/************************************ Funciones de apoyo edición ******************************/

	/**
	 * Valida que los datos de una venta sean correctos
	 */
	public function validations($data) {
		$totalVenta = 0;
		$errors = [];

		$data['cliente'] = trim($data['cliente']);
		$data['apellidos'] = trim($data['apellidos']);
		$data['email'] = trim($data['email']);

		// Todas las ventas deben indicar un Cliente
		if (empty($data['cliente'])) {
			// Solo para tienda y feria se permiten ventas sin cliente
			if (in_array($data['id_canal'], [2, 4, 7, 8, 12])) {
				if (empty($data['email'])) {
					$data['id_cliente'] = 184;
					$data['email'] = 'sincliente@dementegames.cl';
					$data['cliente'] = 'Sin Cliente';
				}
				else {
					$data['cliente'] = $data['email'];
				}
				
			}
			else {
				$errors[] = 'Debes ingresar el email del cliente o ingresar "sincliente@dementegames.cl"';
			}
		}

		//Si se crea cliente en PS debe tener apellidos
		if (!empty($data['crea_cliente'])) {
			if(empty($data['apellidos'])) {
				$errors[] = 'Debes ingresar los apellidos del cliente';
			}
		}

		// Calcula Total de venta
		if (!empty($data['id_producto'])) {
			$detalle = [];
			foreach ($data['id_producto'] as $key => $idProducto) {
				if (!empty($idProducto) && !empty($data['cantidad'][$key])) {
					$totalVenta += $data['cantidad'][$key] * $data['precio'][$key];
					// Llena detalle de resumen de productos
					$detalle[$idProducto] = $data['cantidad'][$key];
				}
				else {
					$errors[] = 'Existe un producto sin ID o sin cantidad';
				}
			}
			$data['detalle'] = json_encode($detalle);

			if (!empty($data['descuento'])) {
				$totalVenta -= $data['descuento'];
			}

			if (!empty($data['descuento_puntos'])) {
				$totalVenta -= $data['descuento_puntos'];
			}
		}
		else {
			// No pueden haber ventas sin productos asociados
			$errors[] = 'No hay productos asociados';
		}

		// El total de la suma de productos y descuento debe ser igual al de la data
		if ($totalVenta != $data['total']) {
			$errors[] = 'La suma de los productos no coincide con el total';
		}

		// Las ventas ONLINE deben tener un transportista asociado
		if (empty($data['id_transportista'])) {
			$errors[] = 'Debes seleccionar un transportista';
		}

		// Se debe seleccionar un Canal de Venta
		if (empty($data['id_canal'])) {
			$errors[] = 'Debes seleccionar un canal de venta';
		}

		// Todas las ventas deben indicar su medio de pago
		if (empty($data['id_medio_pago'])) {
			$errors[] = 'Debes seleccionar un medio de pago';
		}

		// Ventas nuevas de Transbank y Sumup deben indicar un numero de operacion
		if (empty($data['id']) 
			&& ($data['id_medio_pago'] == 3 || $data['id_medio_pago'] == 8)
			&& empty($data['numero_operacion']) 
			&& empty($data['boleta'])) {
				$errors[] = 'Debes indicar el Número de Operación';
		}

		// Si se está asociando a otra venta se revisa que exista solo una venta con ese ps_id_asociado
		if (!empty($data['ps_id_asociado'])) {
			$this->db->select('count(id) as cant');
			$this->db->from('ventas v');
			$this->db->where('v.ps_id', $data['ps_id_asociado']);
			$this->db->where('v.deleted', 0);
			$padre = $this->db->get()->row_array();

			if ($padre['cant'] == 0) {
				// No existe venta padre
				$errors[] = 'No existe la venta a la cual se intenta asociar';
			}
			if ($padre['cant'] > 1) {
				// Existe más de una venta con ps_id
				$errors[] = 'Existe más de una venta con el id al cual se intenta asociar';
			}
		}

		// =========================
		// VALIDACIÓN PUNTOS
		// =========================

		$utilizaPuntos = !empty($data['utiliza_puntos']) ? 1 : 0;
		$descuentoPuntos = !empty($data['descuento_puntos']) ? (int)$data['descuento_puntos'] : 0;
		$idMedioPago = !empty($data['id_medio_pago']) ? (int)$data['id_medio_pago'] : 0;

		// Si el medio de pago es puntos
		if ($idMedioPago == 10) {

			// Debe usar puntos
			if ($utilizaPuntos != 1) {

				$errors[] = 'Si seleccionas el medio de pago Puntos debes activar "Utilizar puntos"';
			}

			// El total final debe quedar en 0
			if ($totalVenta != 0) {

				$errors[] = 'Las ventas pagadas con puntos deben quedar con Total Venta = 0';
			}
		}

		// Si usa puntos y cubre el total completo,
		// entonces el medio de pago debe ser puntos
		if (
			$utilizaPuntos == 1
			&& $descuentoPuntos > 0
			&& $totalVenta == 0
			&& $idMedioPago != 10
		) {

			$errors[] = 'Debes seleccionar el medio de pago Puntos';
		}

		if (!empty($errors)) {
			$data['validation_errors'] = $errors;
		}

		return $data;
	}

	/**
	 * Valida que las ediciones a una venta sean correctas
	 */
	public function edit_validations($data) {
		$errors = [];
		// Si está editando se traen datos anteriores
		if (!empty($data['id'])) {
			//consulta datos anteriores
			$this->db->select('*');
			$this->db->from('ventas v');
			$this->db->where('v.id', $data['id']);
			$ventaAnterior = $this->db->get()->row_array();
		}

		// Si venta se está editando y ya tiene boleta asociada, no se puede modificar el total de la compra
		if (!empty($data['id']) && $ventaAnterior['boleta'] != 0 && $ventaAnterior['total'] != $data['total']) {
			$errors[] = 'No se puede editar el monto total de una venta a la cual ya se le generó boleta.';
		}

		// Si el usuario no es administrador y la venta ya pasó por el cierre del día se validan cosas adicionales
		$fechaHoy = date('Y-m-d');

		// Si NO es administrador y la venta NO es del día
		if ($_SESSION['usuario']['perfil'] != 1 && $ventaAnterior['fecha_boleta'] != $fechaHoy) {

			// Si la boleta tiene un valor distinto de 0, no se puede modificar nada relacionado al documento
			if (!empty($ventaAnterior['boleta']) && $ventaAnterior['boleta'] != '0') {

				if ($ventaAnterior['boleta'] != $data['boleta']) {
					$errors[] = "No está permitido modificar el número de documento de una venta ya validada. Si esta modificación es necesaria, contacta a un administrador";
				}

				if ($ventaAnterior['id_tipo_documento'] != $data['id_tipo_documento']) {
					$errors[] = "No está permitido modificar el tipo de documento de una venta ya validada. Si esta modificación es necesaria, contacta a un administrador";
				}
			}
		}

		$data['venta_anterior'] = $ventaAnterior;

		if (!empty($errors)) {
			$data['validation_errors'] = $errors;
		}

		return $data;
	}

	/**
	 * Setea datos de venta al crear o editar
	 */
	public function set_data($data) {

		// propiedades estados
		$estados = $this->get_estados();
		$data['vendido'] = $estados[$data['id_estado_venta']]['vendido'];
		$data['reservado'] = $estados[$data['id_estado_venta']]['reservado'];
		$data['enviado'] = $estados[$data['id_estado_venta']]['enviado'];

		// Si no existe cliente se crea
		if (empty($data['id_cliente'])) {
			$cliente['nombre'] = $data['cliente'];
			$cliente['email'] = $data['email'];
			$cliente['ps_id'] = $data['ps_id_cliente'];
			$cliente['id_canal_registro'] = $data['id_canal'];
			$cliente['newsletter'] = $data['newsletter'] ?? 0;
			$data['id_cliente'] = $this->Cliente->save($cliente);
			$data['nuevo_cliente'] = 1;
		}
		else {
			// Consuta por email y ps_id del cliente
			$this->db->select('ps_id, email');
			$this->db->from('clientes');
			$this->db->where('id', $data['id_cliente']);
			$this->db->where('deleted', 0);
			$cliente = $this->db->get()->row_array();

			if (empty($cliente['ps_id']) && !empty($data['ps_id_cliente'])) {
				$clienteEditado['ps_id'] = $data['ps_id_cliente'];
			}
			if (empty($cliente['email']) && !empty($data['email'])) {
				$clienteEditado['email'] = $data['email'];
			}
			if (!empty($clienteEditado)) {
				$clienteEditado['id'] = $data['id_cliente'];
				$this->Cliente->save($clienteEditado);
			}
		}

		if ($data['fecha_boleta'] == '' && $data['boleta'] > 0) {
			$data['fecha_boleta'] = date("Y-m-d");
		}

		if ($data['fecha'] != '') {
			$data['fecha'] = date("Y-m-d", strtotime($data['fecha']));
		}
		else {
			// Para notas de crédito la fecha gfestión será igual a la fecha del documento
			if ($data['id_tipo_venta'] == 3) {
				$data['fecha'] = $data['fecha_boleta'];
			}
			else {
				$data['fecha'] = date("Y-m-d");
			}
		}

		// Si venta pasa a Pago Aceptado, Preparación en curso o Disponible para retiro
		// Desde otro estado => se actualiza fecha de gestión
		if (!empty($data['venta_anterior']['id_estado_venta'])) {
			if (in_array($data['id_estado_venta'], [2, 3, 18]) && !in_array($data['venta_anterior']['id_estado_venta'], [2, 3, 18])) {
				$data['fecha'] = date("Y-m-d");
			}
		}

		if ($data['fecha_venta'] == '') {
			if ($data['id_tipo_venta'] == 3) {
				$data['fecha_venta'] = $data['fecha_boleta'];
			}
			else {
				$data['fecha_venta'] = date("Y-m-d H:i:s");
			}
		}

		if ($data['fecha_envio'] == '' && $data['id_estado_venta'] == 4) {
			$data['fecha_envio'] = date("Y-m-d");
		}

		// Para ventas presenciales y feria
		if (in_array($data['id_canal'], [2, 4, 7, 8, 12])) {
			$data['id_transportista'] = !empty($data['id_transportista']) ? $data['id_transportista'] : 1;
			
			// Para las ventas presenciales con Transbank se marca boleta realizada y lista
			if ($data['id_medio_pago'] == 8
				&& empty($data['boleta']) 
				&& !empty($data['numero_operacion'])) {
					$data['id_tipo_documento'] = 7;
					$data['boleta'] = $data['numero_operacion'];
					$data['fecha_boleta'] = date('Y-m-d');
					$data['boleta_lista'] = 1;
			}

			// Para las ventas presenciales con Sumup se marca boleta realizada y lista
			if ($data['id_medio_pago'] == 3
				&& empty($data['boleta']) 
				&& !empty($data['numero_operacion'])) {
					$data['id_tipo_documento'] = 9;
					$data['boleta'] = $data['numero_operacion'];
					$data['fecha_boleta'] = date('Y-m-d');
					$data['boleta_lista'] = 1;
			}

			// Para las ventas presenciales con efectivo y Transferencia se marca boleta realizada y lista solo si viene numero de operacion
			if (($data['id_medio_pago'] == 2 || $data['id_medio_pago'] == 5) 
				&& empty($data['boleta']) 
				&& !empty($data['numero_operacion'])) {
					$data['id_tipo_documento'] = 5;
					$data['boleta'] = $data['numero_operacion'];
					$data['fecha_boleta'] = date('Y-m-d');
					$data['boleta_lista'] = 1;
			}
		}

		// Setea id_vendedor para una nueva venta presencial
		if (empty($data['id']) && empty($data['id_vendedor']) && in_array($data['id_canal'], [2, 4, 7, 8, 12])) {
			$data['id_vendedor'] = $_SESSION['usuario']['id'];
		}

		// Setea id_creador para una nueva venta
		if (empty($data['id']) && empty($data['id_creador'])) {
			$data['id_creador'] = $_SESSION['usuario']['id'];
		}

		// Setea id_punto_venta para una nueva venta
		if (empty($data['id']) && !empty($_SESSION['usuario']['id_punto_venta'])) {
			$data['id_punto_venta'] = $_SESSION['usuario']['id_punto_venta'];
		}

		return $data;
	}

	public function create_sale($venta, $data) {
		$this->db->insert('ventas', $venta);
		$venta['id'] = $this->db->insert_id();

		// Crea registro en log con info inicial de la venta
		$venta['changes'] = $venta;

		// Se llama ajusta_saldo sin id porque indica que no se ha sumado anteriormente al total
		if ($venta['vendido'] == 1 && $venta['id_tipo_venta'] != 4) {
			// Solo se suma al saldo si la venta esta en estado vendido
			$this->ajusta_saldo($venta['total']);
		}

		$data['id'] = $venta['id'];
		$data['vendido_anterior'] = 0;
		$data['reservado_anterior'] = 0;
		$data['enviado_anterior'] = 0;
		$resp = $this->ajusta_stock($data);
		if (!empty($resp)) {
			$venta['changes']['productos'] = $resp;
		}

		return $venta;
	}


	public function update_sale($venta, $data) {

		//Actualiza datos de venta
		$this->db->where('id', $data['id']);
		$this->db->update('ventas', $venta);
		$idVenta = $data['id'];

		// Actualiza log de venta
		// Por cada dato que se guardó se revisa su estado anterior
		$changes = [];
		$ventaAnterior = $data['venta_anterior'];
		foreach ($venta as $key => $val) {

			if ($key == 'fecha_venta') {
				$val = str_replace('T', ' ', $val);
			}
			if (in_array($key, ['fecha', 'fecha_boleta', 'fecha_envio'])) {
				if (empty($val)) {
					$val = '0000-00-00';
				}
			}

			if ($key == 'adeudado') {
				$val = intval($val);
			}

			if ($ventaAnterior[$key] != $val) {
				$changes[$key] = [
					'anterior' => $ventaAnterior[$key],
					'actual' => $val
				];
			}
		}
		$venta['changes'] = $changes;

		//Ajusta saldo segun estados
		$data['vendido_anterior'] = $ventaAnterior['vendido'];
		$data['reservado_anterior'] = $ventaAnterior['reservado'];
		$data['enviado_anterior'] = $ventaAnterior['enviado'];
		if ($data['vendido'] == 0) {
			$venta['total'] = 0;
		}
		if ($data['vendido_anterior'] == 0) {
			$ventaAnterior['total'] = 0;
		}

		if($ventaAnterior['id_tipo_venta'] == 4){
			$ventaAnterior['total'] = 0;
		}
		if($data['id_tipo_venta'] == 4){
			$venta['total'] = 0;
		}

		// Ajusta Dinero de la tienda
		// Venta cancelada no descontaría
		$this->ajusta_saldo($venta['total'], $ventaAnterior['total']);

		//Ajusta Stock enviando datos de estado anterior
		$resp = $this->ajusta_stock($data);
		if (!empty($resp)) {
			$venta['changes']['productos'] = $resp;
		}

		// Actualizar ventas hijas
		/*
		$this->db->select('*');
		$this->db->from('ventas v');
		$this->db->where('v.id', $idVenta);
		$this->db->where('v.deleted', 0);
		$venta = $this->db->get()->row_array();

		$hijas = $this->get_hijas($venta['ps_id']);
		foreach ($hijas as $idHija => $psId) {
			$changed[] = $this->change_state($idHija, $idEstado);
		}
		// Retorna arreglo con id de todas las ventas editadas
		return $changed;
		*/

		//Transportista
		//Asignado

		//estado

		//$this->change_state($idVenta, $new_state);

		return $venta;
	}

	public function load_points($venta, $data) {
		// Calcula puntos
		$totalVenta = $venta['total'];
		$totalProductosSD = 0;
		$totalPuntos = 0;
		foreach ($data['id_producto'] as $key => $value) {
			if ($data['descuento_producto'][$key] == 0) {
				$totalProductosSD += $data['total_producto'][$key];
			}
		}

		// Si Cliente no paga, nunca acumulará puntos
		if ($totalVenta > 0) {
			// Acumulará puntos según el menor monto entre Total Pagado y Total Productos Sin Desc.
			if ($totalVenta > $totalProductosSD) {
				$totalPuntos = floor($totalProductosSD / 20);
			}
			else {
				$totalPuntos = floor($totalVenta / 20);
			}
		}

		if ($totalPuntos > 0) {
			$loyalty = [
				'id_venta' => $venta['id'],
				'ps_id_cliente' => $data['ps_id_cliente'],
				'puntos' => $totalPuntos,
				'id_creador' => $_SESSION['usuario']['id']
			];

			$this->save_loyalty($loyalty);
		}

		return true;
	}

	public function exchange_points($ps_id, $puntosUtilizados) {
		// Trae puntos
		$CI =& get_instance();
		$CI->load->model('cliente_model');
		$puntos = $CI->cliente_model->get_points($ps_id);

		$ps = $this->load->database('prestashop', TRUE);
		foreach ($puntos['puntos'] as $punto) {
			// Cambia todos los puntos disponibles a estado 6
			if ($punto['id_loyalty_state'] == 2) {
				$loyalty = [
					'id_loyalty_state' => 6,
					'date_upd' => date('Y-m-d H:i:s')
				];
				$ps->where('id_loyalty', $punto['id_loyalty']);
				$ps->update('ps_loyalty', $loyalty);
			}
		}

		// Si se utilizaron menos puntos que el total de puntos
		// Se creará un nuevo reguistro con el saldo de puntos
		if ($puntos['total_puntos'] > $puntosUtilizados) {
			$saldo = $puntos['total_puntos'] - $puntosUtilizados;
			$loyalty = [
				'id_loyalty_state' => 2,
				'id_customer' => $ps_id,
				'id_order' => 0,
				'id_cart_rule' => 0,
				'points' => $saldo,
				'description' => 'Saldo compra en tienda',
				'id_venta' => 0,
				'id_creador' => $_SESSION['usuario']['id'],
				'date_add' => date('Y-m-d H:i:s'),
				'date_upd' => date('Y-m-d H:i:s')
			];

			// Crea registro en loyalty
			$ps = $this->load->database('prestashop', TRUE);
			$ps->insert('ps_loyalty', $loyalty);
		}

		return true;
	}

	public function save_loyalty($data) {
		if (!empty($data['puntos'])) {
			$loyalty = [
				'id_loyalty_state' => 2,
				'id_customer' => $data['ps_id_cliente'],
				'id_order' => 0,
				'id_cart_rule' => 0,
				'points' => $data['puntos'],
				'description' => 'Compra en tienda',
				'id_venta' => $data['id_venta'],
				'id_creador' => $_SESSION['usuario']['id'],
				'date_add' => date('Y-m-d H:i:s'),
				'date_upd' => date('Y-m-d H:i:s')
			];

			// Crea registro en loyalty
			$ps = $this->load->database('prestashop', TRUE);
			$ps->insert('ps_loyalty', $loyalty);
		}

		// Actualiza registro de venta con puntos
		$datosPuntos = [
			'puntos' => $data['puntos'],
			'puntos_cargados' => 1
		];
		$this->db->where('id', $data['id_venta']);
		$this->db->update('ventas', $datosPuntos);
		return true;
	}

	public function load_loyalty($cant = 50, $save = 0) {
		// Cuenta cuantas ventas hay
		/*
		SELECT id_cliente, c.nombre, SUM(TOTAL) tot, SUM(TOTAL/50) as puntos 
		FROM ventas v
		LEFT JOIN clientes c ON v.id_cliente = c.id
		WHERE id_cliente IN
		(SELECT id FROM clientes
		WHERE ps_id != 0)
		AND id_canal = 2
		AND descuento = 0
		group by id_cliente
		order by tot DESC;
		*/

		$this->db->select('count(v.id) restantes');
		$this->db->from('ventas v');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->where_in('v.id_canal', [2, 4, 7, 8, 12]);
		$this->db->where('v.descuento', 0);
		$this->db->where('v.descuento', 0);
		$this->db->where('v.puntos_cargados', 0);
		$this->db->where('v.deleted', 0);
		$this->db->where('c.ps_id !=', 0);


		$restantes = $this->db->get()->row_array();

		pr('Existen '.$restantes['restantes'].' ventas sin cargar puntos');

		$this->db->select('v.id, c.ps_id ps_id_cliente, c.nombre, v.fecha_venta, v.total, FLOOR(v.total/50) puntos');
		$this->db->from('ventas v');
		$this->db->join('clientes c','v.id_cliente = c.id', 'left');
		$this->db->where_in('v.id_canal', [2, 7, 8]);
		$this->db->where('v.descuento', 0);
		$this->db->where('v.descuento', 0);
		$this->db->where('v.puntos_cargados', 0);
		$this->db->where('v.deleted', 0);
		$this->db->where('c.ps_id !=', 0);
		$this->db->order_by('v.created', 'ASC');
		$this->db->limit($cant);

		$ventas = $this->db->get()->result_array();

		if (!$save){
			pr('Se cargarán los siguientes '.$cant.' registros');
			pr($ventas);
		}

		if ($save) {
			// Se hace el proceso for each
			foreach($ventas as $venta) {
				$loyalty = [
					'id_venta' => $venta['id'],
					'ps_id_cliente' => $venta['ps_id_cliente'],
					'puntos' => $venta['puntos']
				];
				$a = $this->save_loyalty($loyalty);
				pr($venta);
				pr('Venta ' . $venta['id'] . ': ' . ($a = 1 ? 'Correcto' : 'Fallido'));
			}
		}
		die;


		// Si $save == 1 guarda las 50 primeras
		// Busca 50 ventas con ps_id_cliente > 0, canal = 3 y descuento = 0

		// Lee venta para traer id_cliente
		// Busca ps_id_cliente

		// Calcula puntos

		// Llama save_loyalty
	}

	private function get_id_ubicacion_producto($idProducto, $idAlmacen) {
		// Asegura que exista el registro almacenes_productos
		$idAlmacenProducto = $this->Producto->crear_almacen_producto($idProducto, $idAlmacen);

		// Obtiene la ubicación
		$this->db->select('id_ubicacion');
		$this->db->from('almacenes_productos');
		$this->db->where('id', $idAlmacenProducto);
		$this->db->where('deleted', 0);
		$row = $this->db->get()->row_array();

		// Nunca null: 0 = no definida
		return (int)($row['id_ubicacion'] ?? 0);
	}


/************************************ Otras Consultas *****************************************/
/********************** Consultas no relacionadas a una sola venta ****************************/

	/**
	 * Retorna los datos necearios para administrar las ventas
	 *
	 * En construcción
	 */
	public function get_globales($data) {
		$data['productos'] = $this->Producto->lista();
		$data['codigos_barras'] = $this->Producto->codigos_barras();
		$data['info_productos'] = $this->Producto->list_precios();

		$data['clientes'] = $this->Cliente->list();
		$data['emails'] = $this->Cliente->email_list();
		$data['ps_clientes'] = $this->Cliente->ps_list();
		$data['usuarios'] = $this->Usuario->lista();
		$data['encargados'] = $this->Usuario->lista(1);
		$data['estados_ventas'] = $this->get_estados();
		$data['transportistas'] = $this->get_transportistas();
		$data['transportistas_disponibles'] = $this->get_transportistas_disponibles();

		$data['medios_pagos'] = $this->get_medios_pagos();
		$data['medios_pagos_disponibles'] = $this->get_medios_pagos_disponibles();
		$data['canales'] = $this->get_canales();
		$data['canales_colores'] = $this->get_canales_colores();

		$data['tipos_ventas'] = $this->tipos_ventas();
		$data['tipos_documentos'] = $this->tipos_documentos();
		$data['tipos_documentos_abr'] = $this->tipos_documentos(TRUE);

		$CI =& get_instance();
		$CI->load->model('proveedor_model');
		$data['proveedores'] = $CI->proveedor_model->lista();

		$data['regiones'] = $this->lista_regiones();
		$data['comunas'] = $this->lista_comunas();

		$CI =& get_instance();
		$CI->load->model('puntoventa_model');
		$data['canales_puntos_ventas'] = $CI->puntoventa_model->lista_canales();

		//prx($data);

		return $data;
	}


	/**
	 * Retorna los datos necearios para administrar las ventas, reducido
	 *
	 * En construcción
	 */
	public function get_globales_min($data) {
		//$data['productos'] = $this->Producto->lista();
		//$data['codigos_barras'] = $this->Producto->codigos_barras();
		//$data['info_productos'] = $this->Producto->list_precios();

		//$data['clientes'] = $this->Cliente->list();
		//$data['emails'] = $this->Cliente->email_list();
		//$data['ps_clientes'] = $this->Cliente->ps_list();
		$data['usuarios'] = $this->Usuario->lista();
		$data['encargados'] = $this->Usuario->lista(1);
		$data['estados_ventas'] = $this->get_estados();
		$data['transportistas'] = $this->get_transportistas();
		$data['transportistas_disponibles'] = $this->get_transportistas_disponibles();

		$data['medios_pagos'] = $this->get_medios_pagos();
		$data['medios_pagos_disponibles'] = $this->get_medios_pagos_disponibles();
		$data['canales'] = $this->get_canales();
		$data['canales_colores'] = $this->get_canales_colores();

		$data['tipos_ventas'] = $this->tipos_ventas();
		$data['tipos_documentos'] = $this->tipos_documentos();
		$data['tipos_documentos_abr'] = $this->tipos_documentos(TRUE);

		$CI =& get_instance();
		$CI->load->model('proveedor_model');
		$data['proveedores'] = $CI->proveedor_model->lista();

		$data['regiones'] = $this->lista_regiones();
		$data['comunas'] = $this->lista_comunas();

		$CI =& get_instance();
		$CI->load->model('puntoventa_model');
		$data['canales_puntos_ventas'] = $CI->puntoventa_model->lista_canales();

		//prx($data);

		return $data;
	}


	/**
	 * Entrega totales por meses
	 */
	public function get_totales($tipo) {
		$this->db->select('SUM(total) AS total, COUNT(DISTINCT(id)) AS facturas, DATE_FORMAT(fecha,"%Y%m") AS mes');
		$this->db->from('ventas v');
		$this->db->where('v.vendido', 1);
		$this->db->where('v.id_tipo_venta', $tipo);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('DATE_FORMAT(fecha,"%Y%m")');
		$facturas = $this->db->get()->result_array();
		$total_total = 0;
		foreach($facturas as $mes) {
			$totales[$mes['mes']]['tipo'] = $mes['facturas'];
			$totales[$mes['mes']]['total_tipo'] = $mes['total'];
			$total_total += $mes['total'];
		}
		$totales['total_total'] = $total_total;
		return $totales;
		/*
		//SELECT SUM(total) AS total, COUNT(DISTINCT(boleta)) AS boletas, DATE_FORMAT(fecha,'%Y%m') AS mes FROM ventas GROUP BY DATE_FORMAT(fecha,'%Y%m')
		$this->db->select('SUM(total) AS total, COUNT(DISTINCT(CASE WHEN boleta > 0 THEN BOLETA END)) AS boletas, DATE_FORMAT(fecha,"%Y%m") AS mes, SUM(CASE WHEN boleta < 1 THEN 1 ELSE 0 END) as sin_boleta');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->where('ev.vendido', 1);
		$this->db->where_in('v.id_tipo_venta', [1, 5 ]);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('DATE_FORMAT(fecha,"%Y%m")');
		$boletas = $this->db->get()->result_array();
		$total = 0;
		foreach($boletas as $mes) {
			$totales[$mes['mes']]['boletas'] = $mes['boletas'];
			$totales[$mes['mes']]['total'] = $mes['total'];
			$totales[$mes['mes']]['sin_boleta'] = $mes['sin_boleta'];
			$total += $mes['total'];
		}
		$totales['total'] = $total;

		$this->db->select('SUM(total) AS total, COUNT(DISTINCT(id)) AS facturas, DATE_FORMAT(fecha,"%Y%m") AS mes');
		$this->db->from('ventas v');
		$this->db->where('v.vendido', 1);
		$this->db->where_not_in('v.id_tipo_venta', [1, 5]);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('DATE_FORMAT(fecha,"%Y%m")');
		$facturas = $this->db->get()->result_array();
		$total_facturas = 0;
		foreach($facturas as $mes) {
			$totales[$mes['mes']]['facturas'] = $mes['facturas'];
			$totales[$mes['mes']]['total_facturas'] = $mes['total'];
			$total_facturas += $mes['total'];
		}
		$totales['total_facturas'] = $total_facturas;
		return $totales;
		*/
	}

	/**
	 * Entrega totales de meses por FECHA VENTA
	 */
	public function get_total_meses() {
		//SELECT SUM(total) AS total, COUNT(DISTINCT(boleta)) AS boletas, DATE_FORMAT(fecha,'%Y%m') AS mes FROM ventas GROUP BY DATE_FORMAT(fecha,'%Y%m')
		$this->db->select('SUM(total) AS total, DATE_FORMAT(fecha_venta,"%Y%m") AS mes');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where_in('v.id_tipo_venta', [1, 2, 4, 5]);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('mes');
		$boletas = $this->db->get()->result_array();
		$total = 0;
		foreach($boletas as $mes) {
			$totales[$mes['mes']]['total'] = $mes['total'];
		}
		return $totales;
	}

	/**
	 * Entrega totales por dia
	 * $cant INT cantidad de días a entregar
	 */
	public function get_totales_diarios($cant = 90) {
		//SELECT SUM(total) AS total, COUNT(DISTINCT(boleta)) AS boletas, DATE_FORMAT(fecha,'%Y%m') AS mes FROM ventas GROUP BY DATE_FORMAT(fecha,'%Y%m')
		$this->db->select('SUM(total) AS total, DATE_FORMAT(fecha_venta,"%Y%m%d") AS fecha_key, DATE_FORMAT(fecha_venta,"%d-%m-%Y") AS dia, (ELT(WEEKDAY(fecha_venta) + 1, "Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom")) AS dia_semana');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('fecha_key');
		$this->db->order_by('fecha_key', 'DESC');
		$this->db->limit($cant);
		$ventas = $this->db->get()->result_array();
		foreach ($ventas as $venta) {
			$newVentas[$venta['fecha_key']] = $venta;
		}

		$dias = array("Dom","Lun","Mar","Mié","Jue","Vie","Sab");

		$fecha = date('Ymd');
		for ($i = 0; $i < $cant; $i++) {
			if (!empty($newVentas[$fecha])) {
				$finales[$fecha] = $newVentas[$fecha];
			}
			else {
				$tmpVenta['total'] = 0;
				$tmpVenta['dia'] = date("d-m-Y", strtotime($fecha));
				$tmpVenta['dia_semana'] = $dias[date("w", strtotime($fecha))];
				$finales[$fecha] = $tmpVenta;
			}
			$fecha = date("Ymd", strtotime($fecha . " - 1 days"));
		}

		return array_reverse($finales);
	}

	public function get_estados() {
		$this->db->select('id, nombre, vendido, pagado, reservado, enviado, color, fondo');
		$this->db->from('estados_ventas');
		$this->db->where('deleted', 0);
		$this->db->order_by('orden', 'ASC');
		$estados_ventas = $this->db->get()->result_array();

		$r = [];
		foreach ($estados_ventas as $ev) {
			$r[$ev['id']] = $ev;
		}

		return $r;
	}

	public function get_transportistas() {
		$this->db->select('id, nombre, color, id_almacen, activo');
		$this->db->from('transportistas');
		$this->db->where('deleted', 0);
		$this->db->order_by('activo', 'DESC');
		$this->db->order_by('nombre', 'ASC');
		$transportitas = $this->db->get()->result_array();

		$r[0]['nombre'] = 'Sin Transportista Asignado';
		foreach ($transportitas as $t) {
			$r[$t['id']] = $t;
		}

		return $r;
	}

	public function get_medios_pagos_disponibles() {
		$this->db->select('id, nombre');
		$this->db->from('medios_pagos');
		$this->db->where('deleted', 0);
		$this->db->where('activo', 1);
		$this->db->order_by('orden', 'ASC');
		$this->db->order_by('id', 'ASC');
		$mediosPagos = $this->db->get()->result_array();

		foreach ($mediosPagos as $mp) {
			$r[$mp['id']] = $mp['nombre'];
		}

		return $r;
	}

	public function get_medios_pagos() {
		$this->db->select('id, nombre, color, alias');
		$this->db->from('medios_pagos');
		$this->db->where('deleted', 0);
		$this->db->order_by('orden', 'ASC');
		$this->db->order_by('id', 'ASC');
		$mediosPagos = $this->db->get()->result_array();

		foreach ($mediosPagos as $mp) {
			$r[$mp['id']] = $mp;
		}

		return $r;
	}

	/**
	 * Entrega lista de canales
	 * Si recibe filtros entrega solo los solictados
	 * ejemplo filtros
	 * ['mayorista' => 1]
	 * ['destacado' => 1]
	*/

	public function get_canales($filtros = []) {
		$this->db->select('id, nombre');
		$this->db->from('canales');
		$this->db->where('deleted', 0);

		if (!empty($filtros)) {
			foreach($filtros as $key => $val) {
				$this->db->where($key, $val);
			}
		}

		$this->db->order_by('id', 'ASC');
		$canales = $this->db->get()->result_array();
		$r = [];
		foreach ($canales as $c) {
			$r[$c['id']] = $c['nombre'];
		}
		return $r;
	}

	public function get_canales_colores() {
		$this->db->select('id, color');
		$this->db->from('canales');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$canales = $this->db->get()->result_array();

		foreach ($canales as $c) {
			$r[$c['id']] = $c['color'];
		}
		return $r;
	}

	public function canales_abr() {
		$this->db->select('id, abreviacion');
		$this->db->from('canales');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$canales = $this->db->get()->result_array();

		foreach ($canales as $c) {
			$r[$c['id']] = $c['abreviacion'];
		}
		return $r;
	}

	public function get_transportistas_disponibles() {
		$this->db->select('id, nombre');
		$this->db->from('transportistas');
		$this->db->where('deleted', 0);
		$this->db->where('activo', 1);
		$this->db->order_by('id', 'ASC');
		$transportitas = $this->db->get()->result_array();

		$r = [];
		foreach ($transportitas as $t) {
			$r[$t['id']] = $t['nombre'];
		}

		return $r;
	}

	public function lista_regiones() {
		$this->db->select('id, nombre');
		$this->db->from('regiones');
		//$this->db->where('deleted', 0);
		//$this->db->where('activo', 1);
		$this->db->order_by('id', 'ASC');
		$regiones = $this->db->get()->result_array();

		$r = [];
		foreach ($regiones as $region) {
			$r[$region['id']] = $region['nombre'];
		}

		return $r;
	}

	public function tipos_ventas() {
		$this->db->select('id, nombre');
		$this->db->from('tipos_ventas');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$rows = $this->db->get()->result_array();

		$r = [];

		foreach ($rows as $v) {
			$r[$v['id']] = $v['nombre'];
		}
		return $r;
	}

	public function tipos_documentos($abr = FALSE) {
		$this->db->select('id, nombre, abreviacion');
		$this->db->from('tipos_documentos');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');
		$rows = $this->db->get()->result_array();

		foreach ($rows as $v) {
			if ($abr) {
				$r[$v['id']] = $v['abreviacion'];
			}
			else {
				$r[$v['id']] = $v['nombre'];
			}
		}
		return $r;
	}

	public function lista_comunas() {
		$this->db->select('id, id_region, nombre');
		$this->db->from('comunas');
		//$this->db->where('deleted', 0);
		//$this->db->where('activo', 1);
		$this->db->order_by('id', 'ASC');
		$comunas = $this->db->get()->result_array();

		$r = [];
		foreach ($comunas as $comuna) {
			$r[$comuna['id_region']][$comuna['id']] = $comuna['nombre'];
		}

		return $r;
	}

	public function balance($periodo = ''){

		/*************************** Sección documentos Recibidos (COMPRA) *******************************/

		// Facturas recibidas
		$this->db->select('SUM(TOTAL) as total_facturas, COUNT(id) as cant_facturas');
		$this->db->from('compras');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_compra', 1);
		$this->db->where('contable', 1);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$facturas = $this->db->get()->row_array();
		$balance['recibidos']['facturas']['total'] = $facturas['total_facturas'];
		$balance['recibidos']['facturas']['cantidad'] = $facturas['cant_facturas'];

		// Facturas Exentas recibidas
		$this->db->select('SUM(TOTAL) as total_facturas, COUNT(id) as cant_facturas');
		$this->db->from('compras');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_compra', 4);
		$this->db->where('contable', 1);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$facturasExentas = $this->db->get()->row_array();
		$balance['recibidos']['exentas']['total'] = $facturasExentas['total_facturas'];
		$balance['recibidos']['exentas']['cantidad'] = $facturasExentas['cant_facturas'];

		//Notas de Débito
		$this->db->select('SUM(TOTAL) as total_notas_debito, COUNT(id) as cant_notas_debito');
		$this->db->from('compras');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_compra', 5);
		$this->db->where('contable', 1);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$notasDebito = $this->db->get()->row_array();
		$balance['recibidos']['debito']['total'] = $notasDebito['total_notas_debito'];
		$balance['recibidos']['debito']['cantidad'] = $notasDebito['cant_notas_debito'];

		// Notas de credito Recibidas
		$this->db->select('SUM(TOTAL) as total_notas, COUNT(id) as cant_notas');
		$this->db->from('ventas');
		$this->db->where('vendido', 1);
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where('id_tipo_documento', 3);
		$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = '. $periodo);
		$notas = $this->db->get()->row_array();
		$balance['recibidos']['credito']['total'] = $notas['total_notas'];
		$balance['recibidos']['credito']['cantidad'] = $notas['cant_notas'];

		// Declaraciones de ingreso
		$this->db->select('SUM(TOTAL) as total_dins, COUNT(id) as cant_dins');
		$this->db->from('compras');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_compra', 2);
		$this->db->where('contable', 1);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$dins = $this->db->get()->row_array();
		$balance['recibidos']['dins']['total'] = $dins['total_dins'];
		$balance['recibidos']['dins']['cantidad'] = $dins['cant_dins'];


		/*************************** Sección documentos Emitidos *******************************/

		// Suma facturas emitidas
		$this->db->select('SUM(TOTAL) as total_facturas, COUNT(id) as cant_facturas');
		$this->db->from('ventas');
		$this->db->where('vendido', 1);
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where('id_tipo_documento', 2);
		$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = '. $periodo);
		$facturas = $this->db->get()->row_array();
		$balance['emitidos']['facturas']['total'] = $facturas['total_facturas'];
		$balance['emitidos']['facturas']['cantidad'] = $facturas['cant_facturas'];

		// Suma ventas en Con tipo documento = Boleta
		$this->db->select('SUM(TOTAL) as total_boletas, COUNT(DISTINCT(boleta)) as cant_boletas');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where('id_tipo_documento', 1);
		$this->db->where('boleta >', 0);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$boletas = $this->db->get()->row_array();
		$balance['emitidos']['boletas']['total'] = $boletas['total_boletas'];
		$balance['emitidos']['boleta']['cantidad'] = $boletas['cant_boletas'];

		// Suma ventas con tipo documento = e-Boleta
		$this->db->select('SUM(TOTAL) as total_boletas, COUNT(DISTINCT(boleta)) as cant_boletas');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where('id_tipo_documento', 5);
		$this->db->where('boleta >', 0);
		$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = '. $periodo);
		$boletas = $this->db->get()->row_array();
		$balance['emitidos']['eboletas']['total'] = $boletas['total_boletas'];
		$balance['emitidos']['eboletas']['cantidad'] = $boletas['cant_boletas'];

		// NC Emitidas
		// Suma compras con tipo documento = nota credito
		$this->db->select('SUM(TOTAL) as total_nc, COUNT(id) as cant_nc');
		$this->db->from('compras');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_compra', 6);
		$this->db->where('contable', 1);
		$this->db->where('DATE_FORMAT(fecha, "%Y%m") = '. $periodo);
		$notas = $this->db->get()->row_array();
		$balance['emitidos']['credito']['total'] = $notas['total_nc'];
		$balance['emitidos']['credito']['cantidad'] = $notas['cant_nc'];


		// Suma ventas con tipo documento = Comprobante Electrónico
		$this->db->select('SUM(TOTAL) as total_boletas, COUNT(boleta) as cant_boletas');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where_in('id_tipo_documento', [7, 8, 9, 11, 12]);
		$this->db->where('boleta >', 0);
		$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = '. $periodo);
		$boletas = $this->db->get()->row_array();

		$balance['emitidos']['comprobantes']['total'] = $boletas['total_boletas'];
		$balance['emitidos']['comprobantes']['cantidad'] = $boletas['cant_boletas'];

		return $balance;
	}


	public function ventas_tipo_documento($periodo) {

		$this->db->select('id_tipo_documento, DATE_FORMAT(fecha_boleta, "%Y-%m-%d") as dia, SUM(TOTAL) as total_boletas, COUNT(boleta) as cant_boletas');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('id_tipo_venta', 1);
		$this->db->where('boleta >', 0);
		$this->db->where('DATE_FORMAT(fecha_boleta, "%Y%m") = '. $periodo);
		$this->db->group_by('id_tipo_documento, DATE_FORMAT(fecha_boleta, "%Y%m%d")');
		$boletas = $this->db->get()->result_array();

		// Agrupamos los totales por tipo de documento
		$tipoDocumento = [];
		foreach ($boletas as $boleta) {
			$tipoDocumento[$boleta['id_tipo_documento']][$boleta['dia']] = ['cantidad' => $boleta['cant_boletas'], 'total' => $boleta['total_boletas']];
		}

		$mes = substr($periodo, 4, 2);
		$anno = substr($periodo, 0, 4);
		$mesInicio = $anno . '-' . $mes . '-' . '01';
		$diasMes = date("t", strtotime($mesInicio));

		$sinBoleta = ['cantidad' => 0, 'total' => 0];

		$data = [];

		for ($i = 1; $i <= $diasMes; $i++) {
			$fecha = $anno . '-' . $mes . '-' . ($i < 10 ? '0' . $i : $i);

			foreach ($tipoDocumento as $idTipo => $tipo) {
				if (empty($data[$idTipo]['total'])) {
					$data[$idTipo]['total'] = [
						'cantidad' => 0,
						'monto' => 0
					];
				}

				if (!empty($tipo[$fecha])) {
					$data[$idTipo]['dias'][$fecha] = $tipo[$fecha];
					$data[$idTipo]['total']['cantidad'] += $tipo[$fecha]['cantidad'];
					$data[$idTipo]['total']['monto'] += $tipo[$fecha]['total'];
				}
				else {
					$data[$idTipo]['dias'][$fecha] = $sinBoleta;
				}
			}
		}
		return $data;
	}


	public function next_boleta() {
		$this->db->select('MAX(Boleta) as max_boleta');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$maxBoleta = $this->db->get()->row_array();
		$next = $maxBoleta['max_boleta'] + 1;
		return $next;
	}

	/**
	 * Retorna un arreglo con todos los meses en que se han producido ventas
	 * en formato YYYYMM
	 */
	public function get_meses_ventas($current = true){
		$this->db->select("DATE_FORMAT(fecha_venta,'%Y%m') as mes");
		$this->db->from('ventas');
		$this->db->where('vendido', 1);
		$this->db->where('deleted', 0);
		$this->db->group_by('mes');
		$this->db->order_by('mes', 'DESC');
		$meses = $this->db->get()->result_array();

		if ($current) {
			$tmp_meses[0] = date('Ym');
			foreach ($meses as $k => $v) {
				if ($v['mes'] != $tmp_meses[0]) {
					$tmp_meses[] = $v['mes'];
				}
			}
		}
		else {
			$tmp_meses[0] = 0;
			foreach ($meses as $k => $v) {
				$tmp_meses[] = $v['mes'];
			}
		}

		return $tmp_meses;
	}

	/**
	 * Entrega los datos de envíos realizados por los transportistas
	*/
	public function envios($periodo) {
		if ($periodo == 'semestre') {
			$mesesPeriodo = [
				
			];
		}
		// Estados Enviados
		$estados = [4, 5];

		// Datos por Transportista
		$this->db->select('count(v.id) as envios, v.id_transportista, t.nombre as transportista, DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") as mes');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.deleted', 0);		
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->where('v.ps_id_asociado', 0);
		$this->db->where('v.id_transportista >', 0);
		// No cuenta las compras en tienda retiradas en tienda
		$this->db->group_start();
			$this->db->where_not_in('v.id_canal', [2, 4, 7, 8, 12]);
			$this->db->or_where('v.id_transportista !=', 1);
		$this->db->group_end();
		if ($periodo == 'semestre') {
			$this->db->where('PERIOD_DIFF(date_format(now(), "%Y%m"), DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m")) <= 6');
		}
		else {
			$this->db->where('DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") = "' . $periodo . '"');
		}
		$this->db->group_by('mes');
		$this->db->group_by('t.nombre');
		$this->db->order_by('envios', 'DESC');
		$ventas = $this->db->get()->result_array();

		$nombresTransportistas = [];
		$enviosTransportistas = [];

		foreach ($ventas as $venta) {
			if (!empty($mesesPeriodo)) {
				// Para semestre
			}
			else {
				$enviosTransportistas[$venta['id_transportista']] = $venta['envios'];
				$nombresTransportistas[$venta['id_transportista']] = $venta['transportista'];
			}
		}

		$result['nombresTransportistas'] = $nombresTransportistas;
		$result['enviosTransportistas'] = $enviosTransportistas;

		// Datos por Región

		$this->db->select('count(v.id) as envios, v.id_region, DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") as mes');
		$this->db->from('ventas v');
		$this->db->where('v.deleted', 0);		
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->where('v.ps_id_asociado', 0);
		$this->db->where('v.id_transportista >', 0);
		$this->db->where('v.id_canal', 1);
		$this->db->where('v.id_tipo_venta', 1);
		// Solo ventas que no sean retiro en tienda
		$this->db->where('v.id_transportista !=', 1);
		// Solo ventas que tengan direcccion válida
		$this->db->where('v.id_region !=', 0);
		if ($periodo == 'semestre') {
			$this->db->where('PERIOD_DIFF(date_format(now(), "%Y%m"), DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m")) <= 6');
		}
		else {
			$this->db->where('DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") = "' . $periodo . '"');
		}
		$this->db->group_by('mes');
		$this->db->group_by('v.id_region');
		$this->db->order_by('envios', 'DESC');
		$ventas = $this->db->get()->result_array();

		$regiones = $this->lista_regiones();


		$nombresRegiones = [];
		$enviosRegiones = [];
		$enviosTotales = 0;

		foreach ($ventas as $venta) {
			if (!empty($mesesPeriodo)) {
				// Para semestre
			}
			else {
				$enviosRegiones[$venta['id_region']] = $venta['envios'];
				$nombresRegiones[$venta['id_region']] = $regiones[$venta['id_region']];
				$enviosTotales += $venta['envios'];
			}
		}

		foreach ($regiones as $idRegion => $region){
			if ($periodo == 'semestre') {
				foreach ($mesesPeriodo as $mes) {
					$enviosRegiones[$idRegion][$mes] = 0;
				}
			}
			else {
				if (empty($enviosRegiones[$idRegion])) {
					$nombresRegiones[$idRegion] = $region;
					$enviosRegiones[$idRegion] = 0;
				}
			}
		}

		$result['enviosRM'] = $enviosRegiones[245];

		// Elimina RM de gráfico de regiones
		unset($nombresRegiones['245']);
		unset($enviosRegiones['245']);

		$result['nombresRegiones'] = $nombresRegiones;
		$result['enviosRegiones'] = $enviosRegiones;
		$result['enviosTotales'] = $enviosTotales;


		// Datos por Comuna

		$this->db->select('count(v.id) as envios, v.id_comuna, DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") as mes');
		$this->db->from('ventas v');
		$this->db->where('v.deleted', 0);		
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->where('v.ps_id_asociado', 0);
		$this->db->where('v.id_transportista >', 0);
		$this->db->where('v.id_canal', 1);
		$this->db->where('v.id_tipo_venta', 1);
		// Solo ventas que no sean retiro en tienda
		$this->db->where('v.id_transportista !=', 1);
		// Solo ventas que tengan direcccion válida
		$this->db->where('v.id_region', 245);
		if ($periodo == 'semestre') {
			$this->db->where('PERIOD_DIFF(date_format(now(), "%Y%m"), DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m")) <= 6');
		}
		else {
			$this->db->where('DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") = "' . $periodo . '"');
		}
		$this->db->group_by('mes');
		$this->db->group_by('v.id_comuna');
		$this->db->order_by('envios', 'DESC');
		$ventas = $this->db->get()->result_array();

		$comunas = $this->lista_comunas();

		$nombresComunas = [];
		$enviosComunas = [];

		foreach ($ventas as $venta) {
			if (!empty($mesesPeriodo)) {
				// Para semestre
			}
			else {
				$enviosComunas[$venta['id_comuna']] = $venta['envios'];
				$nombresComunas[$venta['id_comuna']] = $comunas[245][$venta['id_comuna']];
			}
		}

		foreach ($comunas[245] as $idComuna => $comuna){
			if ($periodo == 'semestre') {
				foreach ($mesesPeriodo as $mes) {
					$enviosComunas[$idComuna][$mes] = 0;
				}
			}
			else {
				if (empty($enviosComunas[$idComuna])) {
					$nombresComunas[$idComuna] = $comuna;
					$enviosComunas[$idComuna] = 0;
				}
			}
		}

		$result['nombresComunas'] = $nombresComunas;
		$result['enviosComunas'] = $enviosComunas;

		/*
		pr($this->db->last_query());
		pr($ventas);
		pr($enviosRegiones);
		die;
		*/
		return $result;
	}

	/**
	 * Entrega los datos de envíos realizados por los transportistas
	*/
	public function get_deliveries(){
		// Estados Enviados
		$estados = [4, 5];

		$this->db->select('count(v.id) as envios, v.id_transportista, t.nombre as transportista, DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m") as mes');
		$this->db->from('ventas v');
		$this->db->join('transportistas t','v.id_transportista = t.id', 'left');
		$this->db->where('v.deleted', 0);		
		$this->db->where_in('v.id_estado_venta', $estados);
		$this->db->where('v.ps_id_asociado', 0);
		$this->db->where('v.id_transportista >', 0);
		// No cuenta las compras en tienda retiradas en tienda
		$this->db->group_start();
			$this->db->where_not_in('v.id_canal', [2, 4, 7, 8, 12]);
			$this->db->or_where('v.id_transportista !=', 1);
		$this->db->group_end();

		$this->db->where('PERIOD_DIFF(date_format(now(), "%Y%m"), DATE_FORMAT(CASE WHEN v.fecha_envio > 0 THEN v.fecha_envio ELSE v.fecha END,"%Y%m")) <= 6');
		$this->db->group_by('mes');
		$this->db->group_by('t.nombre');
		$this->db->order_by('mes', 'ASC');
		$this->db->order_by('t.nombre', 'ASC');
		$ventas = $this->db->get()->result_array();

		$meses = [];
		foreach ($ventas as $venta) {
			$envios[$venta['id_transportista']][$venta['mes']] = $venta['envios'];
			$transportistas[$venta['id_transportista']] = $venta['transportista'];
			$meses[$venta['mes']] = $venta['mes'];
		}


		foreach ($meses as $mes) {
			foreach ($transportistas as $kt => $mt) {
				if (!empty($envios[$kt][$mes])) {
					$envios_final[$kt][$mes] = $envios[$kt][$mes];
				}
				else {
					$envios_final[$kt][$mes] = 0;
				}
			}
		}

		$result = [
			'envios' => $envios_final,
			'transportistas' => $transportistas
		];
		return $result;
	}

	/**
	 * Entrega los datos de ventas segun canal de venta (online o presencial)
	 * $cant indica los días que se mostrarán
	 */
	public function get_canales_diarios($cant = 30) {
		$iniDate = date('Y-m-d', strtotime('-'.$cant.' days'));
		//SELECT SUM(total) AS total, COUNT(DISTINCT(boleta)) AS boletas, DATE_FORMAT(fecha,'%Y%m') AS mes FROM ventas GROUP BY DATE_FORMAT(fecha,'%Y%m')
		$this->db->select('SUM(total) AS total, v.id_canal, DATE_FORMAT(fecha_venta,"%Y%m%d") AS fecha_key, DATE_FORMAT(fecha_venta,"%d-%m-%Y") AS dia, (ELT(WEEKDAY(fecha_venta) + 1, "Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom")) AS dia_semana');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where_in('v.id_tipo_venta', [1, 5]);
		$this->db->where('v.fecha_venta >=', $iniDate);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('fecha_key, id_canal');
		$this->db->order_by('fecha_key', 'DESC');
		//$this->db->limit($cant);
		$ventas = $this->db->get()->result_array();

		$canales = $this->get_canales();
		foreach ($canales as $keyCanal => $canal) {
			$totales[$keyCanal] = [];
		}

		foreach ($ventas as $venta) {
			$totales[$venta['id_canal']][$venta['fecha_key']] = $venta['total'];
		}

		$dias = array("Dom","Lun","Mar","Mié","Jue","Vie","Sab");

		$fecha = date('Ymd');
		$finales = [1 => [], 2 => []];
		for ($i = 0; $i < $cant; $i++) {
			foreach ($totales as $km => $canales) {
				if (!empty($totales[$km][$fecha])) {
					$finales[$km][$fecha] = $totales[$km][$fecha];
				}
				else {
					$finales[$km][$fecha] = 0;
				}
			}
			$canales_dias[$fecha] = $dias[date("w", strtotime($fecha))] . ' ' . date("d-m-Y", strtotime($fecha));
			$fecha = date("Ymd", strtotime($fecha . " - 1 days"));
		}

		foreach ($finales as $km => $canales) {
			$return['totales'][$km] = array_reverse($finales[$km], true);
		}

		$return['dias'] = array_reverse($canales_dias, true);

		$this->db->select('id, nombre, color');
		$this->db->from('canales');
		$this->db->where('deleted', 0);
		$this->db->order_by('id', 'ASC');

		$cs = $this->db->get()->result_array();

		foreach($cs as $c) {
			$return['nombres'][$c['id']] = $c['nombre'];
			$return['colores'][$c['id']] = $c['color'];
		}

		return $return;
	}

	/**
	 * Entrega los datos de ventas segun canal de venta (online o presencial) de los ultimos 3 meses
	*/
	public function get_canales_mensual() {
		$iniDate = date('Y-m-d', strtotime('first day of -2 month'));

		//SELECT SUM(total) AS total, COUNT(DISTINCT(boleta)) AS boletas, DATE_FORMAT(fecha,'%Y%m') AS mes FROM ventas GROUP BY DATE_FORMAT(fecha,'%Y%m')
		$this->db->select('SUM(total) AS total, v.id_canal, DATE_FORMAT(fecha_venta,"%Y%m") AS mes_key, DATE_FORMAT(fecha_venta,"%m-%Y") AS mes, (ELT(MONTH(fecha_venta), "ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC")) AS nombre_mes');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('v.fecha_venta >=', $iniDate);
		$this->db->where('v.deleted', 0);
		$this->db->group_by('mes_key, id_canal');
		$this->db->order_by('mes_key', 'DESC');
		//$this->db->limit(9);
		$ventas = $this->db->get()->result_array();

		$canales = $this->get_canales();
		foreach ($canales as $keyCanal => $canal) {
			$totales[$keyCanal] = [];
		}

		foreach ($ventas as $venta) {
			$totales[$venta['id_canal']][$venta['mes_key']] = $venta['total'];
		}

		$meses = array("", "ENE", "FEB", "MAR", "ABR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC");

		$newCant = 3;

		$fecha = date('Ymd', strtotime('first day of this month'));
		$fechaKey = date('Ym');

		// Se asocian ventas a los últimos 3 meses
		for ($i = 0; $i < $newCant; $i++) {
			foreach ($totales as $km => $canales) {
				if (!empty($totales[$km][$fechaKey])) {
					$finales[$km][$fechaKey] = $totales[$km][$fechaKey];
				}
				else {
					$finales[$km][$fechaKey] = 0;
				}
			}
			$canales_meses[$fechaKey] = $meses[date("n", strtotime($fecha))] . ' ' . date("Y", strtotime($fecha));
			$fecha = date("Ymd", strtotime($fecha . " - 1 months"));
			$fechaKey = date("Ym", strtotime($fecha));
		}

		$return['totales'] = [];
		foreach($finales as $finalKey => $final) {
			$return['totales'][$finalKey] = array_reverse($final, true);
		}
		ksort($return['totales']);

		$return['meses'] = array_reverse($canales_meses, true);

		return $return;
	}

	/**
	 * Entrega datos de ventas mensuales
	*/
	public function mensual($periodo, $tipo = 0, $id_canal = null) {
		$result['meta'] = 50000000;

		$this->db->select('id, nombre, color, activo');
		$this->db->from('canales');
		$this->db->where('deleted', 0);
		$this->db->order_by('destacado', 'DESC');
		if ($tipo == 1) {
			$this->db->where('mayorista', 0);
		}
		if ($tipo == 2) {
			$this->db->where('mayorista', 1);
		}

		// NUEVO FILTRO DE CANAL
		if (!empty($id_canal)) {
			if (is_array($id_canal)) {
				$this->db->where_in('id', $id_canal);
			} else {
				$this->db->where('id', $id_canal);
			}
		}

		$canalesDetalles = $this->db->get()->result_array();

		$canalesActivos = [];

		$canales = [];
		$filtroCanales = [];
		foreach ($canalesDetalles as $canal) {
			$canales[$canal['id']] = $canal['nombre'];
			$result['canal'][$canal['id']] = 0;
			$result['porcentaje']['canal'][$canal['id']] = 0;
		}

		$this->db->select('id_tipo_venta, id_canal, SUM(total) AS total');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m") = ', $periodo);
		$this->db->where('v.bonifica', 1);
		$this->db->where_in('v.id_canal', array_keys($canales));
		$this->db->where('v.deleted', 0);
		$this->db->group_by('id_tipo_venta, id_canal');
		$this->db->order_by('total', 'DESC');
		$ventas = $this->db->get()->result_array();

		$result['total'] = 0;
		$result['porcentaje']['total'] = 0;
		if (!empty($ventas)) {
			foreach ($ventas as $v) {
				$t = $v['total'];
				$result['total'] += $t;
				$result['canal'][$v['id_canal']] = (empty($result['canal'][$v['id_canal']]) ? $t : $result['canal'][$v['id_canal']] + $t);
				$canalesActivos[$v['id_canal']] = $canales[$v['id_canal']];
			}
			ksort($result['canal']);

			$result['porcentaje']['total'] = round(($result['total'] * 100) / $result['meta'], 2);

			// Porcentaje de cada canal de venta sobre el total de ventas del mes
			foreach ($result['canal'] as $keyCanal => $canal) {
				$result['porcentaje']['canal'][$keyCanal] = round(($canal * 100) / $result['total'], 2);
			}
		}

		$tt = '';
		$ln = '';
		foreach($result['canal'] as $idc => $tc) {
			if ($tc > 0) {
				$tt .= $ln . $canales[$idc]. ': ' . clp($tc);
				$ln = '<br />';
			}
		}

		$result['detalle_total'] = $tt;


		// Si el periodo es el actual se agregan los canales activos sin ventas
		if ($periodo == date('Ym')) {
			foreach ($canalesDetalles as $canal) {
				if (empty($canalesActivos[$canal['id']]) && $canal['activo'] == 1) {
					$canalesActivos[$canal['id']] = $canal['nombre'];
				}
			}
		}

		// Ventas por categoria
		$this->db->select('p.id_categoria, SUM(pv.precio_total) AS total');
		$this->db->from('ventas v');
		$this->db->join('productos_ventas pv', 'v.id = pv.id_venta', 'inner');
		$this->db->join('productos p', 'pv.id_producto = p.id', 'inner');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m") = ', $periodo);
		$this->db->where('v.bonifica', 1);
		$this->db->where_in('v.id_canal', array_keys($canales));
		$this->db->where('v.deleted', 0);
		$this->db->group_by('p.id_categoria');
		$ventasPorCategoria = $this->db->get()->result_array();

		$result['categoria'] = [];
		$result['porcentaje']['categoria'] = [];

		foreach ($ventasPorCategoria as $vc) {
			$idCategoria = $vc['id_categoria'];
			$totalCategoria = $vc['total'];
			$result['categoria'][$idCategoria] = $totalCategoria;

			if ($result['total'] > 0) {
				$result['porcentaje']['categoria'][$idCategoria] = round(($totalCategoria * 100) / $result['total'], 2);
			} else {
				$result['porcentaje']['categoria'][$idCategoria] = 0;
			}
		}
		arsort($result['porcentaje']['categoria']);

		// === DATOS PARA GRÁFICO CATEGORÍAS ===
		$CI =& get_instance();
		$CI->load->model('categoria_model', 'Categoria');
		$categorias = $this->Categoria->list();

		$result['labelsCategorias'] = [];
		$result['dataCategorias'] = [];
		foreach ($result['porcentaje']['categoria'] as $id => $porcentaje) {
			$nombre = $categorias[$id];
			$result['labelsCategorias'][] = $nombre;
			$result['dataCategorias'][] = $result['categoria'][$id];
		}

		// Fin ventas por categoria

		// Ventas por Proveedor
		$this->db->select('p.id_proveedor, SUM(pv.precio_total) AS total');
		$this->db->from('ventas v');
		$this->db->join('productos_ventas pv', 'v.id = pv.id_venta', 'inner');
		$this->db->join('productos p', 'pv.id_producto = p.id', 'inner');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m") = ', $periodo);
		$this->db->where('v.bonifica', 1);
		$this->db->where_in('v.id_canal', array_keys($canales));
		$this->db->where('v.deleted', 0);
		$this->db->group_by('p.id_proveedor');
		$ventasPorProveedor = $this->db->get()->result_array();

		$result['proveedor'] = [];
		$result['porcentaje']['proveedor'] = [];

		foreach ($ventasPorProveedor as $vp) {
			$idProveedor = $vp['id_proveedor'];
			$totalProveedor = $vp['total'];
			$result['proveedor'][$idProveedor] = $totalProveedor;

			if ($result['total'] > 0) {
				$result['porcentaje']['proveedor'][$idProveedor] = round(($totalProveedor * 100) / $result['total'], 2);
			} else {
				$result['porcentaje']['proveedor'][$idProveedor] = 0;
			}
		}
		arsort($result['porcentaje']['proveedor']);

		// === DATOS PARA GRÁFICO PROVEEDORES ===
		$CI->load->model('proveedor_model', 'Proveedor');
		$proveedores = $this->Proveedor->lista();

		$labelsProveedores = [];
		$dataProveedores = [];
		foreach ($result['porcentaje']['proveedor'] as $id => $porcentaje) {
			$nombre = $proveedores[$id]; // Usa un array $proveedores[id] => nombre si lo tienes
			$result['labelsProveedores'][] = $nombre;
			$result['dataProveedores'][] = $result['proveedor'][$id];
		}
		// Fin ventas por proveedor


		// Consultar total de ventas por día por canal
		// Calcular días que tiene el mes
		$mes = substr($periodo, 4, 2);
		$anno = substr($periodo, 0, 4);
		$mesInicio = $anno . '-' . $mes . '-' . '01';
		$diasMes = date("t", strtotime($mesInicio));

		$this->db->select('SUM(total) AS total, v.id_canal, DATE_FORMAT(fecha_venta,"%e") AS dia_key, DATE_FORMAT(fecha_venta,"%Y%m%d") AS fecha_key, DATE_FORMAT(fecha_venta,"%d-%m-%Y") AS dia, (ELT(WEEKDAY(fecha_venta) + 1, "Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom")) AS dia_semana');
		$this->db->from('ventas v');
		$this->db->join('estados_ventas ev','v.id_estado_venta = ev.id', 'left');
		$this->db->group_start();
			$this->db->where('ev.vendido', 1);
			$this->db->or_where('ev.reservado', 1);
		$this->db->group_end();
		$this->db->where('v.id_tipo_venta', 1);
		$this->db->where('DATE_FORMAT(v.fecha_venta, "%Y%m") = ', $periodo);
		$this->db->where('v.deleted', 0);
		$this->db->where('v.bonifica', 1);
		$this->db->where_in('v.id_canal', array_keys($canales));
		$this->db->group_by('fecha_key, id_canal');
		$this->db->order_by('fecha_key', 'ASC');

		$dias = $this->db->get()->result_array();
		//prx($dias);

		// Acumulado total y por canal
		$fechas = [];
		$diarios = [];
		$acumulados = [];

		if (!empty($dias)) {
			foreach	($dias as $dia) {
				$diarios[$dia['id_canal']][$dia['dia_key']] = $dia['total'];
			}

			$nombreDias = array("Dom","Lun","Mar","Mié","Jue","Vie","Sab");

			for ($i = 1; $i <= $diasMes; $i++) {

				$fecha = $anno . '-' . $mes . '-' . ($i < 10 ? '0' . $i : $i);
				$fechas[$i] = $nombreDias[date("w", strtotime($fecha))] . ' ' . date("d-m-Y", strtotime($fecha));

				if ($i == 1) {
					$acumulados[0][$i] = 0;
				}
				else {
					$acumulados[0][$i] = $acumulados[0][$i - 1];
				}

				$totalDiario[$i] = 0;
				foreach ($diarios as $canalKey => $canal) {
					if (!empty($canal[$i])) {
						$acumulados[0][$i] += $canal[$i];
						$totalDiario[$i] += $canal[$i];
						if ($i == 1) {
							$acumulados[$canalKey][$i] = $canal[$i];
						}
						else {
							$acumulados[$canalKey][$i] = $canal[$i] + $acumulados[$canalKey][$i - 1];
						}
					}
					else {
						$diarios[$canalKey][$i] = 0;
						if ($i == 1) {
							$acumulados[$canalKey][$i] = 0;
						}
						else {
							$acumulados[$canalKey][$i] = $acumulados[$canalKey][$i-1];
						}
					}
				}
				$acumulados['meta'][$i] = round($i * $result['meta'] / $diasMes, 0);
			}
			$diarios[0] = $totalDiario;
		}

		// Ordena elementos para entregar data a gráficos
		ksort($diarios);
		foreach($diarios as &$canal){
			ksort($canal);
		}

		$result['fechas'] = $fechas;
		$result['diarios'] = $diarios;
		$result['acumulados'] = $acumulados;
		$result['canales_activos'] = $canalesActivos;
		//prx($result);
		return $result;
	}


	public function total_categorias(array $filtros) {
		// -----------------------------
		// 1. Totales por categoría
		// -----------------------------
		$this->db
			->select('
				c.id AS id_categoria,
				c.nombre AS categoria,
				SUM(pv.precio_total) AS total_vendido
			')
			->from('productos_ventas pv')
			->join('ventas v', 'v.id = pv.id_venta')
			->join('productos p', 'p.id = pv.id_producto')
			->join('categorias c', 'c.id = p.id_categoria')
			->where('v.fecha_venta >=', $filtros['fecha_desde'])
			->where('v.fecha_venta <', date('Y-m-d', strtotime($filtros['fecha_hasta'] . ' +1 day')));

		if (!empty($filtros['id_canal'])) {
			$this->db->where('v.id_canal', $filtros['id_canal']);
		}

		if (!empty($filtros['id_proveedor']) && $filtros['id_proveedor'] !== 'Todos') {
			$this->db->where('p.id_proveedor', $filtros['id_proveedor']);
		}

		$this->db->group_by('c.id');
		$this->db->order_by('total_vendido', 'DESC');

		$categorias = $this->db->get()->result_array();

		// -----------------------------
		// 2. Total vendido en la tienda
		// -----------------------------
		$total_tienda = array_sum(array_column($categorias, 'total_vendido'));

		// -----------------------------
		// 3. Calcular porcentajes
		// -----------------------------
		foreach ($categorias as &$c) {
			$c['porcentaje_tienda'] = $total_tienda > 0
				? round(($c['total_vendido'] / $total_tienda) * 100)
				: 0;
		}

		return [
			'total_tienda' => $total_tienda,
			'categorias'   => $categorias
		];
	}


	public function total_ubicaciones(array $filtros) {
		// -----------------------------
		// 1. Totales por ubicación
		// -----------------------------
		$this->db
			->select('
				COALESCE(pv.id_ubicacion, 0) AS id_ubicacion,
				IFNULL(u.nombre, "Sin ubicación") AS ubicacion,
				SUM(pv.precio_total) AS total_vendido
			')
			->from('productos_ventas pv')
			->join('ubicaciones u', 'u.id = pv.id_ubicacion', 'left')
			->join('ventas v', 'v.id = pv.id_venta')
			->join('productos p', 'p.id = pv.id_producto')
			->where('v.fecha_venta >=', $filtros['fecha_desde'])
			->where('v.fecha_venta <', date('Y-m-d', strtotime($filtros['fecha_hasta'] . ' +1 day')));

		if (!empty($filtros['id_canal'])) {
			$this->db->where('v.id_canal', $filtros['id_canal']);
		}

		if (!empty($filtros['id_proveedor']) && $filtros['id_proveedor'] !== 'Todos') {
			$this->db->where('p.id_proveedor', $filtros['id_proveedor']);
		}

		$this->db->group_by('COALESCE(pv.id_ubicacion, 0)');
		$this->db->order_by('total_vendido', 'DESC');

		$ubicaciones = $this->db->get()->result_array();

		// ----------------------------------------
		// 2. Ventas por ubicación y categoría
		// ----------------------------------------
		$this->db
			->select('
				COALESCE(pv.id_ubicacion, 0) AS id_ubicacion,
				c.nombre AS categoria,
				SUM(pv.precio_total) AS total_categoria
			')
			->from('productos_ventas pv')
			->join('ventas v', 'v.id = pv.id_venta')
			->join('productos p', 'p.id = pv.id_producto')
			->join('categorias c', 'c.id = p.id_categoria')
			->where('v.fecha_venta >=', $filtros['fecha_desde'])
			->where('v.fecha_venta <', date('Y-m-d', strtotime($filtros['fecha_hasta'] . ' +1 day')));

		if (!empty($filtros['id_canal'])) {
			$this->db->where('v.id_canal', $filtros['id_canal']);
		}

		if (!empty($filtros['id_proveedor']) && $filtros['id_proveedor'] !== 'Todos') {
			$this->db->where('p.id_proveedor', $filtros['id_proveedor']);
		}

		$this->db->group_by(['COALESCE(pv.id_ubicacion, 0)', 'c.id']);

		$categorias = $this->db->get()->result_array();

		// Total vendido en toda la tienda
		$total_tienda = array_sum(array_column($ubicaciones, 'total_vendido'));

		// Indexar categorías por ubicación
		$catPorUbicacion = [];

		foreach ($categorias as $row) {
			$catPorUbicacion[$row['id_ubicacion']][] = $row;
		}

		// Armar resultado final
		foreach ($ubicaciones as &$u) {

			$u['porcentaje_tienda'] = $total_tienda > 0
				? round(($u['total_vendido'] / $total_tienda) * 100)
				: 0;

			$u['categoria_top'] = null;
			$u['categoria_porcentaje'] = 0;

			if (!empty($catPorUbicacion[$u['id_ubicacion']])) {

				usort($catPorUbicacion[$u['id_ubicacion']], function ($a, $b) {
					return $b['total_categoria'] <=> $a['total_categoria'];
				});

				$top = $catPorUbicacion[$u['id_ubicacion']][0];

				$u['categoria_top'] = $top['categoria'];
				$u['categoria_porcentaje'] = $u['total_vendido'] > 0
					? round(($top['total_categoria'] / $u['total_vendido']) * 100)
					: 0;
			}
		}

		return [
			'total_tienda' => $total_tienda,
			'ubicaciones'  => $ubicaciones
		];
	}


/************************* Otras Ediciones *****************************************************/

	/**
	 * Actualiza saldo de la tienda
	 * $total: nuevo monto de venta a sumar
	 * $total_anterior: monto antiguo de la venta a restar
	 */
	public function ajusta_saldo($total = 0, $total_anterior = 0) {
		$dinero = [];
		//Consulta saldo de la tienda
		$this->db->select('id, monto');
		$this->db->from('dineros d');
		$this->db->where('d.id_tipo_dinero', 0);
		$this->db->where('d.deleted', 0);
		$saldo = $this->db->get()->row_array();
		$dinero['monto'] = $saldo['monto'];

		//Suma el nuevo monto de la venta  y resta monto anterior de la venta
		$dinero['monto'] += $total - $total_anterior;
		$this->db->where('id', $saldo['id']);
		$this->db->update('dineros', $dinero);
		return true;
	}

	/**
	 * Nuevo ajusta stock
	 * Considera stock, reservados y disponibles
	 * Actualiza Stock de productos de la venta
	 * $data: datos de los productos e id de venta
	 * @since 30/05/2021
	 */
	public function ajusta_stock($data = []) {
		$changes = [];
		$pvs = [];
		$productosAfectados = [];

		//Si estaba en estado 1 se ajusta stock de los productos
		if (!empty($data['id'])) {
			//Buscar todas las ventas productos
			$this->db->select('*, pv.id as id, pv.precio as precio');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p','pv.id_producto = p.id');
			$this->db->where('pv.id_venta', $data['id']);
			$this->db->where('pv.deleted', 0);
			$this->db->where('p.deleted', 0);
			$productosVentas = $this->db->get()->result_array();

			foreach ($productosVentas as $pv) {
				$pvAnteriores[$pv['id']] = $pv;
			}

			// Si no vienen datos de venta se buscan para restablecer stock de almacen
			if (empty($data['venta_anterior'])) {
				$this->db->select('id_transportista');
				$this->db->from('ventas');
				$this->db->where('id', $data['id']);
				$data['venta_anterior'] = $this->db->get()->row_array();
			}

			// Buscar almacen que corresponde a venta anterior
			if (!empty($data['venta_anterior'])) {
				$this->db->select('id_almacen');
				$this->db->from('transportistas');
				$this->db->where('id', $data['venta_anterior']['id_transportista']);
				$transportistaAnterior = $this->db->get()->row_array();
				// Si no tiene almacen se asume bodega
				$idAlmacenAnterior = $transportistaAnterior['id_almacen'] ?? 1;
			}

			// Si antes estaba vendido o reservado se restablece stock
			/**
			 * Recordar que siempe stock = disponibles + reservados
			 */

			if ($data['vendido_anterior'] == 1 || 
					$data['enviado_anterior'] == 1 || 
					$data['reservado_anterior'] == 1) {

				//Reestablece stock de productos
				foreach ($productosVentas as $pv) {
					if (!empty($pv['id_producto'])) {
						$producto = [];
						// Busca registro de almacen producto
						$this->db->select('id, stock, disponibles, reservados');
						$this->db->from('almacenes_productos');
						$this->db->where('id_producto', $pv['id_producto']);
						$this->db->where('id_almacen', $idAlmacenAnterior);
						$almacenProducto = $this->db->get()->row_array();
						// Nuevo almacen producto para ajustar stocks
						$ap = [];
						if (empty($almacenProducto)) {
							$almacenProducto = [
								'id' => null,
								'stock' => 0,
								'disponibles' => 0,
								'reservados' => 0
							];
							$ap['id_producto'] = $pv['id_producto'];
							$ap['id_almacen'] = $idAlmacenAnterior;
						}

						// Restablece saldo
						if ($data['vendido_anterior'] == 1) {
							$producto['total_vendido'] = $pv['total_vendido'] - $pv['precio_total'];
							$producto['vendidos'] = $pv['vendidos'] - $pv['cantidad'];
						}
						//Restablece Stock
						if ($data['enviado_anterior'] == 1) {
							$producto['stock'] = $pv['stock'] + $pv['cantidad'];
							//Reestablecer Stock Almacen
							$ap['stock'] = $almacenProducto['stock'] + $pv['cantidad'];
						}
						//Restablece reservados
						if ($data['reservado_anterior'] == 1) {
							$producto['reservados'] = $pv['reservados'] - $pv['cantidad'];
							// Reestablecer reservados Almacen
							$ap['reservados'] = $almacenProducto['reservados'] - $pv['cantidad'];
						}
						// Reestablecer disponibles
						$producto['disponibles'] = $pv['disponibles'] + $pv['cantidad'];
						// Reestablecer disponibles Almacen
						$ap['disponibles'] = $almacenProducto['disponibles'] + $pv['cantidad'];

						$this->db->where('id', $pv['id_producto']);
						$this->db->update('productos', $producto);

						// Actualizar Producto Almacen => Si no existía no se crea
						if (!empty($almacenProducto['id'])) {
							$this->db->where('id', $almacenProducto['id']);
							$this->db->update('almacenes_productos', $ap);
						}

						$productosAfectados[$pv['id_producto']][$idAlmacenAnterior] = true;
					}
				}
			}

			if (!empty($data['id_producto'])) {
				// Buscar almacen que corresponde a nueva venta
				$this->db->select('id_almacen');
				$this->db->from('transportistas');
				$this->db->where('id', $data['id_transportista']);
				$transportista = $this->db->get()->row_array();
				$idAlmacen = $transportista['id_almacen'];

				$cambiaTransportista = (
					!empty($data['venta_anterior']['id_transportista']) &&
					$data['venta_anterior']['id_transportista'] != $data['id_transportista']
				);

				// Carga preventiva por si se necesita
				if (!isset($this->Notificacion)) {
					$this->load->model('Notificacion_model', 'Notificacion');
				}

				// Recorre cada producto de la venta
				foreach ($data['id_producto'] as $key => $idProducto) {
					$nuevo = FALSE;
					if (!empty($idProducto) && !empty($data['cantidad'][$key])) {
						$pv = [];
						$pv_anterior = [];
						$pv['id_venta'] = $data['id'];
						$pv['id_producto'] = $idProducto;
						$pv['cantidad'] = $data['cantidad'][$key];
						$pv['precio_normal'] = $data['precio_normal'][$key];
						$pv['descuento'] = $data['descuento_producto'][$key];
						$pv['precio'] = $data['precio'][$key];
						$pv['precio_total'] = $data['cantidad'][$key] * $data['precio'][$key];

						// Definir id_ubicacion solo si corresponde
						if (empty($data['id_producto_venta'][$key])) {
							// Producto nuevo en la venta → siempre calcula ubicación
							$pv['id_ubicacion'] = $this->get_id_ubicacion_producto($idProducto, $idAlmacen);
						}
						else {
							// Producto existente
							if ($cambiaTransportista) {
								// Cambió transportista → recalcular ubicación
								$pv['id_ubicacion'] = $this->get_id_ubicacion_producto($idProducto, $idAlmacen);
							}
							else {
								// NO cambió transportista → mantener ubicación anterior
								$pv['id_ubicacion'] = $pvAnteriores[$data['id_producto_venta'][$key]]['id_ubicacion'];
							}
						}


						// Si es nuevo se guarda y se registra como cambio
						if (empty($data['id_producto_venta'][$key])) {
							$nuevo = TRUE;
							$this->db->insert('productos_ventas', $pv);
							$pv['id'] = $this->db->insert_id();
							$changes[$pv['id']] = $pv;
							$pvs[] = $pv['id'];
						}
						else {
							// Si no es nuevo se actualiza y se analizan los cambios
							$pva = $pvAnteriores[$data['id_producto_venta'][$key]];
							$this->db->where('id', $pva['id']);
							$this->db->update('productos_ventas', $pv);
							$pv['id'] = $pva['id'];
							$pvs[] = $pv['id'];

							$pvc = [];
							foreach ($pv as $k => $v) {
								if ($pva[$k] != $v) {
									$pvc[$k] = ['anterior' => $pva[$k], 'actual' => $v];
								}
							}
							if (!empty($pvc)) {
								if (empty($pvc['id_producto'])) {
									$pvc['id_producto'] = $pv['id_producto'];
								}
								$changes[$pva['id']] = $pvc;
							}
						}

						// Movimientos de stock en productos
						if ((!empty($data['vendido']) && $data['vendido'] == 1) || 
							(!empty($data['reservado']) && $data['reservado'] == 1)) {

							// Busca registro de producto
							$this->db->select('*');
							$this->db->from('productos p');
							$this->db->where('p.id', $idProducto);
							$this->db->where('p.deleted', 0);
							$producto = $this->db->get()->row_array();

							// Busca registro de almacen producto
							$this->db->select('id, stock, disponibles, reservados, deseados_max');
							$this->db->from('almacenes_productos');
							$this->db->where('id_producto', $pv['id_producto']);
							$this->db->where('id_almacen', $idAlmacen);
							$almacenProducto = $this->db->get()->row_array();
							// Nuevo almacen producto para ajustar stocks
							$ap = [];
							if (empty($almacenProducto)) {
								$almacenProducto = [
									'id' => null,
									'stock' => 0,
									'disponibles' => 0,
									'reservados' => 0
								];
								$ap['id_producto'] = $pv['id_producto'];
								$ap['id_almacen'] = $idAlmacen;
							}

							// Ajusta Vendidos
							if ($data['vendido'] == 1) {
								$producto['vendidos'] = $producto['vendidos'] + $pv['cantidad'];
								$producto['total_vendido'] = $producto['total_vendido'] + $pv['precio_total'];
							}
							// Ajusta Stock
							if ($data['enviado']) {
								$producto['stock'] = $producto['stock'] - $pv['cantidad'];
								$ap['stock'] = $almacenProducto['stock'] - $pv['cantidad'];
							}
							// Ajusta Reservados
							if ($data['reservado']) {
								$producto['reservados'] = $producto['reservados'] + $pv['cantidad'];
								$ap['reservados'] = $almacenProducto['reservados'] + $pv['cantidad'];
							}
							// Ajusta Disponibles
							$producto['disponibles'] = $producto['disponibles'] - $pv['cantidad'];
							$ap['disponibles'] = $almacenProducto['disponibles'] - $pv['cantidad'];


							if (!empty($data['fecha_venta'])) {
								if (empty($producto['ultima_venta']) || $producto['ultima_venta'] == '0000-00-00') {
									$producto['ultima_venta'] = $data['fecha_venta'];
								}
								else if (strtotime($data['fecha_venta']) > strtotime($producto['ultima_venta'])) {
									$producto['ultima_venta'] = $data['fecha_venta'];
								}
							}
							$this->db->where('id', $idProducto);
							$this->db->update('productos', $producto);

							// Descuenta stock de marketplaces asociados al canal, si aplica
							if ($data['descuenta_stock'] == 1 && $data['id_transportista'] != 27) {
								// Obtener marketplaces del canal actual
								$this->db->where('id_canal', $data['id_canal']);
								$this->db->where('deleted', 0);
								$marketplaces = $this->db->get('marketplaces')->result();

								foreach ($marketplaces as $marketplace) {
									$idMarketplace = $marketplace->id;

									// Buscar registro del producto en el marketplace
									$this->db->where('id_producto', $pv['id_producto']);
									$this->db->where('id_marketplace', $idMarketplace);
									$this->db->where('deleted', 0);
									$row = $this->db->get('marketplaces_productos')->row();

									if ($row) {
										$nuevoStock = $row->stock - $pv['cantidad'];

										$this->db->where('id', $row->id);
										$this->db->update('marketplaces_productos', ['stock' => $nuevoStock]);
									} 
									// Si el registro no existe debería haber error al seleccionar el producto
									// Revisar cuál sería el funcionamiento deseado
									else {
										$dataInsert = [
											'id_producto'    => $pv['id_producto'],
											'id_marketplace' => $idMarketplace,
											'stock'          => 0 - $pv['cantidad'],
											'activo'         => 1
										];

										$this->db->insert('marketplaces_productos', $dataInsert);
									}
								}
							}

							// Actualizar Producto Almacen => Si no existía SI se crea
							if (!empty($almacenProducto['id'])) {
								$this->db->where('id', $almacenProducto['id']);
								$this->db->update('almacenes_productos', $ap);
							}
							else {
								$this->db->insert('almacenes_productos', $ap);
							}

							$disponiblesAntes = isset($almacenProducto['disponibles']) ? $almacenProducto['disponibles'] : 0;
							$disponiblesDespues = $ap['disponibles'];

							$productosAfectados[$pv['id_producto']][$idAlmacen] = true;

							// 1. Info del almacén actual
							$this->db->from('almacenes');
							$this->db->where('id', $idAlmacen);
							$this->db->where('deleted', 0);
							$almacen = $this->db->get()->row_array();

							$nombreProducto = $data['producto'][$key];

							if ($nuevo && $ap['disponibles'] < 1) {
								// Agotado en tienda / exclusiva / central
								$this->Notificacion->evaluar_agotado_tienda($idProducto, $idAlmacen, $data['producto'][$key], $data['id_canal']);

								// Agotado para venta online solo si aplica
								if ($almacen['stock_online'] == 1) {
									$this->Notificacion->evaluar_agotado_online($idProducto, $idAlmacen, $data['producto'][$key]);
								}
							}
							/*

							// Verifica si aplica notificación
							if ($nuevo && $ap['disponibles'] < 1 && $almacenProducto['deseados_max'] > 1) {
								// === Notificación 1: Agotado en TIENDA con deseados > 1 ===
								if ($almacen['tipo'] == 2) { // 2 = tienda
									$tieneExclusivo = FALSE;
									$stockExclusivo = 0;

									// 2.1 Si la tienda tiene bodega exclusiva asignada, revisa primero ahí
									if (!empty($almacen['id_bodega_exclusiva'])) {
										$this->db->from('almacenes_productos ap');
										$this->db->join('almacenes a', 'ap.id_almacen = a.id', 'left');
										$this->db->where('id_almacen', $almacen['id_bodega_exclusiva']);
										$this->db->where('id_producto', $idProducto);
										$this->db->where('ap.deleted', 0);
										$this->db->where('a.deleted', 0);
										$bodegaExclusiva = $this->db->get()->row_array();

										if ($bodegaExclusiva && $bodegaExclusiva['disponibles'] > 0) {
											$tieneExclusivo = TRUE;
											$stockExclusivo = $bodegaExclusiva['disponibles'];
										}
									}

									if ($tieneExclusivo) {
										// Para este caso se notifica al usuario logueado, que es quien está realizando la venta
										// Notifica que repongan desde bodega exclusiva
										$unidades = $stockExclusivo > 1 ? 'Existen '. $stockExclusivo.' unidades' : 'Existe 1 unidad';
										$mensaje = 'Producto '.$nombreProducto.' agotado en '.$almacen['nombre'].'. '.$unidades.' en '.$bodegaExclusiva['nombre'].' para reponer.';
											$this->Notificacion->agregar('2', 'agotado_exclusiva', $mensaje, $_SESSION['usuario']['id'], base_url("productos/detalle/{$idProducto}"));

										//Agregar notificacion a usuarios con id_canal asignado
										// Notificacion a Edu // Temporal
										//$this->Notificacion->agregar('2', 'agotado_exclusiva', $mensaje, 1, base_url("productos/detalle/{$idProducto}"));
									} 
									else {
										// 2.2 Si no tiene exclusivo, revisa bodegas centrales (tipo = 1)
										$this->db->select('SUM(ap.disponibles) as total');
										$this->db->from('almacenes_productos ap');
										$this->db->join('almacenes a', 'a.id = ap.id_almacen');
										$this->db->where('ap.id_producto', $idProducto);
										$this->db->where('a.tipo', 1);          // 1 = bodega central
										$this->db->where('a.stock_valido', 1);  // solo válidas
										$this->db->where('ap.deleted', 0);
										$this->db->where('a.deleted', 0);
										$res = $this->db->get()->row_array();

										$stockCentrales = $res ? (int)$res['total'] : 0;

										if ($stockCentrales > 0) {
											$notificados = [];
											// Busca usuarios que serán notificados:
											// Usuario logueado
											$unidades = $stockCentrales > 1 ? 'Existen '. $stockCentrales.' unidades' : 'Existe 1 unidad';

											$mensaje = 'Producto '.$nombreProducto.' agotado en '.$almacen['nombre'].'. '.$unidades.' en bodega para reponer.';
											// Deja de notificar a quien hace la venta para notificar a coordinadores y encargados de tienda
											//$this->Notificacion->agregar('2', 'agotado_central', $mensaje, $_SESSION['usuario']['id'], base_url("productos/detalle/{$idProducto}"));
											//$notificados[] = $_SESSION['usuario']['id'];

											// Usuarios del grupo 2 y 3
											$this->db->from('usuarios');
											$this->db->where_in('id_grupo', [2, 3]);
											$this->db->where('deleted', 0);
											$coordinadores = $this->db->get()->result_array();
											
											foreach($coordinadores as $uc){
												// Solo envía notificacion a coordinadores generales o a coordinador del canal especifico
												if ($uc['id_canal'] == 0 || $uc['id_canal'] == $data['id_canal']) {
													if (!in_array($uc['id'], $notificados)){
														$this->Notificacion->agregar('2', 'agotado_central', $mensaje, $uc['id'], base_url("productos/detalle/{$idProducto}"));
														$notificados[] = $uc['id'];
													}
												}
											}

											// Notificación a Edu // Temporal
											if (!in_array(1, $notificados)){
												$this->Notificacion->agregar('2', 'agotado_central', $mensaje, 1, base_url("productos/detalle/{$idProducto}"));
											}
										}
									}
								}
							}
							*/
							/*
							
							// === Notificación 2: Agotado en almacén online ===
							if ($nuevo && $ap['disponibles'] < 1 && $almacen['stock_online'] == 1) {
								// Busca stock disponible Online
								$this->db->select('SUM(ap.disponibles) as total');
								$this->db->from('almacenes_productos ap');
								$this->db->join('almacenes a', 'a.id = ap.id_almacen');
								$this->db->where('ap.id_producto', $idProducto);
								$this->db->where('a.stock_online', 1);
								$this->db->where('a.stock_valido', 1);
								$this->db->where('a.deleted', 0);
								$this->db->where('ap.deleted', 0);
								$stockOnline = $this->db->get()->row_array();

								if ($stockOnline['total'] == 0) {
									// Buscar en otros almacenes válidos pero NO online
									$this->db->select('SUM(ap.disponibles) as total');
									$this->db->from('almacenes_productos ap');
									$this->db->join('almacenes a', 'a.id = ap.id_almacen');
									$this->db->where('ap.id_producto', $idProducto);
									$this->db->where('a.stock_online', 0);
									$this->db->where('a.stock_valido', 1);
									$this->db->where('a.deleted', 0);
									$this->db->where('ap.deleted', 0);
									$stockNoOnline = $this->db->get()->row_array();

									if ($stockNoOnline['total'] > 0) {
										$notificados = [];
										// Genera notificación a grupo 2 y Edu
										$mensaje = 'Producto ' . $nombreProducto . ' agotado para Venta Online pero existe stock en otros almacenes.';

										$this->Notificacion->agregar('2', 'agotado_online', $mensaje, $_SESSION['usuario']['id'], base_url("productos/detalle/{$idProducto}"));
										$notificados[] = $_SESSION['usuario']['id'];

										// Usuarios del grupo 2 y 3
										$this->db->from('usuarios');
										$this->db->where_in('id_grupo', [2, 3]);
										$this->db->where('deleted', 0);
										$coordinadores = $this->db->get()->result_array();

										foreach($coordinadores as $uc){
											if ($uc['id_canal'] == 0) {
												if (!in_array($uc['id'], $notificados)){
													$this->Notificacion->agregar('2', 'agotado_online', $mensaje, $uc['id'], base_url("productos/detalle/{$idProducto}"));
													$notificados[] = $uc['id'];
												}
											}
										}
										
										// Notificación a Edu // Temporal
										if (!in_array(1, $notificados)){
											$this->Notificacion->agregar('2', 'agotado_online', $mensaje, 1, base_url("productos/detalle/{$idProducto}"));
										}
									}
								}
							}

							*/
						}
					}
					else {
						// Un producto no tiene idProducto

					}
				}

				// Se eliminan todos los productos_ventas que ya no están
				$productoVenta['deleted'] = 1;
				$this->db->where('id_venta', $data['id']);
				$this->db->where_not_in('id', $pvs);
				$this->db->update('productos_ventas', $productoVenta);
			}

			if (!empty($productosAfectados)) {
				if (!isset($this->Quiebre)) {
					$this->load->model('Quiebre_model', 'Quiebre');
				}
				foreach ($productosAfectados as $idProducto => $almacenes) {
					foreach ($almacenes as $idAlmacen => $v) {
						$this->Quiebre->evaluar_quiebre($idProducto, $idAlmacen, 7);
					}
					$this->Quiebre->evaluar_quiebre_interno($idProducto, 7);
				}

			}
		}
		return $changes;
	}

	/**
	 * Ajusta stock considerando que solo se cambia el estado
	 * Considera stock, reservados y disponibles
	 * Actualiza Stock de productos de la venta
	 * $data: datos de los productos e id de venta
	 * @since 30/05/2021
	 */
	public function ajusta_stock_estado($data) {
		//Si estaba en estado 1 se ajusta stock de los productos
		if (!empty($data['id'])) {
			//Buscar todas los productos ventas
			$this->db->select('*, pv.id as id, pv.precio as precio');
			$this->db->from('productos_ventas pv');
			$this->db->join('productos p','pv.id_producto = p.id');
			$this->db->where('pv.id_venta', $data['id']);
			$this->db->where('pv.deleted', 0);
			$this->db->where('p.deleted', 0);
			$productosVentas = $this->db->get()->result_array();


			$this->db->select('id_transportista, id_almacen');
			$this->db->from('ventas v');
			$this->db->join('transportistas t','v.id_transportista = t.id');
			$this->db->where('v.id', $data['id']);
			$this->db->where('v.deleted', 0);
			$this->db->where('t.deleted', 0);
			$venta = $this->db->get()->row_array();
			// Si trasnporte no define almacen se asume bodega
			$idAlmacen = $venta['id_almacen'] ?? 1;

			// Por cada producto_venta: restablecemos y luego descontamos según nuevo estado
			foreach ($productosVentas as $pv) {
				if (!empty($pv['id_producto'])) {
					//setea datos anteriores del producto
					$producto['total_vendido'] = $pv['total_vendido'];
					$producto['vendidos'] = $pv['vendidos'];
					$producto['stock'] = $pv['stock'];
					$producto['reservados'] = $pv['reservados'];
					$producto['disponibles'] = $pv['disponibles'];

					// Busca registro de almacen producto
					$this->db->select('id, stock, disponibles, reservados');
					$this->db->from('almacenes_productos');
					$this->db->where('id_producto', $pv['id_producto']);
					$this->db->where('id_almacen', $idAlmacen);
					$almacenProducto = $this->db->get()->row_array();
					// Nuevo almacen producto para ajustar stocks
					$ap = [];
					if (empty($almacenProducto)) {
						$almacenProducto = [
							'id' => null,
							'stock' => 0,
							'disponibles' => 0,
							'reservados' => 0
						];
						$ap['id_producto'] = $pv['id_producto'];
						$ap['id_almacen'] = $venta['id_almacen'];
					}

					$ap['stock'] = $almacenProducto['stock'];
					$ap['disponibles'] = $almacenProducto['disponibles'];
					$ap['reservados'] = $almacenProducto['reservados'];

					//pr('Restablece Stock');
					// Restablece saldo
					if ($data['vendido_anterior'] == 1) {
						//pr('Vendido anterior == 1');
						//pr('Total Vendido: '.$producto['total_vendido'].' => '.($pv['total_vendido'] - $pv['precio_total']));
						//pr('Vendidos: '.$producto['vendidos'].' => ' . ($pv['vendidos'] - $pv['cantidad']));
						$producto['total_vendido'] = $pv['total_vendido'] - $pv['precio_total'];
						$producto['vendidos'] = $pv['vendidos'] - $pv['cantidad'];
					}
					//Restablece Stock
					if ($data['enviado_anterior'] == 1) {
						//pr('Enviado anterior == 1');
						//pr('Stock: '.$producto['stock'].' => ' . ($pv['stock'] + $pv['cantidad']));
						$producto['stock'] = $pv['stock'] + $pv['cantidad'];
						$ap['stock'] = $almacenProducto['stock'] + $pv['cantidad'];
					}
					//Restablece reservados
					if ($data['reservado_anterior'] == 1) {
						//pr('Reservado anterior == 1');
						//pr('Reservados: '.$producto['reservados'].' => ' . ($pv['reservados'] - $pv['cantidad']));
						$producto['reservados'] = $pv['reservados'] - $pv['cantidad'];
						$ap['reservados'] = $almacenProducto['reservados'] - $pv['cantidad'];
					}
					if ($data['enviado_anterior'] == 1 || $data['reservado_anterior'] == 1) {
						//pr('Enviado anterior == 1 || Reservado anterior == 1');
						//pr('Disponibles: '.$producto['disponibles'].' => ' . ($pv['disponibles'] + $pv['cantidad']));
						$producto['disponibles'] = $pv['disponibles'] + $pv['cantidad'];
						$ap['disponibles'] = $almacenProducto['disponibles'] + $pv['cantidad'];
					}

					//Descuenta o suma según nuevo estado
					if ($data['vendido'] == 1) {
						$producto['vendidos'] = $producto['vendidos'] + $pv['cantidad'];
						$producto['total_vendido'] = $producto['total_vendido'] + $pv['precio_total'];
					}
					if ($data['enviado'] == 1) {
						$producto['stock'] = $producto['stock'] - $pv['cantidad'];
						$ap['stock'] = $ap['stock'] - $pv['cantidad'];
					}
					if ($data['reservado'] == 1) {
						$producto['reservados'] = $producto['reservados'] + $pv['cantidad'];
						$ap['reservados'] = $ap['reservados'] + $pv['cantidad'];
					}
					if ($data['enviado'] == 1 || $data['reservado'] == 1) {
						$producto['disponibles'] = $producto['disponibles'] - $pv['cantidad'];
						$ap['disponibles'] = $ap['disponibles'] - $pv['cantidad'];
					}

					$this->db->where('id', $pv['id_producto']);
					$this->db->update('productos', $producto);

					// Actualizar Producto Almacen => Si no existía SI se crea
					if (!empty($almacenProducto['id'])) {
						$this->db->where('id', $almacenProducto['id']);
						$this->db->update('almacenes_productos', $ap);
					}
					else {
						$this->db->insert('almacenes_productos', $ap);
					}
				}
			}
		}
		return TRUE;
	}



	/**
	 * Permite actualizar los detalles de las ventas
	 */
	public function update_detalle() {
		$ventas = $this->get_all();
		foreach($ventas as $mes) {
			foreach($mes as $venta) {
				$this->db->select('pv.*');
				$this->db->from('productos_ventas pv');
				$this->db->where('pv.id_venta', $venta['id']);
				$this->db->where('pv.deleted', 0);
				$productosVentas = $this->db->get()->result_array();
				$detalle = [];
				foreach ($productosVentas as $productoVenta) {
					$detalle[$productoVenta['id_producto']] = $productoVenta['cantidad'];
				}
				$new_venta['detalle'] = json_encode($detalle);
				$this->db->where('id', $venta['id']);
				$this->db->update('ventas', $new_venta);
			}
		}
	}

	/**
	 * Actualiza estados vendido, enviado y reservado de las ventas segun el estado
	 * NO ACTUALIZA PRODUCTOS
	 */

	public function update_states($idProdcuto){
		$this->db->select('id, nombre, vendido, reservado, enviado');
		$this->db->from('estados_ventas');
		$this->db->where('deleted', 0);
		$estados = $this->db->get()->result_array();
		foreach($estados as $estado){
			$es[$estado['id']] = $estado;
		}

		// Buscar solo ventas del $idProducto Recibido
		$this->db->select('v.*');
		$this->db->from('ventas v');
		$this->db->join('productos_ventas pv','v.id = pv.id_venta AND pv.id_producto = ' . $idProdcuto);
		$this->db->where('v.deleted', 0);
		$this->db->where('pv.deleted', 0);
		$ventas = $this->db->get()->result_array();

		foreach ($ventas as $v) {
			$data = [];
			$data['vendido'] = $es[$v['id_estado_venta']]['vendido'];
			$data['reservado'] = $es[$v['id_estado_venta']]['reservado'];
			$data['enviado'] = $es[$v['id_estado_venta']]['enviado'];
			$this->db->where('id', $v['id']);
			$this->db->update('ventas', $data);
		}
	}


	/* 
	 * Actualiza el estado de una venta
	 */
	public function change_state($idVenta, $idEstado) {
		// Trae datos de venta
		$this->db->select('id, id_tipo_venta, id_estado_venta, total, vendido, reservado, enviado, fecha_envio');
		$this->db->from('ventas v');
		$this->db->where('v.id', $idVenta);
		$venta = $this->db->get()->row_array();

		if ($venta['id_estado_venta'] == $idEstado) {
			return $idVenta;
		}

		$estadoAnterior = $venta['id_estado_venta'];
		$vendidoAnterior = $venta['vendido'];
		$reservadoAnterior = $venta['reservado'];
		$enviadoAnterior = $venta['enviado'];

		$venta['id_estado_venta'] = $idEstado;

		// Trae datos de estados
		$estados = $this->get_estados();
		$venta['vendido'] = $estados[$idEstado]['vendido'];
		$venta['reservado'] = $estados[$idEstado]['reservado'];
		$venta['enviado'] = $estados[$idEstado]['enviado'];

		if ((empty($venta['fecha_envio']) || $venta['fecha_envio'] == '0000-00-00') && $venta['enviado'] == 1) {
			$venta['fecha_envio'] = date('Y-m-d');
			$changes['fecha_envio'] = [
				'anterior' => '',
				'actual' => $venta['fecha_envio']
			];
		}

		// Guardar venta
		$this->db->where('id', $idVenta);
		$this->db->update('ventas', $venta);

		$venta['vendido_anterior'] = $vendidoAnterior;
		$venta['reservado_anterior'] = $reservadoAnterior;
		$venta['enviado_anterior'] = $enviadoAnterior;

		$totalAnterior = $venta['total'];
		//Ajusta saldo segun estados
		if ($venta['vendido'] == 0) {
			$venta['total'] = 0;
		}
		if ($venta['vendido_anterior'] == 0) {
			$totalAnterior = 0;
		}

		// Tipo venta no cambia
		if($venta['id_tipo_venta'] != 4){
			// Ajusta Dinero de la tienda
			// Venta cancelada no descontaría
			$this->ajusta_saldo($venta['total'], $totalAnterior);
		}

		//Ajusta Stock enviando datos de estado anterior
		$resp = $this->ajusta_stock_estado($venta);

		$changes['id_estado_venta'] = [
			'anterior' => $estadoAnterior,
			'actual' => $idEstado
		];

		//GUARDAR LOG CON CAMBIO DE ESTADO
		if (!empty($changes)) {
			$log = [
				'tipo_entidad' => 2,
				'id_entidad' => $idVenta,
				'id_usuario' => $_SESSION['usuario']['id'],
				'data' => json_encode($changes)
			];
			$this->db->insert('cambios_log', $log);
		}

		return $idVenta;
	}

	/* 
	 * Actualiza el estado de una venta y sus hijas
	 */
	public function change_parent_state($idVenta, $idEstado) {
		// Cambia estado de padre
		$changed[0]['id_venta'] = $this->change_state($idVenta, $idEstado);

		// Si todo OK busca hijas y cambia estado de sus hijas
		//valida ser el unico con ese ps_id
		$this->db->select('*');
		$this->db->from('ventas v');
		$this->db->where('v.id', $idVenta);
		$this->db->where('v.deleted', 0);
		$venta = $this->db->get()->row_array();

		$hijas = $this->get_hijas($venta['ps_id']);
		foreach ($hijas as $idHija => $psId) {
			$c['id_venta'] = $this->change_state($idHija, $idEstado);
			$changed[] = $c;
		}
		// Retorna arreglo con id de todas las ventas editadas
		return $changed;
	}

/******************************************************** Funciones prestashop *******************************************/

	/**
	 * Busca las ventas de prestahop que aun no han sido importadas
	 */
	public function ps_import(){
		if (ENVIRONMENT == 'production') {
			//$fecha_ini = '2020-09-01';
			$fecha_ini = date("Y-m-d",strtotime(date("Y-m-d") . "- 1 month"));
		}
		else {
			//$fecha_ini = '2022-01-01';
			$fecha_ini = date("Y-m-d",strtotime(date("Y-m-d") . "- 1 month"));
		}

		$this->db->select('ps_id');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('ps_id !=', 0);
		$this->db->where('created >', $fecha_ini);
		$this->db->order_by('created', 'DESC');
		$ventas = $this->db->get()->result_array();

		$imported = [];
		foreach ($ventas as $v) {
			$imported[] = $v['ps_id'];
		}

		$ps = $this->load->database('prestashop', TRUE);

		$ps->select("id_order, current_state, o.id_customer, o.id_carrier, id_address_delivery, payment, total_paid, total_products, total_shipping, o.date_add, firstname, lastname, c.id_default_group, ca.name as carrier_name");
		$ps->from('ps_orders o');
		$ps->join('ps_customer c','o.id_customer = c.id_customer');
		$ps->join('ps_carrier ca','o.id_carrier = ca.id_carrier', 'left');
		$ps->where('o.date_add >=', $fecha_ini);
		$ps->where('current_state !=', 6);
		if (!empty($imported)) {
			$ps->where_not_in('o.id_order', $imported);
		}
		$ps->order_by('o.date_add', 'ASC');
		$ventas_ps = $ps->get()->result_array();

		foreach ($ventas_ps as &$venta_ps) {
			$this->db->select('id');
			$this->db->from('clientes');
			$this->db->where('deleted', 0);
			$this->db->where('ps_id', $venta_ps['id_customer']);
			$cliente = $this->db->get()->row_array();

			if (!empty($cliente)) {
				$venta_ps['id_cliente'] = $cliente['id'];
			}
		}

		return $ventas_ps;
	}

	/**
	 * Entrega info de una venta de Prestashop
	 */
	public function ps_get($id){
		$prestashop = $this->load->database('prestashop', TRUE);

		$prestashop->select("o.id_order, o.current_state, o.id_customer, o.id_carrier, o.id_cart, id_address_delivery, payment, gift, gift_message, CAST(total_paid AS SIGNED) as total_paid, CAST(total_discounts AS SIGNED) as total_discounts, CAST(total_products AS SIGNED) as total_products, CAST(total_shipping AS SIGNED) AS total_shipping, DATE_FORMAT(o.date_add, '%Y-%m-%dT%H:%i:%s') as date_add, c.firstname, c.lastname, c.email, c.id_default_group as group, a.firstname as dir_firstname, a.lastname as dir_lastname, a.address1, a.address2, s.name as state_name, a.city, a.id_country, a.id_state, a.phone, a.dni, ca.name as carrier");
		$prestashop->from('ps_orders o');
		$prestashop->join('ps_customer c','o.id_customer = c.id_customer', 'left');
		$prestashop->join('ps_address a','o.id_address_delivery = a.id_address', 'left');
		$prestashop->join('ps_state s','a.id_state = s.id_state', 'left');
		$prestashop->join('ps_carrier ca','o.id_carrier = ca.id_carrier', 'left');
		$prestashop->where('o.id_order', $id);
		$venta_ps = $prestashop->get()->row_array();

		$venta_ps['dir_firstname'] = ucwords(mb_strtolower($venta_ps['dir_firstname']));
		$venta_ps['dir_lastname'] = ucwords(mb_strtolower($venta_ps['dir_lastname']));
		$venta_ps['address1'] = ucwords(mb_strtolower($venta_ps['address1']));

		$rut_number = str_replace(' ', '', str_replace('-', '', str_replace('.', '', $venta_ps['dni'])));
		if (strlen($rut_number) == 9) {
				$venta_ps['rut'] = sprintf("%s.%s.%s-%s", substr($rut_number, 0, 2), substr($rut_number, 2, 3), substr($rut_number, 5, 3), substr($rut_number, 8, 1));
		}
		else if (strlen($rut_number) == 8) {
			$venta_ps['rut'] = sprintf("%s.%s.%s-%s", substr($rut_number, 0, 1), substr($rut_number, 1, 3), substr($rut_number, 4, 3), substr($rut_number, 7, 1));
		}

		$tmp_phone = str_replace('+', '', str_replace(' ', '', $venta_ps['phone']));
		if (strlen($tmp_phone) == 9) {
			$tmp_phone = '56' . $tmp_phone;
		}
		if (strlen($tmp_phone) == 11) {
			$venta_ps['phone'] = '+' . sprintf("%s %s %s %s", substr($tmp_phone, 0, 2), substr($tmp_phone, 2, 1), substr($tmp_phone, 3, 4), substr($tmp_phone, 7, 4));
		}

		// Para RM se elimina la ciudad
		if ($venta_ps['id_country'] == 245) {
			$venta_ps['city'] = '';
		}

		// Datos de cliente por ps_id//
		$this->db->select('*');
		$this->db->from('clientes');
		$this->db->where('ps_id', $venta_ps['id_customer']);
		$this->db->where('deleted', 0);
		$venta_ps['cliente'] = $this->db->get()->row_array();

		// Caso 1: ps_id_cliente existe
		if (!empty($venta_ps['cliente'])) {
			// Caso 1.1: ps_id_cliente existe pero email es vacío o diferente
			if ($venta_ps['cliente']['email'] != $venta_ps['email'] && $venta_ps['group'] != 2) {
				$cliente['email'] = $venta_ps['email'];
				$this->db->where('id', $venta_ps['cliente']['id']);
				$result = $this->db->update('clientes', $cliente);
			}
		}
		else {
			// Si ps_id_cliente no existe se busca por email
			$this->db->select('*');
			$this->db->from('clientes');
			$this->db->where('email', $venta_ps['email']);
			$this->db->where('deleted', 0);
			$tmp_clientes = $this->db->get()->result_array();

			if (empty($tmp_clientes)) {
				// Caso 2: Crea Cliente
			}

			$asociado = FALSE;
			foreach ($tmp_clientes as $tmp_cliente) {
				$cliente = [];
				// Caso 3: existe email sin ps_id => se asocia ps_id
				if ($tmp_cliente['ps_id'] == 0 && !$asociado) {
					$cliente['ps_id'] = $venta_ps['id_customer'];
					$this->db->where('id', $tmp_cliente['id']);
					$result = $this->db->update('clientes', $cliente);
					$venta_ps['cliente'] = $tmp_cliente;
					$asociado = TRUE;
				}
				// Caso 3.1: existe email con distinto ps_id => se limpia email
				else {
					$cliente['email'] = '';
					$this->db->where('id', $tmp_cliente['id']);
					$result = $this->db->update('clientes', $cliente);
					$asociado = TRUE;
				}
			}

			// Crea cliente nuevo
			// Para Caso 2 y Caso 
			if (empty($venta_ps['cliente'])) {
				$cliente['nombre'] = $venta_ps['firstname'] . ' ' . $venta_ps['lastname'];
				$cliente['ps_id'] = $venta_ps['id_customer'];
				if ($venta_ps['group'] != 2) {
					$cliente['email'] = $venta_ps['email'];
				}
				// Si está leyendo de PS se asume que se registró por web
				$cliente['id_canal_registro'] = 1;
				$result = $this->db->insert('clientes', $cliente);
				$cliente['id'] = $this->db->insert_id();
				$venta_ps['cliente'] = $cliente;
			}
		}

		// productos //
		$prestashop->select("product_id, product_name AS name, product_quantity AS quantity, CAST(unit_price_tax_incl as SIGNED) AS price, CAST(total_price_tax_incl as SIGNED) AS total, id_image");
		$prestashop->from('ps_order_detail od');
		$prestashop->join('ps_image i', 'od.product_id = i.id_product');
		$prestashop->where('id_order', $id);
		$prestashop->where('i.cover', 1);
		$productos_ps = $prestashop->get()->result_array();

		foreach ($productos_ps as &$pps) {
			$this->db->select('id, ps_id');
			$this->db->from('productos');
			$this->db->where('ps_id', $pps['product_id']);
			$this->db->where('deleted', 0);
			$p = $this->db->get()->row_array();
			$pps['id'] = $p['id'];
		}

		$venta_ps['products'] = $productos_ps;

		$prestashop->select("message");
		$prestashop->from('ps_message');
		$prestashop->where('id_order', $id);
		$mensajes_ps = $prestashop->get()->result_array();

		$venta_ps['messages'] = [];
		foreach ($mensajes_ps as $mps) {
			if ($mps['message'] != 'Pago exitoso') {
				$venta_ps['messages'][] = html_entity_decode($mps['message']);
			}
		}

		//Obtiene medio de pago 
		$this->db->select('id');
		$this->db->from('medios_pagos');
		$this->db->where('payment', $venta_ps['payment']);
		$this->db->where('deleted', 0);
		$medioPago = $this->db->get()->row_array();

		$venta_ps['id_medio_pago'] = 0;
		if (!empty($medioPago)) {
			$venta_ps['id_medio_pago'] = $medioPago['id'];
		}

		// Busca todos los pagos asociados al pedido
		$prestashop->select("op.id_order_payment, op.amount");
		$prestashop->from('ps_order_payment op');
		$prestashop->where('op.order_reference', $id);
		$payments = $prestashop->get()->result_array();

		$totalPagado = 0;
		foreach($payments as $payment) {
			$totalPagado += $payment['amount'];
		}
		$venta_ps['total_paid'] = intval($totalPagado);

		return $venta_ps;
	}

	public function get_order_state($id) {
		$ps = $this->load->database('prestashop', TRUE);
		$ps->from('ps_orders o');
		$ps->where('o.id_order', $id);
		$venta_ps = $ps->get()->row_array();

		$ps_state = 0;
		if (!empty($venta_ps['current_state'])) {
			$ps_state = $venta_ps['current_state'];
		}

		return $ps_state;
	}

	/**
	 * Entrega la cantidad de ventas nuevas que no se han importado desde prestashop
	*/
	public function count_news($id) {
		if (ENVIRONMENT == 'production') {
			//$fecha_ini = '2020-09-01';
			$fecha_ini = date("Y-m-d",strtotime(date("Y-m-d") . "- 1 month"));
		}
		else {
			$fecha_ini = '2024-01-01';
			//$fecha_ini = date("Y-m-d",strtotime(date("Y-m-d") . "- 1 month"));
		}

		$this->db->select('ps_id');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where('ps_id !=', 0);
		$this->db->where('created >', $fecha_ini);
		$this->db->order_by('created', 'DESC');
		$ventas = $this->db->get()->result_array();

		$count['count'] = 0;
		$psOrders = [];
		if (!empty($ventas)) {
			$imported = [];
			foreach ($ventas as $v) {
				$imported[] = $v['ps_id'];
			}

			$ps = $this->load->database('prestashop', TRUE);

			$ps->select("id_order");
			$ps->from('ps_orders o');
			$ps->where('o.date_add >=', $fecha_ini);
			$ps->where('current_state !=', 6);
			$ps->where_not_in('o.id_order', $imported);
			$psOrders = $ps->get()->result_array();
		}

		$_SESSION['count_news'] = count($psOrders);

		$pendientes = [
			7 => [ // Italia
				'importar' => 0,
				'preparar' => 0
			],
			8 => [ // Dominicos
				'importar' => 0,
				'preparar' => 0
			],
			12 => [ // Drugstore
				'importar' => 0,
				'preparar' => 0
			]
		];

		// Revisa estas ventas para ver si corresponden a ventas en tienda
		if (!empty($psOrders)) {
			$idsOrders = array_column($psOrders, 'id_order');

			// Traer todas las ventas con carrier
			$ps->select("o.id_order, c.id_carrier, c.name");
			$ps->from('ps_orders o');
			$ps->join('ps_carrier c', 'o.id_carrier = c.id_carrier', 'left');
			$ps->where_in('o.id_order', $idsOrders);
			$psOrders = $ps->get()->result_array();

			foreach($psOrders as $psOrder) {
				switch ($psOrder['name']) {
					case 'Retiro en Tienda Barrio Italia':
						$pendientes[7]['importar']++;
						break;

					case 'Retiro en Tienda Mall Plaza Los Dominicos':
						$pendientes[8]['importar']++;
						break;

					case 'Retiro en Tienda Drugstore':
						$pendientes[12]['importar']++;
						break;
				}
			}
		}

		// Busca ventas que tengan transportista retiro en tienda y se encuentren ene stado Pago Aceptado y Preparación en Curso
		$this->db->select('id, id_transportista');
		$this->db->from('ventas');
		$this->db->where('deleted', 0);
		$this->db->where_in('id_estado_venta', [2,3]); // Pago Aceptado y Preparación en Curso
		$this->db->where_in('id_transportista', [26, 28, 32]); // Retiros en tienda
		$this->db->order_by('created', 'DESC');
		$ventas = $this->db->get()->result_array();

		$pendientes[7]['transportista'] = 26;
		$pendientes[8]['transportista'] = 28;
		$pendientes[12]['transportista'] = 32;

		foreach($ventas as $venta) {
			switch ($venta['id_transportista']) {
				case 26:
					$pendientes[7]['preparar']++;
					break;

				case 28:
					$pendientes[8]['preparar']++;
					break;

				case 32:
					$pendientes[12]['preparar']++;
					break;
			}
		}

		$_SESSION['ventas_pendientes'] = $pendientes;
	}


	/**
	 * Entrega la cantidad de puntos acumulador por una venta según registro de ps_loyalty
	 */
	public function get_points($id = 0, $ps_id = 0) {
		$ps = $this->load->database('prestashop', TRUE);

		$ps->select("points");
		$ps->from('ps_loyalty l');
		
		if ($ps_id) {
			// Si venta tiene ps_id se busca por ps id
			$ps->where('id_order', $ps_id);
		}
		else {
			// Si venta no tiene ps_id se busca por id_venta
			$ps->where('id_venta', $id);
		}
		$order = $ps->get()->row_array();

		$points = 0;
		if (!empty($order['points'])) {
			$points = $order['points'];
		}
		return $points;
	}

	/* Se comentan porque no se usarán más pero sirve el codigo

	public function corrige_direcciones($limit = 50, $confirmacion = 0) {
		// Busca ventas que tengan id_region e id_comuna vaciones y tengan ps_id
		$dbps = (ENVIRONMENT == 'production') ? 'dementeg_presta' : 'dementelocal';


		$this->db->select('*');
		$this->db->from('ventas v');
		$this->db->join($dbps.'.ps_orders o','ON v.ps_id = o.id_order', 'left');
		$this->db->join($dbps.'.ps_address a','ON o.id_address_delivery = a.id_address', 'left');
		$this->db->where('v.deleted', 0);
		$this->db->where('ps_id !=', 0);
		$this->db->where('id_comuna', 0);
		$this->db->order_by('created', 'DESC');
		$this->db->limit($limit);
		$ventas = $this->db->get()->result_array();
		
		foreach($ventas as $v) {
			$v['rut'] = $v['dni'];
			if(!empty($v['dni'])) {
				$rutNumber = str_replace(' ', '', str_replace('-', '', str_replace('.', '', $v['dni'])));
				if (strlen($rutNumber) == 9) {
					$v['rut'] = sprintf("%s.%s.%s-%s", substr($rutNumber, 0, 2), substr($rutNumber, 2, 3), substr($rutNumber, 5, 3), substr($rutNumber, 8, 1));
				}
				else if (strlen($rutNumber) == 8) {
					$v['rut'] = sprintf("%s.%s.%s-%s", substr($rutNumber, 0, 1), substr($rutNumber, 1, 3), substr($rutNumber, 4, 3), substr($rutNumber, 7, 1));
				}
			}

			$tmpPhone = str_replace('+', '', str_replace(' ', '', $v['phone']));
			if (strlen($tmpPhone) == 9) {
				$tmpPhone = '56' . $tmpPhone;
			}
			if (strlen($tmpPhone) == 11) {
				$v['phone'] = '+' . sprintf("%s %s %s %s", substr($tmpPhone, 0, 2), substr($tmpPhone, 2, 1), substr($tmpPhone, 3, 4), substr($tmpPhone, 7, 4));
			}

			$despacho = $v['despacho'];
			if (!empty($v['despacho'])) {
				$obsParts = explode("\r\n+", $v['despacho']);
				if (!empty($obsParts[1])) {
					$secondParts = explode("\r\n", $obsParts[1]);
					$fono = array_shift($secondParts);
					$v['despacho'] = str_replace("\n", '', str_replace("\r", '', implode(' ', $secondParts)));
				}
			}

			$observaciones = $v['observaciones'];
			if (!empty($despacho)) {
				if (!empty($observaciones)) {
					$observaciones .= "\r\n----------\r\n";
				}
				$observaciones .= 'Info despacho anterior:' . "\r\n" . $despacho;
			}

			if (!empty($v['id_state'])) {
				$tmpVenta = [
					'dir_nombre' => $v['firstname'],
					'dir_apellidos' => $v['lastname'],
					'direccion' => $v['address1'],
					'id_region' => $v['id_country'],
					'id_comuna' => $v['id_state'],
					'telefono' => $v['phone'],
					'rut' => $v['rut'],
					'despacho' => $v['despacho'],
					'observaciones' => $observaciones
				];

				pr($tmpVenta);

				if ($confirmacion) {
					$this->db->where('id', $v['id']);
					$result = $this->db->update('ventas', $tmpVenta);
				}
			}
		}

	}

	public function corrige_direcciones_ps($limit = 50, $confirmacion = 0) {
		// Busca ventas que tengan id_region e id_comuna vaciones y tengan ps_id
		$ps = $this->load->database('prestashop', TRUE);

		$ps->select("*");
		$ps->from('ps_address');
		$ps->where('id_state', 0);
		$ps->limit($limit);

		$direcciones = $ps->get()->result_array();

		$this->db->select('*');
		$this->db->from('comunas');
		$comunas = $this->db->get()->result_array();

		foreach($comunas as $c) {
			$comunasNombres[normaliza($c['nombre'])] = $c;
		}

		$encontradas = 0;
		foreach($direcciones as $d) {
			$city = normaliza(trim($d['city']));
			if (!empty($comunasNombres[$city])) {
				$comunaEncontrada = $comunasNombres[$city];
				pr('Ciudad encontrada: ' . $city);
				pr($d);
				pr($comunaEncontrada);
				$encontradas++;

				$tmpAddress = [
					'id_country' => $comunaEncontrada['id_region'],
					'id_state' => $comunaEncontrada['id']
				];

				pr($tmpAddress);

				if($confirmacion) {
					$ps->where('id_address', $d['id_address']);
					$result = $ps->update('ps_address', $tmpAddress);
				}
			}
		}

		pr('Total comunas encontradas: ' . $encontradas);
		
	}
	*/

}