From 0beb8228da16b9726117949beccf115f134da858 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 6 Oct 2014 14:19:08 -0700 Subject: [PATCH] Give applications control over Phortune cart logic Summary: Ref T2787. Similar to D10634, give applications more control over the cart workflow. For now this just means they get to pick exit URIs, but in the future they can manage more details of cart behavior. Test Plan: Funded an initiative and got returned to the initiative instead of dead-ending in Phortune. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T2787 Differential Revision: https://secure.phabricator.com/D10638 --- .../sql/autopatches/20141006.phortunecart.sql | 4 + src/__phutil_library_map__.php | 3 + .../FundInitiativeBackController.php | 5 +- .../fund/phortune/FundBackerCart.php | 80 +++++++++++++++++++ .../cart/PhortuneCartImplementation.php | 22 +++++ .../PhortuneCartCheckoutController.php | 14 ++-- .../phortune/query/PhortuneCartQuery.php | 18 +++++ .../phortune/storage/PhortuneAccount.php | 15 +++- .../phortune/storage/PhortuneCart.php | 30 +++++-- 9 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 resources/sql/autopatches/20141006.phortunecart.sql create mode 100644 src/applications/fund/phortune/FundBackerCart.php create mode 100644 src/applications/phortune/cart/PhortuneCartImplementation.php diff --git a/resources/sql/autopatches/20141006.phortunecart.sql b/resources/sql/autopatches/20141006.phortunecart.sql new file mode 100644 index 0000000000..faf04dd9e2 --- /dev/null +++ b/resources/sql/autopatches/20141006.phortunecart.sql @@ -0,0 +1,4 @@ +TRUNCATE TABLE {$NAMESPACE}_phortune.phortune_cart; + +ALTER TABLE {$NAMESPACE}_phortune.phortune_cart + ADD cartClass VARCHAR(128) NOT NULL COLLATE utf8_bin; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6983689c19..122a1a64c3 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -666,6 +666,7 @@ phutil_register_library_map(array( 'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php', 'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.php', 'FundBacker' => 'applications/fund/storage/FundBacker.php', + 'FundBackerCart' => 'applications/fund/phortune/FundBackerCart.php', 'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php', 'FundBackerListController' => 'applications/fund/controller/FundBackerListController.php', 'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php', @@ -2555,6 +2556,7 @@ phutil_register_library_map(array( 'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php', 'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php', 'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php', + 'PhortuneCartImplementation' => 'applications/phortune/cart/PhortuneCartImplementation.php', 'PhortuneCartQuery' => 'applications/phortune/query/PhortuneCartQuery.php', 'PhortuneCartViewController' => 'applications/phortune/controller/PhortuneCartViewController.php', 'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php', @@ -3514,6 +3516,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', ), + 'FundBackerCart' => 'PhortuneCartImplementation', 'FundBackerEditor' => 'PhabricatorApplicationTransactionEditor', 'FundBackerListController' => 'FundController', 'FundBackerPHIDType' => 'PhabricatorPHIDType', diff --git a/src/applications/fund/controller/FundInitiativeBackController.php b/src/applications/fund/controller/FundInitiativeBackController.php index cfe2c66716..b97786c2b3 100644 --- a/src/applications/fund/controller/FundInitiativeBackController.php +++ b/src/applications/fund/controller/FundInitiativeBackController.php @@ -70,7 +70,10 @@ final class FundInitiativeBackController $viewer, PhabricatorContentSource::newFromRequest($request)); - $cart = $account->newCart($viewer); + $cart_implementation = id(new FundBackerCart()) + ->setInitiative($initiative); + + $cart = $account->newCart($viewer, $cart_implementation); $purchase = $cart->newPurchase($viewer, $product); $purchase diff --git a/src/applications/fund/phortune/FundBackerCart.php b/src/applications/fund/phortune/FundBackerCart.php new file mode 100644 index 0000000000..1d823ae03e --- /dev/null +++ b/src/applications/fund/phortune/FundBackerCart.php @@ -0,0 +1,80 @@ +initiativePHID = $initiative_phid; + return $this; + } + + public function getInitiativePHID() { + return $this->initiativePHID; + } + + public function setInitiative(FundInitiative $initiative) { + $this->initiative = $initiative; + return $this; + } + + public function getInitiative() { + return $this->initiative; + } + + public function willCreateCart( + PhabricatorUser $viewer, + PhortuneCart $cart) { + + $initiative = $this->getInitiative(); + if (!$initiative) { + throw new Exception( + pht('Call setInitiative() before building a cart!')); + } + + $cart->setMetadataValue('initiativePHID', $initiative->getPHID()); + } + + public function loadImplementationsForCarts( + PhabricatorUser $viewer, + array $carts) { + + $phids = array(); + foreach ($carts as $cart) { + $phids[] = $cart->getMetadataValue('initiativePHID'); + } + + $initiatives = id(new FundInitiativeQuery()) + ->setViewer($viewer) + ->withPHIDs($phids) + ->execute(); + $initiatives = mpull($initiatives, null, 'getPHID'); + + $objects = array(); + foreach ($carts as $key => $cart) { + $initiative_phid = $cart->getMetadataValue('initiativePHID'); + + $object = id(new FundBackerCart()) + ->setInitiativePHID($initiative_phid); + + $initiative = idx($initiatives, $initiative_phid); + if ($initiative) { + $object->setInitiative($initiative); + } + + $objects[$key] = $object; + } + + return $objects; + } + + public function getCancelURI(PhortuneCart $cart) { + return '/'.$this->getInitiative()->getMonogram(); + } + + public function getDoneURI(PhortuneCart $cart) { + return '/'.$this->getInitiative()->getMonogram(); + } + +} diff --git a/src/applications/phortune/cart/PhortuneCartImplementation.php b/src/applications/phortune/cart/PhortuneCartImplementation.php new file mode 100644 index 0000000000..fe600d0028 --- /dev/null +++ b/src/applications/phortune/cart/PhortuneCartImplementation.php @@ -0,0 +1,22 @@ +appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Submit Payment')) - ->setDisabled(!$methods)); + $submit = id(new AphrontFormSubmitControl()) + ->setValue(pht('Submit Payment')) + ->setDisabled(!$methods); + + if ($cart->getCancelURI() !== null) { + $submit->addCancelButton($cart->getCancelURI()); + } + + $form->appendChild($submit); } $provider_form = null; diff --git a/src/applications/phortune/query/PhortuneCartQuery.php b/src/applications/phortune/query/PhortuneCartQuery.php index a0f24d1ec9..c81deb4fb8 100644 --- a/src/applications/phortune/query/PhortuneCartQuery.php +++ b/src/applications/phortune/query/PhortuneCartQuery.php @@ -66,6 +66,24 @@ final class PhortuneCartQuery $cart->attachAccount($account); } + $implementations = array(); + + $cart_map = mgroup($carts, 'getCartClass'); + foreach ($cart_map as $class => $class_carts) { + $implementations += newv($class, array())->loadImplementationsForCarts( + $this->getViewer(), + $class_carts); + } + + foreach ($carts as $key => $cart) { + $implementation = idx($implementations, $key); + if (!$implementation) { + unset($carts[$key]); + continue; + } + $cart->attachImplementation($implementation); + } + return $carts; } diff --git a/src/applications/phortune/storage/PhortuneAccount.php b/src/applications/phortune/storage/PhortuneAccount.php index 7f47304ed4..bb4bd1b4b6 100644 --- a/src/applications/phortune/storage/PhortuneAccount.php +++ b/src/applications/phortune/storage/PhortuneAccount.php @@ -56,9 +56,18 @@ final class PhortuneAccount extends PhortuneDAO return $account; } - public function newCart(PhabricatorUser $actor) { - return PhortuneCart::initializeNewCart($actor, $this) - ->save(); + public function newCart( + PhabricatorUser $actor, + PhortuneCartImplementation $implementation) { + + $cart = PhortuneCart::initializeNewCart($actor, $this); + + $cart->setCartClass(get_class($implementation)); + $cart->attachImplementation($implementation); + + $implementation->willCreateCart($actor, $cart); + + return $cart->save(); } public function getConfiguration() { diff --git a/src/applications/phortune/storage/PhortuneCart.php b/src/applications/phortune/storage/PhortuneCart.php index d8e86af0d1..6da806f949 100644 --- a/src/applications/phortune/storage/PhortuneCart.php +++ b/src/applications/phortune/storage/PhortuneCart.php @@ -11,11 +11,13 @@ final class PhortuneCart extends PhortuneDAO protected $accountPHID; protected $authorPHID; + protected $cartClass; protected $status; - protected $metadata; + protected $metadata = array(); private $account = self::ATTACHABLE; private $purchases = self::ATTACHABLE; + private $implementation = self::ATTACHABLE; public static function initializeNewCart( PhabricatorUser $actor, @@ -73,13 +75,11 @@ final class PhortuneCart extends PhortuneDAO public function getDoneURI() { - // TODO: Implement properly. - return '/phortune/cart/'.$this->getID().'/'; + return $this->getImplementation()->getDoneURI($this); } public function getCancelURI() { - // TODO: Implement properly. - return '/'; + return $this->getImplementation()->getCancelURI($this); } public function getDetailURI() { @@ -98,6 +98,7 @@ final class PhortuneCart extends PhortuneDAO ), self::CONFIG_COLUMN_SCHEMA => array( 'status' => 'text32', + 'cartClass' => 'text128', ), self::CONFIG_KEY_SCHEMA => array( 'key_account' => array( @@ -131,6 +132,16 @@ final class PhortuneCart extends PhortuneDAO return $this->assertAttached($this->account); } + public function attachImplementation( + PhortuneCartImplementation $implementation) { + $this->implementation = $implementation; + return $this; + } + + public function getImplementation() { + return $this->assertAttached($this->implementation); + } + public function getTotalPriceAsCurrency() { $prices = array(); foreach ($this->getPurchases() as $purchase) { @@ -140,6 +151,15 @@ final class PhortuneCart extends PhortuneDAO return PhortuneCurrency::newFromList($prices); } + public function setMetadataValue($key, $value) { + $this->metadata[$key] = $value; + return $this; + } + + public function getMetadataValue($key, $default = null) { + return idx($this->metadata, $key, $default); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */