<?php
/**
 * 2022 4webs Hipercalzado
 *
 * DEVELOPED by 4webs.es Prestashop Superhero Partner
 *
 * @author    4webs
 * @copyright 4webs 2022
 * @license   4webs
 * @category administration
 */

class HipercalzadoUtils {

	const HIPERCALZADO_BASE_URL = 'https://www.menuweb.es/seller/api/';
	const HIPERCALZADO_METHOD_ORDERS = 'orders';
	const HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_SHIPPING_INFO = '/tracking';
	const HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_VALIDATE_SHIPPING = '/ship';
	const HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_ACCEPT_LINE = '/accept';

	const HIPERCALZADO_HTTP_GET = 'GET';
	const HIPERCALZADO_HTTP_POST = 'POST';
	const HIPERCALZADO_HTTP_PUT = 'PUT';

	const HIPERCALZADO_MAX_ORDERS = 100;

	const HIPERCALZADO_TAX_RULES_GROUP_NAME = 'Hipercalzado';
	const HIPERCALZADO_TAX_PREFIX_NAME = 'hipercalzado';

	const HIPERCALZADO_RESPONSE_CODES = Array(
		// SUCCESS
		200 => 'OK',
		201 => 'Creado',
		204 => 'Sin contenido',
		// ERROR
		400 => 'Solicitud incorrecta',
		401 => 'No autorizado',
		403 => 'Prohibido',
		404 => 'No encontrado',
		405 => 'Método no permitido',
		410 => 'Desaparecido',
		415 => 'Tipo de medio no admintido',
		429 => 'Demasiadas solicitudes',
		500 => 'Error interno del servidor',
	);

	const HIPERCALZADO_ID_NON_EXISTENT_PRODUCT = 1111111111;

	/**
	 * This function will build the innitial configuration json Object
	 */
	public static function buildInnitialConfiguration()
	{
		$configuration = new stdClass();

		$configuration->user_token = '';
		$configuration->parent_id = 'reference';
		$configuration->sku_id = 'reference';

		$configuration->order_state_default = Configuration::get('PS_OS_PAYMENT', null, Context::getContext()->shop->id_shop_group,  Context::getContext()->shop->id);
		$configuration->order_state_sended = Configuration::get('PS_OS_SHIPPING', null, Context::getContext()->shop->id_shop_group,  Context::getContext()->shop->id);
		$configuration->order_state_cancel = Configuration::get('PS_OS_CANCELED', null, Context::getContext()->shop->id_shop_group,  Context::getContext()->shop->id);

		$configuration->id_employee = 0;

		$configuration->id_carrier = 0;

		$configuration->id_product_fake = 0;

		return json_encode($configuration);
	}

	/**
	 * Updates the modules configuration, decodifies it and stores into DB
	 *
	 * @param $module - the module context
	 * @return boolean - True if ok, false for ko
	 */
	public static function updateConfiguration($module)
	{
		//If isn't a valid JSON data, return null
		$ob = json_decode(json_encode($module->configuration, JSON_UNESCAPED_SLASHES));
		if ($ob === null) {
			return false;
		}

		return Configuration::updateValue(
			$module->name . '_CONFIGURATION',
			json_encode($module->configuration, JSON_UNESCAPED_SLASHES),
			null,
			Context::getContext()->shop->id_shop_group,
			(int)Context::getContext()->shop->id
		);
	}

    /**
	 * This function returns the different fields on products
	 */
	public static function getParetIdentifiers()
	{
		return [
			[
				'id' => 'id_product',
				'name' => HipercalzadoUtils::translate('Product ID'),
				'value' => 'id_product'
			],
			[
				'id' => 'reference',
				'name' => HipercalzadoUtils::translate('SKU'),
				'value' => 'reference'
			]
		];
	}
	
	public static function getSKUIdentifiers()
	{
		return [
			[
				'id' => 'id_product_attribute',
				'name' => HipercalzadoUtils::translate('Combination ID'),
				'value' => 'id_product_attribute'
			],
			[
				'id' => 'reference',
				'name' => HipercalzadoUtils::translate('Combination SKU'),
				'value' => 'reference'
			],
			[
				'id' => 'ean13',
				'name' => HipercalzadoUtils::translate('EAN'),
				'value' => 'ean13'
			]
		];
	}
	
