Error: No hay transportistas disponibles que envien a algunas de sus direcciones

El día a día de un desarrollador puede ser increiblemente aburrido o no. Hoy me ha sucedido que probando la tienda de un cliente, no podía hacer un pedido, al finalizar el pedido, obtenía siempre el error «Error: No hay transportistas disponibles que envien a algunas de sus direcciones».
Revisé todas las configuraciones de transportistas, pesos, zonas, etc… y estaba todo correcto, así que me he decidido por bajar a las profundidades y localizar qué estaba sucediendo, es decir, a trazar código ( como casi todos los días 😀 ).

Lo voy a resumir muchísimo, y si alguien tiene dudas… que pregunte.

1.- Por donde comenzar. El error aparece al realizar el pedido, en mi caso, un pedido rápido. Si abro firebug y clickeo en los términos y condiciones, veo que se lanza una petición ajax al servidor que devuelve toda la información con la que rellena los medios de pago, los transportistas, etc… que la petición se lanza es «pedido-rapido».

[php]
http://localhost/prestashop/es/pedido-rapido
{«HOOK_TOP_PAYMENT»:» «,»HOOK_PAYMENT»:»<p class=\»warning\»>Error: No hay transportistas disponibles que envien a algunas de sus direcciones<\/p>»}
[/php]

2.- Para localizar que controller gestiona esta url nos vamos al backend en «Preferencias > SEO + URL’s» y buscamos ‘pedido-rapido’ en la columna de ‘url-amigable’ y vemos que en página aparece ‘order-opc’. Ese el nombre del controller que gestionará las peticiones para ‘pedido-rapido’

3.- Siguiendo nuestros conocimientos vemos en OrderOpcControllerCore::init() que hay una serie de casos, si la llamada es ajax , nos centramos en el TOS y lo que nos intresa es que lo nos devuelve la funcion «$this->_getPaymentMethods()»

[php]
case ‘updateTOSStatusAndGetPayments’:
if (Tools::isSubmit(‘checked’))
{
$this->context->cookie->checkedTOS = (int)(Tools::getValue(‘checked’));
die(Tools::jsonEncode(array(
‘HOOK_TOP_PAYMENT’ => Hook::exec(‘displayPaymentTop’),
‘HOOK_PAYMENT’ => $this->_getPaymentMethods()
)));
}
break;
[/php]

4.- En _getPaymentMethods() el bloque que nos interesa es este y concretamente «$this->context->cart->getDeliveryOptionList()»

[php]
if (count($this->context->cart->getDeliveryOptionList()) == 0 && !$this->context->cart->isVirtualCart())
{
if ($this->context->cart->isMultiAddressDelivery())
return ‘<p class=»warning»>’.Tools::displayError(‘Error: None of your chosen carriers deliver to some of  the addresses you\’ve selected.’).'</p>’;
else
return ‘<p class=»warning»>’.Tools::displayError(‘Error: None of your chosen carriers deliver to the address you\’ve selected.’).'</p>’;
}
[/php]

5.- Nos vamos a la case Cart para tracear Cart::getDeliveryOptionList() y después de echarle unas trazas vemos que realmente la chicha de todo el proceso de gestión de los envíos lo tenemos en esta linea
[php]
$package_list = $this->getPackageList();
[/php]

6.- La funcion Cart::getPackageList() devolverá informacion sobre los envíos y transportistas con lo que puedes anotarla en tus marcadores de código, para ir directamente y trazar por aquí cuando no sepas muy bien por dónde comenzar.

No obstante en mi caso, resultó que la parte que necesitaba verificar era esta última linea, que carga los transportistas para los productos, almacenes, etc.. etc…

[php]
$product[‘carrier_list’] = array_merge($product[‘carrier_list’], Carrier::getAvailableCarrierList(new Product($product[‘id_product’]), $id_war, $product[‘id_address_delivery’], null, $this));
[/php]

Todo este trabajo, concluye en que mis cookies estaban dando problemas y tuve que borrarlas para que me funcionar, eso pasa por mezclar muchas instalaciones !!!!

Prestashop Madrid

prestashopmadrid

Para los que me conocen, ya sabrán que una de las muchas cosas con las que estoy en los últimos años, es con las tiendas de comercio electrónico Prestashop. Para los que no conocen Prestashop, es una excelente herramienta opensource para comercio electrónico, lo que viene llamándose una tienda online.
Uno de los modelos que sustenta al opensource es el de solicitar mejoras y personalizaciones sobre un software ya desarrollado pero que necesita ciertos retoques, por que cada persona y cada empresa es distinta, nunca puede haber una herramienta que cumpla 100% con los requirimientos de los usuarios. Esto significa que el que software sea libre, sin coste, los desarrolladores, diseñadores, maquetadores etc… cobramos por modificar esas cosas que hacen que algo bueno, se convierta en algo más grande y más personal.

