/** * Builds form given return, success and fail urls. * * @return FormView */ public function buildForm() { $formBuilder = $this->formFactory->createNamedBuilder(null); $orderId = $this->paymentBridge->getOrderId(); $orderCurrency = $this->paymentBridge->getCurrency(); $this->checkCurrency($orderCurrency); /** * Creates the success return route, when coming back * from PayPal web checkout. */ $successReturnUrl = $this->urlFactory->getSuccessReturnUrlForOrderId($orderId); /** * Creates the cancel payment route, when cancelling * the payment process from PayPal web checkout. */ $cancelReturnUrl = $this->urlFactory->getCancelReturnUrlForOrderId($orderId); /** * Creates the IPN payment notification route, * which is triggered after PayPal processes the * payment and returns the validity of the transaction. * * For forther information * * https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/ * https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNIntro/ */ $processUrl = $this->urlFactory->getProcessUrlForOrderId($orderId); $formBuilder->setAction($this->urlFactory->getApiEndpoint())->setMethod('POST')->add('business', 'hidden', ['data' => $this->business])->add('return', 'hidden', ['data' => $successReturnUrl])->add('cancel_return', 'hidden', ['data' => $cancelReturnUrl])->add('notify_url', 'hidden', ['data' => $processUrl])->add('currency_code', 'hidden', ['data' => $orderCurrency])->add('env', 'hidden', ['data' => '']); /** * Create a PayPal cart line for each order line. * * Project specific PaymentBridgeInterface::getExtraData * should return an array of this form * * ['items' => [ * 0 => [ 'item_name' => 'Item 1', 'amount' => 1234, 'quantity' => 2 ], * 1 => [ 'item_name' => 'Item 2', 'amount' => 2345, 'quantity' => 1 ], * ]] * * The 'items' key consists of an array with the basic information * of each line of the order. Amount is the price of the product, * not the total of the order line */ $cartData = $this->paymentBridge->getExtraData(); $itemsData = $cartData['items']; $iteration = 1; foreach ($itemsData as $orderLine) { $formBuilder->add('item_name_' . $iteration, 'hidden', ['data' => $orderLine['item_name']])->add('amount_' . $iteration, 'hidden', ['data' => $orderLine['amount'] / 100])->add('quantity_' . $iteration, 'hidden', ['data' => $orderLine['quantity']]); ++$iteration; } if (isset($cartData['discount_amount_cart'])) { $formBuilder->add('discount_amount_cart', 'hidden', ['data' => $cartData['discount_amount_cart'] / 100]); } return $formBuilder->getForm()->createView(); }
/** * Check if transaction is complete. * * When we receive an IPN response, we should * check that the price paid corresponds to the * amount stored in the PaymentMethod. This double * check is essential since the web checkout form * could be mangled. * * @link https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/ * * @param array $ipnParameters Paypal IPN parameters * * @return bool */ private function transactionSuccessful($ipnParameters) { /** * First of all we have to check the validity of the IPN * message. We need to send back the contents of the query * string coming from Paypal's IPN message. */ $ipnNotifyValidateUrl = $this->urlFactory->getApiEndpoint() . '?' . http_build_query(array_merge($this->urlFactory->getPaypalNotifyValidateQueryParam(), $ipnParameters)); $ipnValidated = file_get_contents($ipnNotifyValidateUrl) == 'VERIFIED'; /** * Matching paid amount with the originating order amount, * this is a security check to prevent frauds by manually * changing the papal form. */ $amountMatches = $this->paymentBridge->getAmount() / 100 == $ipnParameters['mc_gross']; $amountMatches = $amountMatches && $this->paymentBridge->getCurrency() == $ipnParameters['mc_currency']; /** * When a transaction is successful, payment_status has a 'Completed' value. */ return $amountMatches && $ipnValidated && strcmp($ipnParameters['payment_status'], 'Completed') === 0; }