From 31817b9097c110e1c5208246ee119e7592fae406 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 6 Oct 2014 14:51:51 -0700 Subject: [PATCH] Disable Phortune Paypal payment provider Summary: Ref T2787. For test charges, Paypal is putting the charge in a "payment review" state. Dealing with this state requires way more infrastructure than other providers: we're supposed to pause delivery, then poll Paypal every 6 hours to see if the review has resolved. Since I can't seem to generate normal test charges, I can't test Paypal for now. Disable it until we have more infrastructure. (This diff gets us further along, up to the point where I hit this issue.) Test Plan: Read documentation, rolled eyes. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T2787 Differential Revision: https://secure.phabricator.com/D10644 --- .../controller/PhortuneProviderController.php | 14 +++ .../PhortunePaypalPaymentProvider.php | 106 ++++++++++++++++-- .../provider/PhortuneWePayPaymentProvider.php | 10 +- 3 files changed, 110 insertions(+), 20 deletions(-) diff --git a/src/applications/phortune/controller/PhortuneProviderController.php b/src/applications/phortune/controller/PhortuneProviderController.php index 96d2bc4157..be66ca695f 100644 --- a/src/applications/phortune/controller/PhortuneProviderController.php +++ b/src/applications/phortune/controller/PhortuneProviderController.php @@ -71,4 +71,18 @@ final class PhortuneProviderController extends PhortuneController { ->executeOne(); } + public function loadActiveCharge(PhortuneCart $cart) { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + return id(new PhortuneChargeQuery()) + ->setViewer($viewer) + ->withCartPHIDs(array($cart->getPHID())) + ->withStatuses( + array( + PhortuneCharge::STATUS_CHARGING, + )) + ->executeOne(); + } + } diff --git a/src/applications/phortune/provider/PhortunePaypalPaymentProvider.php b/src/applications/phortune/provider/PhortunePaypalPaymentProvider.php index 21af366997..44af747ea9 100644 --- a/src/applications/phortune/provider/PhortunePaypalPaymentProvider.php +++ b/src/applications/phortune/provider/PhortunePaypalPaymentProvider.php @@ -3,6 +3,9 @@ final class PhortunePaypalPaymentProvider extends PhortunePaymentProvider { public function isEnabled() { + // TODO: See note in processControllerRequest(). + return false; + return $this->getPaypalAPIUsername() && $this->getPaypalAPIPassword() && $this->getPaypalAPISignature(); @@ -74,11 +77,28 @@ final class PhortunePaypalPaymentProvider extends PhortunePaymentProvider { PhortuneProviderController $controller, AphrontRequest $request) { + $viewer = $request->getUser(); + $cart = $controller->loadCart($request->getInt('cartID')); if (!$cart) { return new Aphront404Response(); } + $charge = $controller->loadActiveCharge($cart); + switch ($controller->getAction()) { + case 'checkout': + if ($charge) { + throw new Exception(pht('Cart is already charging!')); + } + break; + case 'charge': + case 'cancel': + if (!$charge) { + throw new Exception(pht('Cart is not charging yet!')); + } + break; + } + switch ($controller->getAction()) { case 'checkout': $return_uri = $this->getControllerURI( @@ -95,17 +115,25 @@ final class PhortunePaypalPaymentProvider extends PhortunePaymentProvider { $price = $cart->getTotalPriceAsCurrency(); + $charge = $cart->willApplyCharge($viewer, $this); + + $params = array( + 'PAYMENTREQUEST_0_AMT' => $price->formatBareValue(), + 'PAYMENTREQUEST_0_CURRENCYCODE' => $price->getCurrency(), + 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', + 'PAYMENTREQUEST_0_CUSTOM' => $charge->getPHID(), + + 'RETURNURL' => $return_uri, + 'CANCELURL' => $cancel_uri, + + // TODO: This should be cart-dependent if we eventually support + // physical goods. + 'NOSHIPPING' => '1', + ); + $result = $this ->newPaypalAPICall() - ->setRawPayPalQuery( - 'SetExpressCheckout', - array( - 'PAYMENTREQUEST_0_AMT' => $price->formatBareValue(), - 'PAYMENTREQUEST_0_CURRENCYCODE' => $price->getCurrency(), - 'RETURNURL' => $return_uri, - 'CANCELURL' => $cancel_uri, - 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', - )) + ->setRawPayPalQuery('SetExpressCheckout', $params) ->resolve(); $uri = new PhutilURI('https://www.sandbox.paypal.com/cgi-bin/webscr'); @@ -115,18 +143,74 @@ final class PhortunePaypalPaymentProvider extends PhortunePaymentProvider { 'token' => $result['TOKEN'], )); + $cart->setMetadataValue('provider.checkoutURI', $uri); + $cart->save(); + + $charge->setMetadataValue('paypal.token', $result['TOKEN']); + $charge->save(); + return id(new AphrontRedirectResponse()) ->setIsExternal(true) ->setURI($uri); case 'charge': - var_dump($_REQUEST); + $token = $request->getStr('token'); + + $params = array( + 'TOKEN' => $token, + ); + + $result = $this + ->newPaypalAPICall() + ->setRawPayPalQuery('GetExpressCheckoutDetails', $params) + ->resolve(); + + var_dump($result); + + if ($result['CUSTOM'] !== $charge->getPHID()) { + throw new Exception( + pht('Paypal checkout does not match Phortune charge!')); + } + + if ($result['CHECKOUTSTATUS'] !== 'PaymentActionNotInitiated') { + throw new Exception( + pht( + 'Expected status "%s", got "%s".', + 'PaymentActionNotInitiated', + $result['CHECKOUTSTATUS'])); + } + + $price = $cart->getTotalPriceAsCurrency(); + + $params = array( + 'TOKEN' => $token, + 'PAYERID' => $result['PAYERID'], + + 'PAYMENTREQUEST_0_AMT' => $price->formatBareValue(), + 'PAYMENTREQUEST_0_CURRENCYCODE' => $price->getCurrency(), + 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale', + ); + + $result = $this + ->newPaypalAPICall() + ->setRawPayPalQuery('DoExpressCheckoutPayment', $params) + ->resolve(); + + // TODO: Paypal can send requests back in "PaymentReview" status, + // and does this for test transactions. We're supposed to hold + // the transaction and poll the API every 6 hours. This is unreasonably + // difficult for now and we can't reasonably just fail these charges. + + var_dump($result); + + die(); break; case 'cancel': var_dump($_REQUEST); break; } - throw new Exception("The rest of this isn't implemented yet."); + throw new Exception( + pht('Unsupported action "%s".', $controller->getAction())); } private function newPaypalAPICall() { diff --git a/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php b/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php index 0bfe334654..57dd2d6817 100644 --- a/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php +++ b/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php @@ -100,15 +100,7 @@ final class PhortuneWePayPaymentProvider extends PhortunePaymentProvider { $wepay = new WePay($this->getWePayAccessToken()); - $charge = id(new PhortuneChargeQuery()) - ->setViewer($viewer) - ->withCartPHIDs(array($cart->getPHID())) - ->withStatuses( - array( - PhortuneCharge::STATUS_CHARGING, - )) - ->executeOne(); - + $charge = $controller->loadActiveCharge($cart); switch ($controller->getAction()) { case 'checkout': if ($charge) {