	public static function getOrders($module, $is_cron = false) {

        $shopDefaultLangId = Configuration::get('PS_LANG_DEFAULT', null, Context::getContext()->shop->id_shop_group, Context::getContext()->shop->id);
		$msg = Array(
			'errors' => array(),
			'success' => array()
		);

		if (!empty($module->configuration->user_token)) {

			// Url
			$orders_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '?order_state_codes=ORDER_ACCEPTED&max=' .  HipercalzadoUtils::HIPERCALZADO_MAX_ORDERS;

			do {
				$data = HipercalzadoUtils::makeCurl($orders_url, $module->configuration->user_token);

				if(!empty($data->orders) && is_array($data->orders)) {

					// die(dump($data->orders));

					// Recorremos los pedidos y los almacenamos
					// $WS_ -> informacion obtenida desde el web service
					// $PS_ -> informacion en el sistema Prestashop
					// $HC_ -> informacion en la clase HipercalzadoOrder
					foreach($data->orders as $WS_order) {
						if(HipercalzadoOrder::hipercalzadoOrderExists($WS_order->hc_id_order)) {
							continue;
						}
						// die(dump($WS_order));
						// Recueperamos el pedido en la base de datos, o lo creamos en caso de no existir
						if(!$HC_order = HipercalzadoOrder::getHipercalzadoOrderByHCOrderReference((int) $WS_order->order_id)) {
							$HC_order = new HipercalzadoOrder();
							$HC_order->hc_id_order = (int) $WS_order->order_id;
							$HC_order->shipping_company = pSQL($WS_order->shipping_company);
							$HC_order->can_cancel = (int) $WS_order->can_cancel;
							$HC_order->save();
						}

						// Obtenemos el cliente, y lo creamos en caso de no existir (se usa como clave el email)
						$customer_email = $WS_order->customer_notification_email;
						$WS_customer = $WS_order->customer;

						// Currency
						$id_currency = (!empty($WS_order->currency_iso_code)) ? Currency::getIdByIsoCode($WS_order->currency_iso_code, (int) Context::getContext()->shop->id) :  0;

						if(empty($id_currency)) {
							// Error: No existe la moneda
							$msg['errors'][] = sprintf($module->l('Currency %s not exists in prestashop'), Array($WS_order->currency_iso_code));
							break;
						}
						
						// Customer
						if(!$HC_order->hipercalzadoCustomerExists($customer_email)) {

							// Existe una cuenta con este correo que no es de invitado
							if (Customer::customerExists($customer_email)) {
								$customers_by_email = Customer::getCustomersByEmail($customer_email);
								// Vamos a quedarnos solo con la cuenta de cliente ya que la funcion anterior 
								// nos devuelve todas las cuentas, incluidas las de invitado
								foreach($customers_by_email as $customer_by_email) {
									if(!$customer_by_email['is_guest']) {
										$HC_order->id_customer = (int) $customer_by_email['id_customer'];
										$HC_order->save();
									}
								}
							} else {
								$HC_order->createHipercalzadoCustomer($customer_email, $WS_customer->firstname, $WS_customer->lastname);
							}
						}

						if (empty($HC_order->id_customer)) {
							// Error: No existe la moneda
							$msg['errors'][] = sprintf($module->l('Customer %s not created in Prestashop'), Array($customer_email));
							break;
						}
						// Procesamos las direcciones
			
						// Las concordancia de las direcciones la hacemos a traves del campo street_1
						// Direccion de envio
						$WS_shipping_address = $WS_customer->shipping_address;

						$id_shipping_address = HipercalzadoUtils::getAddressIdByIdCustomerAndStreet($HC_order->id_customer, $WS_shipping_address->street_1);
						// Si no existe la direccion, la creamos
						if (empty($id_shipping_address)) {
							// Creamos la direccion
							$PS_shipping_address = HipercalzadoUtils::createAddressFromWSinfo($WS_shipping_address, $HC_order->id_customer);
							// Obtenemos el id
							$id_shipping_address = $PS_shipping_address->id;
						}

						// Direccion de facturacion
						$WS_billing_address = $WS_customer->billing_address;
						$id_billing_address = HipercalzadoUtils::getAddressIdByIdCustomerAndStreet($HC_order->id_customer, $WS_billing_address->street_1);
						// Si no existe la direccion, la creamos
						if (empty($id_billing_address)) {
							// Creamos la direccion
							$PS_billing_address = HipercalzadoUtils::createAddressFromWSinfo($WS_billing_address, $HC_order->id_customer);
							// Obtenemos el id
							$id_billing_address = $PS_billing_address->id;
						}
							
						if (empty($id_shipping_address) || empty($id_billing_address)) {
							// Error: No se ha creado alguna de las dos direcciones
							break;
						}


						// Si no teniamos creado el carro o el carro no existe, lo hacemos y guardamos el id en la base de datos
						if(!empty($HC_order->id_cart)) {
							$PS_cart = new Cart( (int)$HC_order->id_cart);
						}

						// Si el pedido ya existe, lo obtenemos
						$PS_order = $HC_order->getHipercalzadoOrder();

						if(empty($PS_order)) {

							// Si no existe el carrito lo creamos
							if(empty($PS_cart)) {

								$PS_cart = $HC_order->createHipercalzadoCart($id_shipping_address, $id_billing_address, $shopDefaultLangId, $id_currency, $module->configuration->id_carrier);

								if (empty($PS_cart)) {
									// Error: No se ha creado bien el carrito
									break;
								}

							}

							Context::getContext()->cart = (int)($PS_cart->id);

							// Creamos el pedido
							$PS_order = $HC_order->createHipercalzadoOrder($module, Context::getContext(), $WS_order, $module->configuration->order_state_default, $module->configuration->id_employee, $module->configuration->parent_id, $module->configuration->sku_id);

							if (empty($PS_order)) {
								// Error: No se ha creado bien el pedido
								break;
							}

						} else {
							// EL pedido existe
						}// Fin de crear/editatar pedido nuevo

						// Eliminamos los objetos que ya no vamos a usar
						unset($HC_order);
						unset($PS_cart);
						unset($PS_order);

					} // Fin del foreach de los pedidos devueltos
					

					// En caso de haber mas resultados, montamos la nueva url con los resultados
					if(!empty($data->next_page_token)) 
						$orders_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL 
											. HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS 
											. '?max=' .  HipercalzadoUtils::HIPERCALZADO_MAX_ORDERS
											. '&page_token=' .  $data->next_page_token;
				
				} else {
					if (!$is_cron && !empty($data) && is_array($data)) {
						foreach($data as $error) {
							if (!empty($error->status) && !empty($error->message)) {
								$msg['errors'][] = $error->status . ': ' . $error->message;
							}
						}
					}
				}
			// Mientras queden resultados seguimos iterando
			} while(!empty($data) && !empty($data->next_page_token));
			
		} else return false;

		if (empty($msg['errors'])) {
			$msg['success'][] = HipercalzadoUtils::translate("Process finished correctly");
		}
		return $msg;

	}


