Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14785350
D20719.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
60 KB
Referenced Files
None
Subscribers
None
D20719.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D20719: Make Phortune payment methods transaction-oriented and always support "Add Payment Method"
Attached
Detach File
Event Timeline
Log In to Comment