diff --git a/src/applications/phortune/cart/PhortuneSubscriptionCart.php b/src/applications/phortune/cart/PhortuneSubscriptionCart.php index f913974a6c..6c17e00331 100644 --- a/src/applications/phortune/cart/PhortuneSubscriptionCart.php +++ b/src/applications/phortune/cart/PhortuneSubscriptionCart.php @@ -1,89 +1,89 @@ subscriptionPHID = $subscription_phid; return $this; } public function getSubscriptionPHID() { return $this->subscriptionPHID; } public function setSubscription(PhortuneSubscription $subscription) { $this->subscription = $subscription; return $this; } public function getSubscription() { return $this->subscription; } public function getName(PhortuneCart $cart) { - return pht('Subscription'); + return $this->getSubscription()->getCartName($cart); } public function willCreateCart( PhabricatorUser $viewer, PhortuneCart $cart) { $subscription = $this->getSubscription(); if (!$subscription) { throw new Exception( pht('Call setSubscription() before building a cart!')); } $cart->setMetadataValue('subscriptionPHID', $subscription->getPHID()); } public function loadImplementationsForCarts( PhabricatorUser $viewer, array $carts) { $phids = array(); foreach ($carts as $cart) { $phids[] = $cart->getMetadataValue('subscriptionPHID'); } $subscriptions = id(new PhortuneSubscriptionQuery()) ->setViewer($viewer) ->withPHIDs($phids) ->execute(); $subscriptions = mpull($subscriptions, null, 'getPHID'); $objects = array(); foreach ($carts as $key => $cart) { $subscription_phid = $cart->getMetadataValue('subscriptionPHID'); $subscription = idx($subscriptions, $subscription_phid); if (!$subscription) { continue; } $object = id(new PhortuneSubscriptionCart()) ->setSubscriptionPHID($subscription_phid) ->setSubscription($subscription); $objects[$key] = $object; } return $objects; } public function getCancelURI(PhortuneCart $cart) { return $this->getSubscription()->getURI(); } public function getDoneURI(PhortuneCart $cart) { return $this->getSubscription()->getURI(); } public function getDoneActionName(PhortuneCart $cart) { return pht('Return to Subscription'); } } diff --git a/src/applications/phortune/controller/PhortuneAccountViewController.php b/src/applications/phortune/controller/PhortuneAccountViewController.php index c7f7877844..543f30ed99 100644 --- a/src/applications/phortune/controller/PhortuneAccountViewController.php +++ b/src/applications/phortune/controller/PhortuneAccountViewController.php @@ -1,311 +1,391 @@ accountID = $data['accountID']; - } - - public function processRequest() { - $request = $this->getRequest(); - $user = $request->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); // TODO: Currently, you must be able to edit an account to view the detail // page, because the account must be broadly visible so merchants can // process orders but merchants should not be able to see all the details // of an account. Ideally this page should be visible to merchants, too, // just with less information. $can_edit = true; $account = id(new PhortuneAccountQuery()) - ->setViewer($user) - ->withIDs(array($this->accountID)) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('accountID'))) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$account) { return new Aphront404Response(); } $title = $account->getName(); + $invoices = id(new PhortuneCartQuery()) + ->setViewer($viewer) + ->withAccountPHIDs(array($account->getPHID())) + ->needPurchases(true) + ->withInvoices(true) + ->execute(); + $crumbs = $this->buildApplicationCrumbs(); $this->addAccountCrumb($crumbs, $account, $link = false); $header = id(new PHUIHeaderView()) ->setHeader($title); $edit_uri = $this->getApplicationURI('account/edit/'.$account->getID().'/'); $actions = id(new PhabricatorActionListView()) - ->setUser($user) + ->setUser($viewer) ->setObjectURI($request->getRequestURI()) ->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Account')) ->setIcon('fa-pencil') ->setHref($edit_uri) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $properties = id(new PHUIPropertyListView()) ->setObject($account) - ->setUser($user); + ->setUser($viewer); $this->loadHandles($account->getMemberPHIDs()); $properties->addProperty( pht('Members'), $this->renderHandlesForPHIDs($account->getMemberPHIDs())); + $status_items = $this->getStatusItemsForAccount($account, $invoices); + $status_view = new PHUIStatusListView(); + foreach ($status_items as $item) { + $status_view->addItem( + id(new PHUIStatusItemView()) + ->setIcon( + idx($item, 'icon'), + idx($item, 'color'), + idx($item, 'label')) + ->setTarget(idx($item, 'target')) + ->setNote(idx($item, 'note'))); + } + $properties->addProperty( + pht('Status'), + $status_view); + $properties->setActionList($actions); - $payment_methods = $this->buildPaymentMethodsSection($account); + $invoices = $this->buildInvoicesSection($account, $invoices); $purchase_history = $this->buildPurchaseHistorySection($account); $charge_history = $this->buildChargeHistorySection($account); $subscriptions = $this->buildSubscriptionsSection($account); + $payment_methods = $this->buildPaymentMethodsSection($account); $timeline = $this->buildTransactionTimeline( $account, new PhortuneAccountTransactionQuery()); $timeline->setShouldTerminate(true); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); return $this->buildApplicationPage( array( $crumbs, $object_box, - $payment_methods, + $invoices, $purchase_history, $charge_history, $subscriptions, + $payment_methods, $timeline, ), array( 'title' => $title, )); } private function buildPaymentMethodsSection(PhortuneAccount $account) { $request = $this->getRequest(); $viewer = $request->getUser(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $account, PhabricatorPolicyCapability::CAN_EDIT); $id = $account->getID(); $header = id(new PHUIHeaderView()) ->setHeader(pht('Payment Methods')); $list = id(new PHUIObjectItemListView()) ->setUser($viewer) ->setNoDataString( pht('No payment methods associated with this account.')); $methods = id(new PhortunePaymentMethodQuery()) ->setViewer($viewer) ->withAccountPHIDs(array($account->getPHID())) ->execute(); if ($methods) { $this->loadHandles(mpull($methods, 'getAuthorPHID')); } foreach ($methods as $method) { $id = $method->getID(); $item = new PHUIObjectItemView(); $item->setHeader($method->getFullDisplayName()); switch ($method->getStatus()) { case PhortunePaymentMethod::STATUS_ACTIVE: $item->setBarColor('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->setDisabled(true); break; } $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); } return id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($list); } + private function buildInvoicesSection( + PhortuneAccount $account, + array $carts) { + + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $phids = array(); + foreach ($carts as $cart) { + $phids[] = $cart->getPHID(); + $phids[] = $cart->getMerchantPHID(); + foreach ($cart->getPurchases() as $purchase) { + $phids[] = $purchase->getPHID(); + } + } + $handles = $this->loadViewerHandles($phids); + + $table = id(new PhortuneOrderTableView()) + ->setNoDataString(pht('You have no unpaid invoices.')) + ->setIsInvoices(true) + ->setUser($viewer) + ->setCarts($carts) + ->setHandles($handles); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Invoices Due')); + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($table); + } + private function buildPurchaseHistorySection(PhortuneAccount $account) { $request = $this->getRequest(); $viewer = $request->getUser(); $carts = id(new PhortuneCartQuery()) ->setViewer($viewer) ->withAccountPHIDs(array($account->getPHID())) ->needPurchases(true) ->withStatuses( array( PhortuneCart::STATUS_PURCHASING, PhortuneCart::STATUS_CHARGED, PhortuneCart::STATUS_HOLD, PhortuneCart::STATUS_REVIEW, PhortuneCart::STATUS_PURCHASED, )) ->setLimit(10) ->execute(); $phids = array(); foreach ($carts as $cart) { $phids[] = $cart->getPHID(); foreach ($cart->getPurchases() as $purchase) { $phids[] = $purchase->getPHID(); } } $handles = $this->loadViewerHandles($phids); $orders_uri = $this->getApplicationURI($account->getID().'/order/'); $table = id(new PhortuneOrderTableView()) ->setUser($viewer) ->setCarts($carts) ->setHandles($handles); $header = id(new PHUIHeaderView()) ->setHeader(pht('Recent Orders')) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-list')) ->setHref($orders_uri) ->setText(pht('View All Orders'))); return id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($table); } private function buildChargeHistorySection(PhortuneAccount $account) { $request = $this->getRequest(); $viewer = $request->getUser(); $charges = id(new PhortuneChargeQuery()) ->setViewer($viewer) ->withAccountPHIDs(array($account->getPHID())) ->needCarts(true) ->setLimit(10) ->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 = $this->getApplicationURI($account->getID().'/charge/'); $table = id(new PhortuneChargeTableView()) ->setUser($viewer) ->setCharges($charges) ->setHandles($handles); $header = id(new PHUIHeaderView()) ->setHeader(pht('Recent Charges')) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-list')) ->setHref($charges_uri) ->setText(pht('View All Charges'))); return id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($table); } private function buildSubscriptionsSection(PhortuneAccount $account) { $request = $this->getRequest(); $viewer = $request->getUser(); $subscriptions = id(new PhortuneSubscriptionQuery()) ->setViewer($viewer) ->withAccountPHIDs(array($account->getPHID())) ->setLimit(10) ->execute(); $subscriptions_uri = $this->getApplicationURI( $account->getID().'/subscription/'); $handles = $this->loadViewerHandles(mpull($subscriptions, 'getPHID')); $table = id(new PhortuneSubscriptionTableView()) ->setUser($viewer) ->setHandles($handles) ->setSubscriptions($subscriptions); $header = id(new PHUIHeaderView()) ->setHeader(pht('Recent Subscriptions')) ->addActionLink( id(new PHUIButtonView()) ->setTag('a') ->setIcon( id(new PHUIIconView()) ->setIconFont('fa-list')) ->setHref($subscriptions_uri) ->setText(pht('View All Subscriptions'))); return id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($table); } protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); $crumbs->addAction( id(new PHUIListItemView()) ->setIcon('fa-exchange') ->setHref($this->getApplicationURI('account/')) ->setName(pht('Switch Accounts'))); return $crumbs; } + private function getStatusItemsForAccount( + PhortuneAccount $account, + array $invoices) { + + assert_instances_of($invoices, 'PhortuneCart'); + + $items = array(); + + if ($invoices) { + $items[] = array( + 'icon' => PHUIStatusItemView::ICON_WARNING, + 'color' => 'yellow', + 'target' => pht('Invoices'), + 'note' => pht('You have %d unpaid invoice(s).', count($invoices)), + ); + } else { + $items[] = array( + 'icon' => PHUIStatusItemView::ICON_ACCEPT, + 'color' => 'green', + 'target' => pht('Invoices'), + 'note' => pht('This account has no unpaid invoices.'), + ); + } + + // TODO: If a payment method has expired or is expiring soon, we should + // add a status check for it. + + return $items; + } + } diff --git a/src/applications/phortune/query/PhortuneCartQuery.php b/src/applications/phortune/query/PhortuneCartQuery.php index 6c7aaf77a3..df2003949c 100644 --- a/src/applications/phortune/query/PhortuneCartQuery.php +++ b/src/applications/phortune/query/PhortuneCartQuery.php @@ -1,188 +1,215 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withAccountPHIDs(array $account_phids) { $this->accountPHIDs = $account_phids; return $this; } public function withMerchantPHIDs(array $merchant_phids) { $this->merchantPHIDs = $merchant_phids; return $this; } public function withSubscriptionPHIDs(array $subscription_phids) { $this->subscriptionPHIDs = $subscription_phids; return $this; } public function withStatuses(array $statuses) { $this->statuses = $statuses; return $this; } + + /** + * Include or exclude carts which represent invoices with payments due. + * + * @param bool `true` to select invoices; `false` to exclude invoices. + * @return this + */ + public function withInvoices($invoices) { + $this->invoices = $invoices; + return $this; + } + public function needPurchases($need_purchases) { $this->needPurchases = $need_purchases; return $this; } protected function loadPage() { $table = new PhortuneCart(); $conn = $table->establishConnection('r'); $rows = queryfx_all( $conn, 'SELECT cart.* FROM %T cart %Q %Q %Q', $table->getTableName(), $this->buildWhereClause($conn), $this->buildOrderClause($conn), $this->buildLimitClause($conn)); return $table->loadAllFromArray($rows); } protected function willFilterPage(array $carts) { $accounts = id(new PhortuneAccountQuery()) ->setViewer($this->getViewer()) ->withPHIDs(mpull($carts, 'getAccountPHID')) ->execute(); $accounts = mpull($accounts, null, 'getPHID'); foreach ($carts as $key => $cart) { $account = idx($accounts, $cart->getAccountPHID()); if (!$account) { unset($carts[$key]); continue; } $cart->attachAccount($account); } $merchants = id(new PhortuneMerchantQuery()) ->setViewer($this->getViewer()) ->withPHIDs(mpull($carts, 'getMerchantPHID')) ->execute(); $merchants = mpull($merchants, null, 'getPHID'); foreach ($carts as $key => $cart) { $merchant = idx($merchants, $cart->getMerchantPHID()); if (!$merchant) { unset($carts[$key]); continue; } $cart->attachMerchant($merchant); } $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; } protected function didFilterPage(array $carts) { if ($this->needPurchases) { $purchases = id(new PhortunePurchaseQuery()) ->setViewer($this->getViewer()) ->setParentQuery($this) ->withCartPHIDs(mpull($carts, 'getPHID')) ->execute(); $purchases = mgroup($purchases, 'getCartPHID'); foreach ($carts as $cart) { $cart->attachPurchases(idx($purchases, $cart->getPHID(), array())); } } return $carts; } private function buildWhereClause(AphrontDatabaseConnection $conn) { $where = array(); $where[] = $this->buildPagingClause($conn); if ($this->ids !== null) { $where[] = qsprintf( $conn, 'cart.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, 'cart.phid IN (%Ls)', $this->phids); } if ($this->accountPHIDs !== null) { $where[] = qsprintf( $conn, 'cart.accountPHID IN (%Ls)', $this->accountPHIDs); } if ($this->merchantPHIDs !== null) { $where[] = qsprintf( $conn, 'cart.merchantPHID IN (%Ls)', $this->merchantPHIDs); } if ($this->subscriptionPHIDs !== null) { $where[] = qsprintf( $conn, 'cart.subscriptionPHID IN (%Ls)', $this->subscriptionPHIDs); } if ($this->statuses !== null) { $where[] = qsprintf( $conn, 'cart.status IN (%Ls)', $this->statuses); } + if ($this->invoices !== null) { + if ($this->invoices) { + $where[] = qsprintf( + $conn, + 'cart.status = %s AND cart.subscriptionPHID IS NOT NULL', + PhortuneCart::STATUS_READY); + } else { + $where[] = qsprintf( + $conn, + 'cart.status != %s OR cart.subscriptionPHID IS NULL', + PhortuneCart::STATUS_READY); + } + } + return $this->formatWhereClause($where); } public function getQueryApplicationClass() { return 'PhabricatorPhortuneApplication'; } } diff --git a/src/applications/phortune/storage/PhortuneSubscription.php b/src/applications/phortune/storage/PhortuneSubscription.php index 7b1666260a..51ac283668 100644 --- a/src/applications/phortune/storage/PhortuneSubscription.php +++ b/src/applications/phortune/storage/PhortuneSubscription.php @@ -1,229 +1,233 @@ true, self::CONFIG_SERIALIZATION => array( 'metadata' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'subscriptionClassKey' => 'bytes12', 'subscriptionClass' => 'text128', 'subscriptionRefKey' => 'bytes12', 'subscriptionRef' => 'text128', 'status' => 'text32', ), self::CONFIG_KEY_SCHEMA => array( 'key_subscription' => array( 'columns' => array('subscriptionClassKey', 'subscriptionRefKey'), 'unique' => true, ), 'key_account' => array( 'columns' => array('accountPHID'), ), 'key_merchant' => array( 'columns' => array('merchantPHID'), ), ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhortuneSubscriptionPHIDType::TYPECONST); } public static function initializeNewSubscription( PhortuneAccount $account, PhortuneMerchant $merchant, PhabricatorUser $author, PhortuneSubscriptionImplementation $implementation, PhabricatorTriggerClock $clock) { $trigger = id(new PhabricatorWorkerTrigger()) ->setClock($clock); return id(new PhortuneSubscription()) ->setStatus(self::STATUS_ACTIVE) ->setAccountPHID($account->getPHID()) ->attachAccount($account) ->setMerchantPHID($merchant->getPHID()) ->attachMerchant($merchant) ->setAuthorPHID($author->getPHID()) ->setSubscriptionClass(get_class($implementation)) ->setSubscriptionRef($implementation->getRef()) ->attachImplementation($implementation) ->attachTrigger($trigger); } public function attachImplementation( PhortuneSubscriptionImplementation $impl) { $this->implementation = $impl; return $this; } public function getImplementation() { return $this->assertAttached($this->implementation); } public function attachAccount(PhortuneAccount $account) { $this->account = $account; return $this; } public function getAccount() { return $this->assertAttached($this->account); } public function attachMerchant(PhortuneMerchant $merchant) { $this->merchant = $merchant; return $this; } public function getMerchant() { return $this->assertAttached($this->merchant); } public function attachTrigger(PhabricatorWorkerTrigger $trigger) { $this->trigger = $trigger; return $this; } public function getTrigger() { return $this->assertAttached($this->trigger); } public function save() { $this->subscriptionClassKey = PhabricatorHash::digestForIndex( $this->subscriptionClass); $this->subscriptionRefKey = PhabricatorHash::digestForIndex( $this->subscriptionRef); $trigger = $this->getTrigger(); $is_new = (!$this->getID()); $this->openTransaction(); // If we're saving this subscription for the first time, we're also // going to set up the trigger for it. if ($is_new) { $trigger_phid = PhabricatorPHID::generateNewPHID( PhabricatorWorkerTriggerPHIDType::TYPECONST); $this->setTriggerPHID($trigger_phid); } $result = parent::save(); if ($is_new) { $trigger_action = new PhabricatorScheduleTaskTriggerAction( array( 'class' => 'PhortuneSubscriptionWorker', 'data' => array( 'subscriptionPHID' => $this->getPHID(), ), 'options' => array( 'objectPHID' => $this->getPHID(), 'priority' => PhabricatorWorker::PRIORITY_BULK, ), )); $trigger->setPHID($trigger_phid); $trigger->setAction($trigger_action); $trigger->save(); } $this->saveTransaction(); return $result; } public function getSubscriptionName() { return $this->getImplementation()->getName($this); } + public function getCartName(PhortuneCart $cart) { + return $this->getImplementation()->getCartName($this, $cart); + } + public function getURI() { $account_id = $this->getAccount()->getID(); $id = $this->getID(); return "/phortune/{$account_id}/subscription/view/{$id}/"; } public function getMerchantURI() { $merchant_id = $this->getMerchant()->getID(); $id = $this->getID(); return "/phortune/merchant/{$merchant_id}/subscription/view/{$id}/"; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { // NOTE: Both view and edit use the account's edit policy. We punch a hole // through this for merchants, below. return $this ->getAccount() ->getPolicy(PhabricatorPolicyCapability::CAN_EDIT); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { if ($this->getAccount()->hasAutomaticCapability($capability, $viewer)) { return true; } // If the viewer controls the merchant this subscription bills to, they can // view the subscription. if ($capability == PhabricatorPolicyCapability::CAN_VIEW) { $can_admin = PhabricatorPolicyFilter::hasCapability( $viewer, $this->getMerchant(), PhabricatorPolicyCapability::CAN_EDIT); if ($can_admin) { return true; } } return false; } public function describeAutomaticCapability($capability) { return array( pht('Subscriptions inherit the policies of the associated account.'), pht( 'The merchant you are subscribed with can review and manage the '. 'subscription.'), ); } } diff --git a/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php b/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php index 8376669a2d..8e7559c2e9 100644 --- a/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php +++ b/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php @@ -1,18 +1,24 @@ handles = $handles; return $this; } public function getHandles() { return $this->handles; } public function setCarts(array $carts) { $this->carts = $carts; return $this; } public function getCarts() { return $this->carts; } + public function setIsInvoices($is_invoices) { + $this->isInvoices = $is_invoices; + return $this; + } + + public function getIsInvoices() { + return $this->isInvoices; + } + + public function setNoDataString($no_data_string) { + $this->noDataString = $no_data_string; + return $this; + } + + public function getNoDataString() { + return $this->noDataString; + } + public function render() { $carts = $this->getCarts(); $handles = $this->getHandles(); $viewer = $this->getUser(); + $is_invoices = $this->getIsInvoices(); + $rows = array(); $rowc = array(); foreach ($carts as $cart) { $cart_link = $handles[$cart->getPHID()]->renderLink(); $purchases = $cart->getPurchases(); if (count($purchases) == 1) { $purchase = head($purchases); $purchase_name = $handles[$purchase->getPHID()]->renderLink(); $purchases = array(); } else { $purchase_name = ''; } + if ($is_invoices) { + $merchant_link = $handles[$cart->getMerchantPHID()]->renderLink(); + } else { + $merchant_link = null; + } + $rowc[] = ''; $rows[] = array( $cart->getID(), + $merchant_link, phutil_tag( 'strong', array(), $cart_link), $purchase_name, phutil_tag( 'strong', array(), $cart->getTotalPriceAsCurrency()->formatForDisplay()), PhortuneCart::getNameForStatus($cart->getStatus()), phabricator_datetime($cart->getDateModified(), $viewer), + phabricator_datetime($cart->getDateCreated(), $viewer), + phutil_tag( + 'a', + array( + 'href' => $cart->getCheckoutURI(), + 'class' => 'small green button', + ), + pht('Pay Now')), ); foreach ($purchases as $purchase) { $id = $purchase->getID(); $price = $purchase->getTotalPriceAsCurrency()->formatForDisplay(); $rowc[] = ''; $rows[] = array( + '', '', $handles[$purchase->getPHID()]->renderLink(), $price, '', '', + '', + '', ); } } $table = id(new AphrontTableView($rows)) + ->setNoDataString($this->getNoDataString()) ->setRowClasses($rowc) ->setHeaders( array( pht('ID'), - pht('Order'), + pht('Merchant'), + $is_invoices ? pht('Invoice') : pht('Order'), pht('Purchase'), pht('Amount'), pht('Status'), pht('Updated'), + pht('Invoice Date'), + null, )) ->setColumnClasses( array( + '', '', '', 'wide', 'right', '', 'right', + 'right', + '', + )) + ->setColumnVisibility( + array( + true, + $is_invoices, + true, + true, + true, + !$is_invoices, + !$is_invoices, + $is_invoices, + $is_invoices, )); return $table; } }