mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +01:00
Make payment method management somewhat more reasonable in Phortune
Summary: Ref T2787. Shows somewhat-useful information, allows payment methods to be disabled and renamed. Test Plan: Created, renamed, disabled payment methods. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T2787 Differential Revision: https://secure.phabricator.com/D10203
This commit is contained in:
parent
eb9dcd6fba
commit
aa67a5ffc8
15 changed files with 454 additions and 282 deletions
|
@ -2479,10 +2479,10 @@ phutil_register_library_map(array(
|
|||
'PhortuneNoPaymentProviderException' => 'applications/phortune/exception/PhortuneNoPaymentProviderException.php',
|
||||
'PhortuneNotImplementedException' => 'applications/phortune/exception/PhortuneNotImplementedException.php',
|
||||
'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php',
|
||||
'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/PhortunePaymentMethodCreateController.php',
|
||||
'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/PhortunePaymentMethodDisableController.php',
|
||||
'PhortunePaymentMethodEditController' => 'applications/phortune/controller/PhortunePaymentMethodEditController.php',
|
||||
'PhortunePaymentMethodListController' => 'applications/phortune/controller/PhortunePaymentMethodListController.php',
|
||||
'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php',
|
||||
'PhortunePaymentMethodViewController' => 'applications/phortune/controller/PhortunePaymentMethodViewController.php',
|
||||
'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php',
|
||||
'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php',
|
||||
'PhortunePaypalPaymentProvider' => 'applications/phortune/provider/PhortunePaypalPaymentProvider.php',
|
||||
|
@ -5386,10 +5386,10 @@ phutil_register_library_map(array(
|
|||
'PhortuneDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhortunePaymentMethodCreateController' => 'PhortuneController',
|
||||
'PhortunePaymentMethodDisableController' => 'PhortuneController',
|
||||
'PhortunePaymentMethodEditController' => 'PhortuneController',
|
||||
'PhortunePaymentMethodListController' => 'PhabricatorController',
|
||||
'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhortunePaymentMethodViewController' => 'PhabricatorController',
|
||||
'PhortunePaymentProviderTestCase' => 'PhabricatorTestCase',
|
||||
'PhortunePaypalPaymentProvider' => 'PhortunePaymentProvider',
|
||||
'PhortuneProduct' => array(
|
||||
|
|
|
@ -36,11 +36,15 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
|||
'' => 'PhortuneLandingController',
|
||||
'(?P<accountID>\d+)/' => array(
|
||||
'' => 'PhortuneAccountViewController',
|
||||
'paymentmethod/' => array(
|
||||
'edit/' => 'PhortunePaymentMethodEditController',
|
||||
'card/' => array(
|
||||
'new/' => 'PhortunePaymentMethodCreateController',
|
||||
),
|
||||
'buy/(?P<productID>\d+)/' => 'PhortuneProductPurchaseController',
|
||||
),
|
||||
'card/(?P<id>\d+)/' => array(
|
||||
'edit/' => 'PhortunePaymentMethodEditController',
|
||||
'disable/' => 'PhortunePaymentMethodDisableController',
|
||||
),
|
||||
'cart/(?P<id>\d+)/' => array(
|
||||
'' => 'PhortuneCartViewController',
|
||||
'checkout/' => 'PhortuneCartCheckoutController',
|
||||
|
|
|
@ -79,7 +79,12 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
|
||||
private function buildPaymentMethodsSection(PhortuneAccount $account) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$account,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$id = $account->getID();
|
||||
|
||||
|
@ -88,19 +93,18 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref($this->getApplicationURI($id.'/paymentmethod/edit/'))
|
||||
->setHref($this->getApplicationURI($id.'/card/new/'))
|
||||
->setText(pht('Add Payment Method'))
|
||||
->setIcon(id(new PHUIIconView())->setIconFont('fa-plus')));
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setUser($user)
|
||||
->setUser($viewer)
|
||||
->setNoDataString(
|
||||
pht('No payment methods associated with this account.'));
|
||||
|
||||
$methods = id(new PhortunePaymentMethodQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withAccountPHIDs(array($account->getPHID()))
|
||||
->withStatus(PhortunePaymentMethodQuery::STATUS_OPEN)
|
||||
->execute();
|
||||
|
||||
if ($methods) {
|
||||
|
@ -108,21 +112,40 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
}
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$id = $method->getID();
|
||||
|
||||
$item = new PHUIObjectItemView();
|
||||
$item->setHeader($method->getBrand().' / '.$method->getLastFourDigits());
|
||||
$item->setHeader($method->getFullDisplayName());
|
||||
|
||||
switch ($method->getStatus()) {
|
||||
case PhortunePaymentMethod::STATUS_ACTIVE:
|
||||
$item->addAttribute(pht('Active'));
|
||||
$item->setBarColor('green');
|
||||
|
||||
$disable_uri = $this->getApplicationURI('card/'.$id.'/disable/');
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon('fa-times')
|
||||
->setHref($disable_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
break;
|
||||
case PhortunePaymentMethod::STATUS_DISABLED:
|
||||
$item->setDisabled(true);
|
||||
break;
|
||||
}
|
||||
|
||||
$item->addAttribute(
|
||||
pht(
|
||||
'Added %s by %s',
|
||||
phabricator_datetime($method->getDateCreated(), $user),
|
||||
$this->getHandle($method->getAuthorPHID())->renderLink()));
|
||||
$provider = $method->buildPaymentProvider();
|
||||
$item->addAttribute($provider->getPaymentMethodProviderDescription());
|
||||
$item->setImageURI($provider->getPaymentMethodIcon());
|
||||
|
||||
$edit_uri = $this->getApplicationURI('card/'.$id.'/edit/');
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon('fa-pencil')
|
||||
->setHref($edit_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ final class PhortuneCartCheckoutController
|
|||
$methods = id(new PhortunePaymentMethodQuery())
|
||||
->setViewer($viewer)
|
||||
->withAccountPHIDs(array($account->getPHID()))
|
||||
->withStatus(PhortunePaymentMethodQuery::STATUS_OPEN)
|
||||
->withStatuses(array(PhortunePaymentMethod::STATUS_ACTIVE))
|
||||
->execute();
|
||||
|
||||
$e_method = null;
|
||||
|
@ -57,6 +57,7 @@ final class PhortuneCartCheckoutController
|
|||
->setAccountPHID($account->getPHID())
|
||||
->setCartPHID($cart->getPHID())
|
||||
->setAuthorPHID($viewer->getPHID())
|
||||
->setPaymentProviderKey($provider->getProviderKey())
|
||||
->setPaymentMethodPHID($method->getPHID())
|
||||
->setAmountInCents($cart->getTotalPriceInCents())
|
||||
->setStatus(PhortuneCharge::STATUS_PENDING);
|
||||
|
@ -105,7 +106,7 @@ final class PhortuneCartCheckoutController
|
|||
$method_control->setError($e_method);
|
||||
|
||||
$payment_method_uri = $this->getApplicationURI(
|
||||
$account->getID().'/paymentmethod/edit/');
|
||||
$account->getID().'/card/new/');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
|
||||
final class PhortunePaymentMethodCreateController
|
||||
extends PhortuneController {
|
||||
|
||||
private $accountID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->accountID = $data['accountID'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$account = id(new PhortuneAccountQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($this->accountID))
|
||||
->executeOne();
|
||||
if (!$account) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$cancel_uri = $this->getApplicationURI($account->getID().'/');
|
||||
$account_uri = $this->getApplicationURI($account->getID().'/');
|
||||
|
||||
$providers = PhortunePaymentProvider::getProvidersForAddPaymentMethod();
|
||||
if (!$providers) {
|
||||
throw new Exception(
|
||||
'There are no payment providers enabled that can add payment '.
|
||||
'methods.');
|
||||
}
|
||||
|
||||
$provider_key = $request->getStr('providerKey');
|
||||
if (empty($providers[$provider_key])) {
|
||||
$choices = array();
|
||||
foreach ($providers as $provider) {
|
||||
$choices[] = $this->renderSelectProvider($provider);
|
||||
}
|
||||
|
||||
$content = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phortune-payment-method-list',
|
||||
),
|
||||
$choices);
|
||||
|
||||
return $this->newDialog()
|
||||
->setRenderDialogAsDiv(true)
|
||||
->setTitle(pht('Add Payment Method'))
|
||||
->appendParagraph(pht('Choose a payment method to add:'))
|
||||
->appendChild($content)
|
||||
->addCancelButton($account_uri);
|
||||
}
|
||||
|
||||
$provider = $providers[$provider_key];
|
||||
|
||||
$errors = array();
|
||||
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
||||
$method = id(new PhortunePaymentMethod())
|
||||
->setAccountPHID($account->getPHID())
|
||||
->setAuthorPHID($user->getPHID())
|
||||
->setStatus(PhortunePaymentMethod::STATUS_ACTIVE)
|
||||
->setProviderType($provider->getProviderType())
|
||||
->setProviderDomain($provider->getProviderDomain());
|
||||
|
||||
if (!$errors) {
|
||||
$errors = $this->processClientErrors(
|
||||
$provider,
|
||||
$request->getStr('errors'));
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$client_token_raw = $request->getStr('token');
|
||||
$client_token = json_decode($client_token_raw, true);
|
||||
if (!is_array($client_token)) {
|
||||
$errors[] = pht(
|
||||
'There was an error decoding token information submitted by the '.
|
||||
'client. Expected a JSON-encoded token dictionary, received: %s.',
|
||||
nonempty($client_token_raw, pht('nothing')));
|
||||
} else {
|
||||
if (!$provider->validateCreatePaymentMethodToken($client_token)) {
|
||||
$errors[] = pht(
|
||||
'There was an error with the payment token submitted by the '.
|
||||
'client. Expected a valid dictionary, received: %s.',
|
||||
$client_token_raw);
|
||||
}
|
||||
}
|
||||
if (!$errors) {
|
||||
$errors = $provider->createPaymentMethodFromRequest(
|
||||
$request,
|
||||
$method,
|
||||
$client_token);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$method->save();
|
||||
|
||||
$save_uri = new PhutilURI($account_uri);
|
||||
$save_uri->setFragment('payment');
|
||||
return id(new AphrontRedirectResponse())->setURI($save_uri);
|
||||
} else {
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setTitle(pht('Error Adding Payment Method'))
|
||||
->appendChild(id(new AphrontErrorView())->setErrors($errors))
|
||||
->addCancelButton($request->getRequestURI());
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
||||
|
||||
$form = $provider->renderCreatePaymentMethodForm($request, $errors);
|
||||
|
||||
$form
|
||||
->setUser($user)
|
||||
->setAction($request->getRequestURI())
|
||||
->setWorkflow(true)
|
||||
->addHiddenInput('providerKey', $provider_key)
|
||||
->addHiddenInput('isProviderForm', true)
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Add Payment Method'))
|
||||
->addCancelButton($account_uri));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($provider->getPaymentMethodDescription())
|
||||
->setForm($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Add Payment Method'));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
),
|
||||
array(
|
||||
'title' => $provider->getPaymentMethodDescription(),
|
||||
));
|
||||
}
|
||||
|
||||
private function renderSelectProvider(
|
||||
PhortunePaymentProvider $provider) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$description = $provider->getPaymentMethodDescription();
|
||||
$icon_uri = $provider->getPaymentMethodIcon();
|
||||
$details = $provider->getPaymentMethodProviderDescription();
|
||||
|
||||
$this->requireResource('phortune-css');
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setImage($icon_uri)
|
||||
->addClass('phortune-payment-icon');
|
||||
|
||||
$button = id(new PHUIButtonView())
|
||||
->setSize(PHUIButtonView::BIG)
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setIcon($icon)
|
||||
->setText($description)
|
||||
->setSubtext($details);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->addHiddenInput('providerKey', $provider->getProviderKey())
|
||||
->appendChild($button);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function processClientErrors(
|
||||
PhortunePaymentProvider $provider,
|
||||
$client_errors_raw) {
|
||||
|
||||
$errors = array();
|
||||
|
||||
$client_errors = json_decode($client_errors_raw, true);
|
||||
if (!is_array($client_errors)) {
|
||||
$errors[] = pht(
|
||||
'There was an error decoding error information submitted by the '.
|
||||
'client. Expected a JSON-encoded list of error codes, received: %s.',
|
||||
nonempty($client_errors_raw, pht('nothing')));
|
||||
}
|
||||
|
||||
foreach (array_unique($client_errors) as $key => $client_error) {
|
||||
$client_errors[$key] = $provider->translateCreatePaymentMethodErrorCode(
|
||||
$client_error);
|
||||
}
|
||||
|
||||
foreach (array_unique($client_errors) as $client_error) {
|
||||
switch ($client_error) {
|
||||
case PhortuneErrCode::ERR_CC_INVALID_NUMBER:
|
||||
$message = pht(
|
||||
'The card number you entered is not a valid card number. Check '.
|
||||
'that you entered it correctly.');
|
||||
break;
|
||||
case PhortuneErrCode::ERR_CC_INVALID_CVC:
|
||||
$message = pht(
|
||||
'The CVC code you entered is not a valid CVC code. Check that '.
|
||||
'you entered it correctly. The CVC code is a 3-digit or 4-digit '.
|
||||
'numeric code which usually appears on the back of the card.');
|
||||
break;
|
||||
case PhortuneErrCode::ERR_CC_INVALID_EXPIRY:
|
||||
$message = pht(
|
||||
'The card expiration date is not a valid expiration date. Check '.
|
||||
'that you entered it correctly. You can not add an expired card '.
|
||||
'as a payment method.');
|
||||
break;
|
||||
default:
|
||||
$message = $provider->getCreatePaymentMethodErrorMessage(
|
||||
$client_error);
|
||||
if (!$message) {
|
||||
$message = pht(
|
||||
"There was an unexpected error ('%s') processing payment ".
|
||||
"information.",
|
||||
$client_error);
|
||||
|
||||
phlog($message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$errors[$client_error] = $message;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
final class PhortunePaymentMethodDisableController
|
||||
extends PhortuneController {
|
||||
|
||||
private $methodID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->methodID = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$method = id(new PhortunePaymentMethodQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->methodID))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$method) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($method->getStatus() == PhortunePaymentMethod::STATUS_DISABLED) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$account = $method->getAccount();
|
||||
$account_uri = $this->getApplicationURI($account->getID().'/');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
||||
// TODO: ApplicationTransactions!
|
||||
$method
|
||||
->setStatus(PhortunePaymentMethod::STATUS_DISABLED)
|
||||
->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($account_uri);
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Disable Payment Method?'))
|
||||
->setShortTitle(pht('Disable Payment Method'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'Disable the payment method "%s"?',
|
||||
phutil_tag(
|
||||
'strong',
|
||||
array(),
|
||||
$method->getFullDisplayName())))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You will no longer be able to make payments using this payment '.
|
||||
'method. Disabled payment methods can not be reactivated.'))
|
||||
->addCancelButton($account_uri)
|
||||
->addSubmitButton(pht('Disable Payment Method'));
|
||||
}
|
||||
|
||||
}
|
|
@ -3,133 +3,74 @@
|
|||
final class PhortunePaymentMethodEditController
|
||||
extends PhortuneController {
|
||||
|
||||
private $accountID;
|
||||
private $methodID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->accountID = $data['accountID'];
|
||||
$this->methodID = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$account = id(new PhortuneAccountQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($this->accountID))
|
||||
$method = id(new PhortunePaymentMethodQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->methodID))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$account) {
|
||||
if (!$method) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$cancel_uri = $this->getApplicationURI($account->getID().'/');
|
||||
$account = $method->getAccount();
|
||||
$account_uri = $this->getApplicationURI($account->getID().'/');
|
||||
|
||||
$providers = PhortunePaymentProvider::getProvidersForAddPaymentMethod();
|
||||
if (!$providers) {
|
||||
throw new Exception(
|
||||
'There are no payment providers enabled that can add payment '.
|
||||
'methods.');
|
||||
if ($request->isFormPost()) {
|
||||
|
||||
$name = $request->getStr('name');
|
||||
|
||||
// TODO: Use ApplicationTransactions
|
||||
|
||||
$method->setName($name);
|
||||
$method->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($account_uri);
|
||||
}
|
||||
|
||||
$provider_key = $request->getStr('providerKey');
|
||||
if (empty($providers[$provider_key])) {
|
||||
$choices = array();
|
||||
foreach ($providers as $provider) {
|
||||
$choices[] = $this->renderSelectProvider($provider);
|
||||
}
|
||||
$provider = $method->buildPaymentProvider();
|
||||
|
||||
$content = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phortune-payment-method-list',
|
||||
),
|
||||
$choices);
|
||||
|
||||
return $this->newDialog()
|
||||
->setRenderDialogAsDiv(true)
|
||||
->setTitle(pht('Add Payment Method'))
|
||||
->appendParagraph(pht('Choose a payment method to add:'))
|
||||
->appendChild($content)
|
||||
->addCancelButton($account_uri);
|
||||
}
|
||||
|
||||
$provider = $providers[$provider_key];
|
||||
|
||||
$errors = array();
|
||||
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
||||
$method = id(new PhortunePaymentMethod())
|
||||
->setAccountPHID($account->getPHID())
|
||||
->setAuthorPHID($user->getPHID())
|
||||
->setStatus(PhortunePaymentMethod::STATUS_ACTIVE)
|
||||
->setProviderType($provider->getProviderType())
|
||||
->setProviderDomain($provider->getProviderDomain());
|
||||
|
||||
if (!$errors) {
|
||||
$errors = $this->processClientErrors(
|
||||
$provider,
|
||||
$request->getStr('errors'));
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$client_token_raw = $request->getStr('token');
|
||||
$client_token = json_decode($client_token_raw, true);
|
||||
if (!is_array($client_token)) {
|
||||
$errors[] = pht(
|
||||
'There was an error decoding token information submitted by the '.
|
||||
'client. Expected a JSON-encoded token dictionary, received: %s.',
|
||||
nonempty($client_token_raw, pht('nothing')));
|
||||
} else {
|
||||
if (!$provider->validateCreatePaymentMethodToken($client_token)) {
|
||||
$errors[] = pht(
|
||||
'There was an error with the payment token submitted by the '.
|
||||
'client. Expected a valid dictionary, received: %s.',
|
||||
$client_token_raw);
|
||||
}
|
||||
}
|
||||
if (!$errors) {
|
||||
$errors = $provider->createPaymentMethodFromRequest(
|
||||
$request,
|
||||
$method,
|
||||
$client_token);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$method->save();
|
||||
|
||||
$save_uri = new PhutilURI($account_uri);
|
||||
$save_uri->setFragment('payment');
|
||||
return id(new AphrontRedirectResponse())->setURI($save_uri);
|
||||
} else {
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setTitle(pht('Error Adding Payment Method'))
|
||||
->appendChild(id(new AphrontErrorView())->setErrors($errors))
|
||||
->addCancelButton($request->getRequestURI());
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
||||
|
||||
$form = $provider->renderCreatePaymentMethodForm($request, $errors);
|
||||
|
||||
$form
|
||||
->setUser($user)
|
||||
->setAction($request->getRequestURI())
|
||||
->setWorkflow(true)
|
||||
->addHiddenInput('providerKey', $provider_key)
|
||||
->addHiddenInput('isProviderForm', true)
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name'))
|
||||
->setName('name')
|
||||
->setValue($method->getName()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Details'))
|
||||
->setValue($method->getSummary()))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Expires'))
|
||||
->setValue($method->getDisplayExpires()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Add Payment Method'))
|
||||
->addCancelButton($account_uri));
|
||||
->addCancelButton($account_uri)
|
||||
->setValue(pht('Save Changes')));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($provider->getPaymentMethodDescription())
|
||||
->setForm($form);
|
||||
->setHeaderText(pht('Edit Payment Method'))
|
||||
->appendChild($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Add Payment Method'));
|
||||
$crumbs->addTextCrumb($account->getName(), $account_uri);
|
||||
$crumbs->addTextCrumb($method->getDisplayName());
|
||||
$crumbs->addTextCrumb(pht('Edit'));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
|
@ -137,97 +78,8 @@ final class PhortunePaymentMethodEditController
|
|||
$box,
|
||||
),
|
||||
array(
|
||||
'title' => $provider->getPaymentMethodDescription(),
|
||||
'title' => pht('Edit Payment Method'),
|
||||
));
|
||||
}
|
||||
|
||||
private function renderSelectProvider(
|
||||
PhortunePaymentProvider $provider) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$description = $provider->getPaymentMethodDescription();
|
||||
$icon_uri = $provider->getPaymentMethodIcon();
|
||||
$details = $provider->getPaymentMethodProviderDescription();
|
||||
|
||||
$this->requireResource('phortune-css');
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setImage($icon_uri)
|
||||
->addClass('phortune-payment-icon');
|
||||
|
||||
$button = id(new PHUIButtonView())
|
||||
->setSize(PHUIButtonView::BIG)
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setIcon($icon)
|
||||
->setText($description)
|
||||
->setSubtext($details);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->addHiddenInput('providerKey', $provider->getProviderKey())
|
||||
->appendChild($button);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function processClientErrors(
|
||||
PhortunePaymentProvider $provider,
|
||||
$client_errors_raw) {
|
||||
|
||||
$errors = array();
|
||||
|
||||
$client_errors = json_decode($client_errors_raw, true);
|
||||
if (!is_array($client_errors)) {
|
||||
$errors[] = pht(
|
||||
'There was an error decoding error information submitted by the '.
|
||||
'client. Expected a JSON-encoded list of error codes, received: %s.',
|
||||
nonempty($client_errors_raw, pht('nothing')));
|
||||
}
|
||||
|
||||
foreach (array_unique($client_errors) as $key => $client_error) {
|
||||
$client_errors[$key] = $provider->translateCreatePaymentMethodErrorCode(
|
||||
$client_error);
|
||||
}
|
||||
|
||||
foreach (array_unique($client_errors) as $client_error) {
|
||||
switch ($client_error) {
|
||||
case PhortuneErrCode::ERR_CC_INVALID_NUMBER:
|
||||
$message = pht(
|
||||
'The card number you entered is not a valid card number. Check '.
|
||||
'that you entered it correctly.');
|
||||
break;
|
||||
case PhortuneErrCode::ERR_CC_INVALID_CVC:
|
||||
$message = pht(
|
||||
'The CVC code you entered is not a valid CVC code. Check that '.
|
||||
'you entered it correctly. The CVC code is a 3-digit or 4-digit '.
|
||||
'numeric code which usually appears on the back of the card.');
|
||||
break;
|
||||
case PhortuneErrCode::ERR_CC_INVALID_EXPIRY:
|
||||
$message = pht(
|
||||
'The card expiration date is not a valid expiration date. Check '.
|
||||
'that you entered it correctly. You can not add an expired card '.
|
||||
'as a payment method.');
|
||||
break;
|
||||
default:
|
||||
$message = $provider->getCreatePaymentMethodErrorMessage(
|
||||
$client_error);
|
||||
if (!$message) {
|
||||
$message = pht(
|
||||
"There was an unexpected error ('%s') processing payment ".
|
||||
"information.",
|
||||
$client_error);
|
||||
|
||||
phlog($message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$errors[$client_error] = $message;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhortunePaymentMethodListController extends PhabricatorController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$title = pht('Payment Methods');
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhortunePaymentMethodViewController extends PhabricatorController {
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$title = '...';
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,10 @@ final class PhortuneBalancedPaymentProvider extends PhortunePaymentProvider {
|
|||
return pht('Processed by Balanced');
|
||||
}
|
||||
|
||||
public function getDefaultPaymentMethodDisplayName(
|
||||
PhortunePaymentMethod $method) {
|
||||
return pht('Credit/Debit Card');
|
||||
}
|
||||
|
||||
public function canHandlePaymentMethod(PhortunePaymentMethod $method) {
|
||||
$type = $method->getMetadataValue('type');
|
||||
|
|
|
@ -169,6 +169,11 @@ abstract class PhortunePaymentProvider {
|
|||
throw new PhortuneNotImplementedException($this);
|
||||
}
|
||||
|
||||
public function getDefaultPaymentMethodDisplayName(
|
||||
PhortunePaymentMethod $method) {
|
||||
throw new PhortuneNotImplementedException($this);
|
||||
}
|
||||
|
||||
|
||||
/* -( One-Time Payments )-------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ final class PhortuneStripePaymentProvider extends PhortunePaymentProvider {
|
|||
return pht('Processed by Stripe');
|
||||
}
|
||||
|
||||
public function getDefaultPaymentMethodDisplayName(
|
||||
PhortunePaymentMethod $method) {
|
||||
return pht('Credit/Debit Card');
|
||||
}
|
||||
|
||||
public function canHandlePaymentMethod(PhortunePaymentMethod $method) {
|
||||
$type = $method->getMetadataValue('type');
|
||||
|
|
|
@ -26,9 +26,14 @@ final class PhortuneTestPaymentProvider extends PhortunePaymentProvider {
|
|||
return pht('Infinite Free Money');
|
||||
}
|
||||
|
||||
public function getDefaultPaymentMethodDisplayName(
|
||||
PhortunePaymentMethod $method) {
|
||||
return pht('Vast Wealth');
|
||||
}
|
||||
|
||||
public function canHandlePaymentMethod(PhortunePaymentMethod $method) {
|
||||
$type = $method->getMetadataValue('type');
|
||||
return ($type === 'test.cash' || $type === 'test.multiple');
|
||||
return ($type === 'test.wealth' || $type == 'test.multiple');
|
||||
}
|
||||
|
||||
protected function executeCharge(
|
||||
|
@ -69,8 +74,13 @@ final class PhortuneTestPaymentProvider extends PhortunePaymentProvider {
|
|||
$method
|
||||
->setExpires('2050', '01')
|
||||
->setBrand('FreeMoney')
|
||||
->setLastFourDigits('9999');
|
||||
->setLastFourDigits('9999')
|
||||
->setMetadata(
|
||||
array(
|
||||
'type' => 'test.wealth',
|
||||
));
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6,10 +6,7 @@ final class PhortunePaymentMethodQuery
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $accountPHIDs;
|
||||
|
||||
const STATUS_ANY = 'status-any';
|
||||
const STATUS_OPEN = 'status-open';
|
||||
private $status = self::STATUS_ANY;
|
||||
private $statuses;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -26,8 +23,8 @@ final class PhortunePaymentMethodQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatus($status) {
|
||||
$this->status = $status;
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -77,41 +74,32 @@ final class PhortunePaymentMethodQuery
|
|||
private function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->accountPHIDs) {
|
||||
if ($this->accountPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'accountPHID IN (%Ls)',
|
||||
$this->accountPHIDs);
|
||||
}
|
||||
|
||||
switch ($this->status) {
|
||||
case self::STATUS_ANY;
|
||||
break;
|
||||
case self::STATUS_OPEN:
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'status in (%Ls)',
|
||||
array(
|
||||
PhortunePaymentMethod::STATUS_ACTIVE,
|
||||
PhortunePaymentMethod::STATUS_FAILED,
|
||||
));
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown status '{$this->status}'!");
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'status IN (%Ls)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn);
|
||||
|
|
|
@ -8,8 +8,7 @@ final class PhortunePaymentMethod extends PhortuneDAO
|
|||
implements PhabricatorPolicyInterface {
|
||||
|
||||
const STATUS_ACTIVE = 'payment:active';
|
||||
const STATUS_FAILED = 'payment:failed';
|
||||
const STATUS_REMOVED = 'payment:removed';
|
||||
const STATUS_DISABLED = 'payment:disabled';
|
||||
|
||||
protected $name = '';
|
||||
protected $status;
|
||||
|
@ -82,11 +81,36 @@ final class PhortunePaymentMethod extends PhortuneDAO
|
|||
return head($accept);
|
||||
}
|
||||
|
||||
|
||||
public function getDisplayName() {
|
||||
if (strlen($this->name)) {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
$provider = $this->buildPaymentProvider();
|
||||
return $provider->getDefaultPaymentMethodDisplayName($this);
|
||||
}
|
||||
|
||||
public function getFullDisplayName() {
|
||||
return pht('%s (%s)', $this->getDisplayName(), $this->getSummary());
|
||||
}
|
||||
|
||||
public function getSummary() {
|
||||
return pht('%s %s', $this->getBrand(), $this->getLastFourDigits());
|
||||
}
|
||||
|
||||
public function setExpires($year, $month) {
|
||||
$this->expires = $year.'-'.$month;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplayExpires() {
|
||||
list($year, $month) = explode('-', $this->getExpires());
|
||||
$month = sprintf('%02d', $month);
|
||||
$year = substr($year, -2);
|
||||
return $month.'/'.$year;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
Loading…
Reference in a new issue