. */ /* */ /*************************************************************************************/ namespace Paypal\Controller; use Paypal\Classes\API\PaypalApiCredentials; use Paypal\Classes\API\PaypalApiLogManager; use Paypal\Classes\API\PaypalApiManager; use Paypal\Classes\NVP\Operations\PaypalNvpOperationsDoExpressCheckoutPayment; use Paypal\Classes\NVP\Operations\PaypalNvpOperationsGetExpressCheckoutDetails; use Paypal\Classes\NVP\PaypalNvpMessageSender; use Paypal\Paypal; use Thelia\Core\Event\Order\OrderEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Core\HttpKernel\Exception\RedirectException; use Thelia\Model\Base\OrderQuery; use Thelia\Model\OrderStatus; use Thelia\Model\OrderStatusQuery; use Thelia\Module\BasePaymentModuleController; use Thelia\Tools\URL; /** * Class PaypalResponse * @package Paypal\Controller * @author Thelia */ class PaypalResponse extends BasePaymentModuleController { /** @var PaypalApiLogManager */ private $logger; public function __construct() { $this->logger = new PaypalApiLogManager(); } /** * @param $order_id * @return \Thelia\Core\HttpFoundation\Response */ public function ok($order_id) { $token = null; $message = ''; try { $order = $this->checkorder($order_id, $token); /* * $payerid string value returned by paypal * $logger PaypalApiLogManager used to log transctions with paypal */ $payerid = $this->getRequest()->get('PayerID'); if (! empty($payerid)) { /* * $config ConfigInterface Object that contains configuration * $api PaypalApiCredentials Class used by the library to store and use 3T login(username, password, signature) * $sandbox bool true if sandbox is enabled */ $api = new PaypalApiCredentials(); $sandbox = Paypal::isSandboxMode(); /* * Send getExpressCheckout & doExpressCheckout * empty cart */ $getExpressCheckout = new PaypalNvpOperationsGetExpressCheckoutDetails( $api, $token ); $request = new PaypalNvpMessageSender($getExpressCheckout, $sandbox); $response = PaypalApiManager::nvpToArray($request->send()); $this->logger->logTransaction($response); if (isset($response['ACK']) && $response['ACK'] === 'Success' && isset($response['PAYERID']) && $response['PAYERID'] === $payerid && isset($response['TOKEN']) && $response['TOKEN'] === $token ) { $doExpressCheckout = new PaypalNvpOperationsDoExpressCheckoutPayment( $api, round($order->getTotalAmount(), 2), $order->getCurrency()->getCode(), $payerid, PaypalApiManager::PAYMENT_TYPE_SALE, $token, // FIXME This URL is not used in PaypalNvpOperationsDoExpressCheckoutPayment, and has no defined route URL::getInstance()->absoluteUrl("/module/paypal/listen"), PaypalApiManager::BUTTON_SOURCE ); $request = new PaypalNvpMessageSender($doExpressCheckout, $token); $response = PaypalApiManager::nvpToArray($request->send()); $this->logger->logTransaction($response); // Store correlation ID in the order if (isset($response['CORRELATIONID'])) { $order ->setTransactionRef($response['CORRELATIONID']) ->save(); ; } // In case of pending status, log the reason to get usefull information (multi-currency problem, ...) if (isset($response['ACK']) && $response['ACK'] === "Success" && isset($response['PAYMENTINFO_0_PAYMENTSTATUS']) && $response['PAYMENTINFO_0_PAYMENTSTATUS'] === "Pending") { $message = $this->getTranslator()->trans( "Paypal transaction is pending. Reason: %reason", [ 'reason' => $response['PAYMENTINFO_0_PENDINGREASON'] ], Paypal::DOMAIN ); } /* * In case of success, go to success page * In case of error, show it */ if (isset($response['ACK']) && $response['ACK'] === "Success" && isset($response['PAYMENTINFO_0_PAYMENTSTATUS']) && $response['PAYMENTINFO_0_PAYMENTSTATUS'] === "Completed" && isset($response['TOKEN']) && $response['TOKEN'] === $token ) { /* * Set order status as paid */ $event = new OrderEvent($order); $event->setStatus(OrderStatusQuery::getPaidStatus()->getId()); $this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event); $this->redirectToSuccessPage($order_id); } else { $message = $this->getTranslator()->trans("Failed to validate your payment", [], Paypal::DOMAIN); } } else { $message = $this->getTranslator()->trans("Failed to validate payment parameters", [], Paypal::DOMAIN); } } else { $message = $this->getTranslator()->trans("Failed to find PayerID", [], Paypal::DOMAIN); } $this->logger->getLogger()->info("Order [" . $order_id . "] : " . $message); } catch (RedirectException $ex) { throw $ex; } catch (\Exception $ex) { $this->logger->getLogger()->error("Error occured while processing express checkout : " . $ex->getMessage()); $message = $this->getTranslator()->trans( "Unexpected error: %mesg", [ '%mesg' => $ex->getMessage()], Paypal::DOMAIN ); } $this->redirectToFailurePage($order_id, $message); } /* * @param $order_id int * @return \Thelia\Core\HttpFoundation\Response */ public function cancel($order_id) { $token = null; try { $order = $this->checkorder($order_id, $token); $logger = new PaypalApiLogManager(); $logger->getLogger()->warning("User canceled payment of order ".$order->getRef()); $event = new OrderEvent($order); $event->setStatus(OrderStatusQuery::create()->findOneByCode(OrderStatus::CODE_CANCELED)->getId()); $this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event); $message = $this->getTranslator()->trans("You canceled your payment", [], Paypal::DOMAIN); } catch (\Exception $ex) { $this->logger->getLogger()->error("Error occured while canceling express checkout : " . $ex->getMessage()); $message = $this->getTranslator()->trans( "Unexpected error: %mesg", [ '%mesg' => $ex->getMessage()], Paypal::DOMAIN ); } $this->redirectToFailurePage($order_id, $message); } /* * @param $order_id int * @param &$token string|null * @throws \Exception * @return \Thelia\Model\Order */ public function checkorder($order_id, &$token) { $token = $this->getRequest()->getSession()->get('Paypal.token'); if ($token !== $this->getRequest()->get('token')) { throw new \Exception( $this->getTranslator()->trans( "Invalid Paypal token. Please try again.", [], Paypal::DOMAIN ) ); } if (null === $order = OrderQuery::create()->findPk($order_id)) { throw new \Exception( $this->getTranslator()->trans( "Invalid order ID. This order doesn't exists or doesn't belong to you.", [], Paypal::DOMAIN ) ); } return $order; } /** * Return a module identifier used to calculate the name of the log file, * and in the log messages. * * @return string the module code */ protected function getModuleCode() { return "Paypal"; } }