Buenos días.
Hace unas semanas actualicé el módulo de Paypal oficial a la útima versión (6.4.2) y al hacer pruebas comprobé que los pedidos, si bien terminaban correctamente todo el proceso de pago, quedaban en estado "En espera de pago por Paypal".
He estado buscando más información sin mucho éxito hasta que en el repositorio del módulo (https://github.com/202ecommerce/paypal/issues) vi que había algunas entradas con el mismo problema (en particular la 353). Decidí ponerme a investigar un poco en mi propia instalación y aquí resumo lo que he encontrado. Espero le sirva a alguien que tenga el mismo problema.
La primera pista la encontré en el error.log de Apache donde había una traza interesante:
PHP Fatal error: Uncaught Error: Call to a member function getPaypalOrderByPaymentId() on null in /var/www/html/tienda/modules/paypal/controllers/front/webhookhandler.php:196 Stack trace: #0 /var/www/html/tienda/modules/paypal/controllers/front/webhookhandler.php(114): PaypalWebhookhandlerModuleFrontController->initPaypalOrder() #1 /var/www/html/tienda/classes/Dispatcher.php(510): PaypalWebhookhandlerModuleFrontController->run() #2 /var/www/html/tienda/index.php(28): DispatcherCore->dispatch() #3 {main}\n thrown in /var/www/html/tienda/modules/paypal/controllers/front/webhookhandler.php on line 196
Este error, indica que el fallo está en la linea 196. Yendo al fuente:
luego la propiedad servicePaypalOrder es NULL. Entiendo que esto es un error del módulo de Paypal y así lo he reportado. Sin embargo investigando un poco más, la traza indica que a este método se llama desde la linea 114.
Hay que destacar aquí, que el if indica que esta parte del código está tratando una excepción, así que, antes del error de Paypal, se está produciendo otro, que no da la cara, oculto por el NULL anterior.
Comentando la linea 196 y dejando que devuelva un objeto PaypalOrder vacío, aparece una traza de error en el log del módulo 😊
Ese servicio es mío y es llamado en el hook hookActionPaymentConfirmation en una parte de código del backoffice con symfony. No tiene mucho sentido que el servicio no exista, pero si miramos despacio, entenderemos la situación.
El módulo de Paypal utiliza webhooks para obtener la respuesta de pago desde Paypal. En particular, Paypal llama a un controlador DE FRONT:
"POST /tienda/es/module/paypal/webhookhandler HTTP/1.1" 500 4278 "-" "PayPal/AUHR-214.0-58712720"
Este es un PaypalWebhookhandlerModuleFrontController luego está claro que es de front. El contenedor de Symfony con el que trabaja este controlador de Front, evidentemente es de front. Si hacemos un volcado del objeto vemos que:
[container:protected] => FrontContainer Object
El contenedor de front de Prestashop es en estos momentos mínimo y apenas publica servicios, (evidentemente ninguno de mis módulos) por tanto el error es claro. Pero, ¿por qué se está ejecutando código de Backoffice en un FrontController? Pues porque al contrario de lo que el propio Prestashop dice en su documentación (https://devdocs.prestashop-project.org/8/development/components/context/), en el contexto de ejecución de este FrontController el objeto "employee" no es null. ¿?¿?
Gran error si pretendes conocer el contexto de ejecución usando
if (isset(Context::getContext()->employee))
como yo hago....
¿Alguien conoce una forma mejor de asegurarse de que estamos en contexto Backoffice?
Por ahora he añadido al if anterior el tipo controller:
if (isset($context->employee) && !in_array($context->controller->controller_type, ['front', 'modulefront'])){