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 @@ -5279,6 +5279,7 @@ 'PhortuneCartTransactionQuery' => 'applications/phortune/query/PhortuneCartTransactionQuery.php', 'PhortuneCartUpdateController' => 'applications/phortune/controller/cart/PhortuneCartUpdateController.php', 'PhortuneCartViewController' => 'applications/phortune/controller/cart/PhortuneCartViewController.php', + 'PhortuneCartVoidController' => 'applications/phortune/controller/cart/PhortuneCartVoidController.php', 'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php', 'PhortuneChargePHIDType' => 'applications/phortune/phid/PhortuneChargePHIDType.php', 'PhortuneChargeQuery' => 'applications/phortune/query/PhortuneChargeQuery.php', @@ -5372,10 +5373,8 @@ 'PhortuneSubscription' => 'applications/phortune/storage/PhortuneSubscription.php', 'PhortuneSubscriptionAutopayTransaction' => 'applications/phortune/xaction/subscription/PhortuneSubscriptionAutopayTransaction.php', 'PhortuneSubscriptionCart' => 'applications/phortune/cart/PhortuneSubscriptionCart.php', - 'PhortuneSubscriptionEditController' => 'applications/phortune/controller/subscription/PhortuneSubscriptionEditController.php', 'PhortuneSubscriptionEditor' => 'applications/phortune/editor/PhortuneSubscriptionEditor.php', 'PhortuneSubscriptionImplementation' => 'applications/phortune/subscription/PhortuneSubscriptionImplementation.php', - 'PhortuneSubscriptionListController' => 'applications/phortune/controller/subscription/PhortuneSubscriptionListController.php', 'PhortuneSubscriptionPHIDType' => 'applications/phortune/phid/PhortuneSubscriptionPHIDType.php', 'PhortuneSubscriptionPolicyCodex' => 'applications/phortune/codex/PhortuneSubscriptionPolicyCodex.php', 'PhortuneSubscriptionProduct' => 'applications/phortune/product/PhortuneSubscriptionProduct.php', @@ -11861,6 +11860,7 @@ 'PhortuneCartTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneCartUpdateController' => 'PhortuneCartController', 'PhortuneCartViewController' => 'PhortuneCartController', + 'PhortuneCartVoidController' => 'PhortuneCartController', 'PhortuneCharge' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', @@ -11984,10 +11984,8 @@ ), 'PhortuneSubscriptionAutopayTransaction' => 'PhortuneSubscriptionTransactionType', 'PhortuneSubscriptionCart' => 'PhortuneCartImplementation', - 'PhortuneSubscriptionEditController' => 'PhortuneController', 'PhortuneSubscriptionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneSubscriptionImplementation' => 'Phobject', - 'PhortuneSubscriptionListController' => 'PhortuneController', 'PhortuneSubscriptionPHIDType' => 'PhabricatorPHIDType', 'PhortuneSubscriptionPolicyCodex' => 'PhabricatorPolicyCodex', 'PhortuneSubscriptionProduct' => 'PhortuneProductImplementation', 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 @@ -43,6 +43,8 @@ 'checkout/' => 'PhortuneCartCheckoutController', '(?Pprint)/' => 'PhortuneCartViewController', '(?Pcancel|refund)/' => 'PhortuneCartCancelController', + 'accept/' => 'PhortuneCartAcceptController', + 'void/' => 'PhortuneCartVoidController', 'update/' => 'PhortuneCartUpdateController', ), 'account/' => array( diff --git a/src/applications/phortune/controller/PhortuneController.php b/src/applications/phortune/controller/PhortuneController.php --- a/src/applications/phortune/controller/PhortuneController.php +++ b/src/applications/phortune/controller/PhortuneController.php @@ -2,42 +2,6 @@ abstract class PhortuneController extends PhabricatorController { - protected function addAccountCrumb( - $crumbs, - PhortuneAccount $account, - $link = true) { - - $name = $account->getName(); - $href = null; - - if ($link) { - $href = $this->getApplicationURI($account->getID().'/'); - $crumbs->addTextCrumb($name, $href); - } else { - $crumbs->addTextCrumb($name); - } - } - - protected function addMerchantCrumb( - $crumbs, - PhortuneMerchant $merchant, - $link = true) { - - $name = $merchant->getName(); - $href = null; - - $crumbs->addTextCrumb( - pht('Merchants'), - $this->getApplicationURI('merchant/')); - - if ($link) { - $href = $this->getApplicationURI('merchant/'.$merchant->getID().'/'); - $crumbs->addTextCrumb($name, $href); - } else { - $crumbs->addTextCrumb($name); - } - } - private function loadEnabledProvidersForMerchant(PhortuneMerchant $merchant) { $viewer = $this->getRequest()->getUser(); @@ -84,30 +48,4 @@ return $providers; } - protected function loadMerchantAuthority() { - $request = $this->getRequest(); - $viewer = $this->getViewer(); - - $is_merchant = (bool)$request->getURIData('merchantID'); - if (!$is_merchant) { - return null; - } - - $merchant = id(new PhortuneMerchantQuery()) - ->setViewer($viewer) - ->withIDs(array($request->getURIData('merchantID'))) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$merchant) { - return null; - } - - $viewer->grantAuthority($merchant); - return $merchant; - } - } diff --git a/src/applications/phortune/controller/account/PhortuneAccountChargesController.php b/src/applications/phortune/controller/account/PhortuneAccountChargesController.php --- a/src/applications/phortune/controller/account/PhortuneAccountChargesController.php +++ b/src/applications/phortune/controller/account/PhortuneAccountChargesController.php @@ -12,7 +12,7 @@ $title = $account->getName(); $crumbs = $this->buildApplicationCrumbs() - ->addTextCrumb(pht('Order History')) + ->addTextCrumb(pht('Orders')) ->setBorder(true); $header = $this->buildHeaderView(); @@ -46,22 +46,11 @@ ->setLimit(100) ->execute(); - $phids = array(); - foreach ($charges as $charge) { - $phids[] = $charge->getProviderPHID(); - $phids[] = $charge->getCartPHID(); - $phids[] = $charge->getMerchantPHID(); - $phids[] = $charge->getPaymentMethodPHID(); - } - - $handles = $this->loadViewerHandles($phids); - $charges_uri = $account->getChargeListURI(); $table = id(new PhortuneChargeTableView()) ->setUser($viewer) - ->setCharges($charges) - ->setHandles($handles); + ->setCharges($charges); $header = id(new PHUIHeaderView()) ->setHeader(pht('Recent Charges')) diff --git a/src/applications/phortune/controller/account/PhortuneAccountOrdersController.php b/src/applications/phortune/controller/account/PhortuneAccountOrdersController.php --- a/src/applications/phortune/controller/account/PhortuneAccountOrdersController.php +++ b/src/applications/phortune/controller/account/PhortuneAccountOrdersController.php @@ -12,7 +12,7 @@ $title = $account->getName(); $crumbs = $this->buildApplicationCrumbs() - ->addTextCrumb(pht('Order History')) + ->addTextCrumb(pht('Orders')) ->setBorder(true); $header = $this->buildHeaderView(); diff --git a/src/applications/phortune/controller/account/PhortuneAccountProfileController.php b/src/applications/phortune/controller/account/PhortuneAccountProfileController.php --- a/src/applications/phortune/controller/account/PhortuneAccountProfileController.php +++ b/src/applications/phortune/controller/account/PhortuneAccountProfileController.php @@ -66,13 +66,13 @@ $nav->addFilter( 'orders', - pht('Order History'), + pht('Orders'), $account->getOrdersURI(), 'fa-shopping-bag'); $nav->addFilter( 'charges', - pht('Charge History'), + pht('Charges'), $account->getChargesURI(), 'fa-calculator'); diff --git a/src/applications/phortune/controller/cart/PhortuneCartAcceptController.php b/src/applications/phortune/controller/cart/PhortuneCartAcceptController.php --- a/src/applications/phortune/controller/cart/PhortuneCartAcceptController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartAcceptController.php @@ -3,27 +3,19 @@ final class PhortuneCartAcceptController extends PhortuneCartController { - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); + protected function shouldRequireAccountAuthority() { + return false; + } - // You must control the merchant to accept orders. - $authority = $this->loadMerchantAuthority(); - if (!$authority) { - return new Aphront404Response(); - } + protected function shouldRequireMerchantAuthority() { + return true; + } - $cart = id(new PhortuneCartQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->withMerchantPHIDs(array($authority->getPHID())) - ->needPurchases(true) - ->executeOne(); - if (!$cart) { - return new Aphront404Response(); - } + protected function handleCartRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + $cart = $this->getCart(); - $cancel_uri = $cart->getDetailURI($authority); + $cancel_uri = $cart->getDetailURI(); if ($cart->getStatus() !== PhortuneCart::STATUS_REVIEW) { return $this->newDialog() diff --git a/src/applications/phortune/controller/cart/PhortuneCartCancelController.php b/src/applications/phortune/controller/cart/PhortuneCartCancelController.php --- a/src/applications/phortune/controller/cart/PhortuneCartCancelController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartCancelController.php @@ -3,26 +3,21 @@ final class PhortuneCartCancelController extends PhortuneCartController { - public function handleRequest(AphrontRequest $request) { + protected function shouldRequireAccountAuthority() { + return false; + } + + protected function shouldRequireMerchantAuthority() { + return false; + } + + protected function handleCartRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $action = $request->getURIData('action'); - $authority = $this->loadMerchantAuthority(); - - $cart_query = id(new PhortuneCartQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needPurchases(true); - - if ($authority) { - $cart_query->withMerchantPHIDs(array($authority->getPHID())); - } - - $cart = $cart_query->executeOne(); - if (!$cart) { - return new Aphront404Response(); - } + $cart = $this->getCart(); + $authority = $this->getMerchantAuthority(); switch ($action) { case 'cancel': @@ -45,7 +40,7 @@ return new Aphront404Response(); } - $cancel_uri = $cart->getDetailURI($authority); + $cancel_uri = $cart->getDetailURI(); $merchant = $cart->getMerchant(); try { @@ -60,7 +55,7 @@ return $this->newDialog() ->setTitle($title) ->appendChild($ex->getMessage()) - ->addCancelButton($cancel_uri); + ->addCancelButton($cancel_uri, pht('Rats')); } $charges = id(new PhortuneChargeQuery()) diff --git a/src/applications/phortune/controller/cart/PhortuneCartCheckoutController.php b/src/applications/phortune/controller/cart/PhortuneCartCheckoutController.php --- a/src/applications/phortune/controller/cart/PhortuneCartCheckoutController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartCheckoutController.php @@ -3,18 +3,17 @@ final class PhortuneCartCheckoutController extends PhortuneCartController { - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); + protected function shouldRequireAccountAuthority() { + return true; + } - $cart = id(new PhortuneCartQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needPurchases(true) - ->executeOne(); - if (!$cart) { - return new Aphront404Response(); - } + protected function shouldRequireMerchantAuthority() { + return false; + } + + protected function handleCartRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + $cart = $this->getCart(); $cancel_uri = $cart->getCancelURI(); $merchant = $cart->getMerchant(); @@ -139,7 +138,10 @@ 'cartID' => $cart->getID(), ); - $payment_method_uri = $this->getApplicationURI("{$account_id}/card/new/"); + $payment_method_uri = urisprintf( + 'account/%d/methods/new/', + $account->getID()); + $payment_method_uri = $this->getApplicationURI($payment_method_uri); $payment_method_uri = new PhutilURI($payment_method_uri, $params); $form = id(new AphrontFormView()) diff --git a/src/applications/phortune/controller/cart/PhortuneCartController.php b/src/applications/phortune/controller/cart/PhortuneCartController.php --- a/src/applications/phortune/controller/cart/PhortuneCartController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartController.php @@ -3,6 +3,77 @@ abstract class PhortuneCartController extends PhortuneController { + private $cart; + private $merchantAuthority; + + abstract protected function shouldRequireAccountAuthority(); + abstract protected function shouldRequireMerchantAuthority(); + abstract protected function handleCartRequest(AphrontRequest $request); + + final public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + + if ($this->shouldRequireAccountAuthority()) { + $capabilities = array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } else { + $capabilities = array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + $cart = id(new PhortuneCartQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->needPurchases(true) + ->requireCapabilities($capabilities) + ->executeOne(); + if (!$cart) { + return new Aphront404Response(); + } + + if ($this->shouldRequireMerchantAuthority()) { + PhabricatorPolicyFilter::requireCapability( + $viewer, + $cart->getMerchant(), + PhabricatorPolicyCapability::CAN_EDIT); + } + + $this->cart = $cart; + + $can_edit = PhortuneMerchantQuery::canViewersEditMerchants( + array($viewer->getPHID()), + array($cart->getMerchantPHID())); + if ($can_edit) { + $this->merchantAuthority = $cart->getMerchant(); + } else { + $this->merchantAuthority = null; + } + + return $this->handleCartRequest($request); + } + + final protected function getCart() { + return $this->cart; + } + + final protected function getMerchantAuthority() { + return $this->merchantAuthority; + } + + final protected function hasMerchantAuthority() { + return (bool)$this->merchantAuthority; + } + + final protected function hasAccountAuthority() { + return (bool)PhabricatorPolicyFilter::hasCapability( + $this->getViewer(), + $this->getCart(), + PhabricatorPolicyCapability::CAN_EDIT); + } + protected function buildCartContentTable(PhortuneCart $cart) { $rows = array(); diff --git a/src/applications/phortune/controller/cart/PhortuneCartUpdateController.php b/src/applications/phortune/controller/cart/PhortuneCartUpdateController.php --- a/src/applications/phortune/controller/cart/PhortuneCartUpdateController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartUpdateController.php @@ -3,25 +3,20 @@ final class PhortuneCartUpdateController extends PhortuneCartController { - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - - $authority = $this->loadMerchantAuthority(); + protected function shouldRequireAccountAuthority() { + return false; + } - $cart_query = id(new PhortuneCartQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needPurchases(true); + protected function shouldRequireMerchantAuthority() { + return false; + } - if ($authority) { - $cart_query->withMerchantPHIDs(array($authority->getPHID())); - } + protected function handleCartRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + $id = $request->getURIData('id'); - $cart = $cart_query->executeOne(); - if (!$cart) { - return new Aphront404Response(); - } + $cart = $this->getCart(); + $authority = $this->getMerchantAuthority(); $charges = id(new PhortuneChargeQuery()) ->setViewer($viewer) @@ -60,7 +55,7 @@ } return id(new AphrontRedirectResponse()) - ->setURI($cart->getDetailURI($authority)); + ->setURI($cart->getDetailURI()); } } diff --git a/src/applications/phortune/controller/cart/PhortuneCartViewController.php b/src/applications/phortune/controller/cart/PhortuneCartViewController.php --- a/src/applications/phortune/controller/cart/PhortuneCartViewController.php +++ b/src/applications/phortune/controller/cart/PhortuneCartViewController.php @@ -5,62 +5,33 @@ private $action = null; - public function handleRequest(AphrontRequest $request) { - $viewer = $request->getViewer(); - $id = $request->getURIData('id'); - $this->action = $request->getURIData('action'); - - $authority = $this->loadMerchantAuthority(); - require_celerity_resource('phortune-css'); + protected function shouldRequireAccountAuthority() { + return false; + } - $query = id(new PhortuneCartQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needPurchases(true); + protected function shouldRequireMerchantAuthority() { + return false; + } - if ($authority) { - $query->withMerchantPHIDs(array($authority->getPHID())); - } + protected function handleCartRequest(AphrontRequest $request) { + $viewer = $request->getViewer(); + $cart = $this->getCart(); + $authority = $this->getMerchantAuthority(); + $can_edit = $this->hasAccountAuthority(); - $cart = $query->executeOne(); - if (!$cart) { - return new Aphront404Response(); - } + $this->action = $request->getURIData('action'); $cart_table = $this->buildCartContentTable($cart); - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $cart, - PhabricatorPolicyCapability::CAN_EDIT); - $errors = array(); $error_view = null; $resume_uri = null; switch ($cart->getStatus()) { case PhortuneCart::STATUS_READY: - if ($authority && $cart->getIsInvoice()) { - // We arrived here by following the ad-hoc invoice workflow, and - // are acting with merchant authority. - - $checkout_uri = PhabricatorEnv::getURI($cart->getCheckoutURI()); - - $invoice_message = array( - pht( - 'Manual invoices do not automatically notify recipients yet. '. - 'Send the payer this checkout link:'), - ' ', - phutil_tag( - 'a', - array( - 'href' => $checkout_uri, - ), - $checkout_uri), - ); - + if ($cart->getIsInvoice()) { $error_view = id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_WARNING) - ->setErrors(array($invoice_message)); + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild(pht('This invoice is ready for payment.')); } break; case PhortuneCart::STATUS_PURCHASING: @@ -133,7 +104,7 @@ $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setHeader($cart->getName()) - ->setHeaderIcon('fa-shopping-cart'); + ->setHeaderIcon('fa-shopping-bag'); if ($cart->getStatus() == PhortuneCart::STATUS_PURCHASED) { $done_uri = $cart->getDoneURI(); @@ -160,18 +131,8 @@ ->needCarts(true) ->execute(); - $phids = array(); - foreach ($charges as $charge) { - $phids[] = $charge->getProviderPHID(); - $phids[] = $charge->getCartPHID(); - $phids[] = $charge->getMerchantPHID(); - $phids[] = $charge->getPaymentMethodPHID(); - } - $handles = $this->loadViewerHandles($phids); - $charges_table = id(new PhortuneChargeTableView()) ->setUser($viewer) - ->setHandles($handles) ->setCharges($charges) ->setShowOrder(false); @@ -182,14 +143,13 @@ $account = $cart->getAccount(); - $crumbs = $this->buildApplicationCrumbs(); - if ($authority) { - $this->addMerchantCrumb($crumbs, $authority); - } else { - $this->addAccountCrumb($crumbs, $cart->getAccount()); - } - $crumbs->addTextCrumb(pht('Cart %d', $cart->getID())); - $crumbs->setBorder(true); + $crumbs = $this->buildApplicationCrumbs() + ->addTextCrumb($account->getName(), $account->getURI()) + ->addTextCrumb(pht('Orders'), $account->getOrdersURI()) + ->addTextCrumb(pht('Cart %d', $cart->getID())) + ->setBorder(true); + + require_celerity_resource('phortune-css'); if (!$this->action) { $class = 'phortune-cart-page'; @@ -267,6 +227,7 @@ if ($crumbs) { $page->setCrumbs($crumbs); } + return $page; } @@ -318,20 +279,31 @@ $viewer = $this->getViewer(); $id = $cart->getID(); $curtain = $this->newCurtainView($cart); + $status = $cart->getStatus(); - $can_cancel = ($can_edit && $cart->canCancelOrder()); + $is_ready = ($status === PhortuneCart::STATUS_READY); - if ($authority) { - $prefix = 'merchant/'.$authority->getID().'/'; - } else { - $prefix = ''; - } + $can_cancel = ($can_edit && $cart->canCancelOrder()); + $can_checkout = ($can_edit && $is_ready); + $can_accept = ($status === PhortuneCart::STATUS_REVIEW); + $can_refund = ($authority && $cart->canRefundOrder()); + $can_void = ($authority && $cart->canVoidOrder()); + + $cancel_uri = $this->getApplicationURI("cart/{$id}/cancel/"); + $refund_uri = $this->getApplicationURI("cart/{$id}/refund/"); + $update_uri = $this->getApplicationURI("cart/{$id}/update/"); + $accept_uri = $this->getApplicationURI("cart/{$id}/accept/"); + $print_uri = $this->getApplicationURI("cart/{$id}/print/"); + $checkout_uri = $cart->getCheckoutURI(); + $void_uri = $this->getApplicationURI("cart/{$id}/void/"); - $cancel_uri = $this->getApplicationURI("{$prefix}cart/{$id}/cancel/"); - $refund_uri = $this->getApplicationURI("{$prefix}cart/{$id}/refund/"); - $update_uri = $this->getApplicationURI("{$prefix}cart/{$id}/update/"); - $accept_uri = $this->getApplicationURI("{$prefix}cart/{$id}/accept/"); - $print_uri = $this->getApplicationURI("{$prefix}cart/{$id}/print/"); + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Pay Now')) + ->setIcon('fa-credit-card') + ->setDisabled(!$can_checkout) + ->setWorkflow(!$can_checkout) + ->setHref($checkout_uri)); $curtain->addAction( id(new PhabricatorActionView()) @@ -341,24 +313,6 @@ ->setWorkflow(true) ->setHref($cancel_uri)); - if ($authority) { - if ($cart->getStatus() == PhortuneCart::STATUS_REVIEW) { - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Accept Order')) - ->setIcon('fa-check') - ->setWorkflow(true) - ->setHref($accept_uri)); - } - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Refund Order')) - ->setIcon('fa-reply') - ->setWorkflow(true) - ->setHref($refund_uri)); - } - $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Update Status')) @@ -369,7 +323,7 @@ $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Continue Checkout')) - ->setIcon('fa-shopping-cart') + ->setIcon('fa-shopping-bag') ->setHref($resume_uri)); } @@ -380,6 +334,36 @@ ->setOpenInNewWindow(true) ->setIcon('fa-print')); + if ($authority) { + $curtain->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Accept Order')) + ->setIcon('fa-check') + ->setWorkflow(true) + ->setDisabled(!$can_accept) + ->setHref($accept_uri)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Refund Order')) + ->setIcon('fa-reply') + ->setWorkflow(true) + ->setDisabled(!$can_refund) + ->setHref($refund_uri)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Void Invoice')) + ->setIcon('fa-times') + ->setWorkflow(true) + ->setDisabled(!$can_void) + ->setHref($void_uri)); + } + return $curtain; } diff --git a/src/applications/phortune/controller/cart/PhortuneCartVoidController.php b/src/applications/phortune/controller/cart/PhortuneCartVoidController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/cart/PhortuneCartVoidController.php @@ -0,0 +1,43 @@ +getViewer(); + $cart = $this->getCart(); + + $cancel_uri = $cart->getDetailURI(); + + try { + $title = pht('Unable to Void Invoice'); + $cart->assertCanVoidOrder(); + } catch (Exception $ex) { + return $this->newDialog() + ->setTitle($title) + ->appendChild($ex->getMessage()) + ->addCancelButton($cancel_uri); + } + + if ($request->isFormPost()) { + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + return $this->newDialog() + ->setTitle(pht('Void Invoice?')) + ->appendParagraph( + pht( + 'Really void this invoice? The customer will no longer be asked '. + 'to submit payment for it.')) + ->addCancelButton($cancel_uri) + ->addSubmitButton(pht('Void Invoice')); + } +} diff --git a/src/applications/phortune/controller/subscription/PhortuneSubscriptionEditController.php b/src/applications/phortune/controller/subscription/PhortuneSubscriptionEditController.php deleted file mode 100644 --- a/src/applications/phortune/controller/subscription/PhortuneSubscriptionEditController.php +++ /dev/null @@ -1,185 +0,0 @@ -getViewer(); - $added = $request->getBool('added'); - - $subscription = id(new PhortuneSubscriptionQuery()) - ->setViewer($viewer) - ->withIDs(array($request->getURIData('id'))) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$subscription) { - return new Aphront404Response(); - } - - id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( - $viewer, - $request, - $subscription->getURI()); - $merchant = $subscription->getMerchant(); - $account = $subscription->getAccount(); - - $title = pht('Subscription: %s', $subscription->getSubscriptionName()); - - $header = id(new PHUIHeaderView()) - ->setHeader($subscription->getSubscriptionName()); - - $view_uri = $subscription->getURI(); - - $valid_methods = id(new PhortunePaymentMethodQuery()) - ->setViewer($viewer) - ->withAccountPHIDs(array($account->getPHID())) - ->withStatuses( - array( - PhortunePaymentMethod::STATUS_ACTIVE, - )) - ->withMerchantPHIDs(array($merchant->getPHID())) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->execute(); - $valid_methods = mpull($valid_methods, null, 'getPHID'); - - $current_phid = $subscription->getDefaultPaymentMethodPHID(); - - $e_method = null; - if ($current_phid && empty($valid_methods[$current_phid])) { - $e_method = pht('Needs Update'); - } - - $errors = array(); - if ($request->isFormPost()) { - - $default_method_phid = $request->getStr('defaultPaymentMethodPHID'); - if (!$default_method_phid) { - $default_method_phid = null; - $e_method = null; - } else if (empty($valid_methods[$default_method_phid])) { - $e_method = pht('Invalid'); - if ($default_method_phid == $current_phid) { - $errors[] = pht( - 'This subscription is configured to autopay with a payment method '. - 'that has been deleted. Choose a valid payment method or disable '. - 'autopay.'); - } else { - $errors[] = pht('You must select a valid default payment method.'); - } - } - - // TODO: We should use transactions here, and move the validation logic - // inside the Editor. - - if (!$errors) { - $subscription->setDefaultPaymentMethodPHID($default_method_phid); - $subscription->save(); - - return id(new AphrontRedirectResponse()) - ->setURI($view_uri); - } - } - - // Add the option to disable autopay. - $disable_options = array( - '' => pht('(Disable Autopay)'), - ); - - // Don't require the user to make a valid selection if the current method - // has become invalid. - if ($current_phid && empty($valid_methods[$current_phid])) { - $current_options = array( - $current_phid => pht(''), - ); - } else { - $current_options = array(); - } - - // Add any available options. - $valid_options = mpull($valid_methods, 'getFullDisplayName', 'getPHID'); - - $options = $disable_options + $current_options + $valid_options; - - $crumbs = $this->buildApplicationCrumbs(); - $this->addAccountCrumb($crumbs, $account); - $crumbs->addTextCrumb( - pht('Subscription %d', $subscription->getID()), - $view_uri); - $crumbs->addTextCrumb(pht('Edit')); - $crumbs->setBorder(true); - - - $uri = $this->getApplicationURI($account->getID().'/card/new/'); - $uri = new PhutilURI($uri); - $uri->replaceQueryParam('merchantID', $merchant->getID()); - $uri->replaceQueryParam('subscriptionID', $subscription->getID()); - - $add_method_button = phutil_tag( - 'a', - array( - 'href' => $uri, - 'class' => 'button button-grey', - ), - pht('Add Payment Method...')); - - $radio = id(new AphrontFormRadioButtonControl()) - ->setName('defaultPaymentMethodPHID') - ->setLabel(pht('Autopay With')) - ->setValue($current_phid) - ->setError($e_method); - - foreach ($options as $key => $value) { - $radio->addButton($key, $value, null); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild($radio) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setValue($add_method_button)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Save Changes')) - ->addCancelButton($view_uri)); - - $box = id(new PHUIObjectBoxView()) - ->setUser($viewer) - ->setHeaderText(pht('Subscription')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setFormErrors($errors) - ->appendChild($form); - - if ($added) { - $info_view = id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_SUCCESS) - ->appendChild(pht('Payment method has been successfully added.')); - $box->setInfoView($info_view); - } - - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Edit %s', $subscription->getSubscriptionName())) - ->setHeaderIcon('fa-pencil'); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $box, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - - } - - -} diff --git a/src/applications/phortune/controller/subscription/PhortuneSubscriptionListController.php b/src/applications/phortune/controller/subscription/PhortuneSubscriptionListController.php deleted file mode 100644 --- a/src/applications/phortune/controller/subscription/PhortuneSubscriptionListController.php +++ /dev/null @@ -1,99 +0,0 @@ -getViewer(); - $querykey = $request->getURIData('queryKey'); - $merchant_id = $request->getURIData('merchantID'); - $account_id = $request->getURIData('accountID'); - - $engine = new PhortuneSubscriptionSearchEngine(); - - if ($merchant_id) { - $merchant = id(new PhortuneMerchantQuery()) - ->setViewer($viewer) - ->withIDs(array($merchant_id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$merchant) { - return new Aphront404Response(); - } - $this->merchant = $merchant; - $viewer->grantAuthority($merchant); - $engine->setMerchant($merchant); - } else if ($account_id) { - $account = id(new PhortuneAccountQuery()) - ->setViewer($viewer) - ->withIDs(array($account_id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$account) { - return new Aphront404Response(); - } - $this->account = $account; - $engine->setAccount($account); - } else { - return new Aphront404Response(); - } - - $controller = id(new PhabricatorApplicationSearchController()) - ->setQueryKey($querykey) - ->setSearchEngine($engine) - ->setNavigation($this->buildSideNavView()); - - return $this->delegateToController($controller); - } - - public function buildSideNavView() { - $viewer = $this->getViewer(); - - $nav = new AphrontSideNavFilterView(); - $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); - - id(new PhortuneSubscriptionSearchEngine()) - ->setViewer($viewer) - ->addNavigationItems($nav->getMenu()); - - $nav->selectFilter(null); - - return $nav; - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - - $merchant = $this->merchant; - if ($merchant) { - $id = $merchant->getID(); - $this->addMerchantCrumb($crumbs, $merchant); - $crumbs->addTextCrumb( - pht('Subscriptions'), - $this->getApplicationURI("merchant/subscriptions/{$id}/")); - } - - $account = $this->account; - if ($account) { - $id = $account->getID(); - $this->addAccountCrumb($crumbs, $account); - $crumbs->addTextCrumb( - pht('Subscriptions'), - $this->getApplicationURI("{$id}/subscription/")); - } - - return $crumbs; - } - -} diff --git a/src/applications/phortune/query/PhortuneCartSearchEngine.php b/src/applications/phortune/query/PhortuneCartSearchEngine.php --- a/src/applications/phortune/query/PhortuneCartSearchEngine.php +++ b/src/applications/phortune/query/PhortuneCartSearchEngine.php @@ -105,7 +105,7 @@ $merchant = $this->getMerchant(); $account = $this->getAccount(); if ($merchant) { - return '/phortune/merchant/orders/'.$merchant->getID().'/'.$path; + return $merchant->getOrderListURI($path); } else if ($account) { return $account->getOrderListURI($path); } else { diff --git a/src/applications/phortune/query/PhortuneChargeSearchEngine.php b/src/applications/phortune/query/PhortuneChargeSearchEngine.php --- a/src/applications/phortune/query/PhortuneChargeSearchEngine.php +++ b/src/applications/phortune/query/PhortuneChargeSearchEngine.php @@ -62,7 +62,7 @@ protected function getURI($path) { $account = $this->getAccount(); if ($account) { - return '/phortune/'.$account->getID().'/charge/'; + return $account->getChargeListURI($path); } else { return '/phortune/charge/'.$path; } @@ -89,20 +89,6 @@ return parent::buildSavedQueryFromBuiltin($query_key); } - protected function getRequiredHandlePHIDsForResultList( - array $charges, - PhabricatorSavedQuery $query) { - - $phids = array(); - foreach ($charges as $charge) { - $phids[] = $charge->getProviderPHID(); - $phids[] = $charge->getCartPHID(); - $phids[] = $charge->getMerchantPHID(); - $phids[] = $charge->getPaymentMethodPHID(); - } - - return $phids; - } protected function renderResultList( array $charges, @@ -114,8 +100,7 @@ $table = id(new PhortuneChargeTableView()) ->setUser($viewer) - ->setCharges($charges) - ->setHandles($handles); + ->setCharges($charges); $result = new PhabricatorApplicationSearchResultView(); $result->setTable($table); 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 @@ -96,9 +96,9 @@ $merchant = $this->getMerchant(); $account = $this->getAccount(); if ($merchant) { - return '/phortune/merchant/'.$merchant->getID().'/subscription/'.$path; + return $merchant->getSubscriptionListURI($path); } else if ($account) { - return '/phortune/'.$account->getID().'/subscription/'; + return $account->getSubscriptionListURI($path); } else { return '/phortune/subscription/'.$path; } diff --git a/src/applications/phortune/storage/PhortuneCart.php b/src/applications/phortune/storage/PhortuneCart.php --- a/src/applications/phortune/storage/PhortuneCart.php +++ b/src/applications/phortune/storage/PhortuneCart.php @@ -471,13 +471,10 @@ return $this->getImplementation()->getDescription($this); } - public function getDetailURI(PhortuneMerchant $authority = null) { - if ($authority) { - $prefix = 'merchant/'.$authority->getID().'/'; - } else { - $prefix = ''; - } - return '/phortune/'.$prefix.'cart/'.$this->getID().'/'; + public function getDetailURI() { + return urisprintf( + '/phortune/cart/%d/', + $this->getID()); } public function getCheckoutURI() { @@ -502,6 +499,15 @@ } } + public function canVoidOrder() { + try { + $this->assertCanVoidOrder(); + return true; + } catch (Exception $ex) { + return false; + } + } + public function assertCanCancelOrder() { switch ($this->getStatus()) { case self::STATUS_BUILDING: @@ -534,6 +540,27 @@ return $this->getImplementation()->assertCanRefundOrder($this); } + public function assertCanVoidOrder() { + if (!$this->getIsInvoice()) { + throw new Exception( + pht( + 'This order can not be voided because it is not an invoice.')); + } + + switch ($this->getStatus()) { + case self::STATUS_READY: + break; + default: + throw new Exception( + pht( + 'This order can not be voided because it is not ready for '. + 'payment.')); + } + + return null; + } + + protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, diff --git a/src/applications/phortune/view/PhortuneChargeTableView.php b/src/applications/phortune/view/PhortuneChargeTableView.php --- a/src/applications/phortune/view/PhortuneChargeTableView.php +++ b/src/applications/phortune/view/PhortuneChargeTableView.php @@ -3,7 +3,6 @@ final class PhortuneChargeTableView extends AphrontView { private $charges; - private $handles; private $showOrder; public function setShowOrder($show_order) { @@ -15,15 +14,6 @@ return $this->showOrder; } - public function setHandles(array $handles) { - $this->handles = $handles; - return $this; - } - - public function getHandles() { - return $this->handles; - } - public function setCharges(array $charges) { $this->charges = $charges; return $this; @@ -35,8 +25,17 @@ public function render() { $charges = $this->getCharges(); - $handles = $this->getHandles(); - $viewer = $this->getUser(); + $viewer = $this->getViewer(); + + $phids = array(); + foreach ($charges as $charge) { + $phids[] = $charge->getCartPHID(); + $phids[] = $charge->getProviderPHID(); + $phids[] = $charge->getPaymentMethodPHID(); + $phids[] = $charge->getMerchantPHID(); + } + + $handles = $viewer->loadHandles($phids); $rows = array(); foreach ($charges as $charge) {