	public static function sendNotificationOrderSended($module, $id_order, $is_cron = false) {

        $shopDefaultLangId = Configuration::get('PS_LANG_DEFAULT', null, Context::getContext()->shop->id_shop_group, Context::getContext()->shop->id);
		$msg = Array(
			'errors' => array(),
			'success' => array()
		);

		// Obtenemos el pedido a traves de su id
		$PS_order = new Order($id_order);

		if(!Validate::isLoadedObject($PS_order)) { 
			$msg['errors'][] = $module->l("Order not exists.");
		}

		// Obtenemos los datos del pedido de Hipercalzado segun el id de pedido
		$HC_order = HipercalzadoOrder::getHipercalzadoOrderByOrderId($id_order);

		if (empty($HC_order)) {
			$msg['errors'][] = $module->l("Order from Hipercalzado not exists with this order id.");
		}

		// Obtenemos la informacion de envio
		$PS_order_carrier = new OrderCarrier((int)$PS_order->getIdOrderCarrier());

		if (!Validate::isLoadedObject($PS_order_carrier)) {
			$msg['errors'][] = $module->l("Carrier info from order not exists.");
		}

		// Obtenemos los datos del transportista
		$PS_carrier = new Carrier((int)$PS_order_carrier->id_carrier, $shopDefaultLangId);

		if (!Validate::isLoadedObject($PS_carrier)) {
			$msg['errors'][] = $module->l("Carrier from order not exists.");
		}

		if (empty($module->configuration->user_token)) {
			$msg['errors'][] = $module->l('User token is not configured');
		}

		// Si no hay errores, mandamos el pedido
		if(empty($msg['errors'])) {

			// Urls
			$notify_order_is_sended_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '/' . (int)$HC_order->hc_id_order .  HipercalzadoUtils::HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_SHIPPING_INFO;
			$validate_order_shipping_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '/' . (int)$HC_order->hc_id_order .  HipercalzadoUtils::HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_VALIDATE_SHIPPING;

			$post_fields = Array(
				'carrier_code' => $PS_carrier->name,
   				'carrier_name' => $PS_carrier->name,
   				'tracking_number' => $PS_order_carrier->tracking_number
			);
		
			$data = HipercalzadoUtils::makeCurl($notify_order_is_sended_url, $module->configuration->user_token, HipercalzadoUtils::HIPERCALZADO_HTTP_PUT, $post_fields);

			if (!$is_cron && !empty($data) && (isset($data->status) && $data->status == 204)) {
				
				// Si ha ido correctamente y hemos enviado numero de seguimiento, validamos pedido
				if(!empty($PS_order_carrier->tracking_number)) {
					$data_validate = HipercalzadoUtils::makeCurl($validate_order_shipping_url, $module->configuration->user_token, HipercalzadoUtils::HIPERCALZADO_HTTP_PUT);

					if (!$is_cron && !empty($data_validate) && is_array($data_validate)) {
						foreach($data_validate as $error) {
							$msg['errors'][] = $error->status . ': ' . $error->message;
						}
					} 
				}
			} elseif (!$is_cron && !empty($data) && is_array($data)) {
				foreach($data as $error) {
					$msg['errors'][] = $error->status . ': ' . $error->message;
				}
			}
		}
		

		if (empty($msg['errors'])) {
			$msg['success'][] = $module->l("Process finished correctly");
		}

		unset($PS_order);
		unset($HC_order);
		unset($PS_order_carrier);
		unset($PS_carrier);

		return $msg;

	}

	public static function sendNotificationShippingNumberChange($module, $order, $carrier, $is_cron = false) {

		// $shopDefaultLangId = Configuration::get('PS_LANG_DEFAULT', null, Context::getContext()->shop->id_shop_group, Context::getContext()->shop->id);
		$msg = Array(
			'errors' => array(),
			'success' => array()
		);

		if(!Validate::isLoadedObject($order)) { 
			$msg['errors'][] = $module->l("Order not exists.");
		}

		if(!Validate::isLoadedObject($carrier)) { 
			$msg['errors'][] = $module->l("Carrier not exists.");
		}

		// Obtenemos los datos del pedido de Hipercalzado segun el id de pedido
		$HC_order = HipercalzadoOrder::getHipercalzadoOrderByOrderId((int) $order->id);

		if (empty($HC_order)) {
			$msg['errors'][] = $module->l("Order from Hipercalzado not exists with this order id.");
		}

		// Obtenemos la informacion de envio
		$PS_order_carrier = new OrderCarrier((int)$order->getIdOrderCarrier());

		if (!Validate::isLoadedObject($PS_order_carrier)) {
			$msg['errors'][] = $module->l("Carrier info from order not exists.");
		}

		if (empty($module->configuration->user_token)) {
			$msg['errors'][] = $module->l('User token is not configured');
		}

		// Si no hay errores, mandamos el pedido
		if(empty($msg['errors'])) {

			// Urls
			$change_order_tracking_number_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '/' . (int)$HC_order->hc_id_order .  HipercalzadoUtils::HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_SHIPPING_INFO;

			$post_fields = Array(
				'carrier_code' => $carrier->name,
   				'carrier_name' => $carrier->name,
   				'tracking_number' => $PS_order_carrier->tracking_number
			);
		
			$data = HipercalzadoUtils::makeCurl($change_order_tracking_number_url, $module->configuration->user_token, HipercalzadoUtils::HIPERCALZADO_HTTP_PUT, $post_fields);

			if (!$is_cron && !empty($data) && is_array($data)) {
				foreach($data as $error) {
					$msg['errors'][] = $error->status . ': ' . $error->message;
				}
			} else {
				$msg['success'][] = $module->l("Shipping number change corectly to Hipercalzado");
			}
		}

		unset($PS_order_carrier);
		unset($HC_order);

		return $msg;
		
	}

	public static function sendNotificationOrderCancelled($module, $id_order, $is_cron = false) {

		// $shopDefaultLangId = Configuration::get('PS_LANG_DEFAULT', null, Context::getContext()->shop->id_shop_group, Context::getContext()->shop->id);
		$msg = Array(
			'errors' => array(),
			'success' => array()
		);

		// Obtenemos el pedido a traves de su id
		$PS_order = new Order($id_order);

		if(!Validate::isLoadedObject($PS_order)) { 
			$msg['errors'][] = $module->l("Order not exists.");
		}


		// Obtenemos los datos del pedido de Hipercalzado segun el id de pedido
		$HC_order = HipercalzadoOrder::getHipercalzadoOrderByOrderId($id_order);

		if (empty($HC_order)) {
			$msg['errors'][] = $module->l("Order from Hipercalzado not exists with this order id.");
		}

		if (!$HC_order->can_cancel) {
			$msg['errors'][] = $module->l("Hipercalzado order can't cancel.");
		}

		// Obtenemos la informacion de envio
		$HC_order_lines = HipercalzadoOrderProduct::getList($HC_order->id);

		if (empty($HC_order_lines )) {
			$msg['errors'][] = $module->l("Not order lines from this Hipercalzado order.");
		}

		if (empty($module->configuration->user_token)) {
			$msg['errors'][] = $module->l('User token is not configured');
		}

		// Si no hay errores, mandamos el pedido
		if(empty($msg['errors'])) {

			// Urls
			$notify_refuse_lines = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '/' . (int)$HC_order->hc_id_order .  HipercalzadoUtils::HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_ACCEPT_LINE;

			$order_lines = Array();
			foreach($HC_order_lines as $HC_order_line) {
				if($HC_order_line['can_refund'] && !$HC_order_line['refunded']) {
					$order_lines[] = Array(
						'accept' => false,
						'total_refuse' => $HC_order_line['quantity'],
						'id' => $HC_order_line['hc_id_product'],
					);
				}
			}

			$post_fields = Array(
				'order_lines' => $order_lines,
   				'cancellation_reason' => "solicitado_cancelacion"
			);
		
			$data = HipercalzadoUtils::makeCurl($notify_refuse_lines, $module->configuration->user_token, HipercalzadoUtils::HIPERCALZADO_HTTP_PUT, $post_fields);

			/// die(dump($data));

			if (!$is_cron && !empty($data) && is_array($data)) {
				foreach($data as $error) {
					$msg['errors'][] = $error->status . ': ' . $error->message;
				}
			} else {
				$msg['success'][] = $module->l("Cancellation notificated corectly to Hipercalzado");
			}
		}

		unset($PS_order);
		unset($HC_order);
		unset($HC_order_lines);

		return $msg;
		
	}
	
	
	public static function sendNotificationProductCancelled($module, $id_order, $id_order_detail, $cancel_quantity, $is_cron = false) {

		// $shopDefaultLangId = Configuration::get('PS_LANG_DEFAULT', null, Context::getContext()->shop->id_shop_group, Context::getContext()->shop->id);
		$msg = Array(
			'errors' => array(),
			'success' => array()
		);

		// Obtenemos los datos del pedido de Hipercalzado segun el id de pedido
		$HC_order = HipercalzadoOrder::getHipercalzadoOrderByOrderId($id_order);

		if (empty($HC_order)) {
			$msg['errors'][] = $module->l("Order from Hipercalzado not exists with this order id.");
		}

		// Obtenemos los datos del producto de pedido segun el id del order detail
		$HC_order_line = HipercalzadoOrderProduct::getHipercalzadoOrderProductByPSIdOrderDetail($id_order_detail);

		if (empty($HC_order_line)) {
			$msg['errors'][] = $module->l("Order product from Hipercalzado not exists with this order detail id.");
		}

		if(!$HC_order_line->can_refund || $HC_order_line->refunded) { 
			$msg['errors'][] = $module->l("Order product can`t refund or already refunded.");
		}
		if (empty($module->configuration->user_token)) {
			$msg['errors'][] = $module->l('User token is not configured');
		}

		// Si no hay errores, mandamos el pedido
		if(empty($msg['errors'])) {

			// Urls
			$notify_refuse_lines = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '/' . (int)$HC_order->hc_id_order .  HipercalzadoUtils::HIPERCALZADO_METHOD_PUT_UPDATE_ORDER_ACCEPT_LINE;

			$order_lines = Array();
			$order_lines[] = Array(
				'accept' => false,
				'total_refuse' => $cancel_quantity,
				'id' => $HC_order_line->hc_id_product,
			);
			

			$post_fields = Array(
				'order_lines' => $order_lines,
   				'cancellation_reason' => "solicitado_cancelacion"
			);
		
			$data = HipercalzadoUtils::makeCurl($notify_refuse_lines, $module->configuration->user_token, HipercalzadoUtils::HIPERCALZADO_HTTP_PUT, $post_fields);

			if (!$is_cron && !empty($data) && is_array($data)) {
				foreach($data as $error) {
					$msg['errors'][] = $error->status . ': ' . $error->message;
				}
			} else {
				$msg['success'][] = $module->l("Cancellation notificated corectly to Hipercalzado");
			}
		}

		unset($HC_order);
		unset($HC_order_line);

		return $msg;
		
	}
	
	

	/*
	 * Comprobamos la conexion haciendo una peticion de un producto de prueba
	 */
	public static function checkHipercalzadoConnection($module) {

		$response = new stdClass();

		if (!empty($module->configuration->user_token)) {

			// Url
			$orders_url = HipercalzadoUtils::HIPERCALZADO_BASE_URL . HipercalzadoUtils::HIPERCALZADO_METHOD_ORDERS . '?max=1';
			$data = HipercalzadoUtils::makeCurl($orders_url, $module->configuration->user_token);


			if (!empty($data) && is_object($data) && !empty($data->status)) {
				$response->code = $data->status;
				$response->msg = HipercalzadoUtils::HIPERCALZADO_RESPONSE_CODES[$data->status];
			} elseif (!empty($data) && is_array($data) && !empty($data[0]->status)) {
				$response->code = $data[0]->status;
				$response->msg = $data[0]->message;
			} else {
				$response->code = '';
				$response->msg = $module->l("No data returned");
			}
		} else {
			$response->code = '';
			$response->msg = $module->l("Empty token");
		}

		return $response;

	}

	public static function makeCurl($url, $user_token, $mode = HipercalzadoUtils::HIPERCALZADO_HTTP_GET, $post_fields = array()) {
		
		// Cabeceras
		$headers = array(
            "Content-Type: application/json;charset=\"utf-8\"",
            "Accept: application/json",
            "Authorization: " . $user_token
        ); 

		// Inicializamos 
		$ch = curl_init();

		curl_setopt($ch, CURLOPT_URL, $url); 
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
		// Headers to ignore 
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		
		// En caso de que sea una peticion por post
		if ($mode == HipercalzadoUtils::HIPERCALZADO_HTTP_POST || $mode == HipercalzadoUtils::HIPERCALZADO_HTTP_PUT) {

			if ($mode ==  HipercalzadoUtils::HIPERCALZADO_HTTP_POST) {	
				curl_setopt($ch, CURLOPT_POST, 1);
			} elseif ($mode == HipercalzadoUtils::HIPERCALZADO_HTTP_PUT) {
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
			}

			if(!empty($post_fields) && is_array($post_fields)) {

				$payload = json_encode($post_fields);
				curl_setopt($ch, CURLOPT_POSTFIELDS, $payload );

				// Set the content type to application/json
				curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
				
				$headers[] = "Content-length: ".Tools::strlen($payload);
			}
		}

		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
		$data = curl_exec($ch); 
		$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch); 

		// Creamos el objeto con la respuesta. Si la respuesta no nos devuelve un objeto JSON, 
		// creamos nosotros uno con el codigo de la consulta
		$json_data = json_decode($data);
		if(empty($json_data)) {
			$json = json_encode(array('status' => $httpcode), JSON_FORCE_OBJECT);
			$json_data = json_decode($json);
		} else {
			if (is_object($json_data)) {
				$json_data->status = $httpcode;
			}
			// En caso de que sea un array, la informacion con el codigo de estado nos vuelve con un codugo de estado y un mensage
		}

