<?php
/*
  Clase SuperLineaPedidoCliente
 */

class SuperCabeceraCesta extends Objeto{
	//Variables estáticas que pertenecen a la cesta
	public static $cart = NULL;

	public $codigo = 0;
	public $cliente = 0;
	public $objeto_cliente = NULL;
	public $objetoCliente = NULL;
	public $hash = '';
	//Campos que no vienen de la tabla, los calculamos sobre la marcha:
	public $cantidad = 0;
    public $base = 0;
	public $importe = 0;
	public $descuento = 0;
	public $importe_sin_descuento = 0;
	public $puntos = 0;
	public $puntos_gastados = 0;
	//Pedro 11/Abril/2019 ==> Dirección y datos de contacto del usuario TODO
	public $nombre = '';
	public $email = '';
	public $direccion = '';
	public $cod_postal = '';
	public $localidad = '';
	public $provincia = '';
	public $pais = '';
	public $zona = 0;
	public $telefono = '';
	public $codigoDireccion = 0;
	//Pedro 12/Abril/2019 ==> Tipo de envío y forma de pago
	public $tipo_envio = 0;
	public $objeto_tipo_envio = NULL;
	public $forma_pago = 0;
	public $objeto_forma_pago = NULL;
	//22/Abril/2019 ==> Gastos de envío
	public $g_envio = 0;
	//Pedro 16/Abril/2019 ==> Esta variable actúa a modo de flag indicando que estamos editando la direccion actual:
	private $editando = false;
	//Pedro 24/Abril/2019 ==> Esta variable actúa a modo de flag indicando que estamos Creando una nueva dirección
	private $creando_direccion = false;
	//Pedro 30/Abril/2019 ==> Código promocional utilizado
	public $codigo_promocional = '';
	public $objeto_codigo_promocional = NULL;
	//Líneas del pedido
	public $lineas = array();
	
	public static function getCampos($soloPrincipal = NULL){
		self::$nombreTabla = strtolower(get_called_class());
		self::getTablaRelacionada();
		//self::$campos_tabla = BaseDatos::$dictionary->{self::$nombreTabla . 'Campos'}; //==> Comento esta línea porque creo que no sirve pa na
		//Una vez que tenemos el nombre de la tabla, vamos a obtener los campos de la misma y los nombres para la selec
		if (self::$nombreTabla != ''){
			$campos = ' ';
			if ($soloPrincipal || $soloPrincipal === NULL){
				//$campos .= BaseDatos::dameCamposAlias(BaseDatos::$dictionary->{self::$nombreTabla . 'Campos'}, self::getAlias());
				$campos .= BaseDatos::dameCamposAlias(self::$nombreTabla);
			}
			if ($soloPrincipal === false || $soloPrincipal === NULL){
				$campos .= ( (trim($campos) != ' ') ? ', ' : '' ) . 
				LineaCesta::getCampos() . ', ' . 
				Usuario::getCampos() . ', ' . 
				BaseDatos::dameCamposAlias('tmp_cabecera_pedidos_direccion') . ', ' .
				BaseDatos::dameCamposAlias('tipo_envio_cli') . ', ' .
				BaseDatos::dameCamposAlias('formas_de_pago');
			}
			if ($soloPrincipal == NULL){
				self::$camposSelect = $campos;
			}
		}
		return($campos);
	}
	
	public static function getNombreTabla($soloPrincipal = NULL){
		//Incluimos los globals para coger el valor del idioma:
		//include('comunes/globals.php');
		self::$nombreTabla = strtolower(get_called_class());
		self::getTablaRelacionada();
		//Ahora vamos a componer el nombre de la tabla teniendo en cuenta si es sólo principal, si no o si es todo (NULL)
		$consulta = ' ';
		if ($soloPrincipal || $soloPrincipal === NULL){
			$consulta .= self::$nombreTabla . ' as `' .  self::getAlias() . '` ';
		}
		if ($soloPrincipal === false || $soloPrincipal === NULL){
			$consulta .= self::getJoin('CabeceraCesta', 'cliente', 'Usuario', 'codigo');		//Cogemos el cliente
			$consulta .= self::getJoin('CabeceraCesta', 'codigo', 'LineaCesta', 'cabecera');	//Queremos esta tabla con la de artículo
			$consulta .= self::getJoin('CabeceraCesta', 'codigo', 'tmp_cabecera_pedidos_direccion', 'tmp_cabecera_pedidos');	//Queremos esta tabla con la de artículo
			$consulta .= self::getJoin('CabeceraCesta', 'tipo_envio', 'tipo_envio_cli', 'codigo');	//tipos de envío
			$consulta .= self::getJoin('CabeceraCesta', 'forma_pago', 'formas_de_pago', 'codigo');	//Formas de pago
			$consulta .= LineaCesta::getNombreTabla(false);										//Cogemos los left join de artículo
		}
		$consulta .= ' ';
		//Sólo asignamos el nombre de la tabla si no nos piden más parámetros
		if ($soloPrincipal == NULL){
			self::$nombreTabla = $consulta;
		}
		return($consulta);
	}
	
	public static function getWhereTabla(){
		$argumentos = func_get_args();
		$cliente = isset($argumentos[0]) ? $argumentos[0] : 0;
		$codigo = isset($argumentos[1]) ? $argumentos[1] : 0;
		$hash = isset($argumentos[2]) ? $argumentos[2] : '';
		$limitar = isset($argumentos[3]) ? $argumentos[3] : true;
		//include('comunes/globals.php');
		self::$whereSelect = '';
		if ($cliente > 0) {
			self::$whereSelect = ' `' . self::getAlias() . '`.`cliente` = "' . $cliente . '" ';
		}
		if ($codigo > 0) {
			self::$whereSelect .= (self::$whereSelect != '') ? ' AND ' : '';
			self::$whereSelect .= ' `' .  self::getAlias() . '`.`codigo` = "' . $codigo . '" ';
		}
		if ($hash != '') {
			//Si ya tengo un cliente, entonces hago un OR, si no un AND:
			if (self::$whereSelect != ''){
				if ($cliente > 0) {
					self::$whereSelect .= (self::$whereSelect != '') ? ' OR ' : '';
				}else{
					self::$whereSelect .= (self::$whereSelect != '') ? ' AND ' : '';
				}
			}
			self::$whereSelect .= ' `' .  self::getAlias() . '`.`hash` = "' . $hash . '" ';
		}
		if ($limitar){
			self::$whereSelect .= ' LIMIT 1 ';
		}
		return(self::$whereSelect);
	}
	