Durante años apenas me he acercado a comunidades de desarrollo y de software, hasta el último año en el que he tenido la gran suerte de juntarme con compañeros muy profesionales y con gran conocimiento que han hecho posible que algunos proyectos que nunca llegaron a salir, estén siendo reales en este momento. Por eso más que nunca creo en el software libre y en las comunidades abiertas.

Por este motivo he creado Prestashop Madrid, una grupo para unir a todos los interesados en este software, conversar, mejorar y ayudarnos entre todos tanto laboralmente como personalmente en lo que nos apasiona, por que con la comunidad, se construye, mejor más rápido y se disfruta más.

Para empezar a conocer a todos estos entusiastas de Prestashop y del software libre, he creado un evento:
Presentación Prestashop Madrid que se celebrará el 29 de Mayo en el centro de coworking Materia Gris en Madrid.

Espero veros allí.

cómo instalar eAccelerator para acelerar tu servidor apache

Últimamente tratamos con bastantes tiendas en prestashop y una de las formas de mejorar el rendimiento de las tiendas es usando eaccelerator.
Es muy fácil de instalar si no tenemos el paquete en nuestra distribución, el único inconveniente es que tienes que recompilar cada vez que instales una versión nueva de php.

# instalamos dependencias
apt-get install php5-dev automake autoconf libtool m4

# descargamos y descomprimimos 
wget https://github.com/eaccelerator/eaccelerator/tarball/master -O eaccelerator.tar.gz
tar zxvf eaccelerator.tar.gz

export PHP_PREFIX="/usr"

$PHP_PREFIX/bin/phpize

./configure 
--enable-shared 
--with-php-config=$PHP_PREFIX/bin/php-config

# compilamos
make
# instalamos
make install 

mkdir /tmp/eaccelerator
chmod 0777 /tmp/eaccelerator

En este punto ya tenemos la instalación ahora solo hace falta configurar el módulo, para configurarlo en debian tenemos que editar el fichero

/etc/php5/conf.d/eaccelerator.ini

y agreagmos este contenido

extension="eaccelerator.so"
eaccelerator.shm_size="16"
eaccelerator.cache_dir="/tmp/eaccelerator"
eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
eaccelerator.filter=""
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="0"
eaccelerator.shm_prune_period="0"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"

Reiniciamos apache y echamos un vistazo al log de errores para verificar que no falla el módulo.
Podemos encontrarnos con un error como este :

"eAccelerator: Unable to change cache directory /var/cache/eaccelerator permissions"

Es debido a que no hay permisos para crear la estructura de directorios de la caché.
Desde la documentación de eaccelerator, nos instan a configurar la ruta de la caché en /tmp
según vemos en este enlace
https://github.com/eaccelerator/eaccelerator/wiki/InstallFromSource#wiki-Step_4_Creating_cache_directory

Prestashop redirecciones CMS no manteninete content_only

En Prestashop puedes crear contenido estático, páginas CMS con su propio minieditor CMS. Lo podeis encontrar en el backend / herramientas / CMS. Este contenido puede ser estar traducido a varios idiomas y es aquí donde puede que se nos presente un pequeño problema que vamos a resolver.

Si por ejemplo me creo un contenido CMS de informacion de mi tienda y lo pongo en ingles y castellano, con el ID = 2, la url quedaría algo así
[shell]
http://localhost/prestashop/content/2-informacion
[/shell]

Vale ahora si desde el frontend de la tienda visito la url, se redirijá a castellano o a ingles y quedará algo como esto :

[shell]
# castellano
http://localhost/prestashop/es/content/2-informacion
# ingles
http://localhost/prestashop/en/content/2-informacion
[/shell]

Con lo que si yo maqueto mi tienda con que ponga el primer enlace en un link para que la gente consulte la información de mi tienda no tendré que preocupar del idioma del visitante de la web, ya que se redirijá según el idioma que tenga almacenado en su cookie.

Pero imaginate que quieres que esta información aparezca en una ventana modal con jquery, en ese caso sólo queremos el contenido sin cabeceras, ni menús ni piés de página. Para eso se usa el parámetro content_only=1. Pues bien este parámetro no se mantiene en las redirecciones y para ello tenemos que crear un fichero en override/controllers/CMSController.php:

[shell]
< ?php class CMSController extends CMSControllerCore { public function canonicalRedirection() { // Automatically redirect to the canonical URL if the current in is the right one // $_SERVER['HTTP_HOST'] must be replaced by the real canonical domain if (Configuration::get('PS_CANONICAL_REDIRECT') && strtoupper($_SERVER['REQUEST_METHOD']) == 'GET') { if (Validate::isLoadedObject($this->cms) AND $canonicalURL = self::$link->getCMSLink($this->cms)){

if (!preg_match(‘/^’.Tools::pRegexp($canonicalURL, ‘/’).'([&?].*)?$/’, Tools::getProtocol().$_SERVER[‘HTTP_HOST’].$_SERVER[‘REQUEST_URI’]))
{

if ( Tools::getValue(‘content_only’) == 1 ){
$canonicalURL .= «?content_only=1»;

}

header(‘HTTP/1.0 301 Moved’);
header(‘Cache-Control: no-cache’);
if (_PS_MODE_DEV_)
die(‘[Debug] This page has moved
Please use the following URL instead: ‘.$canonicalURL.’‘);

Tools::redirectLink($canonicalURL);
}
}

if (Validate::isLoadedObject($this->cms_category) AND $canonicalURL = self::$link->getCMSCategoryLink($this->cms_category))
if (!preg_match(‘/^’.Tools::pRegexp($canonicalURL, ‘/’).'([&?].*)?$/’, Tools::getProtocol().$_SERVER[‘HTTP_HOST’].$_SERVER[‘REQUEST_URI’]))
{
header(‘HTTP/1.0 301 Moved’);
header(‘Cache-Control: no-cache’);
if (_PS_MODE_DEV_ )
die(‘[Debug] This page has moved
Please use the following URL instead: ‘.$canonicalURL.’‘);
Tools::redirectLink($canonicalURL);
}
}
}

}
[/shell]

prestashop fix empty cart cookie overwritted

Hi guys

I found a way to fix this issue.

After many hours of trace code I found that cookie is being overwrited when ajax cart is enabled.

This is the cause that the order was lost and cart appears empty and this is the explaination :

– Supose the first time you visit the shop, no cookies are on your browser yet.

– When you add a product using ajax cart ( using a ajax_add_to_cart_button class button ) you are using this piece of code :
[shell]$(‘.ajax_add_to_cart_button’).unbind(‘click’).click(function(){
var idProduct =  $(this).attr(‘rel’).replace(‘ajax_id_product_’, »);
if ($(this).attr(‘disabled’) != ‘disabled’)
ajaxCart.add(idProduct, null, false, this);
return false;
});[/shell]
So you call ajaxCart.add() when you add a product.

Inside ajaxCart.add() there are two significant actions that modify your cookie:

first one is expand the cartblock. Basically open the cart box and send an ajax petition to include ‘expand’ parameter into your cookie
[shell]if ($(‘#cart_block #cart_block_list’).hasClass(‘collapsed’))
this.expand();[/shell]
and inside expand() the expand action the visual box slidedown :
[shell]$(‘#’+parentId+’ #cart_block #cart_block_summary’).slideUp(200, function(){
$(this).addClass(‘collapsed’).removeClass(‘expanded’);
$(‘#’+parentId+’ #cart_block #cart_block_list’).slideDown({
duration: 600,
complete: function(){$(this).addClass(‘expanded’).removeClass(‘collapsed’);}
});
});[/shell]
and store cookie value  :
[shell]$.ajax({
type: ‘GET’,
url: baseDir + ‘modules/blockcart/blockcart-set-collapse.php’,
async: true,
data: ‘ajax_blockcart_display=expand’ + ‘&rand=’ + new Date().getTime()
});[/shell]
Second one, adds the product in your cart.
[shell]$.ajax({
type: ‘POST’,
url: baseDir + ‘cart.php’,
async: true,
cache: false,
dataType : «json»,
data: ‘add=1&ajax=true&qty=’ + ((quantity && quantity != null) ? quantity : ‘1’) + ‘&id_product=’ + idProduct + ‘&token=’ + static_token + ( (parseInt(idCombination) && idCombination != null) ? ‘&ipa=’ + parseInt(idCombination): »),
success: function(jsonData,textStatus,jqXHR)
{
….
….
….

});[/shell]
Well, tracing the code using phpfire I could see that requests are sent in this order :

1.- blockcart-set-collapse.php

2.- cart.php

In cases that works fine I got the return of the request in same order, but when cart gets empty, I reicived cart.php firt and then blockcart-set-collapse.php

This means that blockcart-set-collapse.php is requested without id_cart cookie value, so return a cookie without id_cart.

So id_cart is generated in cart.php call, and blockcart-set-collapse.php returns the cookie after cart.php, so the id_cart is not preserved because is being overwritted.

There are few ways to fix this :

1.- At ajaxCart.add() disable this.expand() , avoid to made ajax call

2.- at ajaxCart.expand() put ajax request before slideDown() call

3.- The second point and made ajaxcall syncronious setting async : false

[shell]$.ajax({
type: ‘GET’,
url: baseDir + ‘modules/blockcart/blockcart-set-collapse.php’,
async: false,
data: ‘ajax_blockcart_display=expand’ + ‘&rand=’ + new Date().getTime()
});[/shell]
Another way to fix this, is to have ever a id_cart at cookie.

I’m not sure but I think at previous prestashop ( 1.3.x) id_cart was stored at cookie in the first request.

At Prestashop 1.4.x cart is generated at FrontControllerCore::init() but not saved even asigned to the cookie.

Reviewing the code quickly, I see that the id_cart is asigned when a product is added to the cart.

So another solution could be to store a cart in cookies ever.

I hope this could help you to fix your shops !

I continue investigating this issue

PounStudio Team !

prestashop / paypal : Uncaught ReferenceError: $ is not defined

Existe un problema con Chrome , prestashop y paypal. Al ir a hacer un pago con paypal se redirige previamente a una web en blanco que genera un formulario para enviar a paypal. Pues chrome bloquea el fichero javascript de jquery. Esto es debido a que tu tienda tiene activado ssl y la url del javascript de jquery no, generando este error en la consola de chrome :

[shell]
Uncaught ReferenceError: $ is not defined
[/shell]

Para solucionarlo edita el fichero modules/paypal/standard/redirect.php y sustituye la linea de url por esta

[shell]
‘url’ => PayPal::getShopDomainSsl(true, true).__PS_BASE_URI__
[/shell]

Hay que usar la funcion PayPal::getShopDomainSsl()

Prestashop 1.5 is out !

prestashop

Como ya veníamos esperando, ha sido publicada la versión 1.5, un par de semanas depués de que se liberase la versión 1.4.9.0.

Como todos sabreis hay grandes cambios como el soporte para multitienda, templating en el backend y algunos cambios en los modelos de objetos, etc… Son grandes cambios para los desarrolladores y nuevas funcionalidades para los usuarios.

La version real es prestashop 1.5.0.9
Iremos desgranando poco a poco las novedades, trucos y recetas para los que estais interesados en esta plataforma de ecommerce que está dando mucho de qué hablar.

 

Más info en :

http://www.prestashop.com

Cambiar los decimales en prestashop

Desde el backend de Prestashop se pueden cambiar fácilmente el formato de los precios así como el número de decimales.

Es muy sencillo, los pasos a seguir son :

  • Acceder al Backend
  • Pinchar en Pagos
  • Divisas
  • Editar la divisa, por ejemplo Euros

Os adjunto una captura de pantalla:

 

prestashop cambiar decimales
prestashop cambiar decimales

Exportar productos desde Prestashop 1.3

Tengo que migrar un proyecto con Prestashop 1.3 a 1.4 y como hay varios procesos y varias personas implicadas en la migración, necesito exportar sólamente los productos de la tienda actual para retocarlos en el entorno de desarrollo. Para ello quiero traerme únicamente las tablas que tienen información de los productos.
El equipo de SEO se encargará de retocar y revisar las fichas de productos y prepararlas para la nueva versión.

He hecho esta lista de tablas para exportar:
[shell]ps_attachment
ps_attachment_lang
ps_attribute
ps_attribute_group
ps_attribute_group_lang
ps_attribute_impact
ps_attribute_lang
ps_category
ps_category_group
ps_category_lang
ps_category_product
ps_customization
ps_customization_field
ps_customization_field_lang
ps_customized_data
ps_feature
ps_feature_lang
ps_feature_product
ps_feature_value
ps_feature_value_lang
ps_image
ps_image_lang
ps_image_type
ps_manufacturer
ps_manufacturer_lang
ps_product
ps_product_attachment
ps_product_attribute
ps_product_attribute_combination
ps_product_attribute_image
ps_product_comment
ps_product_comment2
ps_product_comment2_criterion
ps_product_comment2_criterion_product
ps_product_comment2_grade
ps_product_comment_criterion
ps_product_comment_criterion_product
ps_product_comment_grade
ps_product_download
ps_product_lang
ps_product_sale
ps_product_tag
ps_scene
ps_scene_category
ps_scene_lang
ps_scene_products
ps_supplier
ps_supplier_lang[/shell]
y ahora el script
[shell]user=»root»
password=»»
dbname=»prestashop»
mysqldump -u $user -p$password –add-drop-table –quote-name $dbname ps_attachment ps_attachment_lang \
 ps_attribute ps_attribute_group ps_attribute_group_lang ps_attribute_impact ps_attribute_lang ps_category \
ps_category_group ps_category_lang ps_category_product ps_customization ps_customization_field \
 ps_customization_field_lang ps_customized_data ps_feature ps_feature_lang ps_feature_product \
ps_feature_value ps_feature_value_lang ps_image ps_image_lang ps_image_type ps_manufacturer \
ps_manufacturer_lang ps_product ps_product_attachment ps_product_attribute ps_product_attribute_combination \
 ps_product_attribute_image ps_product_comment ps_product_comment2 ps_product_comment2_criterion \
ps_product_comment2_criterion_product ps_product_comment2_grade ps_product_comment_criterion \
 ps_product_comment_criterion_product ps_product_comment_grade ps_product_download ps_product_lang \
ps_product_sale ps_product_tag ps_scene ps_scene_category ps_scene_lang ps_scene_products ps_supplier \
ps_supplier_lang[/shell]
Quizás también os interese exportar traducciones de prestashop

Actualización:
Tablas para la version 1.4
[shell]
ps_attachment
ps_attachment_lang
ps_attribute
ps_attribute_group
ps_attribute_group_lang
ps_attribute_impact
ps_attribute_lang
ps_cart_product
ps_category
ps_category_group
ps_category_lang
ps_category_product
ps_compare
ps_compare_product
ps_country
ps_country_lang
ps_discount_category
ps_feature
ps_feature_lang
ps_feature_product
ps_feature_value
ps_feature_value_lang
ps_group_reduction
ps_image
ps_image_lang
ps_image_type
ps_manufacturer
ps_manufacturer_lang
ps_product
ps_product_attachment
ps_product_attribute
ps_product_attribute_combination
ps_product_attribute_image
ps_product_comment
ps_product_comment2
ps_product_comment2_criterion
ps_product_comment2_criterion_product
ps_product_comment2_grade
ps_product_comment_criterion
ps_product_comment_criterion_category
ps_product_comment_criterion_lang
ps_product_comment_criterion_product
ps_product_comment_grade
ps_product_country_tax
ps_product_download
ps_product_group_reduction_cache
ps_product_lang
ps_product_sale
ps_product_tag
ps_scene
ps_scene_category
ps_scene_lang
ps_scene_products
ps_stock_mvt
ps_stock_mvt_reason
ps_stock_mvt_reason_lang
ps_tag
ps_wishlist
ps_wishlist_email
ps_wishlist_product
ps_wishlist_product_cart
[/shell]

y el script para la version 1.4:
[shell]
user=»root»
password=»»
dbname=»temp»
mysqldump -u $user -p$password –add-drop-table –quote-name $dbname ps_attachment ps_attachment_lang \
ps_attribute ps_attribute_group ps_attribute_group_lang ps_attribute_impact ps_attribute_lang ps_cart_product \
ps_category ps_category_group ps_category_lang ps_category_product ps_compare ps_compare_product \
ps_country ps_country_lang ps_discount_category ps_feature ps_feature_lang ps_feature_product \
ps_feature_value ps_feature_value_lang ps_group_reduction ps_image ps_image_lang ps_image_type \
ps_manufacturer ps_manufacturer_lang ps_product ps_product_attachment ps_product_attribute \
ps_product_attribute_combination ps_product_attribute_image ps_product_comment ps_product_comment2 \
ps_product_comment2_criterion ps_product_comment2_criterion_product ps_product_comment2_grade \
ps_product_comment_criterion ps_product_comment_criterion_category ps_product_comment_criterion_lang \
ps_product_comment_criterion_product ps_product_comment_grade ps_product_country_tax ps_product_download \
ps_product_group_reduction_cache ps_product_lang ps_product_sale ps_product_tag ps_scene ps_scene_category \
ps_scene_lang ps_scene_products ps_stock_mvt ps_stock_mvt_reason ps_stock_mvt_reason_lang ps_tag \
ps_wishlist ps_wishlist_email ps_wishlist_product ps_wishlist_product_cart
[/shell]