		return $json_data;
	}

	public static function getAddressIdByIdCustomerAndStreet($id_customer, $address1)
    {
        $query = new DbQuery();
        $query->select('id_address');
        $query->from('address');
        $query->where('id_customer = ' . (int) $id_customer);
        $query->where('address1 = "' . pSQL($address1) . '"');
        $query->where('deleted = 0');

        return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
    }
	
	/*
	* Crea una direccion en base a los datos proporcionados por el WS
	*/
	public static function createAddressFromWSinfo($WS_address, $id_customer) {

		// Obtenemos el pais a traves del ISO code
		$id_country = Country::getByIso($WS_address->country_iso_code);

		if(empty($id_country)) return false;
		// Obtenemos la provincia/estado
		$id_state = HipercalzadoUtils::getStateIdByIdCountryAndState($id_country, $WS_address->state);

		// Si no existe la provincia, la anyadimos a la provincia undefined
		if(empty($id_state)) {
			
			$id_state = HipercalzadoUtils::getStateIdByIdCountryAndState($id_country, 'undefined');
			
			// Si no existe la provincia undefined para ese pais la creamos
			if(empty($id_state)) {
				$id_state = HipercalzadoUtils::createUndefinedState($id_country);
			}
		}

		$PS_address = new Address();

		$PS_address->alias 			= 'HC_Address';
		$PS_address->company 		= pSQL($WS_address->company);
		$PS_address->id_country 	= (int) $id_country;
		$PS_address->id_state 		= (int) $id_state;
		$PS_address->id_customer 	= (int) $id_customer;
		$PS_address->city 			= pSQL($WS_address->city);
		$PS_address->postcode 		= pSQL($WS_address->zip_code);
		$PS_address->address1 		= pSQL($WS_address->street_1);
		$PS_address->address2 		= pSQL($WS_address->street_2);
		$PS_address->firstname 		= pSQL($WS_address->firstname);
		$PS_address->lastname 		= pSQL($WS_address->lastname);
		$PS_address->phone 			= pSQL($WS_address->phone);
		$PS_address->phone_mobile	= pSQL($WS_address->phone_secondary);

		// Si se requiere DNI, creamos DNI con 00
		if(HipercalzadoUtils::HipercalzadoAddressdniRequired((int) $id_country))
			$PS_address->dni 		= '00';
		
		$PS_address->save();

		return $PS_address;

	}


	/*
	* Nos devuelve el id de una provincia en base a su nombre y el id del pais
	*/
	public static function getStateIdByIdCountryAndState($id_country, $state)
    {
		$lower_state = Tools::strtolower($state);

        $query = new DbQuery();
        $query->select('id_state');
        $query->from('state');
        $query->where('id_country = ' . (int) $id_country);
        $query->where('LOWER(`name`) = "' . pSQL($lower_state) . '"');
        $query->where('active = 1');

        return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
    }

	/*
	* Crea una provincia con nombre undefined en base al id del pais
	*/
	public static function createUndefinedState($id_country) {
		
		$PS_undefined_state = new State();
		$PS_undefined_state->id_country = (int) $id_country;
		$PS_undefined_state->id_zone = Country::getIdZone((int) $id_country);
		$PS_undefined_state->iso_code = 'XX';
		$PS_undefined_state->name = 'undefined';
		$PS_undefined_state->active = 1;

		$PS_undefined_state->save();

		return $PS_undefined_state->id;

	}

	 /**
     * Return list of employees.
     *
     * @param bool $activeOnly Filter employee by active status
     *
     * @return array|false Employees or false
     */
    public static function getAllEmployees($activeOnly = true)
    {
        return Db::getInstance()->executeS('
			SELECT `id_employee`, `firstname`, `lastname`, `email` 
			FROM `' . _DB_PREFIX_ . 'employee`
			' . ($activeOnly ? ' WHERE `active` = 1' : '') . '
			ORDER BY `lastname` ASC
		');
    }

	public static function getProductByIdentifier($product_sku , $parent_id) {

		$id = Db::getInstance()->getValue(
			'SELECT id_product FROM ' . _DB_PREFIX_ . 'product WHERE ' . pSQL($parent_id) . ' = \'' . pSQL($product_sku) . '\'');

		if (!$id) {
			return false;
		}
		
		$PS_product = new Product($id);

		return $PS_product;
	}



	public static function getProductCombinationByIdentifier($product_sku, $combination_id) {

		$id = Db::getInstance()->getValue(
			'SELECT id_product_attribute FROM ' . _DB_PREFIX_ . 'product_attribute WHERE ' .pSQL($combination_id) . ' = \'' . pSQL($product_sku) . '\'');

		if (!$id) {
			return false;
		}
		
		$PS_combination = new Combination($id);

		return $PS_combination;
	}

	public static function getTaxRuleFromRateAndIDAdress($tax_rate, $id_address, $id_shop) {
		$PS_address = new Address($id_address);

		if(empty($PS_address)) return 0;

		// Obtenemos los grupos de impuestos para la tienda seleccionada
		$taxes_rules_group_available = Db::getInstance()->executeS(
			'SELECT trg.id_tax_rules_group 
				FROM ' . _DB_PREFIX_ . 'tax_rules_group trg
				LEFT JOIN ' . _DB_PREFIX_ . 'tax_rules_group_shop trgs
					ON trg.id_tax_rules_group = trgs.id_tax_rules_group
				WHERE trgs.id_shop = ' . (int)$id_shop . ' 
					AND trg.deleted = 0
					AND trg.active = 1');

		if(empty($taxes_rules_group_available)) return 0;
		$id_taxes_rules_groups = array_column($taxes_rules_group_available, 'id_tax_rules_group');

		if(empty((int)$tax_rate)) return 0;

		// Obtenemos las tax con el rate indicado
		$taxes_with_rate = Db::getInstance()->executeS(
			'SELECT tr.id_tax 
				FROM ' . _DB_PREFIX_ . 'tax_rule tr 
				LEFT JOIN ' . _DB_PREFIX_ . 'tax t 
					ON t.id_tax = tr.id_tax 
				LEFT JOIN ' . _DB_PREFIX_ . 'tax_rules_group trg  
					ON trg.id_tax_rules_group = tr.id_tax_rules_group 
				WHERE t.rate = ' . (int)$tax_rate . ' 
					AND t.active = 1 
					AND t.deleted = 0 
					AND tr.id_tax_rules_group IN (' . implode(',', $id_taxes_rules_groups) . ') 
					AND tr.id_country = ' . $PS_address->id_country . ' 
					AND tr.id_state IN (' . $PS_address->id_state. ' ,0)
				GROUP BY tr.id_tax');

		if(empty($taxes_with_rate)) {
			// Create new tax rate with this rate
			$new_tax = new Tax();
			$new_tax->name = HipercalzadoUtils::createMultiLangField(HipercalzadoUtils::HIPERCALZADO_TAX_PREFIX_NAME . ' ' . $tax_rate . '%');
			$new_tax->rate = (int) $tax_rate;
			$new_tax->active = 1;
			$new_tax->save();
			

			// Creamos o obtenemos el grupo de reglas de impuestos con nombre hipercalzado
			$PS_hc_tax_rules_group = HipercalzadoUtils::getTaxRulesGroupByName(HipercalzadoUtils::HIPERCALZADO_TAX_RULES_GROUP_NAME);
			if(empty($PS_hc_tax_rules_group)) {
				// Create new tax rate with hipercalzado name
				$PS_hc_tax_rules_group = new TaxRulesGroup();
				$PS_hc_tax_rules_group->name = HipercalzadoUtils::HIPERCALZADO_TAX_RULES_GROUP_NAME;
				$PS_hc_tax_rules_group->active = 1;
				$PS_hc_tax_rules_group->save();
			}

			// Creamos un tax rule para esa direccion, tax y tax rule gropu y lo asociamos
			$new_tax_rule = new TaxRule();
			$new_tax_rule->id_tax_rules_group = (int) $PS_hc_tax_rules_group->id;
			$new_tax_rule->id_tax = (int) $new_tax->id;
			$new_tax_rule->id_country = (int) $PS_address->id_country;
			$new_tax_rule->id_state = (int) $PS_address->id_state;
			$new_tax_rule->behavior = 0;
			$new_tax_rule->description = 'Hipercalzado tax rule';
			$new_tax_rule->save();

			// Devolvemos el grupo Hipercazlzado con la nueva tasa
			return $PS_hc_tax_rules_group->id;
		 
		} else {
			$id_taxes = array_column($taxes_with_rate, 'id_tax');
		} //return 0;

		
		$taxes_rule_with_taxes = Db::getInstance()->executeS(
			'SELECT id_tax_rule, id_tax, id_tax_rules_group 
				FROM ' . _DB_PREFIX_ . 'tax_rule 
				WHERE id_tax IN (' . implode(',', $id_taxes) . ') 
				ORDER BY id_state DESC');

		if(empty($taxes_rule_with_taxes)) return 0;

		return $taxes_rule_with_taxes[0]['id_tax_rules_group'];

	}

	public static function getTaxRulesGroupByName($name) {

		$id = Db::getInstance()->getValue(
			'SELECT id_tax_rules_group FROM ' . _DB_PREFIX_ . 'tax_rules_group WHERE name = \'' . pSQL($name) . '\'');

		if (!$id) {
			return false;
		}
		
		$PS_tax_rules_group = new TaxRulesGroup($id);

		return $PS_tax_rules_group;
	}

	/**
     * Returns the id tax corresponding to a rules group
     *
     * @param $id_tax_rules_group int - The id tax rules group (NOT THE TAX_ID)
     * @param $id_address_invoice - The invoice address, mandatory to get the country and calculate the correct tax
     *
     * @return int - The tax id
     */
    public static function getIdTaxFromGroup($id_tax_rules_group, $id_address_invoice = null)
    {
        //If no id_address given, get the prestapos default customer one
        if ($id_address_invoice == null) {
            $id_address_invoice = Configuration::get(
                'prestapos_DEFAULT_ADDRESS_ID',
                null,
                (int) Context::getContext()->shop->id_shop_group,
                (int) Context::getContext()->shop->id
            );
        }

        //First, we need to get the invoice country (to fetch the corresponding taxes)
        $address = new Address((int)$id_address_invoice);
        //Now, fetch the tax id
        $taxIdArr = Db::getInstance()
            ->ExecuteS(
                '
                SELECT id_tax

                FROM `' . _DB_PREFIX_ . 'tax_rule`

                WHERE id_tax_rules_group = ' . pSQL($id_tax_rules_group) . ' AND id_country = ' .
                pSQL($address->id_country)
            );

        if (count($taxIdArr) > 0) {
            return $taxIdArr[0]['id_tax'];
        } else {
            return 0;
        }
    }

	public static function getCurrenciesByShop($id_shop) {

		$ids = Db::getInstance()->ExecuteS(
			'SELECT c.id_currency 
				FROM ' . _DB_PREFIX_ . 'currency c 
				LEFT JOIN ' . _DB_PREFIX_ . 'currency_shop cs
					ON c.id_currency = cs.id_currency
				WHERE c.active = 1
					AND c.deleted = 0 
					AND cs.id_shop = ' . (int)$id_shop);

		if (count($ids) > 0) {
			return array_column($ids, 'id_currency');
        } else {
            return Array();
        }

	}

	public static function createMultiLangField($field)
    {
        $res = array();
        foreach (Language::getIDs(false) as $id_lang) {
            $res[$id_lang] = $field;
        }

        return $res;
    }

	public static function createFakeProduct($module) {
		// Devolvemos el producto fake en caso de que exista
		if(!empty($module->configuration->id_product_fake)) {
			$fake_product = new Product($module->configuration->id_product_fake);
			if (Validate::isLoadedObject($fake_product)) {
				$fake_product->price = 1;
				$fake_product->quantity = 9999999;
				$fake_product->save();
				return $fake_product;
			}
		}
		// Si no lo creamos
		$module->configuration->id_product_fake = 0;
		HipercalzadoUtils::updateConfiguration($module);

		$fake_product = new Product();
		$fake_product->name = HipercalzadoUtils::createMultiLangField('Hipercalzado product not found in Prestashop');
		// Si existe idioma esp, ponemos el nombre en esp
		if($espLangId = Language::getIdByIso('es', true)) {
			$fake_product->name[$espLangId] = 'Producto de Hipercalzado no encontrado en Prestashop';
		}

		$fake_product->price = 1;
		$fake_product->quantity = 9999999;
		$fake_product->add();

		$module->configuration->id_product_fake = $fake_product->id;
		HipercalzadoUtils::updateConfiguration($module);

		return $fake_product;
	} 


	public static function deleteFakeProduct($module) {
		// Devolvemos el producto fake en caso de que exista
		if(!empty($module->configuration->id_product_fake)) {
			$fake_product = new Product($module->configuration->id_product_fake);
			if (Validate::isLoadedObject($fake_product)) {
				$fake_product->delete();
			}
		}
		$module->configuration->id_product_fake = 0;
		HipercalzadoUtils::updateConfiguration($module);
		return true;
	}


    /*
	 * Add product to cart
	 *
	 * @param int $id_product Product ID
	 * @param int $id_product_attribute Product Attribute ID
	 * @param int $id_address_delivery Delivery Address ID
	 * @param int $quantity Quantity value
	 *
	 * @return bool Whether the product has been successfully added
	 */
   public static function addProductToCart(
	   Cart $cart,
	   $line
   ) {

		if(!Validate::isLoadedObject($cart)) {
			return false;
		}
		
		
		// if (!$line['is_fake_product']) {

			// Insertamos en la cart product, en caso de ser fake puede que sea duplcada y actualizamos
			$sql = 'INSERT INTO ' . _DB_PREFIX_ . 'cart_product
			(`id_cart`, `id_product`, `id_shop`, `id_product_attribute`, `quantity`, `id_address_delivery`, `date_add`)
			values(
				' . (int) $cart->id . ',
				' . (int) $line['product_id'] . ',
				' . (int) $cart->id_shop . ',
				' . (int) $line['product_attribute_id'] . ',
				' . (int) $line['product_quantity'] . ',
				' . (int) $cart->id_address_delivery . ', 
				NOW()) 
				ON DUPLICATE KEY UPDATE    
				quantity = quantity + ' . (int) $line['product_quantity'] . '
				';

			Db::getInstance()->execute($sql);
			
			 // Creamos precio especifico y asginamos
            $shop = new Shop((int) $cart->id_shop);

			$cart->updateQty((int)$line['product_quantity'], 
								(int) $line['product_id'], 
								(int) $line['product_attribute_id'], 
								false, 
								'up', 
								(int) $cart->id_address_delivery, 
								$shop,
								false,
								false,
								true,
								true
							);
			
			$cart->save();
			// die(dump($cart->getProducts(true)));

		// }
		
	   return true;
   }

   public static function hipercalzadoProductExistsInCart($id_product, $id_product_attribute, $id_address_delivery, $id_cart) {
		// Backward compatibility: check if there are no products in cart with specific `id_customization` before returning false
		$product_in_cart = (int) Db::getInstance()->getValue('
		SELECT COUNT(`id_product`) FROM `' . _DB_PREFIX_ . 'cart_product`
		WHERE `id_cart` = ' . (int) $id_cart . ' 
		AND `id_customization` = 0 
		AND `id_product` = ' . (int) $id_product . ' 
		AND `id_product_attribute` = ' . (int) $id_product_attribute . ' 
		AND `id_address_delivery` = ' . (int) $id_address_delivery);
		if ($product_in_cart) {
			return true;
		} else {
			return false;
		}
   }

   /**
     * Reduces the product stock
     *
     * @param $productId - The product id
     * @param $reduction - The quantity to decrement
     * @param $isCombination - Is a combination?
     */
    public static function changeProductStock($productId, $reduction, $idCombination)
    {
        //is a virtual product?
        if ($productId > 0) {
            StockAvailable::updateQuantity((int)$productId, (int)$idCombination, $reduction, (int)Shop::getContextShopID());
        }
    }

	/**
     * Request to check if DNI field is required
     * depending on the current selected country.
     *
     * @param int $idCountry
     *
     * @return bool
     */
    public static function HipercalzadoAddressdniRequired($idCountry)
    {
        return (bool) Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(
            'SELECT c.`need_identification_number` ' .
            'FROM `' . _DB_PREFIX_ . 'country` c ' .
            'WHERE c.`id_country` = ' . (int) $idCountry
        );
    }

	public static function translate($string)
    {
        switch (self::getLangISOCode()) {
            case 'es':
                switch ($string) {
                    case 'To generate the user token click on the following link in the \'API\' tab';
                        return 'Para generar el token de usuario, haga click en el siguiente enlace dentro de la pestaña \'API\'';
					case 'Combination ID':
						return 'ID de combinación';
					case 'Combination SKU':
						return 'SKU de combinación';
					case 'EAN':
						return 'EAN';
					case 'Product ID':
						return 'ID de producto';
					case 'Process finished correctly':
						return 'Proceso finalizado correctamente';
                    default:
                        return $string;
                }
                break;
            case 'en':
                switch ($string) {
                    default:
                        return $string;
                }
                break;

            default:
                return $string;
        }
    }

	protected static function getLangISOCode()
    {
        $langID = Context::getContext()->language->id;
        $lang = Db::getInstance()
            ->ExecuteS(
                '
                SELECT iso_code

                FROM `' . _DB_PREFIX_ . 'lang`

                WHERE id_lang = ' . pSQL($langID)
            );
        return $lang[0]['iso_code'];
    }
	
}
