diff --git a/resources/sql/autopatches/20170328.account.01.mailkey.sql b/resources/sql/autopatches/20170328.account.01.mailkey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20170328.account.01.mailkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_phortune.phortune_account + ADD mailKey binary(20) NOT NULL; diff --git a/resources/sql/autopatches/20170328.account.02.mailkey.php b/resources/sql/autopatches/20170328.account.02.mailkey.php new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20170328.account.02.mailkey.php @@ -0,0 +1,18 @@ +establishConnection('w'); +$iterator = new LiskMigrationIterator($table); +foreach ($iterator as $account) { + $id = $account->getID(); + + echo pht('Adding mail key for Phortune Account %d...', $id); + echo "\n"; + + queryfx( + $conn_w, + 'UPDATE %T SET mailKey = %s WHERE id = %d', + $table->getTableName(), + Filesystem::readRandomCharacters(20), + $id); +} diff --git a/resources/sql/autopatches/20170328.merchant.01.mailkey.sql b/resources/sql/autopatches/20170328.merchant.01.mailkey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20170328.merchant.01.mailkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_phortune.phortune_merchant + ADD mailKey binary(20) NOT NULL; diff --git a/resources/sql/autopatches/20170328.merchant.02.mailkey.php b/resources/sql/autopatches/20170328.merchant.02.mailkey.php new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20170328.merchant.02.mailkey.php @@ -0,0 +1,18 @@ +establishConnection('w'); +$iterator = new LiskMigrationIterator($table); +foreach ($iterator as $merchant) { + $id = $merchant->getID(); + + echo pht('Adding mail key for Phortune Merchant %d...', $id); + echo "\n"; + + queryfx( + $conn_w, + 'UPDATE %T SET mailKey = %s WHERE id = %d', + $table->getTableName(), + Filesystem::readRandomCharacters(20), + $id); +} 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 @@ -4310,15 +4310,23 @@ 'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php', 'PholioUploadedImageView' => 'applications/pholio/view/PholioUploadedImageView.php', 'PhortuneAccount' => 'applications/phortune/storage/PhortuneAccount.php', - 'PhortuneAccountEditController' => 'applications/phortune/controller/PhortuneAccountEditController.php', + 'PhortuneAccountAddManagerController' => 'applications/phortune/controller/account/PhortuneAccountAddManagerController.php', + 'PhortuneAccountBillingController' => 'applications/phortune/controller/account/PhortuneAccountBillingController.php', + 'PhortuneAccountEditController' => 'applications/phortune/controller/account/PhortuneAccountEditController.php', + 'PhortuneAccountEditEngine' => 'applications/phortune/editor/PhortuneAccountEditEngine.php', 'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php', 'PhortuneAccountHasMemberEdgeType' => 'applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php', - 'PhortuneAccountListController' => 'applications/phortune/controller/PhortuneAccountListController.php', + 'PhortuneAccountListController' => 'applications/phortune/controller/account/PhortuneAccountListController.php', + 'PhortuneAccountManagerController' => 'applications/phortune/controller/account/PhortuneAccountManagerController.php', + 'PhortuneAccountNameTransaction' => 'applications/phortune/xaction/PhortuneAccountNameTransaction.php', 'PhortuneAccountPHIDType' => 'applications/phortune/phid/PhortuneAccountPHIDType.php', + 'PhortuneAccountProfileController' => 'applications/phortune/controller/account/PhortuneAccountProfileController.php', 'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php', + 'PhortuneAccountSubscriptionController' => 'applications/phortune/controller/account/PhortuneAccountSubscriptionController.php', 'PhortuneAccountTransaction' => 'applications/phortune/storage/PhortuneAccountTransaction.php', 'PhortuneAccountTransactionQuery' => 'applications/phortune/query/PhortuneAccountTransactionQuery.php', - 'PhortuneAccountViewController' => 'applications/phortune/controller/PhortuneAccountViewController.php', + 'PhortuneAccountTransactionType' => 'applications/phortune/xaction/PhortuneAccountTransactionType.php', + 'PhortuneAccountViewController' => 'applications/phortune/controller/account/PhortuneAccountViewController.php', 'PhortuneAdHocCart' => 'applications/phortune/cart/PhortuneAdHocCart.php', 'PhortuneAdHocProduct' => 'applications/phortune/product/PhortuneAdHocProduct.php', 'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php', @@ -4356,21 +4364,31 @@ 'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php', 'PhortuneMemberHasMerchantEdgeType' => 'applications/phortune/edge/PhortuneMemberHasMerchantEdgeType.php', 'PhortuneMerchant' => 'applications/phortune/storage/PhortuneMerchant.php', + 'PhortuneMerchantAddManagerController' => 'applications/phortune/controller/merchant/PhortuneMerchantAddManagerController.php', 'PhortuneMerchantCapability' => 'applications/phortune/capability/PhortuneMerchantCapability.php', - 'PhortuneMerchantController' => 'applications/phortune/controller/PhortuneMerchantController.php', - 'PhortuneMerchantEditController' => 'applications/phortune/controller/PhortuneMerchantEditController.php', + 'PhortuneMerchantContactInfoTransaction' => 'applications/phortune/xaction/PhortuneMerchantContactInfoTransaction.php', + 'PhortuneMerchantController' => 'applications/phortune/controller/merchant/PhortuneMerchantController.php', + 'PhortuneMerchantDescriptionTransaction' => 'applications/phortune/xaction/PhortuneMerchantDescriptionTransaction.php', + 'PhortuneMerchantEditController' => 'applications/phortune/controller/merchant/PhortuneMerchantEditController.php', 'PhortuneMerchantEditEngine' => 'applications/phortune/editor/PhortuneMerchantEditEngine.php', 'PhortuneMerchantEditor' => 'applications/phortune/editor/PhortuneMerchantEditor.php', 'PhortuneMerchantHasMemberEdgeType' => 'applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php', - 'PhortuneMerchantInvoiceCreateController' => 'applications/phortune/controller/PhortuneMerchantInvoiceCreateController.php', - 'PhortuneMerchantListController' => 'applications/phortune/controller/PhortuneMerchantListController.php', + 'PhortuneMerchantInvoiceCreateController' => 'applications/phortune/controller/merchant/PhortuneMerchantInvoiceCreateController.php', + 'PhortuneMerchantInvoiceEmailTransaction' => 'applications/phortune/xaction/PhortuneMerchantInvoiceEmailTransaction.php', + 'PhortuneMerchantInvoiceFooterTransaction' => 'applications/phortune/xaction/PhortuneMerchantInvoiceFooterTransaction.php', + 'PhortuneMerchantListController' => 'applications/phortune/controller/merchant/PhortuneMerchantListController.php', + 'PhortuneMerchantManagerController' => 'applications/phortune/controller/merchant/PhortuneMerchantManagerController.php', + 'PhortuneMerchantNameTransaction' => 'applications/phortune/xaction/PhortuneMerchantNameTransaction.php', 'PhortuneMerchantPHIDType' => 'applications/phortune/phid/PhortuneMerchantPHIDType.php', - 'PhortuneMerchantPictureController' => 'applications/phortune/controller/PhortuneMerchantPictureController.php', + 'PhortuneMerchantPictureController' => 'applications/phortune/controller/merchant/PhortuneMerchantPictureController.php', + 'PhortuneMerchantPictureTransaction' => 'applications/phortune/xaction/PhortuneMerchantPictureTransaction.php', + 'PhortuneMerchantProfileController' => 'applications/phortune/controller/merchant/PhortuneMerchantProfileController.php', 'PhortuneMerchantQuery' => 'applications/phortune/query/PhortuneMerchantQuery.php', 'PhortuneMerchantSearchEngine' => 'applications/phortune/query/PhortuneMerchantSearchEngine.php', 'PhortuneMerchantTransaction' => 'applications/phortune/storage/PhortuneMerchantTransaction.php', 'PhortuneMerchantTransactionQuery' => 'applications/phortune/query/PhortuneMerchantTransactionQuery.php', - 'PhortuneMerchantViewController' => 'applications/phortune/controller/PhortuneMerchantViewController.php', + 'PhortuneMerchantTransactionType' => 'applications/phortune/xaction/PhortuneMerchantTransactionType.php', + 'PhortuneMerchantViewController' => 'applications/phortune/controller/merchant/PhortuneMerchantViewController.php', 'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php', 'PhortuneOrderTableView' => 'applications/phortune/view/PhortuneOrderTableView.php', 'PhortunePayPalPaymentProvider' => 'applications/phortune/provider/PhortunePayPalPaymentProvider.php', @@ -9739,15 +9757,23 @@ 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), + 'PhortuneAccountAddManagerController' => 'PhortuneController', + 'PhortuneAccountBillingController' => 'PhortuneAccountProfileController', 'PhortuneAccountEditController' => 'PhortuneController', + 'PhortuneAccountEditEngine' => 'PhabricatorEditEngine', 'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneAccountHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhortuneAccountListController' => 'PhortuneController', + 'PhortuneAccountManagerController' => 'PhortuneAccountProfileController', + 'PhortuneAccountNameTransaction' => 'PhortuneAccountTransactionType', 'PhortuneAccountPHIDType' => 'PhabricatorPHIDType', + 'PhortuneAccountProfileController' => 'PhortuneController', 'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhortuneAccountTransaction' => 'PhabricatorApplicationTransaction', + 'PhortuneAccountSubscriptionController' => 'PhortuneAccountProfileController', + 'PhortuneAccountTransaction' => 'PhabricatorModularTransaction', 'PhortuneAccountTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhortuneAccountViewController' => 'PhortuneController', + 'PhortuneAccountTransactionType' => 'PhabricatorModularTransactionType', + 'PhortuneAccountViewController' => 'PhortuneAccountProfileController', 'PhortuneAdHocCart' => 'PhortuneCartImplementation', 'PhortuneAdHocProduct' => 'PhortuneProductImplementation', 'PhortuneCart' => array( @@ -9796,21 +9822,31 @@ 'PhabricatorApplicationTransactionInterface', 'PhabricatorPolicyInterface', ), + 'PhortuneMerchantAddManagerController' => 'PhortuneController', 'PhortuneMerchantCapability' => 'PhabricatorPolicyCapability', + 'PhortuneMerchantContactInfoTransaction' => 'PhortuneMerchantTransactionType', 'PhortuneMerchantController' => 'PhortuneController', + 'PhortuneMerchantDescriptionTransaction' => 'PhortuneMerchantTransactionType', 'PhortuneMerchantEditController' => 'PhortuneMerchantController', 'PhortuneMerchantEditEngine' => 'PhabricatorEditEngine', 'PhortuneMerchantEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneMerchantHasMemberEdgeType' => 'PhabricatorEdgeType', - 'PhortuneMerchantInvoiceCreateController' => 'PhortuneMerchantController', + 'PhortuneMerchantInvoiceCreateController' => 'PhortuneMerchantProfileController', + 'PhortuneMerchantInvoiceEmailTransaction' => 'PhortuneMerchantTransactionType', + 'PhortuneMerchantInvoiceFooterTransaction' => 'PhortuneMerchantTransactionType', 'PhortuneMerchantListController' => 'PhortuneMerchantController', + 'PhortuneMerchantManagerController' => 'PhortuneMerchantProfileController', + 'PhortuneMerchantNameTransaction' => 'PhortuneMerchantTransactionType', 'PhortuneMerchantPHIDType' => 'PhabricatorPHIDType', - 'PhortuneMerchantPictureController' => 'PhortuneMerchantController', + 'PhortuneMerchantPictureController' => 'PhortuneMerchantProfileController', + 'PhortuneMerchantPictureTransaction' => 'PhortuneMerchantTransactionType', + 'PhortuneMerchantProfileController' => 'PhortuneController', 'PhortuneMerchantQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneMerchantSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhortuneMerchantTransaction' => 'PhabricatorApplicationTransaction', + 'PhortuneMerchantTransaction' => 'PhabricatorModularTransaction', 'PhortuneMerchantTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhortuneMerchantViewController' => 'PhortuneMerchantController', + 'PhortuneMerchantTransactionType' => 'PhabricatorModularTransactionType', + 'PhortuneMerchantViewController' => 'PhortuneMerchantProfileController', 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 'PhortuneOrderTableView' => 'AphrontView', 'PhortunePayPalPaymentProvider' => 'PhortunePaymentProvider', @@ -9818,7 +9854,7 @@ 'PhortuneDAO', 'PhabricatorPolicyInterface', ), - 'PhortunePaymentMethodCreateController' => 'PhortuneController', + 'PhortunePaymentMethodCreateController' => 'PhortuneAccountProfileController', 'PhortunePaymentMethodDisableController' => 'PhortuneController', 'PhortunePaymentMethodEditController' => 'PhortuneController', 'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType', 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 @@ -67,7 +67,17 @@ ), 'account/' => array( '' => 'PhortuneAccountListController', - 'edit/(?:(?P\d+)/)?' => 'PhortuneAccountEditController', + $this->getEditRoutePattern('edit/') + => 'PhortuneAccountEditController', + 'add/manager/(?:(?P\d+)/)?' + => 'PhortuneAccountAddManagerController', + 'billing/(?:(?P\d+)/)?' => 'PhortuneAccountBillingController', + 'subscription/(?:(?P\d+)/)?' + => 'PhortuneAccountSubscriptionController', + 'manager/' => array( + '(?:(?P\d+)/)?' => 'PhortuneAccountManagerController', + 'add/(?:(?P\d+)/)?' => 'PhortuneAccountAddManagerController', + ), ), 'product/' => array( '' => 'PhortuneProductListController', @@ -87,6 +97,10 @@ => 'PhortuneMerchantEditController', 'orders/(?P\d+)/(?:query/(?P[^/]+)/)?' => 'PhortuneCartListController', + 'manager/' => array( + '(?:(?P\d+)/)?' => 'PhortuneMerchantManagerController', + 'add/(?:(?P\d+)/)?' => 'PhortuneMerchantAddManagerController', + ), '(?P\d+)/' => array( 'cart/(?P\d+)/' => array( '' => 'PhortuneCartViewController', diff --git a/src/applications/phortune/controller/PhortuneAccountEditController.php b/src/applications/phortune/controller/PhortuneAccountEditController.php deleted file mode 100644 --- a/src/applications/phortune/controller/PhortuneAccountEditController.php +++ /dev/null @@ -1,137 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - if ($id) { - $account = id(new PhortuneAccountQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$account) { - return new Aphront404Response(); - } - $is_new = false; - } else { - $account = PhortuneAccount::initializeNewAccount($viewer); - $account->attachMemberPHIDs(array($viewer->getPHID())); - $is_new = true; - } - - $v_name = $account->getName(); - $e_name = true; - - $v_members = $account->getMemberPHIDs(); - $e_members = null; - - $validation_exception = null; - - if ($request->isFormPost()) { - $v_name = $request->getStr('name'); - $v_members = $request->getArr('memberPHIDs'); - - $type_name = PhortuneAccountTransaction::TYPE_NAME; - $type_edge = PhabricatorTransactions::TYPE_EDGE; - - $xactions = array(); - $xactions[] = id(new PhortuneAccountTransaction()) - ->setTransactionType($type_name) - ->setNewValue($v_name); - - $xactions[] = id(new PhortuneAccountTransaction()) - ->setTransactionType($type_edge) - ->setMetadataValue( - 'edge:type', - PhortuneAccountHasMemberEdgeType::EDGECONST) - ->setNewValue( - array( - '=' => array_fuse($v_members), - )); - - $editor = id(new PhortuneAccountEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true); - - try { - $editor->applyTransactions($account, $xactions); - - $account_uri = $this->getApplicationURI($account->getID().'/'); - return id(new AphrontRedirectResponse())->setURI($account_uri); - } catch (PhabricatorApplicationTransactionValidationException $ex) { - $validation_exception = $ex; - $e_name = $ex->getShortMessage($type_name); - $e_members = $ex->getShortMessage($type_edge); - } - } - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->setBorder(true); - - if ($is_new) { - $cancel_uri = $this->getApplicationURI('account/'); - $crumbs->addTextCrumb(pht('Accounts'), $cancel_uri); - $crumbs->addTextCrumb(pht('Create Account')); - - $title = pht('Create Payment Account'); - $submit_button = pht('Create Account'); - } else { - $cancel_uri = $this->getApplicationURI($account->getID().'/'); - $crumbs->addTextCrumb($account->getName(), $cancel_uri); - $crumbs->addTextCrumb(pht('Edit')); - - $title = pht('Edit %s', $account->getName()); - $submit_button = pht('Save Changes'); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setName('name') - ->setLabel(pht('Name')) - ->setValue($v_name) - ->setError($e_name)) - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setLabel(pht('Members')) - ->setName('memberPHIDs') - ->setValue($v_members) - ->setError($e_members)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue($submit_button) - ->addCancelButton($cancel_uri)); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Account')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setValidationException($validation_exception) - ->setForm($form); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->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/PhortunePaymentMethodCreateController.php b/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php --- a/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php +++ b/src/applications/phortune/controller/PhortunePaymentMethodCreateController.php @@ -1,7 +1,7 @@ getViewer(); @@ -14,13 +14,24 @@ if (!$account) { return new Aphront404Response(); } - $account_id = $account->getID(); + $this->setAccount($account); + // Try an individual merchant first $merchant = id(new PhortuneMerchantQuery()) ->setViewer($viewer) ->withIDs(array($request->getInt('merchantID'))) ->executeOne(); + + // If none passed in, see if only 1 exists if (!$merchant) { + $merchants = id(new PhortuneMerchantQuery()) + ->setViewer($viewer) + ->execute(); + if (count($merchants) == 1) { + $merchant = head($merchants); + } + } else { + // Allow user to select a merchant from a dropdown? return new Aphront404Response(); } @@ -32,7 +43,7 @@ $cancel_uri = $this->getApplicationURI( "{$account_id}/subscription/edit/{$subscription_id}/"); } else { - $cancel_uri = $this->getApplicationURI($account->getID().'/'); + $cancel_uri = $this->getApplicationURI("account/billing/{$account_id}/"); } $providers = $this->loadCreatePaymentMethodProvidersForMerchant($merchant); @@ -125,9 +136,8 @@ } else if ($subscription_id) { $next_uri = $cancel_uri; } else { - $account_uri = $this->getApplicationURI($account->getID().'/'); - $next_uri = new PhutilURI($account_uri); - $next_uri->setFragment('payment'); + $next_uri = $this->getApplicationURI( + "account/billing/{$account_id}/"); } return id(new AphrontRedirectResponse())->setURI($next_uri); @@ -158,17 +168,15 @@ ->addCancelButton($cancel_uri)); $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Method')) + ->setHeaderText(pht('Add Payment Method')) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($account->getName()); $crumbs->addTextCrumb(pht('Add Payment Method')); - $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader(pht('Add Payment Method')) - ->setHeaderIcon('fa-plus-square'); + $header = $this->buildHeaderView(); $view = id(new PHUITwoColumnView()) ->setHeader($header) diff --git a/src/applications/phortune/controller/PhortunePaymentMethodDisableController.php b/src/applications/phortune/controller/PhortunePaymentMethodDisableController.php --- a/src/applications/phortune/controller/PhortunePaymentMethodDisableController.php +++ b/src/applications/phortune/controller/PhortunePaymentMethodDisableController.php @@ -25,7 +25,8 @@ } $account = $method->getAccount(); - $account_uri = $this->getApplicationURI($account->getID().'/'); + $account_id = $account->getID(); + $account_uri = $this->getApplicationURI("account/billing/{$account_id}/"); if ($request->isFormPost()) { diff --git a/src/applications/phortune/controller/PhortuneSubscriptionEditController.php b/src/applications/phortune/controller/PhortuneSubscriptionEditController.php --- a/src/applications/phortune/controller/PhortuneSubscriptionEditController.php +++ b/src/applications/phortune/controller/PhortuneSubscriptionEditController.php @@ -111,7 +111,8 @@ $crumbs->addTextCrumb( pht('Subscription %d', $subscription->getID()), $view_uri); - $crumbs->addTextCrumb(pht('Edit')); + $crumbs->addTextCrumb(pht('Manage')); + $crumbs->setBorder(true); $uri = $this->getApplicationURI($account->getID().'/card/new/'); @@ -152,7 +153,7 @@ ->appendChild($form); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Edit %s', $subscription->getSubscriptionName())) + ->setHeader(pht('Manage: %s', $subscription->getSubscriptionName())) ->setHeaderIcon('fa-pencil'); $view = id(new PHUITwoColumnView()) diff --git a/src/applications/phortune/controller/PhortuneSubscriptionViewController.php b/src/applications/phortune/controller/PhortuneSubscriptionViewController.php --- a/src/applications/phortune/controller/PhortuneSubscriptionViewController.php +++ b/src/applications/phortune/controller/PhortuneSubscriptionViewController.php @@ -36,7 +36,7 @@ $header = id(new PHUIHeaderView()) ->setHeader($title) - ->setHeaderIcon('fa-calendar-o'); + ->setHeaderIcon('fa-retweet'); $curtain = $this->newCurtainView($subscription); $edit_uri = $subscription->getEditURI(); @@ -44,7 +44,7 @@ $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') - ->setName(pht('Edit Subscription')) + ->setName(pht('Manage Payment')) ->setHref($edit_uri) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); @@ -55,6 +55,7 @@ } else { $this->addAccountCrumb($crumbs, $account); } + $crumbs->addTextCrumb(pht('Subscription')); $crumbs->addTextCrumb($subscription->getSubscriptionCrumbName()); $crumbs->setBorder(true); diff --git a/src/applications/phortune/controller/account/PhortuneAccountAddManagerController.php b/src/applications/phortune/controller/account/PhortuneAccountAddManagerController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountAddManagerController.php @@ -0,0 +1,75 @@ +getViewer(); + $id = $request->getURIData('id'); + + $account = id(new PhortuneAccountQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$account) { + return new Aphront404Response(); + } + + $v_members = array(); + $e_members = null; + $account_uri = $this->getApplicationURI("/account/manager/{$id}/"); + + if ($request->isFormPost()) { + $xactions = array(); + $v_members = $request->getArr('memberPHIDs'); + $type_edge = PhabricatorTransactions::TYPE_EDGE; + + $xactions[] = id(new PhortuneAccountTransaction()) + ->setTransactionType($type_edge) + ->setMetadataValue( + 'edge:type', + PhortuneAccountHasMemberEdgeType::EDGECONST) + ->setNewValue( + array( + '+' => array_fuse($v_members), + )); + + $editor = id(new PhortuneAccountEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + try { + $editor->applyTransactions($account, $xactions); + + return id(new AphrontRedirectResponse())->setURI($account_uri); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + $e_members = $ex->getShortMessage($type_edge); + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setDatasource(new PhabricatorPeopleDatasource()) + ->setLabel(pht('Members')) + ->setName('memberPHIDs') + ->setValue($v_members) + ->setError($e_members)); + + return $this->newDialog() + ->setTitle(pht('Add New Manager')) + ->appendForm($form) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->addCancelButton($account_uri) + ->addSubmitButton(pht('Add Manager')); + + } + +} diff --git a/src/applications/phortune/controller/account/PhortuneAccountBillingController.php b/src/applications/phortune/controller/account/PhortuneAccountBillingController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountBillingController.php @@ -0,0 +1,179 @@ +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($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$account) { + return new Aphront404Response(); + } + + $this->setAccount($account); + $title = $account->getName(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Billing')); + + $header = $this->buildHeaderView(); + $methods = $this->buildPaymentMethodsSection($account); + $charge_history = $this->buildChargeHistorySection($account); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $methods, + $charge_history, + )); + + $navigation = $this->buildSideNavView('billing'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setNavigation($navigation) + ->appendChild($view); + + } + + private function buildPaymentMethodsSection(PhortuneAccount $account) { + $viewer = $this->getViewer(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $account, + PhabricatorPolicyCapability::CAN_EDIT); + + $id = $account->getID(); + + // TODO: Allow adding a card here directly + $add = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('New Payment Method')) + ->setIcon('fa-plus') + ->setHref($this->getApplicationURI("{$id}/card/new/")); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Payment Methods')) + ->addActionLink($add); + + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer) + ->setFlush(true) + ->setNoDataString( + pht('No payment methods associated with this account.')); + + $methods = id(new PhortunePaymentMethodQuery()) + ->setViewer($viewer) + ->withAccountPHIDs(array($account->getPHID())) + ->withStatuses( + array( + PhortunePaymentMethod::STATUS_ACTIVE, + )) + ->execute(); + + 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; + } + + $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) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + + private function buildChargeHistorySection(PhortuneAccount $account) { + $viewer = $this->getViewer(); + + $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('fa-list') + ->setHref($charges_uri) + ->setText(pht('View All Charges'))); + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($table); + } + +} diff --git a/src/applications/phortune/controller/account/PhortuneAccountEditController.php b/src/applications/phortune/controller/account/PhortuneAccountEditController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountEditController.php @@ -0,0 +1,10 @@ +setController($this) + ->buildResponse(); + } +} diff --git a/src/applications/phortune/controller/PhortuneAccountListController.php b/src/applications/phortune/controller/account/PhortuneAccountListController.php rename from src/applications/phortune/controller/PhortuneAccountListController.php rename to src/applications/phortune/controller/account/PhortuneAccountListController.php --- a/src/applications/phortune/controller/PhortuneAccountListController.php +++ b/src/applications/phortune/controller/account/PhortuneAccountListController.php @@ -18,6 +18,7 @@ $merchants = id(new PhortuneMerchantQuery()) ->setViewer($viewer) ->withMemberPHIDs(array($viewer->getPHID())) + ->needProfileImage(true) ->execute(); $title = pht('Accounts'); @@ -39,7 +40,7 @@ ->setHeader($account->getName()) ->setHref($this->getApplicationURI($account->getID().'/')) ->setObject($account) - ->setImageIcon('fa-credit-card'); + ->setImageIcon('fa-user-circle'); $payment_list->addItem($item); } @@ -71,7 +72,7 @@ ->setHeader($merchant->getName()) ->setHref($this->getApplicationURI('/merchant/'.$merchant->getID().'/')) ->setObject($merchant) - ->setImageIcon('fa-bank'); + ->setImageURI($merchant->getProfileImageURI()); $merchant_list->addItem($item); } diff --git a/src/applications/phortune/controller/account/PhortuneAccountManagerController.php b/src/applications/phortune/controller/account/PhortuneAccountManagerController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountManagerController.php @@ -0,0 +1,101 @@ +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($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$account) { + return new Aphront404Response(); + } + + $this->setAccount($account); + $title = $account->getName(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Managers')); + + $header = $this->buildHeaderView(); + $members = $this->buildMembersSection($account); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $members, + )); + + $navigation = $this->buildSideNavView('managers'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setNavigation($navigation) + ->appendChild($view); + + } + + private function buildMembersSection(PhortuneAccount $account) { + $viewer = $this->getViewer(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $account, + PhabricatorPolicyCapability::CAN_EDIT); + + $id = $account->getID(); + + $add = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('New Manager')) + ->setIcon('fa-plus') + ->setWorkflow(true) + ->setHref("/phortune/account/manager/add/{$id}/"); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Account Managers')) + ->addActionLink($add); + + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer); + + $member_phids = $account->getMemberPHIDs(); + $handles = $viewer->loadHandles($member_phids); + + foreach ($member_phids as $member_phid) { + $image_uri = $handles[$member_phid]->getImageURI(); + $image_href = $handles[$member_phid]->getURI(); + $person = $handles[$member_phid]; + + $member = id(new PHUIObjectItemView()) + ->setImageURI($image_uri) + ->setHref($image_href) + ->setHeader($person->getFullName()) + ->addAttribute(pht('Account Manager')); + + $list->addItem($member); + } + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + +} diff --git a/src/applications/phortune/controller/account/PhortuneAccountProfileController.php b/src/applications/phortune/controller/account/PhortuneAccountProfileController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountProfileController.php @@ -0,0 +1,84 @@ +account = $account; + return $this; + } + + public function getAccount() { + return $this->account; + } + + public function buildApplicationMenu() { + return $this->buildSideNavView()->getMenu(); + } + + protected function buildHeaderView() { + $viewer = $this->getViewer(); + $account = $this->getAccount(); + $title = $account->getName(); + + $header = id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader($title) + ->setHeaderIcon('fa-user-circle'); + + return $header; + } + + protected function buildApplicationCrumbs() { + $account = $this->getAccount(); + $id = $account->getID(); + $account_uri = $this->getApplicationURI("/{$id}/"); + + $crumbs = parent::buildApplicationCrumbs(); + $crumbs->addTextCrumb($account->getName(), $account_uri); + $crumbs->setBorder(true); + return $crumbs; + } + + protected function buildSideNavView($filter = null) { + $viewer = $this->getViewer(); + $account = $this->getAccount(); + $id = $account->getID(); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI(new PhutilURI($this->getApplicationURI())); + + $nav->addLabel(pht('Account')); + + $nav->addFilter( + 'overview', + pht('Overview'), + $this->getApplicationURI("/{$id}/"), + 'fa-user-circle'); + + $nav->addFilter( + 'subscriptions', + pht('Subscriptions'), + $this->getApplicationURI("/account/subscription/{$id}/"), + 'fa-retweet'); + + $nav->addFilter( + 'billing', + pht('Billing'), + $this->getApplicationURI("/account/billing/{$id}/"), + 'fa-credit-card'); + + $nav->addFilter( + 'managers', + pht('Managers'), + $this->getApplicationURI("/account/manager/{$id}/"), + 'fa-group'); + + $nav->selectFilter($filter); + + return $nav; + } + +} diff --git a/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php b/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/account/PhortuneAccountSubscriptionController.php @@ -0,0 +1,79 @@ +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($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$account) { + return new Aphront404Response(); + } + + $this->setAccount($account); + $title = $account->getName(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Subscriptions')); + + $header = $this->buildHeaderView(); + $subscriptions = $this->buildSubscriptionsSection($account); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $subscriptions, + )); + + $navigation = $this->buildSideNavView('subscriptions'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setNavigation($navigation) + ->appendChild($view); + + } + + private function buildSubscriptionsSection(PhortuneAccount $account) { + $viewer = $this->getViewer(); + + $subscriptions = id(new PhortuneSubscriptionQuery()) + ->setViewer($viewer) + ->withAccountPHIDs(array($account->getPHID())) + ->setLimit(25) + ->execute(); + + $handles = $this->loadViewerHandles(mpull($subscriptions, 'getPHID')); + + $table = id(new PhortuneSubscriptionTableView()) + ->setUser($viewer) + ->setHandles($handles) + ->setSubscriptions($subscriptions); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Subscriptions')); + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setTable($table); + } + +} diff --git a/src/applications/phortune/controller/PhortuneAccountViewController.php b/src/applications/phortune/controller/account/PhortuneAccountViewController.php rename from src/applications/phortune/controller/PhortuneAccountViewController.php rename to src/applications/phortune/controller/account/PhortuneAccountViewController.php --- a/src/applications/phortune/controller/PhortuneAccountViewController.php +++ b/src/applications/phortune/controller/account/PhortuneAccountViewController.php @@ -1,9 +1,11 @@ getViewer(); + $id = $request->getURIData('accountID'); // 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 @@ -14,7 +16,7 @@ $account = id(new PhortuneAccountQuery()) ->setViewer($viewer) - ->withIDs(array($request->getURIData('accountID'))) + ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, @@ -25,6 +27,7 @@ return new Aphront404Response(); } + $this->setAccount($account); $title = $account->getName(); $invoices = id(new PhortuneCartQuery()) @@ -35,19 +38,14 @@ ->execute(); $crumbs = $this->buildApplicationCrumbs(); - $this->addAccountCrumb($crumbs, $account, $link = false); $crumbs->setBorder(true); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-credit-card'); + $header = $this->buildHeaderView(); - $curtain = $this->buildCurtainView($account, $invoices); + $curtain = $this->buildCurtainView($account); + $status = $this->buildStatusView($account, $invoices); $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, @@ -58,22 +56,34 @@ ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( + $status, $invoices, $purchase_history, - $charge_history, - $subscriptions, - $payment_methods, $timeline, )); + $navigation = $this->buildSideNavView('overview'); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($navigation) ->appendChild($view); } - private function buildCurtainView(PhortuneAccount $account, $invoices) { + private function buildStatusView(PhortuneAccount $account, $invoices) { + $status_items = $this->getStatusItemsForAccount($account, $invoices); + $view = array(); + foreach ($status_items as $item) { + $view[] = id(new PHUIInfoView()) + ->setSeverity(idx($item, 'severity')) + ->appendChild(idx($item, 'note')); + } + return $view; + } + + private function buildCurtainView(PhortuneAccount $account) { $viewer = $this->getViewer(); $can_edit = PhabricatorPolicyFilter::hasCapability( @@ -92,19 +102,6 @@ ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); - $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'))); - } - $member_phids = $account->getMemberPHIDs(); $handles = $viewer->loadHandles($member_phids); @@ -125,89 +122,12 @@ } $curtain->newPanel() - ->setHeaderText(pht('Status')) - ->appendChild($status_view); - - $curtain->newPanel() - ->setHeaderText(pht('Members')) + ->setHeaderText(pht('Managers')) ->appendChild($member_list); return $curtain; } - private function buildPaymentMethodsSection(PhortuneAccount $account) { - $viewer = $this->getViewer(); - - $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) - ->setFlush(true) - ->setNoDataString( - pht('No payment methods associated with this account.')); - - $methods = id(new PhortunePaymentMethodQuery()) - ->setViewer($viewer) - ->withAccountPHIDs(array($account->getPHID())) - ->withStatuses( - array( - PhortunePaymentMethod::STATUS_ACTIVE, - )) - ->execute(); - - 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; - } - - $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) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setObjectList($list); - } - private function buildInvoicesSection( PhortuneAccount $account, array $carts) { @@ -289,84 +209,6 @@ ->setTable($table); } - private function buildChargeHistorySection(PhortuneAccount $account) { - $viewer = $this->getViewer(); - - $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('fa-list') - ->setHref($charges_uri) - ->setText(pht('View All Charges'))); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); - } - - private function buildSubscriptionsSection(PhortuneAccount $account) { - $viewer = $this->getViewer(); - - $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()) - ->setIcon('fa-list')) - ->setHref($subscriptions_uri) - ->setText(pht('View All Subscriptions'))); - - return id(new PHUIObjectBoxView()) - ->setHeader($header) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table); - } - protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); @@ -382,24 +224,31 @@ private function getStatusItemsForAccount( PhortuneAccount $account, array $invoices) { + $viewer = $this->getViewer(); assert_instances_of($invoices, 'PhortuneCart'); - $items = array(); + $methods = id(new PhortunePaymentMethodQuery()) + ->setViewer($viewer) + ->withAccountPHIDs(array($account->getPHID())) + ->withStatuses( + array( + PhortunePaymentMethod::STATUS_ACTIVE, + )) + ->execute(); + if ($invoices) { $items[] = array( - 'icon' => PHUIStatusItemView::ICON_WARNING, - 'color' => 'yellow', - 'target' => pht('Invoices'), + 'severity' => PHUIInfoView::SEVERITY_ERROR, 'note' => pht('You have %d unpaid invoice(s).', count($invoices)), ); - } else { + } + + if (!$methods) { $items[] = array( - 'icon' => PHUIStatusItemView::ICON_ACCEPT, - 'color' => 'green', - 'target' => pht('Invoices'), - 'note' => pht('This account has no unpaid invoices.'), + 'severity' => PHUIInfoView::SEVERITY_NOTICE, + 'note' => pht('No payment methods are associated with this account.'), ); } diff --git a/src/applications/phortune/controller/merchant/PhortuneMerchantAddManagerController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantAddManagerController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantAddManagerController.php @@ -0,0 +1,76 @@ +getViewer(); + $id = $request->getURIData('id'); + + $merchant = id(new PhortuneMerchantQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needProfileImage(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$merchant) { + return new Aphront404Response(); + } + + $v_members = array(); + $e_members = null; + $merchant_uri = $this->getApplicationURI("/merchant/manager/{$id}/"); + + if ($request->isFormPost()) { + $xactions = array(); + $v_members = $request->getArr('memberPHIDs'); + $type_edge = PhabricatorTransactions::TYPE_EDGE; + + $xactions[] = id(new PhortuneMerchantTransaction()) + ->setTransactionType($type_edge) + ->setMetadataValue( + 'edge:type', + PhortuneMerchantHasMemberEdgeType::EDGECONST) + ->setNewValue( + array( + '+' => array_fuse($v_members), + )); + + $editor = id(new PhortuneMerchantEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + try { + $editor->applyTransactions($merchant, $xactions); + + return id(new AphrontRedirectResponse())->setURI($merchant_uri); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + $e_members = $ex->getShortMessage($type_edge); + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setDatasource(new PhabricatorPeopleDatasource()) + ->setLabel(pht('Members')) + ->setName('memberPHIDs') + ->setValue($v_members) + ->setError($e_members)); + + return $this->newDialog() + ->setTitle(pht('Add New Manager')) + ->appendForm($form) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->addCancelButton($merchant_uri) + ->addSubmitButton(pht('Add Manager')); + + } + +} diff --git a/src/applications/phortune/controller/PhortuneMerchantController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantController.php rename from src/applications/phortune/controller/PhortuneMerchantController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantController.php diff --git a/src/applications/phortune/controller/PhortuneMerchantEditController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantEditController.php rename from src/applications/phortune/controller/PhortuneMerchantEditController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantEditController.php diff --git a/src/applications/phortune/controller/PhortuneMerchantInvoiceCreateController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantInvoiceCreateController.php rename from src/applications/phortune/controller/PhortuneMerchantInvoiceCreateController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantInvoiceCreateController.php --- a/src/applications/phortune/controller/PhortuneMerchantInvoiceCreateController.php +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantInvoiceCreateController.php @@ -1,7 +1,7 @@ getUser(); @@ -11,6 +11,7 @@ return new Aphront404Response(); } + $this->setMerchant($merchant); $merchant_id = $merchant->getID(); $cancel_uri = $this->getApplicationURI("/merchant/{$merchant_id}/"); @@ -88,8 +89,7 @@ $title = pht('New Invoice'); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($merchant->getName()); - $crumbs->setBorder(true); + $crumbs->addTextCrumb($title); $v_title = $request->getStr('title'); $e_title = true; @@ -245,9 +245,12 @@ $box, )); + $navigation = $this->buildSideNavView('orders'); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($navigation) ->appendChild($view); } diff --git a/src/applications/phortune/controller/PhortuneMerchantListController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantListController.php rename from src/applications/phortune/controller/PhortuneMerchantListController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantListController.php diff --git a/src/applications/phortune/controller/merchant/PhortuneMerchantManagerController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantManagerController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantManagerController.php @@ -0,0 +1,91 @@ +getViewer(); + $id = $request->getURIData('id'); + + $merchant = id(new PhortuneMerchantQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needProfileImage(true) + ->executeOne(); + if (!$merchant) { + return new Aphront404Response(); + } + + $this->setMerchant($merchant); + $header = $this->buildHeaderView(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Managers')); + + $header = $this->buildHeaderView(); + $members = $this->buildMembersSection($merchant); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $members, + )); + + $navigation = $this->buildSideNavView('managers'); + + return $this->newPage() + ->setTitle(pht('Managers')) + ->setCrumbs($crumbs) + ->setNavigation($navigation) + ->appendChild($view); + + } + + private function buildMembersSection(PhortuneMerchant $merchant) { + $viewer = $this->getViewer(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $merchant, + PhabricatorPolicyCapability::CAN_EDIT); + + $id = $merchant->getID(); + + $add = id(new PHUIButtonView()) + ->setTag('a') + ->setText(pht('New Manager')) + ->setIcon('fa-plus') + ->setWorkflow(true) + ->setHref("/phortune/merchant/manager/add/{$id}/"); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Merchant Account Managers')) + ->addActionLink($add); + + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer); + + $member_phids = $merchant->getMemberPHIDs(); + $handles = $viewer->loadHandles($member_phids); + + foreach ($member_phids as $member_phid) { + $image_uri = $handles[$member_phid]->getImageURI(); + $image_href = $handles[$member_phid]->getURI(); + $person = $handles[$member_phid]; + + $member = id(new PHUIObjectItemView()) + ->setImageURI($image_uri) + ->setHref($image_href) + ->setHeader($person->getFullName()) + ->addAttribute(pht('Merchant Manager')); + + $list->addItem($member); + } + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setObjectList($list); + } + +} diff --git a/src/applications/phortune/controller/PhortuneMerchantPictureController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantPictureController.php rename from src/applications/phortune/controller/PhortuneMerchantPictureController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantPictureController.php --- a/src/applications/phortune/controller/PhortuneMerchantPictureController.php +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantPictureController.php @@ -1,7 +1,7 @@ getViewer(); @@ -21,6 +21,7 @@ return new Aphront404Response(); } + $this->setMerchant($merchant); $uri = $merchant->getViewURI(); $supported_formats = PhabricatorFile::getTransformableImageFormats(); @@ -76,7 +77,8 @@ $xactions = array(); $xactions[] = id(new PhortuneMerchantTransaction()) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_PICTURE) + ->setTransactionType( + PhortuneMerchantPictureTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); $editor = id(new PhortuneMerchantEditor()) @@ -91,7 +93,7 @@ } } - $title = pht('Edit Merchant Picture'); + $title = pht('Edit Logo'); $form = id(new PHUIFormLayoutView()) ->setUser($viewer); @@ -207,12 +209,10 @@ ->setForm($upload_form); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($merchant->getName(), $uri); - $crumbs->addTextCrumb(pht('Merchant Logo')); - $crumbs->setBorder(true); + $crumbs->addTextCrumb(pht('Edit Logo')); $header = id(new PHUIHeaderView()) - ->setHeader(pht('Edit Merchant Logo')) + ->setHeader(pht('Edit Logo')) ->setHeaderIcon('fa-camera'); $view = id(new PHUITwoColumnView()) @@ -222,9 +222,12 @@ $upload_box, )); + $navigation = $this->buildSideNavView(); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($navigation) ->appendChild( array( $view, diff --git a/src/applications/phortune/controller/merchant/PhortuneMerchantProfileController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantProfileController.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantProfileController.php @@ -0,0 +1,92 @@ +merchant = $merchant; + return $this; + } + + public function getMerchant() { + return $this->merchant; + } + + public function buildApplicationMenu() { + return $this->buildSideNavView()->getMenu(); + } + + protected function buildHeaderView() { + $viewer = $this->getViewer(); + $merchant = $this->getMerchant(); + $title = $merchant->getName(); + + $header = id(new PHUIHeaderView()) + ->setHeader($title) + ->setUser($viewer) + ->setPolicyObject($merchant) + ->setImage($merchant->getProfileImageURI()); + + return $header; + } + + protected function buildApplicationCrumbs() { + $merchant = $this->getMerchant(); + $id = $merchant->getID(); + $merchant_uri = $this->getApplicationURI("/merchant/{$id}/"); + + $crumbs = parent::buildApplicationCrumbs(); + $crumbs->addTextCrumb($merchant->getName(), $merchant_uri); + $crumbs->setBorder(true); + return $crumbs; + } + + protected function buildSideNavView($filter = null) { + $viewer = $this->getViewer(); + $merchant = $this->getMerchant(); + $id = $merchant->getID(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $merchant, + PhabricatorPolicyCapability::CAN_EDIT); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI(new PhutilURI($this->getApplicationURI())); + + $nav->addLabel(pht('Merchant')); + + $nav->addFilter( + 'overview', + pht('Overview'), + $this->getApplicationURI("/merchant/{$id}/"), + 'fa-building-o'); + + if ($can_edit) { + $nav->addFilter( + 'orders', + pht('Orders'), + $this->getApplicationURI("merchant/orders/{$id}/"), + 'fa-retweet'); + + $nav->addFilter( + 'subscriptions', + pht('Subscriptions'), + $this->getApplicationURI("merchant/{$id}/subscription/"), + 'fa-shopping-cart'); + + $nav->addFilter( + 'managers', + pht('Managers'), + $this->getApplicationURI("/merchant/manager/{$id}/"), + 'fa-group'); + } + + $nav->selectFilter($filter); + + return $nav; + } + +} diff --git a/src/applications/phortune/controller/PhortuneMerchantViewController.php b/src/applications/phortune/controller/merchant/PhortuneMerchantViewController.php rename from src/applications/phortune/controller/PhortuneMerchantViewController.php rename to src/applications/phortune/controller/merchant/PhortuneMerchantViewController.php --- a/src/applications/phortune/controller/PhortuneMerchantViewController.php +++ b/src/applications/phortune/controller/merchant/PhortuneMerchantViewController.php @@ -1,7 +1,7 @@ getViewer(); @@ -16,21 +16,15 @@ return new Aphront404Response(); } + $this->setMerchant($merchant); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($merchant->getName()); - $crumbs->setBorder(true); + $header = $this->buildHeaderView(); $title = pht( 'Merchant %d %s', $merchant->getID(), $merchant->getName()); - $header = id(new PHUIHeaderView()) - ->setHeader($merchant->getName()) - ->setUser($viewer) - ->setPolicyObject($merchant) - ->setImage($merchant->getProfileImageURI()); - $providers = id(new PhortunePaymentProviderConfigQuery()) ->setViewer($viewer) ->withMerchantPHIDs(array($merchant->getPHID())) @@ -48,6 +42,8 @@ new PhortuneMerchantTransactionQuery()); $timeline->setShouldTerminate(true); + $navigation = $this->buildSideNavView('overview'); + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) @@ -60,6 +56,7 @@ return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($navigation) ->appendChild($view); } @@ -198,22 +195,6 @@ $curtain->addAction( id(new PhabricatorActionView()) - ->setName(pht('View Orders')) - ->setIcon('fa-shopping-cart') - ->setHref($this->getApplicationURI("merchant/orders/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('View Subscriptions')) - ->setIcon('fa-moon-o') - ->setHref($this->getApplicationURI("merchant/{$id}/subscription/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $curtain->addAction( - id(new PhabricatorActionView()) ->setName(pht('New Invoice')) ->setIcon('fa-fax') ->setHref($this->getApplicationURI("merchant/{$id}/invoice/new/")) @@ -240,7 +221,7 @@ } $curtain->newPanel() - ->setHeaderText(pht('Members')) + ->setHeaderText(pht('Managers')) ->appendChild($member_list); return $curtain; diff --git a/src/applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php b/src/applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php --- a/src/applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php +++ b/src/applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php @@ -14,7 +14,7 @@ $add_edges) { return pht( - '%s added %s account member(s): %s.', + '%s added %s account manager(s): %s.', $actor, $add_count, $add_edges); @@ -26,7 +26,7 @@ $rem_edges) { return pht( - '%s removed %s account member(s): %s.', + '%s removed %s account manager(s): %s.', $actor, $rem_count, $rem_edges); @@ -41,7 +41,7 @@ $rem_edges) { return pht( - '%s edited %s account member(s), added %s: %s; removed %s: %s.', + '%s edited %s account manager(s), added %s: %s; removed %s: %s.', $actor, $total_count, $add_count, @@ -57,7 +57,7 @@ $add_edges) { return pht( - '%s added %s account member(s) to %s: %s.', + '%s added %s account manager(s) to %s: %s.', $actor, $add_count, $object, @@ -71,7 +71,7 @@ $rem_edges) { return pht( - '%s removed %s account member(s) from %s: %s.', + '%s removed %s account manager(s) from %s: %s.', $actor, $rem_count, $object, @@ -88,7 +88,7 @@ $rem_edges) { return pht( - '%s edited %s account member(s) for %s, added %s: %s; removed %s: %s.', + '%s edited %s account manager(s) for %s, added %s: %s; removed %s: %s.', $actor, $total_count, $object, diff --git a/src/applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php b/src/applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php --- a/src/applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php +++ b/src/applications/phortune/edge/PhortuneMerchantHasMemberEdgeType.php @@ -14,7 +14,7 @@ $add_edges) { return pht( - '%s added %s merchant member(s): %s.', + '%s added %s merchant manager(s): %s.', $actor, $add_count, $add_edges); @@ -26,7 +26,7 @@ $rem_edges) { return pht( - '%s removed %s merchant member(s): %s.', + '%s removed %s merchant manager(s): %s.', $actor, $rem_count, $rem_edges); @@ -41,7 +41,7 @@ $rem_edges) { return pht( - '%s edited %s merchant member(s), added %s: %s; removed %s: %s.', + '%s edited %s merchant manager(s), added %s: %s; removed %s: %s.', $actor, $total_count, $add_count, @@ -57,7 +57,7 @@ $add_edges) { return pht( - '%s added %s merchant member(s) to %s: %s.', + '%s added %s merchant manager(s) to %s: %s.', $actor, $add_count, $object, @@ -71,7 +71,7 @@ $rem_edges) { return pht( - '%s removed %s merchant member(s) from %s: %s.', + '%s removed %s merchant manager(s) from %s: %s.', $actor, $rem_count, $object, @@ -88,7 +88,7 @@ $rem_edges) { return pht( - '%s edited %s merchant member(s) for %s, added %s: %s; removed %s: %s.', + '%s edited %s merchant manager(s) for %s, added %s: %s; removed %s: %s.', $actor, $total_count, $object, diff --git a/src/applications/phortune/editor/PhortuneAccountEditEngine.php b/src/applications/phortune/editor/PhortuneAccountEditEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/editor/PhortuneAccountEditEngine.php @@ -0,0 +1,108 @@ +getViewer()); + } + + protected function newObjectQuery() { + return new PhortuneAccountQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create Payment Account'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Account: %s', $object->getName()); + } + + protected function getObjectEditShortText($object) { + return $object->getName(); + } + + protected function getObjectCreateShortText() { + return pht('Create Account'); + } + + protected function getObjectName() { + return pht('Account'); + } + + protected function getObjectCreateCancelURI($object) { + return $this->getApplication()->getApplicationURI('/'); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('edit/'); + } + + protected function getObjectViewURI($object) { + return $object->getViewURI(); + } + + protected function buildCustomEditFields($object) { + $viewer = $this->getViewer(); + + if ($this->getIsCreate()) { + $member_phids = array($viewer->getPHID()); + } else { + $member_phids = $object->getMemberPHIDs(); + } + + $fields = array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setDescription(pht('Account name.')) + ->setConduitTypeDescription(pht('New account name.')) + ->setTransactionType( + PhortuneAccountNameTransaction::TRANSACTIONTYPE) + ->setValue($object->getName()) + ->setIsRequired(true), + + id(new PhabricatorUsersEditField()) + ->setKey('members') + ->setAliases(array('memberPHIDs')) + ->setLabel(pht('Members')) + ->setUseEdgeTransactions(true) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue( + 'edge:type', + PhortuneAccountHasMemberEdgeType::EDGECONST) + ->setDescription(pht('Initial account members.')) + ->setConduitDescription(pht('Set account members.')) + ->setConduitTypeDescription(pht('New list of members.')) + ->setInitialValue($object->getMemberPHIDs()) + ->setValue($member_phids), + ); + + return $fields; + + } + +} diff --git a/src/applications/phortune/editor/PhortuneAccountEditor.php b/src/applications/phortune/editor/PhortuneAccountEditor.php --- a/src/applications/phortune/editor/PhortuneAccountEditor.php +++ b/src/applications/phortune/editor/PhortuneAccountEditor.php @@ -1,6 +1,5 @@ getTransactionType()) { - case PhortuneAccountTransaction::TYPE_NAME: - return $object->getName(); - } - return parent::getCustomTransactionOldValue($object, $xaction); + array $xactions) { + return true; } - protected function getCustomTransactionNewValue( + protected function shouldSendMail( PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhortuneAccountTransaction::TYPE_NAME: - return $xaction->getNewValue(); - } - return parent::getCustomTransactionNewValue($object, $xaction); + array $xactions) { + return true; } - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhortuneAccountTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; + public function getMailTagsMap() { + return array( + PhortuneAccountTransaction::MAILTAG_DETAILS => + pht('Someone changes the accounts\'s details.'), + ); + } + + protected function getMailTo(PhabricatorLiskDAO $object) { + $phids = array(); + + $account = id(new PhortuneAccountQuery()) + ->setViewer($this->requireActor()) + ->withPHIDs(array($object->getPHID())) + ->executeOne(); + + foreach ($account->getMemberPHIDs() as $account_member) { + $phids[] = $account_member; } - return parent::applyCustomInternalTransaction($object, $xaction); + + return $phids; } - protected function applyCustomExternalTransaction( + protected function buildMailBody( PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhortuneAccountTransaction::TYPE_NAME: - return; - } - return parent::applyCustomExternalTransaction($object, $xaction); + array $xactions) { + + $body = parent::buildMailBody($object, $xactions); + $body->addLinkSection( + pht('ACCOUNT DETAIL'), + PhabricatorEnv::getProductionURI('/phortune/'.$object->getID().'/')); + return $body; + } + + protected function getMailSubjectPrefix() { + return pht('[Phortune]'); + } + + protected function getMailCC(PhabricatorLiskDAO $object) { + return array(); } protected function validateTransaction( @@ -71,47 +85,29 @@ $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { - case PhortuneAccountTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Account name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; case PhabricatorTransactions::TYPE_EDGE: foreach ($xactions as $xaction) { switch ($xaction->getMetadataValue('edge:type')) { case PhortuneAccountHasMemberEdgeType::EDGECONST: - // TODO: This is a bit cumbersome, but validation happens before - // transaction normalization. Maybe provide a cleaner attack on - // this eventually? There's no way to generate "+" or "-" - // transactions right now. $new = $xaction->getNewValue(); - $set = idx($new, '=', array()); - - if (empty($set[$this->requireActor()->getPHID()])) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht('You can not remove yourself as an account member.'), - $xaction); - $errors[] = $error; + $set = idx($new, '-', array()); + $actor_phid = $this->requireActor()->getPHID(); + foreach ($set as $phid) { + if ($actor_phid == $phid) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + pht('You can not remove yourself as an account manager.'), + $xaction); + $errors[] = $error; + } } - break; + break; } } break; } - return $errors; } + } diff --git a/src/applications/phortune/editor/PhortuneMerchantEditEngine.php b/src/applications/phortune/editor/PhortuneMerchantEditEngine.php --- a/src/applications/phortune/editor/PhortuneMerchantEditEngine.php +++ b/src/applications/phortune/editor/PhortuneMerchantEditEngine.php @@ -81,7 +81,8 @@ ->setDescription(pht('Merchant name.')) ->setConduitTypeDescription(pht('New Merchant name.')) ->setIsRequired(true) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_NAME) + ->setTransactionType( + PhortuneMerchantNameTransaction::TRANSACTIONTYPE) ->setValue($object->getName()), id(new PhabricatorUsersEditField()) @@ -104,7 +105,8 @@ ->setLabel(pht('Description')) ->setDescription(pht('Merchant description.')) ->setConduitTypeDescription(pht('New merchant description.')) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_DESCRIPTION) + ->setTransactionType( + PhortuneMerchantDescriptionTransaction::TRANSACTIONTYPE) ->setValue($object->getDescription()), id(new PhabricatorRemarkupEditField()) @@ -112,7 +114,8 @@ ->setLabel(pht('Contact Info')) ->setDescription(pht('Merchant contact information.')) ->setConduitTypeDescription(pht('Merchant contact information.')) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_CONTACTINFO) + ->setTransactionType( + PhortuneMerchantContactInfoTransaction::TRANSACTIONTYPE) ->setValue($object->getContactInfo()), id(new PhabricatorTextEditField()) @@ -121,7 +124,8 @@ ->setDescription(pht('Email address invoices are sent from.')) ->setConduitTypeDescription( pht('Email address invoices are sent from.')) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_INVOICEEMAIL) + ->setTransactionType( + PhortuneMerchantInvoiceEmailTransaction::TRANSACTIONTYPE) ->setValue($object->getInvoiceEmail()), id(new PhabricatorRemarkupEditField()) @@ -129,7 +133,8 @@ ->setLabel(pht('Invoice Footer')) ->setDescription(pht('Footer on invoice forms.')) ->setConduitTypeDescription(pht('Footer on invoice forms.')) - ->setTransactionType(PhortuneMerchantTransaction::TYPE_INVOICEFOOTER) + ->setTransactionType( + PhortuneMerchantInvoiceFooterTransaction::TRANSACTIONTYPE) ->setValue($object->getInvoiceFooter()), ); diff --git a/src/applications/phortune/editor/PhortuneMerchantEditor.php b/src/applications/phortune/editor/PhortuneMerchantEditor.php --- a/src/applications/phortune/editor/PhortuneMerchantEditor.php +++ b/src/applications/phortune/editor/PhortuneMerchantEditor.php @@ -11,102 +11,78 @@ return pht('Phortune Merchants'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this merchant.', $author); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhortuneMerchantTransaction::TYPE_NAME; - $types[] = PhortuneMerchantTransaction::TYPE_DESCRIPTION; - $types[] = PhortuneMerchantTransaction::TYPE_CONTACTINFO; - $types[] = PhortuneMerchantTransaction::TYPE_PICTURE; - $types[] = PhortuneMerchantTransaction::TYPE_INVOICEEMAIL; - $types[] = PhortuneMerchantTransaction::TYPE_INVOICEFOOTER; + $types[] = PhortuneMerchantNameTransaction::TRANSACTIONTYPE; + $types[] = PhortuneMerchantDescriptionTransaction::TRANSACTIONTYPE; + $types[] = PhortuneMerchantContactInfoTransaction::TRANSACTIONTYPE; + $types[] = PhortuneMerchantPictureTransaction::TRANSACTIONTYPE; + $types[] = PhortuneMerchantInvoiceEmailTransaction::TRANSACTIONTYPE; + $types[] = PhortuneMerchantInvoiceFooterTransaction::TRANSACTIONTYPE; + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDGE; return $types; } - protected function getCustomTransactionOldValue( + protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PhortuneMerchantTransaction::TYPE_NAME: - return $object->getName(); - case PhortuneMerchantTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case PhortuneMerchantTransaction::TYPE_CONTACTINFO: - return $object->getContactInfo(); - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - return $object->getInvoiceEmail(); - case PhortuneMerchantTransaction::TYPE_INVOICEFOOTER: - return $object->getInvoiceFooter(); - case PhortuneMerchantTransaction::TYPE_PICTURE: - return $object->getProfileImagePHID(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); + array $xactions) { + return true; } - protected function getCustomTransactionNewValue( + protected function shouldSendMail( PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhortuneMerchantTransaction::TYPE_NAME: - case PhortuneMerchantTransaction::TYPE_DESCRIPTION: - case PhortuneMerchantTransaction::TYPE_CONTACTINFO: - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - case PhortuneMerchantTransaction::TYPE_INVOICEFOOTER: - case PhortuneMerchantTransaction::TYPE_PICTURE: - return $xaction->getNewValue(); - } + array $xactions) { + return true; + } - return parent::getCustomTransactionNewValue($object, $xaction); + public function getMailTagsMap() { + return array( + PhortuneMerchantTransaction::MAILTAG_DETAILS => + pht('Someone changes the merchants\'s details.'), + ); } - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhortuneMerchantTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; - case PhortuneMerchantTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - return; - case PhortuneMerchantTransaction::TYPE_CONTACTINFO: - $object->setContactInfo($xaction->getNewValue()); - return; - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - $object->setInvoiceEmail($xaction->getNewValue()); - return; - case PhortuneMerchantTransaction::TYPE_INVOICEFOOTER: - $object->setInvoiceFooter($xaction->getNewValue()); - return; - case PhortuneMerchantTransaction::TYPE_PICTURE: - $object->setProfileImagePHID($xaction->getNewValue()); - return; + protected function getMailTo(PhabricatorLiskDAO $object) { + $phids = array(); + + $merchant = id(new PhortuneMerchantQuery()) + ->setViewer($this->requireActor()) + ->withPHIDs(array($object->getPHID())) + ->executeOne(); + + foreach ($merchant->getMemberPHIDs() as $merchant_member) { + $phids[] = $merchant_member; } - return parent::applyCustomInternalTransaction($object, $xaction); + return $phids; } - protected function applyCustomExternalTransaction( + protected function buildMailBody( PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhortuneMerchantTransaction::TYPE_NAME: - case PhortuneMerchantTransaction::TYPE_DESCRIPTION: - case PhortuneMerchantTransaction::TYPE_CONTACTINFO: - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - case PhortuneMerchantTransaction::TYPE_INVOICEFOOTER: - case PhortuneMerchantTransaction::TYPE_PICTURE: - return; - } + array $xactions) { - return parent::applyCustomExternalTransaction($object, $xaction); + $body = parent::buildMailBody($object, $xactions); + $body->addLinkSection( + pht('MERCHANT DETAIL'), + PhabricatorEnv::getProductionURI( + '/phortune/merchant/'.$object->getID().'/')); + return $body; + } + + protected function getMailSubjectPrefix() { + return pht('[Phortune]'); + } + + protected function getMailCC(PhabricatorLiskDAO $object) { + return array(); } protected function validateTransaction( @@ -117,48 +93,28 @@ $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { - case PhortuneMerchantTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Merchant name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - $new_email = null; + case PhabricatorTransactions::TYPE_EDGE: foreach ($xactions as $xaction) { - switch ($xaction->getTransactionType()) { - case PhortuneMerchantTransaction::TYPE_INVOICEEMAIL: - $new_email = $xaction->getNewValue(); - break; - } - } - if (strlen($new_email)) { - $email = new PhutilEmailAddress($new_email); - $domain = $email->getDomainName(); - - if (!$domain) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht('%s is not a valid email.', $new_email), - nonempty(last($xactions), null)); - - $errors[] = $error; + switch ($xaction->getMetadataValue('edge:type')) { + case PhortuneMerchantHasMemberEdgeType::EDGECONST: + $new = $xaction->getNewValue(); + $set = idx($new, '-', array()); + $actor_phid = $this->requireActor()->getPHID(); + foreach ($set as $phid) { + if ($actor_phid == $phid) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + pht('You can not remove yourself as an merchant manager.'), + $xaction); + $errors[] = $error; + } + } + break; } } break; } - return $errors; } 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 @@ -12,12 +12,12 @@ PhabricatorPolicyInterface { protected $name; + protected $mailKey; private $memberPHIDs = self::ATTACHABLE; public static function initializeNewAccount(PhabricatorUser $actor) { $account = id(new PhortuneAccount()); - $account->memberPHIDs = array(); return $account; @@ -31,7 +31,7 @@ $xactions = array(); $xactions[] = id(new PhortuneAccountTransaction()) - ->setTransactionType(PhortuneAccountTransaction::TYPE_NAME) + ->setTransactionType(PhortuneAccountNameTransaction::TRANSACTIONTYPE) ->setNewValue(pht('Default Account')); $xactions[] = id(new PhortuneAccountTransaction()) @@ -78,6 +78,7 @@ self::CONFIG_AUX_PHID => true, self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'text255', + 'mailKey' => 'bytes20', ), ) + parent::getConfiguration(); } @@ -96,6 +97,17 @@ return $this; } + public function getViewURI() { + return '/phortune/'.$this->getID().'/'; + } + + public function save() { + if (!$this->getMailKey()) { + $this->setMailKey(Filesystem::readRandomCharacters(20)); + } + return parent::save(); + } + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/phortune/storage/PhortuneAccountTransaction.php b/src/applications/phortune/storage/PhortuneAccountTransaction.php --- a/src/applications/phortune/storage/PhortuneAccountTransaction.php +++ b/src/applications/phortune/storage/PhortuneAccountTransaction.php @@ -1,9 +1,9 @@ getAuthorPHID(); + public function getBaseTransactionClass() { + return 'PhortuneAccountTransactionType'; + } - $old = $this->getOldValue(); - $new = $this->getNewValue(); + public function getMailTags() { + $tags = parent::getMailTags(); switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this account.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this account from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } + case PhortuneAccountNameTransaction::TRANSACTIONTYPE: + case PhabricatorTransactions::TYPE_EDGE: + default: + $tags[] = self::MAILTAG_DETAILS; break; } - - return parent::getTitle(); + return $tags; } } 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 @@ -12,6 +12,7 @@ protected $invoiceEmail; protected $invoiceFooter; protected $profileImagePHID; + protected $mailKey; private $memberPHIDs = self::ATTACHABLE; private $profileImageFile = self::ATTACHABLE; @@ -35,6 +36,7 @@ 'invoiceEmail' => 'text255', 'invoiceFooter' => 'text', 'profileImagePHID' => 'phid?', + 'mailKey' => 'bytes20', ), ) + parent::getConfiguration(); } @@ -70,6 +72,14 @@ return $this->assertAttached($this->profileImageFile); } + public function save() { + if (!$this->getMailKey()) { + $this->setMailKey(Filesystem::readRandomCharacters(20)); + } + return parent::save(); + } + + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/phortune/storage/PhortuneMerchantTransaction.php b/src/applications/phortune/storage/PhortuneMerchantTransaction.php --- a/src/applications/phortune/storage/PhortuneMerchantTransaction.php +++ b/src/applications/phortune/storage/PhortuneMerchantTransaction.php @@ -1,14 +1,9 @@ getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this merchant.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this merchant from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for this merchant.', - $this->renderHandleLink($author_phid)); - case self::TYPE_CONTACTINFO: - return pht( - '%s updated the contact information for this merchant.', - $this->renderHandleLink($author_phid)); - case self::TYPE_INVOICEEMAIL: - return pht( - '%s updated the invoice email for this merchant.', - $this->renderHandleLink($author_phid)); - case self::TYPE_INVOICEFOOTER: - return pht( - '%s updated the invoice footer for this merchant.', - $this->renderHandleLink($author_phid)); - } - - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'PhortuneMerchantTransactionType'; } - public function shouldHide() { - $old = $this->getOldValue(); - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_CONTACTINFO: - case self::TYPE_INVOICEEMAIL: - case self::TYPE_INVOICEFOOTER: - return ($old === null); - } - return parent::shouldHide(); - } + public function getMailTags() { + $tags = parent::getMailTags(); - public function hasChangeDetails() { switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return ($this->getOldValue() !== null); - case self::TYPE_CONTACTINFO: - return ($this->getOldValue() !== null); - case self::TYPE_INVOICEEMAIL: - return ($this->getOldValue() !== null); - case self::TYPE_INVOICEFOOTER: - return ($this->getOldValue() !== null); + case PhortuneMerchantNameTransaction::TRANSACTIONTYPE: + case PhortuneMerchantDescriptionTransaction::TRANSACTIONTYPE: + case PhortuneMerchantContactInfoTransaction::TRANSACTIONTYPE: + case PhortuneMerchantInvoiceEmailTransaction::TRANSACTIONTYPE: + case PhortuneMerchantInvoiceFooterTransaction::TRANSACTIONTYPE: + case PhabricatorTransactions::TYPE_EDGE: + default: + $tags[] = self::MAILTAG_DETAILS; + break; } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); + return $tags; } } diff --git a/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php b/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneAccountNameTransaction.php @@ -0,0 +1,55 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if (strlen($old) && strlen($new)) { + return pht( + '%s renamed this account from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } else { + return pht( + '%s created this account.', + $this->renderAuthor()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Accounts must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newRequiredError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneAccountTransactionType.php b/src/applications/phortune/xaction/PhortuneAccountTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneAccountTransactionType.php @@ -0,0 +1,4 @@ +getContactInfo(); + } + + public function applyInternalEffects($object, $value) { + $object->setContactInfo($value); + } + + public function getTitle() { + return pht( + '%s updated the merchant contact info.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the merchant contact info for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO MERCHANT CONTACT INFO'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantDescriptionTransaction.php b/src/applications/phortune/xaction/PhortuneMerchantDescriptionTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantDescriptionTransaction.php @@ -0,0 +1,56 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the merchant description.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the merchant description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO MERCHANT DESCRIPTION'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantInvoiceEmailTransaction.php b/src/applications/phortune/xaction/PhortuneMerchantInvoiceEmailTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantInvoiceEmailTransaction.php @@ -0,0 +1,94 @@ +getInvoiceEmail(); + } + + public function applyInternalEffects($object, $value) { + $object->setInvoiceEmail($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if (strlen($old) && strlen($new)) { + return pht( + '%s updated the invoice email from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } else if (strlen($old)) { + return pht( + '%s removed the invoice email.', + $this->renderAuthor()); + } else { + return pht( + '%s set the invoice email to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if (strlen($old) && strlen($new)) { + return pht( + '%s updated %s invoice email from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } else if (strlen($old)) { + return pht( + '%s removed the invoice email for %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s set the invoice email for %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } + } + + public function getIcon() { + return 'fa-envelope'; + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = $object->getColumnMaximumByteLength('invoiceEmail'); + foreach ($xactions as $xaction) { + if ($xaction->getNewValue()) { + $email = new PhutilEmailAddress($xaction->getNewValue()); + $domain = $email->getDomainName(); + if (!$domain) { + $errors[] = $this->newRequiredError( + pht('Invoice email "%s" must be a valid email.', + $xaction->getNewValue())); + } + + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newRequiredError( + pht('The email can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + } + + return $errors; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantInvoiceFooterTransaction.php b/src/applications/phortune/xaction/PhortuneMerchantInvoiceFooterTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantInvoiceFooterTransaction.php @@ -0,0 +1,56 @@ +getInvoiceFooter(); + } + + public function applyInternalEffects($object, $value) { + $object->setInvoiceFooter($value); + } + + public function getTitle() { + return pht( + '%s updated the merchant invoice footer.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the merchant invoice footer for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO MERCHANT INVOICE FOOTER'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantNameTransaction.php b/src/applications/phortune/xaction/PhortuneMerchantNameTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantNameTransaction.php @@ -0,0 +1,55 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this merchant from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed %s merchant name from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Merchants must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newRequiredError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantPictureTransaction.php b/src/applications/phortune/xaction/PhortuneMerchantPictureTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantPictureTransaction.php @@ -0,0 +1,33 @@ +getProfileImagePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setProfileImagePHID($value); + } + + public function getTitle() { + return pht( + '%s updated the picture.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the picture for merchant %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-camera-retro'; + } + +} diff --git a/src/applications/phortune/xaction/PhortuneMerchantTransactionType.php b/src/applications/phortune/xaction/PhortuneMerchantTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/phortune/xaction/PhortuneMerchantTransactionType.php @@ -0,0 +1,4 @@ + '%s accepted this revision as: %3$s.', + + '%s added %s account manager(s): %s.' => array( + array( + '%s added an account manager: %3$s.', + '%s added account managers: %3$s.', + ), + ), + + '%s removed %s account manager(s): %s.' => array( + array( + '%s removed an account manager: %3$s.', + '%s removed account managers: %3$s.', + ), + ), + + '%s added %s merchant manager(s): %s.' => array( + array( + '%s added a merchant manager: %3$s.', + '%s added merchant managers: %3$s.', + ), + ), + + '%s removed %s merchant manager(s): %s.' => array( + array( + '%s removed a merchant manager: %3$s.', + '%s removed merchant managers: %3$s.', + ), + ), + + ); }