diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 27eac0ee59..89efdefeb2 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2557,8 +2557,10 @@ phutil_register_library_map(array( 'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php', 'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php', 'PhortuneCartImplementation' => 'applications/phortune/cart/PhortuneCartImplementation.php', + 'PhortuneCartListController' => 'applications/phortune/controller/PhortuneCartListController.php', 'PhortuneCartPHIDType' => 'applications/phortune/phid/PhortuneCartPHIDType.php', 'PhortuneCartQuery' => 'applications/phortune/query/PhortuneCartQuery.php', + 'PhortuneCartSearchEngine' => 'applications/phortune/query/PhortuneCartSearchEngine.php', 'PhortuneCartViewController' => 'applications/phortune/controller/PhortuneCartViewController.php', 'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php', 'PhortuneChargePHIDType' => 'applications/phortune/phid/PhortuneChargePHIDType.php', @@ -5608,8 +5610,10 @@ phutil_register_library_map(array( ), 'PhortuneCartCheckoutController' => 'PhortuneCartController', 'PhortuneCartController' => 'PhortuneController', + 'PhortuneCartListController' => 'PhortuneController', 'PhortuneCartPHIDType' => 'PhabricatorPHIDType', 'PhortuneCartQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhortuneCartSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneCartViewController' => 'PhortuneCartController', 'PhortuneCharge' => array( 'PhortuneDAO', diff --git a/src/applications/fund/phortune/FundBackerCart.php b/src/applications/fund/phortune/FundBackerCart.php index 7196b21f48..239b50baa7 100644 --- a/src/applications/fund/phortune/FundBackerCart.php +++ b/src/applications/fund/phortune/FundBackerCart.php @@ -23,7 +23,7 @@ final class FundBackerCart extends PhortuneCartImplementation { return $this->initiative; } - public function getName() { + public function getName(PhortuneCart $cart) { return pht('Fund Initiative'); } diff --git a/src/applications/phortune/application/PhabricatorPhortuneApplication.php b/src/applications/phortune/application/PhabricatorPhortuneApplication.php index 90312a0cd8..f4b468b30f 100644 --- a/src/applications/phortune/application/PhabricatorPhortuneApplication.php +++ b/src/applications/phortune/application/PhabricatorPhortuneApplication.php @@ -67,6 +67,8 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication { 'merchant/' => array( '(?:query/(?P[^/]+)/)?' => 'PhortuneMerchantListController', 'edit/(?:(?P\d+)/)?' => 'PhortuneMerchantEditController', + 'orders/(?P\d+)/(?:query/(?P[^/]+)/)?' + => 'PhortuneCartListController', '(?P\d+)/' => 'PhortuneMerchantViewController', ), ), diff --git a/src/applications/phortune/cart/PhortuneCartImplementation.php b/src/applications/phortune/cart/PhortuneCartImplementation.php index 43124dce41..337c66a136 100644 --- a/src/applications/phortune/cart/PhortuneCartImplementation.php +++ b/src/applications/phortune/cart/PhortuneCartImplementation.php @@ -12,8 +12,7 @@ abstract class PhortuneCartImplementation { PhabricatorUser $viewer, array $carts); - abstract public function getName(); - + abstract public function getName(PhortuneCart $cart); abstract public function getCancelURI(PhortuneCart $cart); abstract public function getDoneURI(PhortuneCart $cart); diff --git a/src/applications/phortune/controller/PhortuneCartListController.php b/src/applications/phortune/controller/PhortuneCartListController.php new file mode 100644 index 0000000000..57f486b6c3 --- /dev/null +++ b/src/applications/phortune/controller/PhortuneCartListController.php @@ -0,0 +1,79 @@ +merchantID = idx($data, 'merchantID'); + $this->queryKey = idx($data, 'queryKey'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $engine = new PhortuneCartSearchEngine(); + + if ($this->merchantID) { + $merchant = id(new PhortuneMerchantQuery()) + ->setViewer($viewer) + ->withIDs(array($this->merchantID)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$merchant) { + return new Aphront404Response(); + } + $this->merchant = $merchant; + $engine->setMerchant($merchant); + } + + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->queryKey) + ->setSearchEngine($engine) + ->setNavigation($this->buildSideNavView()); + + return $this->delegateToController($controller); + } + + public function buildSideNavView() { + $viewer = $this->getRequest()->getUser(); + + $nav = new AphrontSideNavFilterView(); + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); + + id(new PhortuneCartSearchEngine()) + ->setViewer($viewer) + ->addNavigationItems($nav->getMenu()); + + $nav->selectFilter(null); + + return $nav; + } + + public function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $merchant = $this->merchant; + if ($merchant) { + $id = $merchant->getID(); + $crumbs->addTextCrumb( + $merchant->getName(), + $this->getApplicationURI("merchant/{$id}/")); + $crumbs->addTextCrumb( + pht('Orders'), + $this->getApplicationURI("merchant/orders/{$id}/")); + } + + return $crumbs; + } + +} diff --git a/src/applications/phortune/controller/PhortuneMerchantViewController.php b/src/applications/phortune/controller/PhortuneMerchantViewController.php index 2821a9ec6d..809e5d7ca5 100644 --- a/src/applications/phortune/controller/PhortuneMerchantViewController.php +++ b/src/applications/phortune/controller/PhortuneMerchantViewController.php @@ -177,6 +177,14 @@ final class PhortuneMerchantViewController ->setWorkflow(!$can_edit) ->setHref($this->getApplicationURI("merchant/edit/{$id}/"))); + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('View Orders')) + ->setIcon('fa-shopping-cart') + ->setHref($this->getApplicationURI("merchant/orders/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + return $view; } diff --git a/src/applications/phortune/phid/PhortuneCartPHIDType.php b/src/applications/phortune/phid/PhortuneCartPHIDType.php index c9488d84ab..f42e563cee 100644 --- a/src/applications/phortune/phid/PhortuneCartPHIDType.php +++ b/src/applications/phortune/phid/PhortuneCartPHIDType.php @@ -29,7 +29,7 @@ final class PhortuneCartPHIDType extends PhabricatorPHIDType { $cart = $objects[$phid]; $id = $cart->getID(); - $name = $cart->getImplementation()->getName(); + $name = $cart->getName(); $handle->setName($name); $handle->setURI("/phortune/cart/{$id}/"); diff --git a/src/applications/phortune/query/PhortuneCartQuery.php b/src/applications/phortune/query/PhortuneCartQuery.php index b0e86c9715..fd37591257 100644 --- a/src/applications/phortune/query/PhortuneCartQuery.php +++ b/src/applications/phortune/query/PhortuneCartQuery.php @@ -6,6 +6,7 @@ final class PhortuneCartQuery private $ids; private $phids; private $accountPHIDs; + private $merchantPHIDs; private $statuses; private $needPurchases; @@ -25,6 +26,11 @@ final class PhortuneCartQuery return $this; } + public function withMerchantPHIDs(array $merchant_phids) { + $this->merchantPHIDs = $merchant_phids; + return $this; + } + public function withStatuses(array $statuses) { $this->statuses = $statuses; return $this; @@ -145,6 +151,13 @@ final class PhortuneCartQuery $this->accountPHIDs); } + if ($this->merchantPHIDs !== null) { + $where[] = qsprintf( + $conn, + 'cart.merchantPHID IN (%Ls)', + $this->merchantPHIDs); + } + if ($this->statuses !== null) { $where[] = qsprintf( $conn, diff --git a/src/applications/phortune/query/PhortuneCartSearchEngine.php b/src/applications/phortune/query/PhortuneCartSearchEngine.php new file mode 100644 index 0000000000..8d2046cd91 --- /dev/null +++ b/src/applications/phortune/query/PhortuneCartSearchEngine.php @@ -0,0 +1,167 @@ +merchant = $merchant; + return $this; + } + + public function getMerchant() { + return $this->merchant; + } + + public function getResultTypeDescription() { + return pht('Phortune Orders'); + } + + public function buildSavedQueryFromRequest(AphrontRequest $request) { + $saved = new PhabricatorSavedQuery(); + + return $saved; + } + + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { + $query = id(new PhortuneCartQuery()) + ->needPurchases(true) + ->withStatuses( + array( + PhortuneCart::STATUS_PURCHASING, + PhortuneCart::STATUS_CHARGED, + PhortuneCart::STATUS_PURCHASED, + )); + + $viewer = $this->requireViewer(); + + $merchant = $this->getMerchant(); + if ($merchant) { + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $merchant, + PhabricatorPolicyCapability::CAN_EDIT); + if (!$can_edit) { + throw new Exception( + pht('You can not query orders for a merchant you do not control.')); + } + $query->withMerchantPHIDs(array($merchant->getPHID())); + } else { + $accounts = id(new PhortuneAccountQuery()) + ->withMemberPHIDs($viewer->getPHID()) + ->execute(); + if ($accounts) { + $query->withAccountPHIDs(mpull($accounts, 'getPHID')); + } else { + throw new Exception(pht('You have no accounts!')); + } + } + + return $query; + } + + public function buildSearchForm( + AphrontFormView $form, + PhabricatorSavedQuery $saved_query) {} + + protected function getURI($path) { + $merchant = $this->getMerchant(); + if ($merchant) { + return '/phortune/merchant/'.$merchant->getID().'/order/'.$path; + } else { + return '/phortune/order/'.$path; + } + } + + public function getBuiltinQueryNames() { + $names = array( + 'all' => pht('All Orders'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function getRequiredHandlePHIDsForResultList( + array $carts, + PhabricatorSavedQuery $query) { + $phids = array(); + foreach ($carts as $cart) { + $phids[] = $cart->getPHID(); + $phids[] = $cart->getMerchantPHID(); + $phids[] = $cart->getAuthorPHID(); + } + return $phids; + } + + protected function renderResultList( + array $carts, + PhabricatorSavedQuery $query, + array $handles) { + assert_instances_of($carts, 'PhortuneCart'); + + $viewer = $this->requireViewer(); + + $rows = array(); + foreach ($carts as $cart) { + $merchant = $cart->getMerchant(); + + $rows[] = array( + $cart->getID(), + $handles[$cart->getPHID()]->renderLink(), + $handles[$merchant->getPHID()]->renderLink(), + $handles[$cart->getAuthorPHID()]->renderLink(), + $cart->getTotalPriceAsCurrency()->formatForDisplay(), + PhortuneCart::getNameForStatus($cart->getStatus()), + phabricator_datetime($cart->getDateModified(), $viewer), + ); + } + + $table = id(new AphrontTableView($rows)) + ->setNoDataString(pht('No orders match the query.')) + ->setHeaders( + array( + pht('ID'), + pht('Order'), + pht('Merchant'), + pht('Authorized By'), + pht('Amount'), + pht('Status'), + pht('Updated'), + )) + ->setColumnClasses( + array( + '', + 'pri', + '', + '', + 'wide right', + '', + 'right', + )); + + $merchant = $this->getMerchant(); + if ($merchant) { + $header = pht('Orders for %s', $merchant->getName()); + } else { + $header = pht('Your Orders'); + } + + return id(new PHUIObjectBoxView()) + ->setHeaderText($header) + ->appendChild($table); + } +} diff --git a/src/applications/phortune/storage/PhortuneCart.php b/src/applications/phortune/storage/PhortuneCart.php index e2c84f0d3e..5ca4401998 100644 --- a/src/applications/phortune/storage/PhortuneCart.php +++ b/src/applications/phortune/storage/PhortuneCart.php @@ -51,6 +51,20 @@ final class PhortuneCart extends PhortuneDAO return $purchase; } + public static function getStatusNameMap() { + return array( + self::STATUS_BUILDING => pht('Building'), + self::STATUS_READY => pht('Ready'), + self::STATUS_PURCHASING => pht('Purchasing'), + self::STATUS_CHARGED => pht('Charged'), + self::STATUS_PURCHASED => pht('Purchased'), + ); + } + + public static function getNameForStatus($status) { + return idx(self::getStatusNameMap(), $status, $status); + } + public function activateCart() { $this->setStatus(self::STATUS_READY)->save(); return $this; @@ -128,6 +142,9 @@ final class PhortuneCart extends PhortuneDAO return $this; } + public function getName() { + return $this->getImplementation()->getName($this); + } public function getDoneURI() { return $this->getImplementation()->getDoneURI($this);