    function __construct($opciones = NULL) {
		//08/Mayo/2019 ==> Hay que inicualizar los campos en la lista de campos de la tabla sólo si no está inicializada:
		if (empty(static::$publicFieldList)){
			static::initPublicFields();
		}

		//TODO ==> Es interesante que siempre, después de esto llamemos a una función que quite del fieldList aquellos campos que no queremos que sean modificados 
		$opciones = new ObOptions($opciones);
		$filaCabecera = $opciones->getDefaultValue('filaCabecera', NULL);
		$codigoPedido = $opciones->getDefaultValue('codigoPedido', NULL);
		$objeto_cliente = $opciones->getDefaultValue('objeto_cliente', NULL);	//Si no nos pasan cliente, queremos que la carga se haga por sesion SIEMPRE
		$cargarLineas = $opciones->getDefaultValue('cargarLineas', true);
		$codigoCliente = $opciones->getDefaultValue('codigoCliente', 0);	//El código de cliente se le pasa para hacer la carga, no hay que cogerlo de la sesión para que la cesta se cargue por hash
		$crearSiNoExiste = $opciones->getDefaultValue('crearSiNoExiste', true);	//Pedro 11/Abril/2019 ==> Este flag crea una cesta si al cargarla no ex
		$fusionarCesta = $opciones->getDefaultValue('fusionarCesta', true);	//Esto hace que esta cesta compruebe el usuario logueado para realizar la fusión de productos
		$recalcularCesta = false;
		/*echo("Cargar líneas:\n");
		var_dump($cargarLineas);
		echo("----------\n");*/
		//Al crear este objeto puede ser la cesta asociada a la sesión (setStaticCart = false) o ser una cesta más
		$setStaticCart = false;
		
		$fila = NULL;
		if ($filaCabecera != NULL){
			$fila = $filaCabecera;
		}else{
			//Pedro 09/Abril/2019 ==> A partir de ahora la cesta se carga (después de por código) por hash. Así no se duplicará. En caso de estar logueado y cargar una cesta
				// que no tiene cliente, lo asignamos, guardamos y fusionamos con lo que hubiera antes
			$sentencia_sql = 'SELECT ' . self::getCampos() . ' 
									FROM ' . self::getNombreTabla() . ' ' ;
			$sentencia_where = '';
			if (intval($codigoPedido) > 0) {	// ==> Si tengo un código de pedido lo cargo (no suele ser lo normal)
				//Preparamos el FROM con las uniones correspondientes
				$sentencia_where = ' WHERE ' . self::getWhereTabla(NULL, $codigoPedido, '', false); //Cargamos todas las líneas del pedido
			}else if ($codigoCliente > 0 || ($objeto_cliente != NULL && $objeto_cliente->codigo > 0) ){
				if ($codigoCliente == 0){
					$codigoCliente = $objeto_cliente->codigo;
				}
				$sentencia_where = ' WHERE ' . self::getWhereTabla($codigoCliente, NULL, '', false); //Cargamos todas las líneas del pedido
			}else{
				//En estos casos siempre se carga la cesta por hash, por tanto estamos con la estática
				$setStaticCart = true;
				//Vamos a cargar la cesta actual con el hash de la sesión:
				$sentencia_where = ' WHERE ' . self::getWhereTabla(NULL, NULL, $hash = Sesion::getHashSesion(), false);	//Estamos cargando la cesta con líneas
			}
			
			if ($sentencia_where != ''){
				$sentencia_sql = $sentencia_sql . $sentencia_where . '; ';
				//echo("$sentencia_sql\n");
				$bd = new BaseDatos();
				if ($bd->isConectado()){
					$bd->setConsultaSQL($sentencia_sql);
					$fila = $bd->getFila();
				}
				
			}
		}
		
		//echo("Toca cargar datos:\n");
		if ( $fila != NULL ){	// ==> Si hay que crearlo y/o tenemos fila entonces pasamos por aquí, en caso contrario hay que tener fila por narices
			//echo("Tenemos fila para cargar la cesta\n");
			//Para evitar muchos problemas de recursividad, desde este momento vamos a asignar la cesta a la variable estática
			if ($crearSiNoExiste){
				if (static::$cart != $this){
					$recalcularCesta = true;
					static::$cart = $this;
				}
			}

			//Extraemos los datos de la carga realizada
			$this->extractData($fila);

			//Vamos a ver si las líneas hay que cargarlas o vienen en la lista:
			$codigoLineaPedido = $this->getProp($fila, 'codigo', LineaCesta::getAlias());
			//Si el código es nulo, no nos lo han pasado y hay que cargarlo:
			//echo("Cargamos lineas?\n");
			if ($cargarLineas){
				//echo("Cargamos las líneas\n");
				if ($codigoLineaPedido == NULL){
					//echo("Cargamos las líneas pasando la cesta\n");
					//hay que cargar las líneas:
					//$this->lineas = LineaCesta::getList($this->codigo); //Paso el código, pero podría haber pasado el objeto pedido
					$this->lineas = LineaCesta::getList($this); //Paso el objeto, pero podría haber pasado el código
				}else{
					//echo("Se cargan las líneas con la select recibida\n");
					//tenemos las líneas cargadas en esta misma select:
					do{
						$tmp_linea = new LineaCesta(
							new OpcionesWidget(array(
								'filaLineaPedido' => $fila,
								'objetoPedido' => $this	// No es necesario, $fila ya lleva la cesta, pero esto es más rápido pues el objeto ya está creado
							)));
						$this->lineas[$tmp_linea->codigo] = $tmp_linea;						
					}while ($fila = $bd->getFila());
				}
			}else{
				//echo("No tenemos que cargar las líneas\n");
			}
		}else{
			//Else de control

		}
		
		//Pedro 06/Mayo/2019 ==> No hay que datos para esta cesta, pero vamo sa ver si hay una cesta para este usuario, en cuyo caso hay que fusionar:
		if ($cargarLineas){
			//Pedro 09/Mayo/2019 ==> Esto antes se hacía en la función anterior, pero si no había líneas, no se fusionaba la cesta. 
			//Hacemos un diagrama de flujo y llegamos a la conclusión de que la mejor manera de hacer esto es la siguiente:
			//No tengo código de usuario y hay un usuario logueado ==> Cargo la cesta del usuario logueado ==> mi código y el de la cesta del usuario logueado son 
			//	distintos ==> Funsionamos
			//Vamos a tener en cuenta que haya un usuario logueado y que esta cesta aún no tenga el cliente asignado:
			$objeto_cliente = Usuario::logueado();
			if ( ($fusionarCesta ) && ($this->cliente == 0) && ($objeto_cliente != NULL) ){	//Aprovecho el "short-circuit evaluation" de PHP que evalúa las condiciones en orden.
				//CUando pasa por aquí es porque la cesta no tiene cliente pero en la sesión si lo hay. Ahora vamos a fusionar cestas si hay una cesta anterior:
				if ($objeto_cliente->codigo > 0){
					$cesta_old = new CabeceraCesta(array('objeto_cliente' => $objeto_cliente, 'crearSiNoExiste' => false, 'fusionarCesta' => false));	//Cesta vieja cargada con el código de cliente
					if ( ($this->codigo != $cesta_old->codigo) && (!empty($cesta_old->lineas)) )	{
						//Hacemos la fusión, es el momento de asegurarnos de tener un código SIEMPRE:
						$this->setCode();
						//Fusionamos:
						foreach($cesta_old->lineas as $codigo_linea_old => $linea_old){
							//Resulta que la select de esta cesta provoca una línea vacía porque ya hay una cabecera de pedido con el cliente asignado (se ha provocado arriba al pulsar
							//Vamos a buscar en este carrito esta línea:
							$lote = $linea_old->lote;
							$oferta = $linea_old->oferta;
							$puntos_gastados = $linea_old->puntos_gastados;
							$nuevaCantidad = $linea_old->cantidad;
							$linea_actual = $this->findProduct($linea_old->objeto_articulo, array(
								'lote' => $lote,
								'oferta' => $oferta,
								'puntos_gastados' => $puntos_gastados
							));
							
							if ($linea_actual != NULL){
								//El producto está en la cesta actual, vamos a incrementarlo:
								$nuevaCantidad += $linea_actual->cantidad;
							}
							$this->addProduct(array(
								'objetoArticulo' => $linea_old->objeto_articulo,
								'linea' => $linea_actual,
								'lote' => $lote,
								'oferta' => $oferta,
								'puntos_gastados' => $puntos_gastados,
								'cantidad' => $nuevaCantidad
							));
							//Hecho esto, tenemos que meter la línea en la cesta si no estába metida
						}
						//Ahora tenemos que borrar toda la cesta old
						$cesta_old->deleteCart();
					}
				}
				//Lo último es guardar esta cesta después de la fusión
				$this->setCustomer(array('objetoCliente' => $objeto_cliente));
				$recalcularCesta = true;
			}
			
		}			
		
		//Ahora calculamos importes y demás datos de la cesta en caso de que esta cesta no sea la estática:
		if ($recalcularCesta){
			$this->recalculate();
		}
		
		//Pedro 10/Mayo/209 ==> Vamos a asegurarnos de que la cesta estática tenga SIEMPRE el congtenido correcto
		if ($crearSiNoExiste || $setStaticCart){
			static::$cart = $this;
		}
    }
	public function extractData($fila){
		$this->codigo = (int) $this->getProp($fila, 'codigo');
		$this->cliente = (int) $this->getProp($fila, 'cliente');
		if ($this->cliente > 0){
			$this->objetoCliente = $this->objeto_cliente = new Usuario(array('filaUsuario' => $fila));
		}
		$this->hash = $this->getProp($fila, 'hash');
		$this->nombre = $this->getProp($fila, 'nombre', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->email = $this->getProp($fila, 'email', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->direccion = $this->getProp($fila, 'direccion', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->cod_postal =  $this->getProp($fila, 'cod_postal', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->localidad = $this->getProp($fila, 'localidad', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->provincia = $this->getProp($fila, 'provincia', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->pais =  $this->getProp($fila, 'pais', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->zona = (int) $this->getProp($fila, 'zona', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->telefono = $this->getProp($fila, 'telefono', BaseDatos::dameAlias('tmp_cabecera_pedidos_direccion'));
		$this->tipo_envio = (int) $this->getProp($fila, 'tipo_envio');
		$this->objeto_tipo_envio = new TipoEnvioCliente(array('filaTipoEnvio' => $fila));
		$this->forma_pago = (int) $this->getProp($fila, 'forma_pago');
		$this->objeto_forma_pago = new FormasPago(array('filaFormaPago' => $fila));
		$this->codigoDireccion = (int) $this->getProp($fila, 'direccion_envio');
		$this->codigo_promocional = $this->getProp($fila, 'codigo_promocional');
		if ($this->codigo_promocional != ''){
			$this->objeto_codigo_promocional = new CodigosPromocionales(array('codigo_promocional' => $this->codigo_promocional));
		}
	}
	
	public static function initPublicFields(){
		//En esta función se deben de poner los nombres de los campos en la tabla
		//Sólo pondremos aquellos campos a los que les vamos a dar acceso al usuario
		$publicFieldList = array();
		$publicFieldList[] = 'codigo';
		$publicFieldList[] = 'cliente';
		$publicFieldList[] = 'hash';
		$publicFieldList[] = 'direccion_envio';
		$publicFieldList[] = 'tipo_envio';
		$publicFieldList[] = 'forma_pago';
		$publicFieldList[] = 'codigo_promocional';

		static::$publicFieldList = $publicFieldList;
	}
    function __destruct() {
        
    }

	public static function getCart($createIfNull = true){
		if (static::$cart == NULL){
			if ($createIfNull){
				static::$cart = new CabeceraCesta();	//Cargando así la cesta se mete sóla en el objeto estático
			}
		}else{
			$cart = static::$cart;
			$objeto_cliente =  Usuario::logueado();
			//Tenemos una cesta estática el problema es que podemos haberla cargado ANTES que otros datos como el cliente y por tanto puede estar incompleta.
				//Aquí vamos a chequear el cliente y hacer recálculos si procede:
			if ($cart->objeto_cliente != $objeto_cliente){
				$cart->setCustomer(array('objetoCliente' => $objeto_cliente));
				$cart->recalculate();
			}
			static::$cart = $cart;
		}
		return(static::$cart);
	}
	

	public static function remoteAddProduct($data){
		//En data tenemos los datos a añadir a la línea (producto, cantidad, lote, etc.)
		//Vamos a ver si en "data" tenemos un EAN:
		//Si data es un string, hay que des-serializarlo (viene en json):
		if (is_string($data)){
			$data = json_decode($data);
		}
		$objeto_articulo = NULL;
		$ean = '';
		$codigoArticulo = 0;
		$cantidad = 0;
		$accion = '';
		$lote = 0;
		$oferta = 0;
		$retorno = new stdClass();
		if (isset($data->codigo_articulo)){
			$ean = $data->codigo_articulo;
		}else if (isset($data->ean)){
			$ean = $data->ean;
		}
		if ($ean != ''){
			$objeto_articulo = new Articulo($ean);
		}
		//Si hemos podido cargar el artículo vamos a seguir:
		if (is_a($objeto_articulo, "Articulo")){
			//Vamos a cargar la sesión:
			Sesion::init();
			//Vamos a cargar la cesta:
			//echo("cargamos la cestita\n");
			$cart = static::getCart();
			//echo("cestita cargada\n");
			//Es importante comprobar que exista una cabecera:
			$cart->setCode();
			//Vamos a coger el resto de datos:
			$cantidad = (isset($data->cantidad))? $data->cantidad : NULL;
			$accion = (isset($data->accion))? $data->accion : NULL;
			$lote = (isset($data->lote))? $data->lote : NULL;
			$oferta = (isset($data->oferta))? $data->oferta : NULL;
			$puntos_gastados = (isset($data->puntos_gastados))? $data->puntos_gastados : NULL;
			$linea = static::findInCart($objeto_articulo, array('lote' => $lote, 'oferta' => $oferta, 'puntos_gastados' => $puntos_gastados));
			//Si la acción es restar, nos vamos a asegurar que siempre sea "sumar"
			if ($accion == 'restar'){
				$accion = 'sumar';
				$cantidad *= -1;
			}
			//Si no hay línea hay que crearla siempre que vayamos a insertar algo:
			if ( ($linea == NULL) && ($cantidad > 0) ){
				//Ahora hay que crear una línea:
				$linea = new LineaCesta(new OpcionesWidget(array('objetoPedido' => $cart, 'objetoArticulo' => $objeto_articulo)));
			}
			//Vamos a corregir la acción, en primer siempre se suma, nunca se resta:
			if ($linea != NULL){
				//Vamos a guardar la línea en la última borrada:
				Sesion::set('lastDeleted', clone $linea);
				
				//Ahora vamos a tener en cuenta si lo que nos pasan es absoluto o no:
				if ($accion == 'absoluto'){
					$nuevaCantidad = $cantidad;
				}else{
					//Cuando sumamos, tenemos que tener en cuenta la cantidad del lote y/o de la oferta:
					if ($linea->codigo_oferta > 0){
						//La cantidad de la línea está multiplicada por la cantida de la oferta:
						$nuevaCantidad = ($linea->cantidad/$linea->oferta->cantidad) + $cantidad;
					}else if ($linea->codigo_oferta > 0){
						$nuevaCantidad = $linea->cantidad + $cantidad;
					}else{					
						$nuevaCantidad = $linea->cantidad + $cantidad;
					}
				}
				//Vamos a controlar la acción y la nueva cantidad:
				//Ya tenemos la nueva cantidad a asignar, vamos a añadirla a la línea y a guardarla, pero ojo, que si es 0 o menor tenemos que borrar la línea:
				if ($nuevaCantidad <= 0){
					$nuevaCantidad = 0;
				}
				//echo("La nueva cantidad es: $nuevaCantidad\n");
				//Para que TODO se haga por el mismo proceso, llamamos al addProduct de la cesta:
				$cart->addProduct(array(
					'objetoArticulo' => $objeto_articulo,
					'linea' => $linea,
					'lote' => $lote,
					'oferta' => $oferta,
					'puntos_gastados' => $puntos_gastados,
					'cantidad' => $nuevaCantidad
				));

				//Recalculamos los importes y las cantidades del carrito:
				$cart->recalculate();

				//Por último hacemos un commit de la sesión para que se reflejen los cambios sobre el último borrado y otras cosas así:
				Sesion::commit();

			}
		}
		//Aquí tenemos que dar un retorno:
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public function addProduct($opciones){
		//Extraemos los datos de "options"
		$opciones = new ObOptions($opciones);
		$objetoArticulo = $opciones->getDefaultValue('objetoArticulo', NULL);
		$linea = $opciones->getDefaultValue('linea', NULL);
		$lote = $opciones->getDefaultValue('lote', 0);
		$oferta = $opciones->getDefaultValue('oferta', 0);
		$puntos_gastados = $opciones->getDefaultValue('puntos_gastados', 0);
		$cantidad = $opciones->getDefaultValue('cantidad', 0);
		//Es básico que la cesta tenga código para añadirle un producto
		if ($cantidad > 0){
			$this->setCode();
		}
		
		//Si no nos han pasado línea, la buscamos en esta cesta
		if($linea == NULL){
			//$linea = static::findInCart($objeto_articulo, array('lote' => $lote, 'oferta' => $oferta, 'puntos_gastados' => $puntos_gastados));
			$linea = $this->findProduct($objetoArticulo, array(
				'lote' => $lote,
				'oferta' => $oferta,
				'puntos_gastados' => $puntos_gastados
			));
		}
		//Si no ha y línea es pq es nueva, si la cantidad es positiva y no hay línea la creamos
		if (($linea == NULL) && ($cantidad > 0)){
			//Creamos una línea nueva:
			$linea = new LineaCesta(new OpcionesWidget(array('objetoPedido' => $this, 'objetoArticulo' => $objetoArticulo)));
		}
		if ($linea != NULL){
			//Ejecutamos el proceso de las líneas que asigna la cantidad y recalcula los precios
			$linea->setCantidad(new OpcionesWidget(array(
				'cantidad' => $cantidad,
				'oferta' => $oferta,
				'lote' => $lote,
				'puntos_gastados' => $puntos_gastados
			)));
			//Grabamos la línea
			$linea->grabar();
			//Ahora tenemos en cuenta si es un borrado o no
			if ($linea->cantidad == 0){
				unset($this->lineas[$linea->codigo]);
			}else{
				//Si no se ha borrado nada, quitamos la línea de la sesión:
				Sesion::remove('lastDeleted');
				//echo("codigo insertado: " . $linea->codigo . "\n");
				$this->lineas[$linea->codigo] = $linea;
			}
		}
	}
	
	public static function findInCart($product, $options = NULL){
		$cart = static::getCart();
		return($cart->findProduct($product, $options));
	}
	
	public function findProduct($product, $options = NULL){
		$lote = (isset($options['lote'])) ? $options['lote'] : NULL;
		$oferta = (isset($options['oferta'])) ? $options['oferta'] : NULL;
		$puntos_gastados = (isset($options['puntos_gastados'])) ? $options['puntos_gastados'] : NULL;
		$linea = NULL;
		$lineas = $this->lineas;
		if (is_array($lineas)){
			//echo("es un array---");
			foreach($lineas as $clave => $valor){
				//echo("Línea $clave---");
				//Vamos a buscar por ean o por código:
				if ( ($valor->ean == $product->ean) || ($valor->articulo == $product->codigo) ){
					//El producto está en la cesta, tenemos que ver si el lote o la oferta coinciden:
					if ( ($lote == NULL && $oferta == NULL && $puntos_gastados == NULL)
							&&
						($valor->lote == NULL && $valor->oferta == NULL && $valor->puntos_gastados == NULL) ){
						$linea = $valor;
						break;
					}else if ( ($lote != NULL) && ($lote == $valor->lote) ){
						$linea = $valor;
						break;
					}else if ( ($oferta != NULL) && ($oferta == $valor->codigo_oferta) ){
						$linea = $valor;
						break;
					}else if ( ($puntos_gastados != NULL) && ($puntos_gastados == $valor->puntos_gastados) ){
						$linea = $valor;
						break;
					}
					
				}
			}
		}
		return($linea);
	}

	//Esta función indica si podemos finalizar el pedido o no
	public function readyToFinish(){
		$retorno = true;
		//Si no hay líneas, no seguimos mirando nada:
		if ($this->cantidad == 0){
			$retorno = false;
		}
		//El usuario tiene que ser distinto de NULL (usuario logueado o con datos de envío)
		if ($this->objeto_cliente == NULL){
			$retorno = false;
		}
		//Si no hay tipo de envío no seguimos:
		if ($this->objeto_tipo_envio->codigo == 0){
			$retorno = false;
		}else{
			//Aquí falta ver si la dirección de envío está completa (Si el envío requiere envío)
			
			//Si el tipo de envío requiere pago y el pago no es correcto, entonces no podemos seguir
				//Al igual que antes, niego la condición
			if (!( (!$this->objeto_tipo_envio->requiere_pago) || ($this->objeto_forma_pago->codigo > 0) )){
				$retorno = false;
			}
		}
		return($retorno);
	}
	
	//Finalizamos el pedido grabándolo en la BD en la tabla de pedidos y enviando los emails que sean correspondientes:
		//Devuelve el código del pedido creado
	public function finish(){
		return(PedidoCliente::newOrderFromCart($this));
	}

	public function shippingCosts(){
		//Aquí vamos a meter más adelante el cálculo de los gastos de envío, por ahora son 0
		$this->g_envio = 0;
		//Si no hay total, no hay gastos de envío:
		if ($this->cantidad > 0){
			if ($this->objeto_tipo_envio != NULL){
				$this->g_envio = $this->objeto_tipo_envio->getGastosEnvio();
			}
		}
		return($this->g_envio);
	}
	
	public static function currentShippingCosts(){
		//Aquí vamos a meter más adelante el cálculo de los gastos de envío, por ahora son 0
		$retorno = 0;
		$cart = static::getCart();
		return($cart->shippingCosts());
	}
	
	public function empty(){
		foreach($this->lineas as $clave => $linea){
			$linea->setCantidad(new OpcionesWidget(array(
					'cantidad' => 0,
					'oferta' => $linea->oferta,
					'lote' => $linea->lote,
					'puntos_gastados' => $linea->puntos_gastados
				)));
			$linea->grabar();
			unset($this->lineas[$clave]);
		}
		$this->recalculate();
	}
	
	public static function emtpyCart(){
		Sesion::remove("lastDeleted");
		//Vamos a actualizar los componentes que nos han pasado:
		$cart = static::getCart();
		$cart->empty();
	}
	//------------------------------------------------------------------------------------------
	//Funciones remotas
	//------------------------------------------------------------------------------------------
	public static function remoteDiscardRestoreProduct($data){
		Sesion::remove("lastDeleted");
		//Vamos a actualizar los componentes que nos han pasado:
		$retorno = new stdClass();
		//Por último hacemos un commit de la sesión:
		Sesion::commit();
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public static function remoteEmtpyCart($data){
		static::emtpyCart();
		$retorno = new stdClass();
		//Por último hacemos un commit de la sesión:
		Sesion::commit();
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public function deleteCart(){
		//si hay líneas, vacío el carrito:
		if (count($this->lineas) > 0){
			$this->empty();
		}
		//Ahora hago el delete:
		$currentCart = static::getCart(false);
		//Si el carrito de la sesión es el que estamos borrando, hay que quitarlo también de la sesión
		if ($currentCart != NULL){
			if ($currentCart->codigo == $this->codigo){
				static::$cart == NULL;
			}
		}
		//Ahora eliminamos la dirección asociada:
		$sentencia_sql = 'DELETE FROM `tmp_cabecera_pedidos_direccion` WHERE `tmp_cabecera_pedidos` = \'' . $this->codigo . '\'; ';
		//por último, borramos de la BD:
		$sentencia_sql .= 'DELETE FROM `' . static::getNombreTablaSinAlias() . '` WHERE `codigo` = \'' . $this->codigo . '\'; ';
		$bd = new BaseDatos();
		if ($bd->isConectado()){
			$bd->setConsultaSQL($sentencia_sql);
		}
		
	}

	//Pedro 11/Abril//2019 ==> Vamos a asegurarnos con esta función de que esta cesta tiene código, para eso sólo metemos el hash 
	private function setCode(){
		if ($this->codigo == 0){
			$bd = new BaseDatos();
			$hash = Sesion::getHashSesion();
			if ($bd->isConectado()){
				$sentencia_sql = 'INSERT INTO `' . self::getNombreTablaSinAlias() . '` ( `hash` )
							VALUES (\'' . $hash . '\') 
							ON DUPLICATE KEY UPDATE `hash` = VALUES(`hash`) ;';
				$bd->setConsultaSQL($sentencia_sql);
				$sentencia_sql = 'SELECT ' . self::getCampos(true) . ' 
								FROM ' . self::getNombreTabla(true) . ' 
								WHERE ' . self::getWhereTabla(NULL, NULL, $hash, false);
				$bd->setConsultaSQL($sentencia_sql);
				$fila = $bd->getFila();
				$this->codigo = $this->getProp($fila, 'codigo');
			}
		}
	}
	
	//Pedro 11/Abril/2019 ==> Estas funciones grabarán en la tabla de la cabecera otros datos como Tipo de envío, forma de pago, gastos de envío, totales, etc:
	private function recalculate(){
		$this->cantidad = 0;
		$this->base = 0;
		$this->importe = 0;
		$this->importe_sin_descuento = 0;
		$this->puntos = 0;
		$this->puntos_gastados = 0;
		$this->descuento = 0;
		foreach($this->lineas as $clave => $valor){
			$this->cantidad += $valor->cantidad;
			$this->base += $valor->base;
			$this->importe += $valor->importe;
			$this->puntos += $valor->puntos;
			$this->puntos_gastados += $valor->puntos_gastados;
		}
		//echo("Despues de recalcular tenemos: " . $this->cantidad . " elementos por un valor de : " . $this->importe . "euros\n ");
		//Ahora vamos a calcular el importe sin el descuento:
		//OJO esto está mal, Este campo es sin restar el descuento
		$this->importe_sin_descuento += Price::setDiscount($this->importe, $this->descuento);
		//Aplicamos código promocional
		$this->applyDiscountCode();
		/*$revisar_g_envio = true;
		if ($this->objeto_codigo_promocional != NULL){
			var_dump($this->objeto_codigo_promocional);
			//Es posible que al aplicar el código de descuento no necesite gastos de envío:
			if (!$this->objeto_codigo_promocional->g_envio_gratis){
				$revisar_g_envio = false;
			}
		}
		if($revisar_g_envio){*/
			//Pedro 22/Abril/2019 ==> Gastos de envío:
			$this->shippingCosts();
		//}
	}
	
	private function setCustomer($opciones = NULL){
		//Si hemos recibido un número, entonces nos han mandado el código de cliente
		if (is_numeric($opciones)){
			$opciones = new ObOptions(array('codigoCliente' => $opciones));
		}else{
			$opciones = new ObOptions($opciones);
		}
		//Valores que hemos podido recibir:
		$objetoCliente = $opciones->getDefaultValue('objetoCliente', NULL);
		$codigoCliente = $opciones->getDefaultValue('codigoCliente', 0);
		//Esto lo vamos hacer así para optimizar:
		if ( ($objetoCliente == NULL) && ($codigoCliente > 0) ){
			$objetoCliente = new Usuario($codigoCliente);
		}
		if ($objetoCliente == NULL){
			$objetoCliente = $this->objeto_cliente;
		}
		//Si tenemos objeto cliente, el código de cliente lo cogemos del mismo:
		if ($objetoCliente != NULL){
			$codigoCliente = $objetoCliente->codigo;
		}
		
		//Ahora hay que setear el objeto cliente y el código de cliente en la clase cart:
		$this->cliente = $codigoCliente;
		$this->objetoCliente = $this->objeto_cliente = $objetoCliente;
		if ($this->objeto_cliente != NULL){
			//Si tiene código tenemos que guardarlo aquí y tener en cuenta que la dirección se coge del cliente
			if ($objetoCliente->codigo > 0){
				//Lo guardamos en este pedido:
				$this->setCustomerCode($objetoCliente->codigo);
				$obDireccion = $objetoCliente->getCurrentDirection();
			}else{
				//En caso contrario la dirección se coge de la cesta
				$opciones = array(
					'cliente' => 0,
					'direccion' => $this->direccion,
					'nombre' => ($objetoCliente->nombre_comercial != '') ? $objetoCliente->nombre_comercial : $objetoCliente->nombre_legal,
					'cod_postal' => $this->cod_postal,
					'localidad' => $this->localidad,
					'provincia' => $this->provincia,
					'pais' => $this->pais,
					'telefono' => $this->telefono
				);
				$obDireccion = new Direcciones($opciones);
			}
			//Ahora vamos a a guardar el resto de datos en la tabla correspondiente:
			if ($obDireccion != NULL){
				$this->setShippingDestination(array('objetoDireccion' => $obDireccion));
			}
			//Recalculamos:
			$this->recalculate();
		}
		
	}
	
	private function setCustomerCode($code){
		$bd = new BaseDatos();
		$hash = Sesion::getHashSesion();
		if ($bd->isConectado()){
			$sentencia_sql = 'UPDATE ' . self::getNombreTabla(true) . ' SET  `cliente` = \'' . $code . '\'
							WHERE ' . self::getWhereTabla(NULL, NULL, $hash, false);
			$bd->setConsultaSQL($sentencia_sql);
		}
		$this->cliente = $code;
	}
	
	//Pedro 12/Abril/2019 ==> Asignamos tipo de envío y forma de pago
	public function setShippingType($options){
		if (is_numeric($options)){
			$options = new ObOptions(array('tipo_envio' => $options));
		}
		$options = new ObOptions($options);
		$tipo_envio = $options->getDefaultValue('tipo_envio', 0);
		//Nos aseguramos de que tenga un código el tipo de envío
		$this->setCode();
		$bd = new BaseDatos();
		if ($bd->isConectado()){
			$sentencia_sql = 'UPDATE ' . self::getNombreTabla(true) . ' SET  `tipo_envio` = \'' . $tipo_envio . '\'
							WHERE ' . self::getWhereTabla(NULL, NULL, $this->hash, false);
			$bd->setConsultaSQL($sentencia_sql);
			//echo($sentencia_sql);
		}
		$this->tipo_envio = $tipo_envio;
		$this->objeto_tipo_envio = new TipoEnvioCliente(array('codigoEnvio' => $this->tipo_envio));
		//Ahora hay que recalcular los gastos de envío:
		$this->recalculate();
	}
	public static function remoteSetShippingType($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$cart = static::getCart();
		$cart->setShippingType($data);
		$retorno = json_encode($retorno);		
		return($retorno);
	}
	public function setPaymentType($options){
		if (is_numeric($options)){
			$options = new ObOptions(array('forma_pago' => $options));
		}
		$options = new ObOptions($options);
		$forma_pago = $options->getDefaultValue('forma_pago', 0);
		//Nos aseguramos de que tenga un código el tipo de envío
		$this->setCode();
		$bd = new BaseDatos();
		if ($bd->isConectado()){
			$sentencia_sql = 'UPDATE ' . self::getNombreTabla(true) . ' SET  `forma_pago` = \'' . $forma_pago . '\'
							WHERE ' . self::getWhereTabla(NULL, NULL, $this->hash, false);
			$bd->setConsultaSQL($sentencia_sql);
		}
		$this->forma_pago = $forma_pago;
		//Recalculamos el pedido
		$this->recalculate();
	}
	public static function  remoteSetPaymentType($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$cart = static::getCart();
		$cart->setPaymentType($data);
		$retorno = new stdClass();
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public static function getShippingType(){
		$retorno = 0;
		$cart = static::getCart();
		if ($cart != NULL){
			$retorno = $cart->tipo_envio;
		}
		return($retorno);
	}
	
	public static function getPaymentType(){
		$retorno = 0;
		$cart = static::getCart();
		if ($cart != NULL){
			$retorno = $cart->forma_pago;
		}
		return($retorno);
	}
	function setShippingDestination($options){
		//Si recibimos un código, es la direección de envío:
		if (is_numeric($options)){
			$options = array('codigoDireccion');
		}
		
		//El objeto usuario lo cogemos de la cesta. No de "logueado" esto lo vamos a ir quitando porque la cesta ya cogió al usuario en su momento:
		if ($this->objeto_cliente != NULL){
			$options = new ObOptions($options);
			$email = $options->getDefaultValue('email', $this->objeto_cliente->email);
			$codigoDireccion = $options->getDefaultValue('codigoDireccion', 0);
			$objetoDireccion = $options->getDefaultValue('objetoDireccion', NULL);
			$nombre = $options->getDefaultValue('nombre', '');
			$direccion = $options->getDefaultValue('direccion', '');
			$telefono = $options->getDefaultValue('telefono', '');
			$cod_postal = $options->getDefaultValue('cod_postal', '');
			$localidad = $options->getDefaultValue('localidad', '');
			$provincia = $options->getDefaultValue('provincia', '');
			$pais = $options->getDefaultValue('pais', '');
			$zona = $options->getDefaultValue('zona', 0);
			//Si no tenemos objeto dirección hay que crearlo:
			if ($objetoDireccion == NULL){
				$objetoDireccion = new Direcciones(array('direccion' => $direccion, 'cod_postal' => $cod_postal, 'localidad' => $localidad, 'provincia' => $provincia, 
										'telefono' => $telefono, 'nombre' => $nombre, 'pais' => $pais, 'zona' => $zona, 'codigo' => $codigoDireccion));
			}

			//Llegados a este punto, si tenemos un objeto dirección, lo guardamos:
			if ($objetoDireccion != NULL){
				$this->setCode();	//Nos aseguramos de tener un código para este pedido
				$sentencia_sql = '';
				//OJO, si tenemos un usuario hay que actualizar el objeto dirección
				if ($this->objeto_cliente->codigo > 0){
					//En este caso tenemos que actualizar la dirección de envío:
					$objetoDireccion->save();
					//Además vamos a ponerle al usuario logueado la dirección que acabamos de guardar:
					Usuario::logueadoUpdateDireccion($objetoDireccion);
					//SI el objeto direccion tiene un código diferente al que hemos seleccionado tenemos que actualizar la dirección de envío por defecto del cliente:
						//Pedro 24/Abril/2019 ==> Antes teníamos en cuenta también que la dirección nueva tuviese un código, pero se da el caso al cerrar la sesión que queremos quitar la dirección de envío asociada
					if ( $objetoDireccion->codigo != $this->codigoDireccion){
						//Guardamos en el cliente el código de la dirección por defecto
						//TODO
						$this->codigoDireccion = $objetoDireccion->codigo;
						$sentencia_sql .= ' UPDATE `' . self::getNombreTablaSinAlias() . '` SET `direccion_envio` = \'' . $this->codigoDireccion . '\' WHERE codigo = \'' . $this->codigo . '\' ;';
						//echo("$sentencia_sql\n");
					}
					
				}
				//actualizamos la dirección sólo si es distinta:
				$currentShippingDestination = $this->getCurrentShippingDestination();
				if ( $currentShippingDestination != $objetoDireccion){
					//Eliminamos cualquier dirección que haya para esta cesta y creamos una nueva:
					$sentencia_sql .= 'DELETE FROM `tmp_cabecera_pedidos_direccion` WHERE `tmp_cabecera_pedidos` = \'' . $this->codigo . '\';';
					//Si todos los campso están vacíos no creamos apunte ninguno:
					$a = $objetoDireccion;	//Voy a usar una variable de nombre corto para simplificar estas líneas de código
					if (trim($a->nombre . $email . $a->direccion . $a->cod_postal . $a->localidad . $a->provincia . $a->pais . $a->zona . $a->telefono) != ''){
						//Creamos un nuevo apunte en las direcciones de la cesta
						$sentencia_sql .= ' INSERT INTO `tmp_cabecera_pedidos_direccion` 
							(`tmp_cabecera_pedidos`, `nombre`, `email`, `direccion`, `cod_postal`, `localidad`, `provincia`, `pais`, `zona`, `telefono`)
							VALUES
							(\'' . $this->codigo . '\', \'' . $a->nombre . '\', \'' . $email . '\', \'' . $a->direccion . '\', \'' . $a->cod_postal . '\', 
							\'' . $a->localidad . '\', \'' . $a->provincia . '\', \'' . $a->pais . '\', \'' . $a->zona . '\', \'' . $a->telefono . '\' );';
					}
				}
				//echo($sentencia_sql);
				//Ejecutamos el sql
				if ($sentencia_sql != ''){
					$bd = new BaseDatos();
					if ($bd->isConectado()){
						$bd->setConsultaSQL($sentencia_sql);
					}
				}
				$this->nombre = $objetoDireccion->nombre;
				$this->email = $email;
				$this->direccion = $objetoDireccion->direccion;
				$this->cod_postal = $objetoDireccion->cod_postal;
				$this->localidad = $objetoDireccion->localidad;
				$this->provincia = $objetoDireccion->provincia;
				$this->pais = $objetoDireccion->pais;
				$this->zona = $objetoDireccion->zona;
				$this->telefono = $objetoDireccion->telefono;
				$this->editando = false;	//Indicamos que YA NO estamos editando la dirección
				$this->creando = false;	//Indicamos que YA NO estamos creando una nueva dirección
				//recalculamos
				$this->recalculate();
				//Si la cesta estática es esta, actualizamos:
				if (static::$cart != NULL){
					if (static::$cart->codigo != $this->codigo){
						static::$cart = $this;
					}
				}
			}else{
				echo('Error, no hay objeto direccion');
			}
		}else{
			echo('Error, no hay objeto cliente');
		}
	}
	public static function remoteSetShippingDestination($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$cart = static::getCart();
		$data = new ObOptions($data);	//Nos aseguramos de que "data" tenga el formato que necesitamos
		$codigoDireccion = $data->getDefaultValue('codigo', 0);
		$nombre = $data->getDefaultValue('nombre', NULL);
		$direccion = $data->getDefaultValue('direccion', NULL);
		$telefono = $data->getDefaultValue('telefono', NULL);
		$cod_postal = $data->getDefaultValue('cod_postal', NULL);
		$localidad = $data->getDefaultValue('localidad', NULL);
		$provincia = $data->getDefaultValue('provincia', NULL);
		$pais = $data->getDefaultValue('pais', '');
		$zona = $data->getDefaultValue('zona', 0);
		//Pedro 24/Abril/2019 ==> El array que crea las direcciones de envío no va a llevar aquellos datos que no nos pasen para no guardar una diercción vacía:
		$array_datos_direccion = array('direccion' => $direccion, 'cod_postal' => $cod_postal, 'localidad' => $localidad, 'provincia' => $provincia, 
										'telefono' => $telefono, 'nombre' => $nombre, 'pais' => $pais, 'zona' => $zona, 'codigo' => $codigoDireccion, 'cliente' => $cart->cliente);
		foreach($array_datos_direccion as $clave => $valor){
			if ($valor == NULL){
				unset($array_datos_direccion[$clave]);
			}
		}

		$objetoDireccion = new Direcciones($array_datos_direccion);
		
		//Directamente ejecutamos la función dináimca del carrito
		$cart->setShippingDestination(array('objetoDireccion' => $objetoDireccion));

		$retorno = json_encode($retorno);		
		return($retorno);
	}
	public function getCurrentShippingDestination(){
		/*$retorno = new Direcciones(array('direccion' => $this->direccion, 'cod_postal' => $this->cod_postal, 'localidad' => $this->localidad,
												'provincia' => $this->provincia, 'telefono' => $this->telefono, 'nombre' => $this->nombre, 'pais' =>  $this->pais, 'zona' => $this->zona,
												'codigo' => $this->codigoDireccion));*/
		//Pedro 24/Abril/2019 ==> hasta ahora se creaba la dirección pasándole el código, pero no quiero crearla pasándole dicho código. lo que quiero en esta función es coger la dirección asociada a la cesta
				//Y no la dirección que hay en "direcciones"
		$retorno = new Direcciones(array('direccion' => $this->direccion, 'cod_postal' => $this->cod_postal, 'localidad' => $this->localidad,
												'provincia' => $this->provincia, 'telefono' => $this->telefono, 'nombre' => $this->nombre, 'pais' =>  $this->pais, 'zona' => $this->zona));
		return($retorno);
	}

	public static function getShippingDestination(){
		$cart = static::getCart();
		return($cart->getCurrentShippingDestination());
	}
	
	public static function remoteGetShippingDestination(){
		return(static::getShippingDestination());
	}
	
	public function setEditando($valor = true){
		$this->editando = $valor;
	}
	
	public static function remoteSetEditando($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$cart = static::getCart();
		$data = new ObOptions($data);
		$cart->setEditando($data->getDefaultValue('editando', true));
		$retorno = json_encode($retorno);		
		return($retorno);
	}
	public function getEditando(){
		return($this->editando);
	}
	
	public function setCreando($valor = true){
		$this->creando_direccion = $valor;
	}
	
	public static function remoteSetCreando($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$cart = static::getCart();
		$data = new ObOptions($data);
		$cart->setCreando($data->getDefaultValue('creando', true));
		$retorno = json_encode($retorno);		
		return($retorno);
	}
	public function getCreando(){
		return($this->creando_direccion);
	}
	
	//Pedro 23/Abril/2019 ==> Cuando nos deslogueamos de la cesta hay que eliminar la dirección de envío de la misma y después desloguearse del usuario
	public static function cartLogout(){
		//Si me creo un objeto dirección vacío y lo paso al pedido hago que se elimine el viejo y no se apunte este
		$opciones = array(
			'codigo' => 0,
			'email' => '',
			'nombre' => '',
			'direccion' => '',
			'cod_postal' => '',
			'localidad' => '',
			'provincia' => '',
			'pais' => '',
			'zona' => '',
			'telefono' => ''	
		);
		$obDireccion = new Direcciones($opciones);
		$cart = static::getCart();
		//Asignamos la direccion vacía al carrito
		$cart->setShippingDestination($opciones);
		//Le borramos el cliente
		$cart->setCustomerCode(0);
		//Ahora deslogueamos al cliente
		Usuario::cartLogout();
	}
	
	//Pedro 02/Mayo/2019 ==> Funciones para gestionar los códigos de descuento
	
	
	public function applyDiscountCode($code = NULL){
		$code = ($code == NULL) ? $this->codigo_promocional : $code;
		//SI no nos han pasado código promocional y no tenemos ninguno, no hacemos nada:
		if ( ($code != NULL) || ($this->codigo_promocional != '') ){
			//Para evitar recursividad, esta función va a suponer SIEMPRE que la cesta está recalculada
				//Es posible que en un momento determinado el poder aplicar un código de descuento dependa de un importe mínimo, por ejemplo
			//Antes de aplicar un código de descuento, vamos a ver si es posible:
			$codigo_promocional = new CodigosPromocionales(array('codigo_promocional' => $code));
			if ($codigo_promocional->checkDiscountCode()){
				//Aquí vamos a tener en cuenta ahora los parámetros que dependan de la cesta:
				if ($codigo_promocional->escaparates != ''){
					//En este caso el importe de descuento hay que calcularlo por línea y aplicarle a cada línea su descuento. Después de eso hay que recalcular el total
				}else{
					//En este caso el descuento es global:
					$this->descuento = $codigo_promocional->descuento;
					$this->importe = ($this->importe_sin_descuento * (100 - $this->descuento) ) / 100;
					if ($codigo_promocional->g_envio_gratis){
						$this->g_envio = 0;
					}else{
						//PEdro 09/Mayo/2019 ==> En este caso vamos a recalcular siempre los gastos de envío para curarnos en salud:
						$this->shippingCosts();
					}
				}
				//Si nos han pasado un codigo promocional distinto al que tenemos, vamos a guardarlo:
				if ($this->codigo_promocional != $code){
					//Lo actualizamos en la BD
					static::updateField(array($this->cliente, $this->codigo, $this->hash), 'codigo_promocional', $code);
					//Si el carro de la sesión es este modificamos su código promocional
					if (static::$cart == $this){
						static::$cart->codigo_promocional = $code;
					}
					//Por último a este le quitamos el código
					$this->codigo_promocional = $code;
					$this->objeto_codigo_promocional = new CodigosPromocionales(array('codigo_promocional' => $this->codigo_promocional));
				}
			}else{
				//Si el código no se puede utilizar y resulta que es el que tiene la cesta, hay que quitárselo:
				if ($this->codigo_promocional == $code){
					//Lo actualizamos en la BD
					static::updateField(array($this->cliente, $this->codigo, $this->hash), 'codigo_promocional', '');
					//Si el carro de la sesión es este modificamos su código promocional
					if (static::$cart == $this){
						static::$cart->codigo_promocional = '';
					}
					//Por último a este le quitamos el código
					$this->codigo_promocional = '';
					$this->objeto_codigo_promocional = NULL;
				}
			}
		}
	}
	
	public static function remoteApplyDiscountCode($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$data = new ObOptions($data);	//Nos aseguramos de que "data" tenga el formato que necesitamos
		$code = $data->getDefaultValue('code', NULL);
		$cart = static::getCart();
		$cart->applyDiscountCode($code);
		$retorno = json_encode($retorno);		
		return($retorno);
	}
	
	public function removeDiscountCode(){
		if ($this->codigo_promocional != ''){
			//Lo actualizamos en la BD
			static::updateField(array($this->cliente, $this->codigo, $this->hash), 'codigo_promocional', '');
			//Si el carro de la sesión es este modificamos su código promocional
			if (static::$cart == $this){
				static::$cart->codigo_promocional = '';
			}
			//Por último a este le quitamos el código
			$this->codigo_promocional = '';
			$this->objeto_codigo_promocional = NULL;
			$this->recalculate();
		}
	}
	
	public static function remoteRemoveDiscountCode($data){
		if (is_string($data)){
			$data = json_decode($data);
		}
		$retorno = new stdClass();
		$cart = static::getCart();
		$cart->removeDiscountCode();
		$retorno = json_encode($retorno);		
		return($retorno);
	}
}

?>