PageRenderTime 53ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php

http://github.com/facebook/phabricator
PHP | 279 lines | 232 code | 44 blank | 3 comment | 25 complexity | cc3a215ed340f6f866e438f096a268cb MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
  1. <?php
  2. final class PhortunePaymentMethodCreateController
  3. extends PhortuneController {
  4. public function handleRequest(AphrontRequest $request) {
  5. $viewer = $request->getViewer();
  6. $account_id = $request->getURIData('accountID');
  7. $account = id(new PhortuneAccountQuery())
  8. ->setViewer($viewer)
  9. ->withIDs(array($account_id))
  10. ->executeOne();
  11. if (!$account) {
  12. return new Aphront404Response();
  13. }
  14. $account_id = $account->getID();
  15. $merchant = id(new PhortuneMerchantQuery())
  16. ->setViewer($viewer)
  17. ->withIDs(array($request->getInt('merchantID')))
  18. ->executeOne();
  19. if (!$merchant) {
  20. return new Aphront404Response();
  21. }
  22. $cart_id = $request->getInt('cartID');
  23. $subscription_id = $request->getInt('subscriptionID');
  24. if ($cart_id) {
  25. $cancel_uri = $this->getApplicationURI("cart/{$cart_id}/checkout/");
  26. } else if ($subscription_id) {
  27. $cancel_uri = $this->getApplicationURI(
  28. "{$account_id}/subscription/edit/{$subscription_id}/");
  29. } else {
  30. $cancel_uri = $this->getApplicationURI($account->getID().'/');
  31. }
  32. $providers = $this->loadCreatePaymentMethodProvidersForMerchant($merchant);
  33. if (!$providers) {
  34. throw new Exception(
  35. pht(
  36. 'There are no payment providers enabled that can add payment '.
  37. 'methods.'));
  38. }
  39. if (count($providers) == 1) {
  40. // If there's only one provider, always choose it.
  41. $provider_id = head_key($providers);
  42. } else {
  43. $provider_id = $request->getInt('providerID');
  44. if (empty($providers[$provider_id])) {
  45. $choices = array();
  46. foreach ($providers as $provider) {
  47. $choices[] = $this->renderSelectProvider($provider);
  48. }
  49. $content = phutil_tag(
  50. 'div',
  51. array(
  52. 'class' => 'phortune-payment-method-list',
  53. ),
  54. $choices);
  55. return $this->newDialog()
  56. ->setRenderDialogAsDiv(true)
  57. ->setTitle(pht('Add Payment Method'))
  58. ->appendParagraph(pht('Choose a payment method to add:'))
  59. ->appendChild($content)
  60. ->addCancelButton($cancel_uri);
  61. }
  62. }
  63. $provider = $providers[$provider_id];
  64. $errors = array();
  65. if ($request->isFormPost() && $request->getBool('isProviderForm')) {
  66. $method = id(new PhortunePaymentMethod())
  67. ->setAccountPHID($account->getPHID())
  68. ->setAuthorPHID($viewer->getPHID())
  69. ->setMerchantPHID($merchant->getPHID())
  70. ->setProviderPHID($provider->getProviderConfig()->getPHID())
  71. ->setStatus(PhortunePaymentMethod::STATUS_ACTIVE);
  72. if (!$errors) {
  73. $errors = $this->processClientErrors(
  74. $provider,
  75. $request->getStr('errors'));
  76. }
  77. if (!$errors) {
  78. $client_token_raw = $request->getStr('token');
  79. $client_token = null;
  80. try {
  81. $client_token = phutil_json_decode($client_token_raw);
  82. } catch (PhutilJSONParserException $ex) {
  83. $errors[] = pht(
  84. 'There was an error decoding token information submitted by the '.
  85. 'client. Expected a JSON-encoded token dictionary, received: %s.',
  86. nonempty($client_token_raw, pht('nothing')));
  87. }
  88. if (!$provider->validateCreatePaymentMethodToken($client_token)) {
  89. $errors[] = pht(
  90. 'There was an error with the payment token submitted by the '.
  91. 'client. Expected a valid dictionary, received: %s.',
  92. $client_token_raw);
  93. }
  94. if (!$errors) {
  95. $errors = $provider->createPaymentMethodFromRequest(
  96. $request,
  97. $method,
  98. $client_token);
  99. }
  100. }
  101. if (!$errors) {
  102. $method->save();
  103. // If we added this method on a cart flow, return to the cart to
  104. // check out.
  105. if ($cart_id) {
  106. $next_uri = $this->getApplicationURI(
  107. "cart/{$cart_id}/checkout/?paymentMethodID=".$method->getID());
  108. } else if ($subscription_id) {
  109. $next_uri = $cancel_uri;
  110. } else {
  111. $account_uri = $this->getApplicationURI($account->getID().'/');
  112. $next_uri = new PhutilURI($account_uri);
  113. $next_uri->setFragment('payment');
  114. }
  115. return id(new AphrontRedirectResponse())->setURI($next_uri);
  116. } else {
  117. $dialog = id(new AphrontDialogView())
  118. ->setUser($viewer)
  119. ->setTitle(pht('Error Adding Payment Method'))
  120. ->appendChild(id(new PHUIInfoView())->setErrors($errors))
  121. ->addCancelButton($request->getRequestURI());
  122. return id(new AphrontDialogResponse())->setDialog($dialog);
  123. }
  124. }
  125. $form = $provider->renderCreatePaymentMethodForm($request, $errors);
  126. $form
  127. ->setUser($viewer)
  128. ->setAction($request->getRequestURI())
  129. ->setWorkflow(true)
  130. ->addHiddenInput('providerID', $provider_id)
  131. ->addHiddenInput('cartID', $request->getInt('cartID'))
  132. ->addHiddenInput('subscriptionID', $request->getInt('subscriptionID'))
  133. ->addHiddenInput('isProviderForm', true)
  134. ->appendChild(
  135. id(new AphrontFormSubmitControl())
  136. ->setValue(pht('Add Payment Method'))
  137. ->addCancelButton($cancel_uri));
  138. $box = id(new PHUIObjectBoxView())
  139. ->setHeaderText(pht('Method'))
  140. ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
  141. ->setForm($form);
  142. $crumbs = $this->buildApplicationCrumbs();
  143. $crumbs->addTextCrumb(pht('Add Payment Method'));
  144. $crumbs->setBorder(true);
  145. $header = id(new PHUIHeaderView())
  146. ->setHeader(pht('Add Payment Method'))
  147. ->setHeaderIcon('fa-plus-square');
  148. $view = id(new PHUITwoColumnView())
  149. ->setHeader($header)
  150. ->setFooter(array(
  151. $box,
  152. ));
  153. return $this->newPage()
  154. ->setTitle($provider->getPaymentMethodDescription())
  155. ->setCrumbs($crumbs)
  156. ->appendChild($view);
  157. }
  158. private function renderSelectProvider(
  159. PhortunePaymentProvider $provider) {
  160. $request = $this->getRequest();
  161. $viewer = $request->getUser();
  162. $description = $provider->getPaymentMethodDescription();
  163. $icon_uri = $provider->getPaymentMethodIcon();
  164. $details = $provider->getPaymentMethodProviderDescription();
  165. $this->requireResource('phortune-css');
  166. $icon = id(new PHUIIconView())
  167. ->setSpriteSheet(PHUIIconView::SPRITE_LOGIN)
  168. ->setSpriteIcon($provider->getPaymentMethodIcon());
  169. $button = id(new PHUIButtonView())
  170. ->setSize(PHUIButtonView::BIG)
  171. ->setColor(PHUIButtonView::GREY)
  172. ->setIcon($icon)
  173. ->setText($description)
  174. ->setSubtext($details)
  175. ->setMetadata(array('disableWorkflow' => true));
  176. $form = id(new AphrontFormView())
  177. ->setUser($viewer)
  178. ->setAction($request->getRequestURI())
  179. ->addHiddenInput('providerID', $provider->getProviderConfig()->getID())
  180. ->appendChild($button);
  181. return $form;
  182. }
  183. private function processClientErrors(
  184. PhortunePaymentProvider $provider,
  185. $client_errors_raw) {
  186. $errors = array();
  187. $client_errors = null;
  188. try {
  189. $client_errors = phutil_json_decode($client_errors_raw);
  190. } catch (PhutilJSONParserException $ex) {
  191. $errors[] = pht(
  192. 'There was an error decoding error information submitted by the '.
  193. 'client. Expected a JSON-encoded list of error codes, received: %s.',
  194. nonempty($client_errors_raw, pht('nothing')));
  195. }
  196. foreach (array_unique($client_errors) as $key => $client_error) {
  197. $client_errors[$key] = $provider->translateCreatePaymentMethodErrorCode(
  198. $client_error);
  199. }
  200. foreach (array_unique($client_errors) as $client_error) {
  201. switch ($client_error) {
  202. case PhortuneErrCode::ERR_CC_INVALID_NUMBER:
  203. $message = pht(
  204. 'The card number you entered is not a valid card number. Check '.
  205. 'that you entered it correctly.');
  206. break;
  207. case PhortuneErrCode::ERR_CC_INVALID_CVC:
  208. $message = pht(
  209. 'The CVC code you entered is not a valid CVC code. Check that '.
  210. 'you entered it correctly. The CVC code is a 3-digit or 4-digit '.
  211. 'numeric code which usually appears on the back of the card.');
  212. break;
  213. case PhortuneErrCode::ERR_CC_INVALID_EXPIRY:
  214. $message = pht(
  215. 'The card expiration date is not a valid expiration date. Check '.
  216. 'that you entered it correctly. You can not add an expired card '.
  217. 'as a payment method.');
  218. break;
  219. default:
  220. $message = $provider->getCreatePaymentMethodErrorMessage(
  221. $client_error);
  222. if (!$message) {
  223. $message = pht(
  224. "There was an unexpected error ('%s') processing payment ".
  225. "information.",
  226. $client_error);
  227. phlog($message);
  228. }
  229. break;
  230. }
  231. $errors[$client_error] = $message;
  232. }
  233. return $errors;
  234. }
  235. }