Page MenuHomePhabricator

D20719.diff
No OneTemporary

D20719.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -92,7 +92,7 @@
'rsrc/css/application/pholio/pholio.css' => '88ef5ef1',
'rsrc/css/application/phortune/phortune-credit-card-form.css' => '3b9868a8',
'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/phriction/phriction-document-css.css' => '03380da0',
'rsrc/css/application/policy/policy-edit.css' => '8794e2ed',
@@ -810,7 +810,7 @@
'pholio-inline-comments-css' => '722b48c2',
'phortune-credit-card-form' => 'd12d214f',
'phortune-credit-card-form-css' => '3b9868a8',
- 'phortune-css' => '12e8251a',
+ 'phortune-css' => '508a1a5e',
'phortune-invoice-css' => '4436b241',
'phrequent-css' => 'bd79cc67',
'phriction-document-css' => '03380da0',
diff --git a/resources/sql/autopatches/20190816.payment.01.xaction.sql b/resources/sql/autopatches/20190816.payment.01.xaction.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20190816.payment.01.xaction.sql
@@ -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};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -5249,7 +5249,8 @@
'PhortuneAccountOrdersController' => 'applications/phortune/controller/account/PhortuneAccountOrdersController.php',
'PhortuneAccountOverviewController' => 'applications/phortune/controller/account/PhortuneAccountOverviewController.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',
'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php',
'PhortuneAccountSubscriptionController' => 'applications/phortune/controller/account/PhortuneAccountSubscriptionController.php',
@@ -5325,12 +5326,18 @@
'PhortuneOrderTableView' => 'applications/phortune/view/PhortuneOrderTableView.php',
'PhortunePayPalPaymentProvider' => 'applications/phortune/provider/PhortunePayPalPaymentProvider.php',
'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php',
- 'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/payment/PhortunePaymentMethodCreateController.php',
- 'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/payment/PhortunePaymentMethodDisableController.php',
- 'PhortunePaymentMethodEditController' => 'applications/phortune/controller/payment/PhortunePaymentMethodEditController.php',
+ 'PhortunePaymentMethodCreateController' => 'applications/phortune/controller/paymentmethod/PhortunePaymentMethodCreateController.php',
+ 'PhortunePaymentMethodDisableController' => 'applications/phortune/controller/paymentmethod/PhortunePaymentMethodDisableController.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',
'PhortunePaymentMethodPolicyCodex' => 'applications/phortune/codex/PhortunePaymentMethodPolicyCodex.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',
'PhortunePaymentProviderConfig' => 'applications/phortune/storage/PhortunePaymentProviderConfig.php',
'PhortunePaymentProviderConfigEditor' => 'applications/phortune/editor/PhortunePaymentProviderConfigEditor.php',
@@ -11805,7 +11812,8 @@
'PhortuneAccountOrdersController' => 'PhortuneAccountProfileController',
'PhortuneAccountOverviewController' => 'PhortuneAccountProfileController',
'PhortuneAccountPHIDType' => 'PhabricatorPHIDType',
- 'PhortuneAccountPaymentMethodsController' => 'PhortuneAccountProfileController',
+ 'PhortuneAccountPaymentMethodListController' => 'PhortuneAccountProfileController',
+ 'PhortuneAccountPaymentMethodViewController' => 'PhortuneAccountController',
'PhortuneAccountProfileController' => 'PhortuneAccountController',
'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhortuneAccountSubscriptionController' => 'PhortuneAccountProfileController',
@@ -11896,13 +11904,20 @@
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
'PhabricatorPolicyCodexInterface',
+ 'PhabricatorApplicationTransactionInterface',
),
'PhortunePaymentMethodCreateController' => 'PhortuneController',
'PhortunePaymentMethodDisableController' => 'PhortuneController',
'PhortunePaymentMethodEditController' => 'PhortuneController',
+ 'PhortunePaymentMethodEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'PhortunePaymentMethodNameTransaction' => 'PhortunePaymentMethodTransactionType',
'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType',
'PhortunePaymentMethodPolicyCodex' => 'PhabricatorPolicyCodex',
'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhortunePaymentMethodStatusTransaction' => 'PhortunePaymentMethodTransactionType',
+ 'PhortunePaymentMethodTransaction' => 'PhabricatorModularTransaction',
+ 'PhortunePaymentMethodTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhortunePaymentMethodTransactionType' => 'PhabricatorModularTransactionType',
'PhortunePaymentProvider' => 'Phobject',
'PhortunePaymentProviderConfig' => array(
'PhortuneDAO',
diff --git a/src/applications/phortune/application/PhabricatorPhortuneApplication.php b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
--- a/src/applications/phortune/application/PhabricatorPhortuneApplication.php
+++ b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
@@ -72,7 +72,10 @@
'(?P<accountID>\d+)/' => array(
'details/' => 'PhortuneAccountDetailsController',
- 'methods/' => 'PhortuneAccountPaymentMethodsController',
+ 'methods/' => array(
+ '' => 'PhortuneAccountPaymentMethodListController',
+ '(?P<id>\d+)/' => 'PhortuneAccountPaymentMethodViewController',
+ ),
'orders/' => 'PhortuneAccountOrdersController',
'charges/' => 'PhortuneAccountChargesController',
'subscriptions/' => 'PhortuneAccountSubscriptionController',
diff --git a/src/applications/phortune/controller/account/PhortuneAccountController.php b/src/applications/phortune/controller/account/PhortuneAccountController.php
--- a/src/applications/phortune/controller/account/PhortuneAccountController.php
+++ b/src/applications/phortune/controller/account/PhortuneAccountController.php
@@ -23,6 +23,10 @@
abstract protected function shouldRequireAccountEditCapability();
abstract protected function handleAccountRequest(AphrontRequest $request);
+ private function hasAccount() {
+ return (bool)$this->account;
+ }
+
final protected function getAccount() {
if ($this->account === null) {
throw new Exception(
@@ -37,8 +41,10 @@
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
- $account = $this->getAccount();
- if ($account) {
+ // If we hit a policy exception, we can make it here without finding
+ // an account.
+ if ($this->hasAccount()) {
+ $account = $this->getAccount();
$crumbs->addTextCrumb($account->getName(), $account->getURI());
}
diff --git a/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodsController.php b/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodListController.php
rename from src/applications/phortune/controller/account/PhortuneAccountPaymentMethodsController.php
rename to src/applications/phortune/controller/account/PhortuneAccountPaymentMethodListController.php
--- a/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodsController.php
+++ b/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodListController.php
@@ -1,6 +1,6 @@
<?php
-final class PhortuneAccountPaymentMethodsController
+final class PhortuneAccountPaymentMethodListController
extends PhortuneAccountProfileController {
protected function shouldRequireAccountEditCapability() {
@@ -46,15 +46,17 @@
$id = $account->getID();
- // TODO: Allow adding a card here directly
$add = id(new PHUIButtonView())
->setTag('a')
- ->setText(pht('New Payment Method'))
+ ->setText(pht('Add Payment Method'))
->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())
- ->setHeader(pht('Payment Methods'));
+ ->setHeader(pht('Payment Methods'))
+ ->addActionLink($add);
$list = id(new PHUIObjectItemListView())
->setUser($viewer)
@@ -74,39 +76,14 @@
foreach ($methods as $method) {
$id = $method->getID();
- $item = new PHUIObjectItemView();
- $item->setHeader($method->getFullDisplayName());
-
- switch ($method->getStatus()) {
- 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;
- }
+ $item = id(new PHUIObjectItemView())
+ ->setObjectName($method->getObjectName())
+ ->setHeader($method->getFullDisplayName())
+ ->setHref($method->getURI());
$provider = $method->buildPaymentProvider();
$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);
}
diff --git a/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodViewController.php b/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/account/PhortuneAccountPaymentMethodViewController.php
@@ -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);
+ }
+
+}
diff --git a/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php b/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php
--- a/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php
+++ b/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php
@@ -47,11 +47,8 @@
->setLimit(25)
->execute();
- $handles = $this->loadViewerHandles(mpull($subscriptions, 'getPHID'));
-
$table = id(new PhortuneSubscriptionTableView())
->setUser($viewer)
- ->setHandles($handles)
->setSubscriptions($subscriptions);
$header = id(new PHUIHeaderView())
diff --git a/src/applications/phortune/controller/payment/PhortunePaymentMethodCreateController.php b/src/applications/phortune/controller/payment/PhortunePaymentMethodCreateController.php
deleted file mode 100644
--- a/src/applications/phortune/controller/payment/PhortunePaymentMethodCreateController.php
+++ /dev/null
@@ -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;
- }
-
-}
diff --git a/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodCreateController.php b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodCreateController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodCreateController.php
@@ -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;
+ }
+
+}
diff --git a/src/applications/phortune/controller/payment/PhortunePaymentMethodDisableController.php b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodDisableController.php
rename from src/applications/phortune/controller/payment/PhortunePaymentMethodDisableController.php
rename to src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodDisableController.php
--- a/src/applications/phortune/controller/payment/PhortunePaymentMethodDisableController.php
+++ b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodDisableController.php
@@ -26,14 +26,23 @@
$account = $method->getAccount();
$account_id = $account->getID();
- $account_uri = $this->getApplicationURI("/account/billing/{$account_id}/");
+ $account_uri = $account->getPaymentMethodsURI();
if ($request->isFormPost()) {
+ $xactions = array();
- // TODO: ApplicationTransactions!!!!
- $method
- ->setStatus(PhortunePaymentMethod::STATUS_DISABLED)
- ->save();
+ $xactions[] = $method->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhortunePaymentMethodStatusTransaction::TRANSACTIONTYPE)
+ ->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);
}
diff --git a/src/applications/phortune/controller/payment/PhortunePaymentMethodEditController.php b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodEditController.php
rename from src/applications/phortune/controller/payment/PhortunePaymentMethodEditController.php
rename to src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodEditController.php
--- a/src/applications/phortune/controller/payment/PhortunePaymentMethodEditController.php
+++ b/src/applications/phortune/controller/paymentmethod/PhortunePaymentMethodEditController.php
@@ -20,25 +20,36 @@
return new Aphront404Response();
}
+ $next_uri = $method->getURI();
+
$account = $method->getAccount();
- $account_uri = $this->getApplicationURI($account->getID().'/');
+ $v_name = $method->getName();
if ($request->isFormPost()) {
+ $v_name = $request->getStr('name');
+
+ $xactions = array();
- $name = $request->getStr('name');
+ $xactions[] = $method->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhortunePaymentMethodNameTransaction::TRANSACTIONTYPE)
+ ->setNewValue($v_name);
- // TODO: Use ApplicationTransactions
+ $editor = id(new PhortunePaymentMethodEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
- $method->setName($name);
- $method->save();
+ $editor->applyTransactions($method, $xactions);
- return id(new AphrontRedirectResponse())->setURI($account_uri);
+ return id(new AphrontRedirectResponse())->setURI($next_uri);
}
$provider = $method->buildPaymentProvider();
$form = id(new AphrontFormView())
- ->setUser($viewer)
+ ->setViewer($viewer)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
@@ -54,7 +65,7 @@
->setValue($method->getDisplayExpires()))
->appendChild(
id(new AphrontFormSubmitControl())
- ->addCancelButton($account_uri)
+ ->addCancelButton($next_uri)
->setValue(pht('Save Changes')));
$box = id(new PHUIObjectBoxView())
@@ -62,11 +73,12 @@
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb($account->getName(), $account_uri);
- $crumbs->addTextCrumb($method->getDisplayName());
- $crumbs->addTextCrumb(pht('Edit'));
- $crumbs->setBorder(true);
+ $crumbs = $this->buildApplicationCrumbs()
+ ->addTextCrumb($account->getName(), $account->getURI())
+ ->addTextCrumb(pht('Payment Methods'), $account->getPaymentMethodsURI())
+ ->addTextCrumb($method->getObjectName(), $method->getURI())
+ ->addTextCrumb(pht('Edit'))
+ ->setBorder(true);
$header = id(new PHUIHeaderView())
->setHeader(pht('Edit Payment Method'))
@@ -74,15 +86,15 @@
$view = id(new PHUITwoColumnView())
->setHeader($header)
- ->setFooter(array(
- $box,
- ));
+ ->setFooter(
+ array(
+ $box,
+ ));
return $this->newPage()
->setTitle(pht('Edit Payment Method'))
->setCrumbs($crumbs)
->appendChild($view);
-
}
}
diff --git a/src/applications/phortune/editor/PhortunePaymentMethodEditor.php b/src/applications/phortune/editor/PhortunePaymentMethodEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/editor/PhortunePaymentMethodEditor.php
@@ -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);
+ }
+
+}
diff --git a/src/applications/phortune/query/PhortunePaymentMethodTransactionQuery.php b/src/applications/phortune/query/PhortunePaymentMethodTransactionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/query/PhortunePaymentMethodTransactionQuery.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhortunePaymentMethodTransactionQuery
+ extends PhabricatorApplicationTransactionQuery {
+
+ public function getTemplateApplicationTransaction() {
+ return new PhortunePaymentMethodTransaction();
+ }
+
+}
diff --git a/src/applications/phortune/query/PhortuneSubscriptionQuery.php b/src/applications/phortune/query/PhortuneSubscriptionQuery.php
--- a/src/applications/phortune/query/PhortuneSubscriptionQuery.php
+++ b/src/applications/phortune/query/PhortuneSubscriptionQuery.php
@@ -8,6 +8,7 @@
private $accountPHIDs;
private $merchantPHIDs;
private $statuses;
+ private $paymentMethodPHIDs;
private $needTriggers;
@@ -36,24 +37,22 @@
return $this;
}
+ public function withPaymentMethodPHIDs(array $method_phids) {
+ $this->paymentMethodPHIDs = $method_phids;
+ return $this;
+ }
+
public function needTriggers($need_triggers) {
$this->needTriggers = $need_triggers;
return $this;
}
+ public function newResultObject() {
+ return new PhortuneSubscription();
+ }
+
protected function loadPage() {
- $table = new PhortuneSubscription();
- $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);
+ return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $subscriptions) {
@@ -67,6 +66,7 @@
$account = idx($accounts, $subscription->getAccountPHID());
if (!$account) {
unset($subscriptions[$key]);
+ $this->didRejectResult($subscription);
continue;
}
$subscription->attachAccount($account);
@@ -86,6 +86,7 @@
$merchant = idx($merchants, $subscription->getMerchantPHID());
if (!$merchant) {
unset($subscriptions[$key]);
+ $this->didRejectResult($subscription);
continue;
}
$subscription->attachMerchant($merchant);
@@ -112,6 +113,7 @@
$implementation = idx($implementations, $ref);
if (!$implementation) {
unset($subscriptions[$key]);
+ $this->didRejectResult($subscription);
continue;
}
$subscription->attachImplementation($implementation);
@@ -133,6 +135,7 @@
$trigger = idx($triggers, $subscription->getTriggerPHID());
if (!$trigger) {
unset($subscriptions[$key]);
+ $this->didRejectResult($subscription);
continue;
}
$subscription->attachTrigger($trigger);
@@ -142,10 +145,8 @@
return $subscriptions;
}
- protected function buildWhereClause(AphrontDatabaseConnection $conn) {
- $where = array();
-
- $where[] = $this->buildPagingClause($conn);
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
@@ -182,7 +183,18 @@
$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() {
diff --git a/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php b/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php
--- a/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php
+++ b/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php
@@ -125,18 +125,6 @@
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(
array $subscriptions,
PhabricatorSavedQuery $query,
@@ -147,7 +135,6 @@
$table = id(new PhortuneSubscriptionTableView())
->setUser($viewer)
- ->setHandles($handles)
->setSubscriptions($subscriptions);
$merchant = $this->getMerchant();
diff --git a/src/applications/phortune/storage/PhortuneAccount.php b/src/applications/phortune/storage/PhortuneAccount.php
--- a/src/applications/phortune/storage/PhortuneAccount.php
+++ b/src/applications/phortune/storage/PhortuneAccount.php
@@ -117,6 +117,12 @@
$this->getID());
}
+ public function getPaymentMethodsURI() {
+ return urisprintf(
+ '/phortune/account/%d/methods/',
+ $this->getID());
+ }
+
public function attachMerchantPHIDs(array $merchant_phids) {
$this->merchantPHIDs = $merchant_phids;
return $this;
diff --git a/src/applications/phortune/storage/PhortuneMerchant.php b/src/applications/phortune/storage/PhortuneMerchant.php
--- a/src/applications/phortune/storage/PhortuneMerchant.php
+++ b/src/applications/phortune/storage/PhortuneMerchant.php
@@ -70,6 +70,10 @@
return $this->assertAttached($this->profileImageFile);
}
+ public function getObjectName() {
+ return pht('Merchant %d', $this->getID());
+ }
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/phortune/storage/PhortunePaymentMethod.php b/src/applications/phortune/storage/PhortunePaymentMethod.php
--- a/src/applications/phortune/storage/PhortunePaymentMethod.php
+++ b/src/applications/phortune/storage/PhortunePaymentMethod.php
@@ -9,7 +9,8 @@
implements
PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface,
- PhabricatorPolicyCodexInterface {
+ PhabricatorPolicyCodexInterface,
+ PhabricatorApplicationTransactionInterface {
const STATUS_ACTIVE = 'payment:active';
const STATUS_DISABLED = 'payment:disabled';
@@ -140,6 +141,29 @@
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 )----------------------------------------- */
diff --git a/src/applications/phortune/storage/PhortunePaymentMethodTransaction.php b/src/applications/phortune/storage/PhortunePaymentMethodTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/storage/PhortunePaymentMethodTransaction.php
@@ -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';
+ }
+
+}
diff --git a/src/applications/phortune/view/PhortuneSubscriptionTableView.php b/src/applications/phortune/view/PhortuneSubscriptionTableView.php
--- a/src/applications/phortune/view/PhortuneSubscriptionTableView.php
+++ b/src/applications/phortune/view/PhortuneSubscriptionTableView.php
@@ -3,19 +3,9 @@
final class PhortuneSubscriptionTableView extends AphrontView {
private $subscriptions;
- private $handles;
private $isMerchantView;
private $notice;
- public function setHandles(array $handles) {
- $this->handles = $handles;
- return $this;
- }
-
- public function getHandles() {
- return $this->handles;
- }
-
public function setSubscriptions(array $subscriptions) {
$this->subscriptions = $subscriptions;
return $this;
@@ -40,9 +30,15 @@
}
public function render() {
+ return $this->newTableView();
+ }
+
+ public function newTableView() {
$subscriptions = $this->getSubscriptions();
- $handles = $this->getHandles();
- $viewer = $this->getUser();
+ $viewer = $this->getViewer();
+
+ $phids = mpull($subscriptions, 'getPHID');
+ $handles = $viewer->loadHandles($phids);
$rows = array();
$rowc = array();
diff --git a/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodNameTransaction.php b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodNameTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodNameTransaction.php
@@ -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());
+ }
+ }
+
+}
diff --git a/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodStatusTransaction.php b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodStatusTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodStatusTransaction.php
@@ -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());
+ }
+
+}
diff --git a/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodTransactionType.php b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/xaction/paymentmethod/PhortunePaymentMethodTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class PhortunePaymentMethodTransactionType
+ extends PhabricatorModularTransactionType {}
diff --git a/webroot/rsrc/css/application/phortune/phortune.css b/webroot/rsrc/css/application/phortune/phortune.css
--- a/webroot/rsrc/css/application/phortune/phortune.css
+++ b/webroot/rsrc/css/application/phortune/phortune.css
@@ -7,15 +7,6 @@
height: 34px;
}
-.phortune-payment-method-list {
- margin: 8px 24px 0;
-}
-
-.phortune-payment-method-list button {
- margin: 4px 0;
- width: 100%;
-}
-
.phortune-payment-onetime-list {
width: 280px;
}

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 25, 12:13 PM (11 h, 34 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7050492
Default Alt Text
D20719.diff (60 KB)

Event Timeline