Existe en Prestashop, por lo menos hasta la versión más reciente a día de hoy ( Prestashop 1.4.3 ) un extraño problema con los módulos de pago. Aunque no se si catalogarlo como bug sería lo adecuado.
(ACTUALIZACIóN) Han solucionado el problema en la 1.4.4
¿Habéis notado alguna vez que aún funcionando bien un módulo de pago hay raras ocasiones en las que finaliza el pedido con «Error de pago» a pesar de que el pago ha ido bien? ¿Habéis hecho pruebas y habéis detectado que el problema sólo es reproducible en determinados servidores y con determinados importes en el pedido?
Pues bien, aunque este problema no aflore o no se detecte en todas las instalaciones de Prestashop es algo que puede empezar a ocurrirnos en cualquier momento, y la causa es cuanto menos curiosa, la precisión finita de los números float.
Si rastreamos el error llegaremos a el fichero PaymentModules.php en el método validateOrder, concretamente a este trozo de código:
// Amount paid by customer is not the right one -> Status = payment error if ($order->total_paid != $order->total_paid_real) $id_order_state = _PS_OS_ERROR_;
Resulta que aunque $order->total_paid y $order->total_paid_real sean el «mismo número» la expresión del if evalua como verdadero. Es más, si hacemos un var_dump() de ambas variables nos dará el exactamente mismo resulado para ambas. ¿como es posible entonces que no sean iguales según el operador != de php?
El quiz es el tipo de la variable y el qué o cómo podemos ver realmente el verdadero valor de la variable. Aunque hagamos un var_dump de la variable, que en este caso son de tipo float, lo que veamos es la conversión del valor real de la variable a un tipo string para representarlo en el resultado de var_dump. Esto es lo que nos puede llevar a engaño ya que no vemos el valor real que maneja la máquina.
Tal y como nos avisan en php la precisión de los float o números de punto flotante no es infinita. «Así que nunca se confía en resultados de números flotantes hasta el último dígito y nunca se comparan números de punto flotante para igualdad«.
En Prestashop parecen haber pasado este punto por alto en el trozo de código indicado anteriormente. De momento nuestra solución, mientras no propongan otra cosa desde prestashop, es cambiar ese trozo de código por el siguiente:
// Amount paid by customer is not the right one -> Status = payment error if ((string)$order->total_paid != (string)$order->total_paid_real) $id_order_state = _PS_OS_ERROR_;
(ACTUALIZACIÓN) El código por el que han optado para solucionarlo:
if (number_format($order->total_paid, 2) != number_format($order->total_paid_real, 2))
Espero que este post os evite los quebraderos de cabeza que nos ha supuesto este pequeño detalle a nosotros. Seguramente a lo largo y ancho del código de Prestashop habrá más comparaciones similares pero estando sobre aviso será más fácil detectar el problema.