mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-03 11:21:01 +01:00
Make Phortune payment methods transaction-oriented and always support "Add Payment Method"
Summary: Depends on D20718. Ref T13366. Ref T13367. - Phortune payment methods currently do not use transactions; update them. - Give them a proper view page with a transaction log. - Add an "Add Payment Method" button which always works. - Show which subscriptions a payment method is associated with. - Get rid of the "Active" status indicator since we now treat "disabled" as "removed", to align with user expectation/intent. - Swap out of some of the super weird div-form-button UI into the new "big, clickable" UI for choice dialogs among a small number of options on a single dimension. Test Plan: - As a mechant-authority and account-authority, created payment methods from carts, subscriptions, and accounts. Edited and viewed payment methods. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13367, T13366 Differential Revision: https://secure.phabricator.com/D20719
This commit is contained in:
parent
c4e0ac4d27
commit
201634848e
25 changed files with 906 additions and 424 deletions
|
@ -92,7 +92,7 @@ return array(
|
||||||
'rsrc/css/application/pholio/pholio.css' => '88ef5ef1',
|
'rsrc/css/application/pholio/pholio.css' => '88ef5ef1',
|
||||||
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '3b9868a8',
|
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '3b9868a8',
|
||||||
'rsrc/css/application/phortune/phortune-invoice.css' => '4436b241',
|
'rsrc/css/application/phortune/phortune-invoice.css' => '4436b241',
|
||||||
'rsrc/css/application/phortune/phortune.css' => '12e8251a',
|
'rsrc/css/application/phortune/phortune.css' => '508a1a5e',
|
||||||
'rsrc/css/application/phrequent/phrequent.css' => 'bd79cc67',
|
'rsrc/css/application/phrequent/phrequent.css' => 'bd79cc67',
|
||||||
'rsrc/css/application/phriction/phriction-document-css.css' => '03380da0',
|
'rsrc/css/application/phriction/phriction-document-css.css' => '03380da0',
|
||||||
'rsrc/css/application/policy/policy-edit.css' => '8794e2ed',
|
'rsrc/css/application/policy/policy-edit.css' => '8794e2ed',
|
||||||
|
@ -810,7 +810,7 @@ return array(
|
||||||
'pholio-inline-comments-css' => '722b48c2',
|
'pholio-inline-comments-css' => '722b48c2',
|
||||||
'phortune-credit-card-form' => 'd12d214f',
|
'phortune-credit-card-form' => 'd12d214f',
|
||||||
'phortune-credit-card-form-css' => '3b9868a8',
|
'phortune-credit-card-form-css' => '3b9868a8',
|
||||||
'phortune-css' => '12e8251a',
|
'phortune-css' => '508a1a5e',
|
||||||
'phortune-invoice-css' => '4436b241',
|
'phortune-invoice-css' => '4436b241',
|
||||||
'phrequent-css' => 'bd79cc67',
|
'phrequent-css' => 'bd79cc67',
|
||||||
'phriction-document-css' => '03380da0',
|
'phriction-document-css' => '03380da0',
|
||||||
|
|
19
resources/sql/autopatches/20190816.payment.01.xaction.sql
Normal file
19
resources/sql/autopatches/20190816.payment.01.xaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_phortune.phortune_paymentmethodtransaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) NOT NULL,
|
||||||
|
oldValue LONGTEXT NOT NULL,
|
||||||
|
newValue LONGTEXT NOT NULL,
|
||||||
|
contentSource LONGTEXT NOT NULL,
|
||||||
|
metadata LONGTEXT NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (`phid`),
|
||||||
|
KEY `key_object` (`objectPHID`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};
|
|
@ -5249,7 +5249,8 @@ phutil_register_library_map(array(
|
||||||
'PhortuneAccountOrdersController' => 'applications/phortune/controller/account/PhortuneAccountOrdersController.php',
|
'PhortuneAccountOrdersController' => 'applications/phortune/controller/account/PhortuneAccountOrdersController.php',
|
||||||
'PhortuneAccountOverviewController' => 'applications/phortune/controller/account/PhortuneAccountOverviewController.php',
|
'PhortuneAccountOverviewController' => 'applications/phortune/controller/account/PhortuneAccountOverviewController.php',
|
||||||
'PhortuneAccountPHIDType' => 'applications/phortune/phid/PhortuneAccountPHIDType.php',
|
'PhortuneAccountPHIDType' => 'applications/phortune/phid/PhortuneAccountPHIDType.php',
|
||||||
'PhortuneAccountPaymentMethodsController' => 'applications/phortune/controller/account/PhortuneAccountPaymentMethodsController.php',
|
'PhortuneAccountPaymentMethodListController' => 'applications/phortune/controller/account/PhortuneAccountPaymentMethodListController.php',
|
||||||
|
'PhortuneAccountPaymentMethodViewController' => 'applications/phortune/controller/account/PhortuneAccountPaymentMethodViewController.php',
|
||||||
'PhortuneAccountProfileController' => 'applications/phortune/controller/account/PhortuneAccountProfileController.php',
|
'PhortuneAccountProfileController' => 'applications/phortune/controller/account/PhortuneAccountProfileController.php',
|
||||||
'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php',
|
'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php',
|
||||||
'PhortuneAccountSubscriptionController' => 'applications/phortune/controller/account/PhortuneAccountSubscriptionController.php',
|
'PhortuneAccountSubscriptionController' => 'applications/phortune/controller/account/PhortuneAccountSubscriptionController.php',
|
||||||
|
@ -5325,12 +5326,18 @@ phutil_register_library_map(array(
|
||||||
'PhortuneOrderTableView' => 'applications/phortune/view/PhortuneOrderTableView.php',
|
'PhortuneOrderTableView' => 'applications/phortune/view/PhortuneOrderTableView.php',
|
||||||
'PhortunePayPalPaymentProvider' => 'applications/phortune/provider/PhortunePayPalPaymentProvider.php',
|
'PhortunePayPalPaymentProvider' => 'applications/phortune/provider/PhortunePayPalPaymentProvider.php',
|
||||||
'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php',
|
'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php',
|
||||||
'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/payment/PhortunePaymentMethodCreateController.php',
|
'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/paymentmethod/PhortunePaymentMethodCreateController.php',
|
||||||
'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/payment/PhortunePaymentMethodDisableController.php',
|
'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/paymentmethod/PhortunePaymentMethodDisableController.php',
|
||||||
'PhortunePaymentMethodEditController' => 'applications/phortune/controller/payment/PhortunePaymentMethodEditController.php',
|
'PhortunePaymentMethodEditController' => 'applications/phortune/controller/paymentmethod/PhortunePaymentMethodEditController.php',
|
||||||
|
'PhortunePaymentMethodEditor' => 'applications/phortune/editor/PhortunePaymentMethodEditor.php',
|
||||||
|
'PhortunePaymentMethodNameTransaction' => 'applications/phortune/xaction/paymentmethod/PhortunePaymentMethodNameTransaction.php',
|
||||||
'PhortunePaymentMethodPHIDType' => 'applications/phortune/phid/PhortunePaymentMethodPHIDType.php',
|
'PhortunePaymentMethodPHIDType' => 'applications/phortune/phid/PhortunePaymentMethodPHIDType.php',
|
||||||
'PhortunePaymentMethodPolicyCodex' => 'applications/phortune/codex/PhortunePaymentMethodPolicyCodex.php',
|
'PhortunePaymentMethodPolicyCodex' => 'applications/phortune/codex/PhortunePaymentMethodPolicyCodex.php',
|
||||||
'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php',
|
'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php',
|
||||||
|
'PhortunePaymentMethodStatusTransaction' => 'applications/phortune/xaction/paymentmethod/PhortunePaymentMethodStatusTransaction.php',
|
||||||
|
'PhortunePaymentMethodTransaction' => 'applications/phortune/storage/PhortunePaymentMethodTransaction.php',
|
||||||
|
'PhortunePaymentMethodTransactionQuery' => 'applications/phortune/query/PhortunePaymentMethodTransactionQuery.php',
|
||||||
|
'PhortunePaymentMethodTransactionType' => 'applications/phortune/xaction/paymentmethod/PhortunePaymentMethodTransactionType.php',
|
||||||
'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php',
|
'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php',
|
||||||
'PhortunePaymentProviderConfig' => 'applications/phortune/storage/PhortunePaymentProviderConfig.php',
|
'PhortunePaymentProviderConfig' => 'applications/phortune/storage/PhortunePaymentProviderConfig.php',
|
||||||
'PhortunePaymentProviderConfigEditor' => 'applications/phortune/editor/PhortunePaymentProviderConfigEditor.php',
|
'PhortunePaymentProviderConfigEditor' => 'applications/phortune/editor/PhortunePaymentProviderConfigEditor.php',
|
||||||
|
@ -11805,7 +11812,8 @@ phutil_register_library_map(array(
|
||||||
'PhortuneAccountOrdersController' => 'PhortuneAccountProfileController',
|
'PhortuneAccountOrdersController' => 'PhortuneAccountProfileController',
|
||||||
'PhortuneAccountOverviewController' => 'PhortuneAccountProfileController',
|
'PhortuneAccountOverviewController' => 'PhortuneAccountProfileController',
|
||||||
'PhortuneAccountPHIDType' => 'PhabricatorPHIDType',
|
'PhortuneAccountPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhortuneAccountPaymentMethodsController' => 'PhortuneAccountProfileController',
|
'PhortuneAccountPaymentMethodListController' => 'PhortuneAccountProfileController',
|
||||||
|
'PhortuneAccountPaymentMethodViewController' => 'PhortuneAccountController',
|
||||||
'PhortuneAccountProfileController' => 'PhortuneAccountController',
|
'PhortuneAccountProfileController' => 'PhortuneAccountController',
|
||||||
'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhortuneAccountSubscriptionController' => 'PhortuneAccountProfileController',
|
'PhortuneAccountSubscriptionController' => 'PhortuneAccountProfileController',
|
||||||
|
@ -11896,13 +11904,20 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
'PhabricatorExtendedPolicyInterface',
|
'PhabricatorExtendedPolicyInterface',
|
||||||
'PhabricatorPolicyCodexInterface',
|
'PhabricatorPolicyCodexInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
),
|
),
|
||||||
'PhortunePaymentMethodCreateController' => 'PhortuneController',
|
'PhortunePaymentMethodCreateController' => 'PhortuneController',
|
||||||
'PhortunePaymentMethodDisableController' => 'PhortuneController',
|
'PhortunePaymentMethodDisableController' => 'PhortuneController',
|
||||||
'PhortunePaymentMethodEditController' => 'PhortuneController',
|
'PhortunePaymentMethodEditController' => 'PhortuneController',
|
||||||
|
'PhortunePaymentMethodEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'PhortunePaymentMethodNameTransaction' => 'PhortunePaymentMethodTransactionType',
|
||||||
'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType',
|
'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhortunePaymentMethodPolicyCodex' => 'PhabricatorPolicyCodex',
|
'PhortunePaymentMethodPolicyCodex' => 'PhabricatorPolicyCodex',
|
||||||
'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhortunePaymentMethodStatusTransaction' => 'PhortunePaymentMethodTransactionType',
|
||||||
|
'PhortunePaymentMethodTransaction' => 'PhabricatorModularTransaction',
|
||||||
|
'PhortunePaymentMethodTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'PhortunePaymentMethodTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
'PhortunePaymentProvider' => 'Phobject',
|
'PhortunePaymentProvider' => 'Phobject',
|
||||||
'PhortunePaymentProviderConfig' => array(
|
'PhortunePaymentProviderConfig' => array(
|
||||||
'PhortuneDAO',
|
'PhortuneDAO',
|
||||||
|
|
|
@ -72,7 +72,10 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
'(?P<accountID>\d+)/' => array(
|
'(?P<accountID>\d+)/' => array(
|
||||||
'details/' => 'PhortuneAccountDetailsController',
|
'details/' => 'PhortuneAccountDetailsController',
|
||||||
'methods/' => 'PhortuneAccountPaymentMethodsController',
|
'methods/' => array(
|
||||||
|
'' => 'PhortuneAccountPaymentMethodListController',
|
||||||
|
'(?P<id>\d+)/' => 'PhortuneAccountPaymentMethodViewController',
|
||||||
|
),
|
||||||
'orders/' => 'PhortuneAccountOrdersController',
|
'orders/' => 'PhortuneAccountOrdersController',
|
||||||
'charges/' => 'PhortuneAccountChargesController',
|
'charges/' => 'PhortuneAccountChargesController',
|
||||||
'subscriptions/' => 'PhortuneAccountSubscriptionController',
|
'subscriptions/' => 'PhortuneAccountSubscriptionController',
|
||||||
|
|
|
@ -23,6 +23,10 @@ abstract class PhortuneAccountController
|
||||||
abstract protected function shouldRequireAccountEditCapability();
|
abstract protected function shouldRequireAccountEditCapability();
|
||||||
abstract protected function handleAccountRequest(AphrontRequest $request);
|
abstract protected function handleAccountRequest(AphrontRequest $request);
|
||||||
|
|
||||||
|
private function hasAccount() {
|
||||||
|
return (bool)$this->account;
|
||||||
|
}
|
||||||
|
|
||||||
final protected function getAccount() {
|
final protected function getAccount() {
|
||||||
if ($this->account === null) {
|
if ($this->account === null) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
@ -37,8 +41,10 @@ abstract class PhortuneAccountController
|
||||||
protected function buildApplicationCrumbs() {
|
protected function buildApplicationCrumbs() {
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
$account = $this->getAccount();
|
// If we hit a policy exception, we can make it here without finding
|
||||||
if ($account) {
|
// an account.
|
||||||
|
if ($this->hasAccount()) {
|
||||||
|
$account = $this->getAccount();
|
||||||
$crumbs->addTextCrumb($account->getName(), $account->getURI());
|
$crumbs->addTextCrumb($account->getName(), $account->getURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhortuneAccountPaymentMethodsController
|
final class PhortuneAccountPaymentMethodListController
|
||||||
extends PhortuneAccountProfileController {
|
extends PhortuneAccountProfileController {
|
||||||
|
|
||||||
protected function shouldRequireAccountEditCapability() {
|
protected function shouldRequireAccountEditCapability() {
|
||||||
|
@ -46,15 +46,17 @@ final class PhortuneAccountPaymentMethodsController
|
||||||
|
|
||||||
$id = $account->getID();
|
$id = $account->getID();
|
||||||
|
|
||||||
// TODO: Allow adding a card here directly
|
|
||||||
$add = id(new PHUIButtonView())
|
$add = id(new PHUIButtonView())
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
->setText(pht('New Payment Method'))
|
->setText(pht('Add Payment Method'))
|
||||||
->setIcon('fa-plus')
|
->setIcon('fa-plus')
|
||||||
->setHref($this->getApplicationURI("{$id}/card/new/"));
|
->setHref($this->getApplicationURI("{$id}/card/new/"))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit);
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Payment Methods'));
|
->setHeader(pht('Payment Methods'))
|
||||||
|
->addActionLink($add);
|
||||||
|
|
||||||
$list = id(new PHUIObjectItemListView())
|
$list = id(new PHUIObjectItemListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
|
@ -74,39 +76,14 @@ final class PhortuneAccountPaymentMethodsController
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
$id = $method->getID();
|
$id = $method->getID();
|
||||||
|
|
||||||
$item = new PHUIObjectItemView();
|
$item = id(new PHUIObjectItemView())
|
||||||
$item->setHeader($method->getFullDisplayName());
|
->setObjectName($method->getObjectName())
|
||||||
|
->setHeader($method->getFullDisplayName())
|
||||||
switch ($method->getStatus()) {
|
->setHref($method->getURI());
|
||||||
case PhortunePaymentMethod::STATUS_ACTIVE:
|
|
||||||
$item->setStatusIcon('fa-check 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->setStatusIcon('fa-ban lightbluetext');
|
|
||||||
$item->setDisabled(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$provider = $method->buildPaymentProvider();
|
$provider = $method->buildPaymentProvider();
|
||||||
$item->addAttribute($provider->getPaymentMethodProviderDescription());
|
$item->addAttribute($provider->getPaymentMethodProviderDescription());
|
||||||
|
|
||||||
$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);
|
$list->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneAccountPaymentMethodViewController
|
||||||
|
extends PhortuneAccountController {
|
||||||
|
|
||||||
|
protected function shouldRequireAccountEditCapability() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleAccountRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$account = $this->getAccount();
|
||||||
|
|
||||||
|
$method = id(new PhortunePaymentMethodQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->withStatuses(
|
||||||
|
array(
|
||||||
|
PhortunePaymentMethod::STATUS_ACTIVE,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$method) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Payment Methods'), $account->getPaymentMethodsURI())
|
||||||
|
->addTextCrumb($method->getObjectName())
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($method->getFullDisplayName());
|
||||||
|
|
||||||
|
$details = $this->newDetailsView($method);
|
||||||
|
|
||||||
|
$timeline = $this->buildTransactionTimeline(
|
||||||
|
$method,
|
||||||
|
new PhortunePaymentMethodTransactionQuery());
|
||||||
|
$timeline->setShouldTerminate(true);
|
||||||
|
|
||||||
|
$autopay = $this->newAutopayView($method);
|
||||||
|
|
||||||
|
$curtain = $this->buildCurtainView($method);
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setCurtain($curtain)
|
||||||
|
->setMainColumn(
|
||||||
|
array(
|
||||||
|
$details,
|
||||||
|
$autopay,
|
||||||
|
$timeline,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($method->getObjectName())
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildCurtainView(PhortunePaymentMethod $method) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$method,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$edit_uri = $this->getApplicationURI(
|
||||||
|
urisprintf(
|
||||||
|
'card/%d/edit/',
|
||||||
|
$method->getID()));
|
||||||
|
|
||||||
|
$remove_uri = $this->getApplicationURI(
|
||||||
|
urisprintf(
|
||||||
|
'card/%d/disable/',
|
||||||
|
$method->getID()));
|
||||||
|
|
||||||
|
$curtain = $this->newCurtainView($method);
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Payment Method'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setHref($edit_uri)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Remove Payment Method'))
|
||||||
|
->setIcon('fa-times')
|
||||||
|
->setHref($remove_uri)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
return $curtain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newDetailsView(PhortunePaymentMethod $method) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$merchant_phid = $method->getMerchantPHID();
|
||||||
|
$handles = $viewer->loadHandles(
|
||||||
|
array(
|
||||||
|
$merchant_phid,
|
||||||
|
));
|
||||||
|
|
||||||
|
$view = id(new PHUIPropertyListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
if (strlen($method->getName())) {
|
||||||
|
$view->addProperty(pht('Name'), $method->getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
$view->addProperty(pht('Summary'), $method->getSummary());
|
||||||
|
$view->addProperty(pht('Expires'), $method->getDisplayExpires());
|
||||||
|
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Merchant'),
|
||||||
|
$handles[$merchant_phid]->renderLink());
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Payment Method Details'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->addPropertyList($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newAutopayView(PhortunePaymentMethod $method) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$subscriptions = id(new PhortuneSubscriptionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPaymentMethodPHIDs(array($method->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$table = id(new PhortuneSubscriptionTableView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setSubscriptions($subscriptions)
|
||||||
|
->newTableView();
|
||||||
|
|
||||||
|
$table->setNoDataString(
|
||||||
|
pht(
|
||||||
|
'This payment method is not the default payment method for '.
|
||||||
|
'any subscriptions.'));
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Autopay Subscriptions'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -47,11 +47,8 @@ final class PhortuneAccountSubscriptionController
|
||||||
->setLimit(25)
|
->setLimit(25)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$handles = $this->loadViewerHandles(mpull($subscriptions, 'getPHID'));
|
|
||||||
|
|
||||||
$table = id(new PhortuneSubscriptionTableView())
|
$table = id(new PhortuneSubscriptionTableView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setHandles($handles)
|
|
||||||
->setSubscriptions($subscriptions);
|
->setSubscriptions($subscriptions);
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
|
|
|
@ -1,303 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhortunePaymentMethodCreateController
|
|
||||||
extends PhortuneController {
|
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
|
||||||
$viewer = $request->getViewer();
|
|
||||||
$account_id = $request->getURIData('accountID');
|
|
||||||
|
|
||||||
$account = id(new PhortuneAccountQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withIDs(array($account_id))
|
|
||||||
->executeOne();
|
|
||||||
if (!$account) {
|
|
||||||
return new Aphront404Response();
|
|
||||||
}
|
|
||||||
$account_id = $account->getID();
|
|
||||||
|
|
||||||
$merchant = id(new PhortuneMerchantQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withIDs(array($request->getInt('merchantID')))
|
|
||||||
->executeOne();
|
|
||||||
if (!$merchant) {
|
|
||||||
return new Aphront404Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
$cart_id = $request->getInt('cartID');
|
|
||||||
$subscription_id = $request->getInt('subscriptionID');
|
|
||||||
if ($cart_id) {
|
|
||||||
$cancel_uri = $this->getApplicationURI("cart/{$cart_id}/checkout/");
|
|
||||||
} else if ($subscription_id) {
|
|
||||||
$cancel_uri = $this->getApplicationURI(
|
|
||||||
"{$account_id}/subscription/edit/{$subscription_id}/");
|
|
||||||
} else {
|
|
||||||
$cancel_uri = $this->getApplicationURI($account->getID().'/');
|
|
||||||
}
|
|
||||||
|
|
||||||
$providers = $this->loadCreatePaymentMethodProvidersForMerchant($merchant);
|
|
||||||
if (!$providers) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'There are no payment providers enabled that can add payment '.
|
|
||||||
'methods.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($providers) == 1) {
|
|
||||||
// If there's only one provider, always choose it.
|
|
||||||
$provider_id = head_key($providers);
|
|
||||||
} else {
|
|
||||||
$provider_id = $request->getInt('providerID');
|
|
||||||
if (empty($providers[$provider_id])) {
|
|
||||||
$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($cancel_uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$provider = $providers[$provider_id];
|
|
||||||
|
|
||||||
$errors = array();
|
|
||||||
$display_exception = null;
|
|
||||||
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
|
||||||
$method = id(new PhortunePaymentMethod())
|
|
||||||
->setAccountPHID($account->getPHID())
|
|
||||||
->setAuthorPHID($viewer->getPHID())
|
|
||||||
->setMerchantPHID($merchant->getPHID())
|
|
||||||
->setProviderPHID($provider->getProviderConfig()->getPHID())
|
|
||||||
->setStatus(PhortunePaymentMethod::STATUS_ACTIVE);
|
|
||||||
|
|
||||||
// Limit the rate at which you can attempt to add payment methods. This
|
|
||||||
// is intended as a line of defense against using Phortune to validate a
|
|
||||||
// large list of stolen credit card numbers.
|
|
||||||
|
|
||||||
PhabricatorSystemActionEngine::willTakeAction(
|
|
||||||
array($viewer->getPHID()),
|
|
||||||
new PhortuneAddPaymentMethodAction(),
|
|
||||||
1);
|
|
||||||
|
|
||||||
if (!$errors) {
|
|
||||||
$errors = $this->processClientErrors(
|
|
||||||
$provider,
|
|
||||||
$request->getStr('errors'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$errors) {
|
|
||||||
$client_token_raw = $request->getStr('token');
|
|
||||||
$client_token = null;
|
|
||||||
try {
|
|
||||||
$client_token = phutil_json_decode($client_token_raw);
|
|
||||||
} catch (PhutilJSONParserException $ex) {
|
|
||||||
$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')));
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
try {
|
|
||||||
$provider->createPaymentMethodFromRequest(
|
|
||||||
$request,
|
|
||||||
$method,
|
|
||||||
$client_token);
|
|
||||||
} catch (PhortuneDisplayException $exception) {
|
|
||||||
$display_exception = $exception;
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
$errors = array(
|
|
||||||
pht('There was an error adding this payment method:'),
|
|
||||||
$ex->getMessage(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$errors && !$display_exception) {
|
|
||||||
$method->save();
|
|
||||||
|
|
||||||
// If we added this method on a cart flow, return to the cart to
|
|
||||||
// check out.
|
|
||||||
if ($cart_id) {
|
|
||||||
$next_uri = $this->getApplicationURI(
|
|
||||||
"cart/{$cart_id}/checkout/?paymentMethodID=".$method->getID());
|
|
||||||
} else if ($subscription_id) {
|
|
||||||
$next_uri = new PhutilURI($cancel_uri);
|
|
||||||
$next_uri->replaceQueryParam('added', true);
|
|
||||||
} else {
|
|
||||||
$account_uri = $this->getApplicationURI($account->getID().'/');
|
|
||||||
$next_uri = new PhutilURI($account_uri);
|
|
||||||
$next_uri->setFragment('payment');
|
|
||||||
}
|
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
|
||||||
} else {
|
|
||||||
if ($display_exception) {
|
|
||||||
$dialog_body = $display_exception->getView();
|
|
||||||
} else {
|
|
||||||
$dialog_body = id(new PHUIInfoView())
|
|
||||||
->setErrors($errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->newDialog()
|
|
||||||
->setTitle(pht('Error Adding Payment Method'))
|
|
||||||
->appendChild($dialog_body)
|
|
||||||
->addCancelButton($request->getRequestURI());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$form = $provider->renderCreatePaymentMethodForm($request, $errors);
|
|
||||||
|
|
||||||
$form
|
|
||||||
->setUser($viewer)
|
|
||||||
->setAction($request->getRequestURI())
|
|
||||||
->setWorkflow(true)
|
|
||||||
->addHiddenInput('providerID', $provider_id)
|
|
||||||
->addHiddenInput('cartID', $request->getInt('cartID'))
|
|
||||||
->addHiddenInput('subscriptionID', $request->getInt('subscriptionID'))
|
|
||||||
->addHiddenInput('isProviderForm', true)
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormSubmitControl())
|
|
||||||
->setValue(pht('Add Payment Method'))
|
|
||||||
->addCancelButton($cancel_uri));
|
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText(pht('Method'))
|
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
|
||||||
->setForm($form);
|
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
|
||||||
$crumbs->addTextCrumb(pht('Add Payment Method'));
|
|
||||||
$crumbs->setBorder(true);
|
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
|
||||||
->setHeader(pht('Add Payment Method'))
|
|
||||||
->setHeaderIcon('fa-plus-square');
|
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
|
||||||
->setHeader($header)
|
|
||||||
->setFooter(array(
|
|
||||||
$box,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newPage()
|
|
||||||
->setTitle($provider->getPaymentMethodDescription())
|
|
||||||
->setCrumbs($crumbs)
|
|
||||||
->appendChild($view);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private function renderSelectProvider(
|
|
||||||
PhortunePaymentProvider $provider) {
|
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$description = $provider->getPaymentMethodDescription();
|
|
||||||
$icon_uri = $provider->getPaymentMethodIcon();
|
|
||||||
$details = $provider->getPaymentMethodProviderDescription();
|
|
||||||
|
|
||||||
$this->requireResource('phortune-css');
|
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
|
||||||
->setSpriteSheet(PHUIIconView::SPRITE_LOGIN)
|
|
||||||
->setSpriteIcon($provider->getPaymentMethodIcon());
|
|
||||||
|
|
||||||
$button = id(new PHUIButtonView())
|
|
||||||
->setSize(PHUIButtonView::BIG)
|
|
||||||
->setColor(PHUIButtonView::GREY)
|
|
||||||
->setIcon($icon)
|
|
||||||
->setText($description)
|
|
||||||
->setSubtext($details)
|
|
||||||
->setMetadata(array('disableWorkflow' => true));
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->setAction($request->getRequestURI())
|
|
||||||
->addHiddenInput('providerID', $provider->getProviderConfig()->getID())
|
|
||||||
->appendChild($button);
|
|
||||||
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function processClientErrors(
|
|
||||||
PhortunePaymentProvider $provider,
|
|
||||||
$client_errors_raw) {
|
|
||||||
|
|
||||||
$errors = array();
|
|
||||||
|
|
||||||
$client_errors = null;
|
|
||||||
try {
|
|
||||||
$client_errors = phutil_json_decode($client_errors_raw);
|
|
||||||
} catch (PhutilJSONParserException $ex) {
|
|
||||||
$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,462 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodCreateController
|
||||||
|
extends PhortuneController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$account_id = $request->getURIData('accountID');
|
||||||
|
$account = id(new PhortuneAccountQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($account_id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$account) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart_id = $request->getInt('cartID');
|
||||||
|
$subscription_id = $request->getInt('subscriptionID');
|
||||||
|
$merchant_id = $request->getInt('merchantID');
|
||||||
|
|
||||||
|
if ($cart_id) {
|
||||||
|
$cart = id(new PhortuneCartQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withIDs(array($cart_id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$cart) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$subscription_phid = $cart->getSubscriptionPHID();
|
||||||
|
if ($subscription_phid) {
|
||||||
|
$subscription = id(new PhortuneSubscriptionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withPHIDs(array($subscription_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$subscription) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$subscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$merchant = $cart->getMerchant();
|
||||||
|
|
||||||
|
$cart_id = $cart->getID();
|
||||||
|
$subscription_id = null;
|
||||||
|
$merchant_id = null;
|
||||||
|
|
||||||
|
$next_uri = $cart->getCheckoutURI();
|
||||||
|
} else if ($subscription_id) {
|
||||||
|
$subscription = id(new PhortuneSubscriptionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withIDs(array($subscription_id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$subscription) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart = null;
|
||||||
|
$merchant = $subscription->getMerchant();
|
||||||
|
|
||||||
|
$cart_id = null;
|
||||||
|
$subscription_id = $subscription->getID();
|
||||||
|
$merchant_id = null;
|
||||||
|
|
||||||
|
$next_uri = $subscription->getURI();
|
||||||
|
} else if ($merchant_id) {
|
||||||
|
$merchant_phids = $account->getMerchantPHIDs();
|
||||||
|
if ($merchant_phids) {
|
||||||
|
$merchant = id(new PhortuneMerchantQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($merchant_id))
|
||||||
|
->withPHIDs($merchant_phids)
|
||||||
|
->executeOne();
|
||||||
|
} else {
|
||||||
|
$merchant = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$merchant) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart = null;
|
||||||
|
$subscription = null;
|
||||||
|
|
||||||
|
$cart_id = null;
|
||||||
|
$subscription_id = null;
|
||||||
|
$merchant_id = $merchant->getID();
|
||||||
|
|
||||||
|
$next_uri = $account->getPaymentMethodsURI();
|
||||||
|
} else {
|
||||||
|
$next_uri = $account->getPaymentMethodsURI();
|
||||||
|
|
||||||
|
$merchant_phids = $account->getMerchantPHIDs();
|
||||||
|
if ($merchant_phids) {
|
||||||
|
$merchants = id(new PhortuneMerchantQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs($merchant_phids)
|
||||||
|
->needProfileImage(true)
|
||||||
|
->execute();
|
||||||
|
} else {
|
||||||
|
$merchants = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$merchants) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('No Merchants'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You have not established a relationship with any merchants '.
|
||||||
|
'yet. Create an order or subscription before adding payment '.
|
||||||
|
'methods.'))
|
||||||
|
->addCancelButton($next_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's more than one merchant, ask the user to pick which one they
|
||||||
|
// want to pay. If there's only one, just pick it for them.
|
||||||
|
if (count($merchants) > 1) {
|
||||||
|
$menu = $this->newMerchantMenu($merchants);
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->appendInstructions(
|
||||||
|
pht(
|
||||||
|
'Choose the merchant you want to pay.'));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Choose a Merchant'))
|
||||||
|
->appendForm($form)
|
||||||
|
->appendChild($menu)
|
||||||
|
->addCancelButton($next_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart = null;
|
||||||
|
$subscription = null;
|
||||||
|
$merchant = head($merchants);
|
||||||
|
|
||||||
|
$cart_id = null;
|
||||||
|
$subscription_id = null;
|
||||||
|
$merchant_id = $merchant->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
$providers = $this->loadCreatePaymentMethodProvidersForMerchant($merchant);
|
||||||
|
if (!$providers) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'There are no payment providers enabled that can add payment '.
|
||||||
|
'methods.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$state_params = array(
|
||||||
|
'cartID' => $cart_id,
|
||||||
|
'subscriptionID' => $subscription_id,
|
||||||
|
'merchantID' => $merchant_id,
|
||||||
|
);
|
||||||
|
$state_params = array_filter($state_params);
|
||||||
|
|
||||||
|
$state_uri = new PhutilURI($request->getRequestURI());
|
||||||
|
foreach ($state_params as $key => $value) {
|
||||||
|
$state_uri->replaceQueryParam($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider_id = $request->getInt('providerID');
|
||||||
|
if (isset($providers[$provider_id])) {
|
||||||
|
$provider = $providers[$provider_id];
|
||||||
|
} else {
|
||||||
|
// If there's more than one provider, ask the user to pick how they
|
||||||
|
// want to pay. If there's only one, just pick it.
|
||||||
|
if (count($providers) > 1) {
|
||||||
|
$menu = $this->newProviderMenu($providers, $state_uri);
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Choose a Payment Method'))
|
||||||
|
->appendChild($menu)
|
||||||
|
->addCancelButton($next_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider = head($providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider_id = $provider->getProviderConfig()->getID();
|
||||||
|
|
||||||
|
$state_params['providerID'] = $provider_id;
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
$display_exception = null;
|
||||||
|
if ($request->isFormPost() && $request->getBool('isProviderForm')) {
|
||||||
|
$method = id(new PhortunePaymentMethod())
|
||||||
|
->setAccountPHID($account->getPHID())
|
||||||
|
->setAuthorPHID($viewer->getPHID())
|
||||||
|
->setMerchantPHID($merchant->getPHID())
|
||||||
|
->setProviderPHID($provider->getProviderConfig()->getPHID())
|
||||||
|
->setStatus(PhortunePaymentMethod::STATUS_ACTIVE);
|
||||||
|
|
||||||
|
// Limit the rate at which you can attempt to add payment methods. This
|
||||||
|
// is intended as a line of defense against using Phortune to validate a
|
||||||
|
// large list of stolen credit card numbers.
|
||||||
|
|
||||||
|
PhabricatorSystemActionEngine::willTakeAction(
|
||||||
|
array($viewer->getPHID()),
|
||||||
|
new PhortuneAddPaymentMethodAction(),
|
||||||
|
1);
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$errors = $this->processClientErrors(
|
||||||
|
$provider,
|
||||||
|
$request->getStr('errors'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$client_token_raw = $request->getStr('token');
|
||||||
|
$client_token = null;
|
||||||
|
try {
|
||||||
|
$client_token = phutil_json_decode($client_token_raw);
|
||||||
|
} catch (PhutilJSONParserException $ex) {
|
||||||
|
$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')));
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
try {
|
||||||
|
$provider->createPaymentMethodFromRequest(
|
||||||
|
$request,
|
||||||
|
$method,
|
||||||
|
$client_token);
|
||||||
|
} catch (PhortuneDisplayException $exception) {
|
||||||
|
$display_exception = $exception;
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$errors = array(
|
||||||
|
pht('There was an error adding this payment method:'),
|
||||||
|
$ex->getMessage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors && !$display_exception) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $method->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_CREATE)
|
||||||
|
->setNewValue(true);
|
||||||
|
|
||||||
|
$editor = id(new PhortunePaymentMethodEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
$editor->applyTransactions($method, $xactions);
|
||||||
|
|
||||||
|
$next_uri = new PhutilURI($next_uri);
|
||||||
|
|
||||||
|
// If we added this method on a cart flow, return to the cart to
|
||||||
|
// checkout with this payment method selected.
|
||||||
|
if ($cart_id) {
|
||||||
|
$next_uri->replaceQueryParam('paymentMethodID', $method->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||||
|
} else {
|
||||||
|
if ($display_exception) {
|
||||||
|
$dialog_body = $display_exception->getView();
|
||||||
|
} else {
|
||||||
|
$dialog_body = id(new PHUIInfoView())
|
||||||
|
->setErrors($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Error Adding Payment Method'))
|
||||||
|
->appendChild($dialog_body)
|
||||||
|
->addCancelButton($request->getRequestURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $provider->renderCreatePaymentMethodForm($request, $errors);
|
||||||
|
|
||||||
|
$form
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setAction($request->getPath())
|
||||||
|
->setWorkflow(true)
|
||||||
|
->addHiddenInput('isProviderForm', true)
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue(pht('Add Payment Method'))
|
||||||
|
->addCancelButton($next_uri));
|
||||||
|
|
||||||
|
foreach ($state_params as $key => $value) {
|
||||||
|
$form->addHiddenInput($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Method'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setForm($form);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Add Payment Method'))
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Add Payment Method'))
|
||||||
|
->setHeaderIcon('fa-plus-square');
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setFooter(
|
||||||
|
array(
|
||||||
|
$box,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($provider->getPaymentMethodDescription())
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processClientErrors(
|
||||||
|
PhortunePaymentProvider $provider,
|
||||||
|
$client_errors_raw) {
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$client_errors = null;
|
||||||
|
try {
|
||||||
|
$client_errors = phutil_json_decode($client_errors_raw);
|
||||||
|
} catch (PhutilJSONParserException $ex) {
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newMerchantMenu(array $merchants) {
|
||||||
|
assert_instances_of($merchants, 'PhortuneMerchant');
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$menu = id(new PHUIObjectItemListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setBig(true)
|
||||||
|
->setFlush(true);
|
||||||
|
|
||||||
|
foreach ($merchants as $merchant) {
|
||||||
|
$merchant_uri = id(new PhutilURI($request->getRequestURI()))
|
||||||
|
->replaceQueryParam('merchantID', $merchant->getID());
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setObjectName($merchant->getObjectName())
|
||||||
|
->setHeader($merchant->getName())
|
||||||
|
->setHref($merchant_uri)
|
||||||
|
->setClickable(true)
|
||||||
|
->setImageURI($merchant->getProfileImageURI());
|
||||||
|
|
||||||
|
$menu->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newProviderMenu(array $providers, PhutilURI $state_uri) {
|
||||||
|
assert_instances_of($providers, 'PhortunePaymentProvider');
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$menu = id(new PHUIObjectItemListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setBig(true)
|
||||||
|
->setFlush(true);
|
||||||
|
|
||||||
|
foreach ($providers as $provider) {
|
||||||
|
$provider_id = $provider->getProviderConfig()->getID();
|
||||||
|
|
||||||
|
$provider_uri = id(clone $state_uri)
|
||||||
|
->replaceQueryParam('providerID', $provider_id);
|
||||||
|
|
||||||
|
$description = $provider->getPaymentMethodDescription();
|
||||||
|
$icon_uri = $provider->getPaymentMethodIcon();
|
||||||
|
$details = $provider->getPaymentMethodProviderDescription();
|
||||||
|
|
||||||
|
$icon = id(new PHUIIconView())
|
||||||
|
->setSpriteSheet(PHUIIconView::SPRITE_LOGIN)
|
||||||
|
->setSpriteIcon($icon_uri);
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($description)
|
||||||
|
->setHref($provider_uri)
|
||||||
|
->setClickable(true)
|
||||||
|
->addAttribute($details)
|
||||||
|
->setImageIcon($icon);
|
||||||
|
|
||||||
|
$menu->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,14 +26,23 @@ final class PhortunePaymentMethodDisableController
|
||||||
|
|
||||||
$account = $method->getAccount();
|
$account = $method->getAccount();
|
||||||
$account_id = $account->getID();
|
$account_id = $account->getID();
|
||||||
$account_uri = $this->getApplicationURI("/account/billing/{$account_id}/");
|
$account_uri = $account->getPaymentMethodsURI();
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
// TODO: ApplicationTransactions!!!!
|
$xactions[] = $method->getApplicationTransactionTemplate()
|
||||||
$method
|
->setTransactionType(
|
||||||
->setStatus(PhortunePaymentMethod::STATUS_DISABLED)
|
PhortunePaymentMethodStatusTransaction::TRANSACTIONTYPE)
|
||||||
->save();
|
->setNewValue(PhortunePaymentMethod::STATUS_DISABLED);
|
||||||
|
|
||||||
|
$editor = id(new PhortunePaymentMethodEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
$editor->applyTransactions($method, $xactions);
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($account_uri);
|
return id(new AphrontRedirectResponse())->setURI($account_uri);
|
||||||
}
|
}
|
|
@ -20,25 +20,36 @@ final class PhortunePaymentMethodEditController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$next_uri = $method->getURI();
|
||||||
|
|
||||||
$account = $method->getAccount();
|
$account = $method->getAccount();
|
||||||
$account_uri = $this->getApplicationURI($account->getID().'/');
|
$v_name = $method->getName();
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
|
$v_name = $request->getStr('name');
|
||||||
|
|
||||||
$name = $request->getStr('name');
|
$xactions = array();
|
||||||
|
|
||||||
// TODO: Use ApplicationTransactions
|
$xactions[] = $method->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhortunePaymentMethodNameTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($v_name);
|
||||||
|
|
||||||
$method->setName($name);
|
$editor = id(new PhortunePaymentMethodEditor())
|
||||||
$method->save();
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($account_uri);
|
$editor->applyTransactions($method, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
$provider = $method->buildPaymentProvider();
|
$provider = $method->buildPaymentProvider();
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($viewer)
|
->setViewer($viewer)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Name'))
|
->setLabel(pht('Name'))
|
||||||
|
@ -54,7 +65,7 @@ final class PhortunePaymentMethodEditController
|
||||||
->setValue($method->getDisplayExpires()))
|
->setValue($method->getDisplayExpires()))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSubmitControl())
|
id(new AphrontFormSubmitControl())
|
||||||
->addCancelButton($account_uri)
|
->addCancelButton($next_uri)
|
||||||
->setValue(pht('Save Changes')));
|
->setValue(pht('Save Changes')));
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
@ -62,11 +73,12 @@ final class PhortunePaymentMethodEditController
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
->setForm($form);
|
->setForm($form);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
$crumbs->addTextCrumb($account->getName(), $account_uri);
|
->addTextCrumb($account->getName(), $account->getURI())
|
||||||
$crumbs->addTextCrumb($method->getDisplayName());
|
->addTextCrumb(pht('Payment Methods'), $account->getPaymentMethodsURI())
|
||||||
$crumbs->addTextCrumb(pht('Edit'));
|
->addTextCrumb($method->getObjectName(), $method->getURI())
|
||||||
$crumbs->setBorder(true);
|
->addTextCrumb(pht('Edit'))
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Edit Payment Method'))
|
->setHeader(pht('Edit Payment Method'))
|
||||||
|
@ -74,15 +86,15 @@ final class PhortunePaymentMethodEditController
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
$view = id(new PHUITwoColumnView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setFooter(array(
|
->setFooter(
|
||||||
$box,
|
array(
|
||||||
));
|
$box,
|
||||||
|
));
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle(pht('Edit Payment Method'))
|
->setTitle(pht('Edit Payment Method'))
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->appendChild($view);
|
->appendChild($view);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorPhortuneApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Phortune Payment Methods');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreateObjectTitle($author, $object) {
|
||||||
|
return pht('%s created this payment method.', $author);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new PhortunePaymentMethodTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ final class PhortuneSubscriptionQuery
|
||||||
private $accountPHIDs;
|
private $accountPHIDs;
|
||||||
private $merchantPHIDs;
|
private $merchantPHIDs;
|
||||||
private $statuses;
|
private $statuses;
|
||||||
|
private $paymentMethodPHIDs;
|
||||||
|
|
||||||
private $needTriggers;
|
private $needTriggers;
|
||||||
|
|
||||||
|
@ -36,24 +37,22 @@ final class PhortuneSubscriptionQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withPaymentMethodPHIDs(array $method_phids) {
|
||||||
|
$this->paymentMethodPHIDs = $method_phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function needTriggers($need_triggers) {
|
public function needTriggers($need_triggers) {
|
||||||
$this->needTriggers = $need_triggers;
|
$this->needTriggers = $need_triggers;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new PhortuneSubscription();
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhortuneSubscription();
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
$conn = $table->establishConnection('r');
|
|
||||||
|
|
||||||
$rows = queryfx_all(
|
|
||||||
$conn,
|
|
||||||
'SELECT subscription.* FROM %T subscription %Q %Q %Q',
|
|
||||||
$table->getTableName(),
|
|
||||||
$this->buildWhereClause($conn),
|
|
||||||
$this->buildOrderClause($conn),
|
|
||||||
$this->buildLimitClause($conn));
|
|
||||||
|
|
||||||
return $table->loadAllFromArray($rows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function willFilterPage(array $subscriptions) {
|
protected function willFilterPage(array $subscriptions) {
|
||||||
|
@ -67,6 +66,7 @@ final class PhortuneSubscriptionQuery
|
||||||
$account = idx($accounts, $subscription->getAccountPHID());
|
$account = idx($accounts, $subscription->getAccountPHID());
|
||||||
if (!$account) {
|
if (!$account) {
|
||||||
unset($subscriptions[$key]);
|
unset($subscriptions[$key]);
|
||||||
|
$this->didRejectResult($subscription);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$subscription->attachAccount($account);
|
$subscription->attachAccount($account);
|
||||||
|
@ -86,6 +86,7 @@ final class PhortuneSubscriptionQuery
|
||||||
$merchant = idx($merchants, $subscription->getMerchantPHID());
|
$merchant = idx($merchants, $subscription->getMerchantPHID());
|
||||||
if (!$merchant) {
|
if (!$merchant) {
|
||||||
unset($subscriptions[$key]);
|
unset($subscriptions[$key]);
|
||||||
|
$this->didRejectResult($subscription);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$subscription->attachMerchant($merchant);
|
$subscription->attachMerchant($merchant);
|
||||||
|
@ -112,6 +113,7 @@ final class PhortuneSubscriptionQuery
|
||||||
$implementation = idx($implementations, $ref);
|
$implementation = idx($implementations, $ref);
|
||||||
if (!$implementation) {
|
if (!$implementation) {
|
||||||
unset($subscriptions[$key]);
|
unset($subscriptions[$key]);
|
||||||
|
$this->didRejectResult($subscription);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$subscription->attachImplementation($implementation);
|
$subscription->attachImplementation($implementation);
|
||||||
|
@ -133,6 +135,7 @@ final class PhortuneSubscriptionQuery
|
||||||
$trigger = idx($triggers, $subscription->getTriggerPHID());
|
$trigger = idx($triggers, $subscription->getTriggerPHID());
|
||||||
if (!$trigger) {
|
if (!$trigger) {
|
||||||
unset($subscriptions[$key]);
|
unset($subscriptions[$key]);
|
||||||
|
$this->didRejectResult($subscription);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$subscription->attachTrigger($trigger);
|
$subscription->attachTrigger($trigger);
|
||||||
|
@ -142,10 +145,8 @@ final class PhortuneSubscriptionQuery
|
||||||
return $subscriptions;
|
return $subscriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn);
|
|
||||||
|
|
||||||
if ($this->ids !== null) {
|
if ($this->ids !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
|
@ -182,7 +183,18 @@ final class PhortuneSubscriptionQuery
|
||||||
$this->statuses);
|
$this->statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($conn, $where);
|
if ($this->paymentMethodPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'subscription.defaultPaymentMethodPHID IN (%Ls)',
|
||||||
|
$this->paymentMethodPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPrimaryTableAlias() {
|
||||||
|
return 'subscription';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryApplicationClass() {
|
public function getQueryApplicationClass() {
|
||||||
|
|
|
@ -125,18 +125,6 @@ final class PhortuneSubscriptionSearchEngine
|
||||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRequiredHandlePHIDsForResultList(
|
|
||||||
array $subscriptions,
|
|
||||||
PhabricatorSavedQuery $query) {
|
|
||||||
$phids = array();
|
|
||||||
foreach ($subscriptions as $subscription) {
|
|
||||||
$phids[] = $subscription->getPHID();
|
|
||||||
$phids[] = $subscription->getMerchantPHID();
|
|
||||||
$phids[] = $subscription->getAuthorPHID();
|
|
||||||
}
|
|
||||||
return $phids;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function renderResultList(
|
protected function renderResultList(
|
||||||
array $subscriptions,
|
array $subscriptions,
|
||||||
PhabricatorSavedQuery $query,
|
PhabricatorSavedQuery $query,
|
||||||
|
@ -147,7 +135,6 @@ final class PhortuneSubscriptionSearchEngine
|
||||||
|
|
||||||
$table = id(new PhortuneSubscriptionTableView())
|
$table = id(new PhortuneSubscriptionTableView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setHandles($handles)
|
|
||||||
->setSubscriptions($subscriptions);
|
->setSubscriptions($subscriptions);
|
||||||
|
|
||||||
$merchant = $this->getMerchant();
|
$merchant = $this->getMerchant();
|
||||||
|
|
|
@ -117,6 +117,12 @@ final class PhortuneAccount extends PhortuneDAO
|
||||||
$this->getID());
|
$this->getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPaymentMethodsURI() {
|
||||||
|
return urisprintf(
|
||||||
|
'/phortune/account/%d/methods/',
|
||||||
|
$this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
public function attachMerchantPHIDs(array $merchant_phids) {
|
public function attachMerchantPHIDs(array $merchant_phids) {
|
||||||
$this->merchantPHIDs = $merchant_phids;
|
$this->merchantPHIDs = $merchant_phids;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -70,6 +70,10 @@ final class PhortuneMerchant extends PhortuneDAO
|
||||||
return $this->assertAttached($this->profileImageFile);
|
return $this->assertAttached($this->profileImageFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getObjectName() {
|
||||||
|
return pht('Merchant %d', $this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ final class PhortunePaymentMethod
|
||||||
implements
|
implements
|
||||||
PhabricatorPolicyInterface,
|
PhabricatorPolicyInterface,
|
||||||
PhabricatorExtendedPolicyInterface,
|
PhabricatorExtendedPolicyInterface,
|
||||||
PhabricatorPolicyCodexInterface {
|
PhabricatorPolicyCodexInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface {
|
||||||
|
|
||||||
const STATUS_ACTIVE = 'payment:active';
|
const STATUS_ACTIVE = 'payment:active';
|
||||||
const STATUS_DISABLED = 'payment:disabled';
|
const STATUS_DISABLED = 'payment:disabled';
|
||||||
|
@ -140,6 +141,29 @@ final class PhortunePaymentMethod
|
||||||
return ($this->getStatus() === self::STATUS_ACTIVE);
|
return ($this->getStatus() === self::STATUS_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return urisprintf(
|
||||||
|
'/phortune/account/%d/methods/%d/',
|
||||||
|
$this->getAccount()->getID(),
|
||||||
|
$this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjectName() {
|
||||||
|
return pht('Payment Method %d', $this->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new PhortunePaymentMethodEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new PhortunePaymentMethodTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodTransaction
|
||||||
|
extends PhabricatorModularTransaction {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'phortune';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return PhortunePaymentMethodPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseTransactionClass() {
|
||||||
|
return 'PhortunePaymentMethodTransactionType';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,19 +3,9 @@
|
||||||
final class PhortuneSubscriptionTableView extends AphrontView {
|
final class PhortuneSubscriptionTableView extends AphrontView {
|
||||||
|
|
||||||
private $subscriptions;
|
private $subscriptions;
|
||||||
private $handles;
|
|
||||||
private $isMerchantView;
|
private $isMerchantView;
|
||||||
private $notice;
|
private $notice;
|
||||||
|
|
||||||
public function setHandles(array $handles) {
|
|
||||||
$this->handles = $handles;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandles() {
|
|
||||||
return $this->handles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setSubscriptions(array $subscriptions) {
|
public function setSubscriptions(array $subscriptions) {
|
||||||
$this->subscriptions = $subscriptions;
|
$this->subscriptions = $subscriptions;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -40,9 +30,15 @@ final class PhortuneSubscriptionTableView extends AphrontView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
|
return $this->newTableView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newTableView() {
|
||||||
$subscriptions = $this->getSubscriptions();
|
$subscriptions = $this->getSubscriptions();
|
||||||
$handles = $this->getHandles();
|
$viewer = $this->getViewer();
|
||||||
$viewer = $this->getUser();
|
|
||||||
|
$phids = mpull($subscriptions, 'getPHID');
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$rowc = array();
|
$rowc = array();
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodNameTransaction
|
||||||
|
extends PhortunePaymentMethodTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'name';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setName($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$old_value = $this->getOldValue();
|
||||||
|
$new_value = $this->getNewValue();
|
||||||
|
|
||||||
|
if (strlen($old_value) && strlen($new_value)) {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this payment method from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
} else if (strlen($new_value)) {
|
||||||
|
return pht(
|
||||||
|
'%s set the name of this payment method to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s removed the name of this payment method (was: %s).',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderOldValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortunePaymentMethodStatusTransaction
|
||||||
|
extends PhortunePaymentMethodTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'status';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setStatus($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the status of this payment method.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhortunePaymentMethodTransactionType
|
||||||
|
extends PhabricatorModularTransactionType {}
|
|
@ -7,15 +7,6 @@
|
||||||
height: 34px;
|
height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phortune-payment-method-list {
|
|
||||||
margin: 8px 24px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phortune-payment-method-list button {
|
|
||||||
margin: 4px 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.phortune-payment-onetime-list {
|
.phortune-payment-onetime-list {
|
||||||
width: 280px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue