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 @@ -1124,29 +1124,40 @@ 'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php', 'FundBackerProduct' => 'applications/fund/phortune/FundBackerProduct.php', 'FundBackerQuery' => 'applications/fund/query/FundBackerQuery.php', + 'FundBackerRefundTransaction' => 'applications/fund/xaction/FundBackerRefundTransaction.php', 'FundBackerSearchEngine' => 'applications/fund/query/FundBackerSearchEngine.php', + 'FundBackerStatusTransaction' => 'applications/fund/xaction/FundBackerStatusTransaction.php', 'FundBackerTransaction' => 'applications/fund/storage/FundBackerTransaction.php', 'FundBackerTransactionQuery' => 'applications/fund/query/FundBackerTransactionQuery.php', + 'FundBackerTransactionType' => 'applications/fund/xaction/FundBackerTransactionType.php', 'FundController' => 'applications/fund/controller/FundController.php', 'FundCreateInitiativesCapability' => 'applications/fund/capability/FundCreateInitiativesCapability.php', 'FundDAO' => 'applications/fund/storage/FundDAO.php', 'FundDefaultViewCapability' => 'applications/fund/capability/FundDefaultViewCapability.php', 'FundInitiative' => 'applications/fund/storage/FundInitiative.php', 'FundInitiativeBackController' => 'applications/fund/controller/FundInitiativeBackController.php', + 'FundInitiativeBackerTransaction' => 'applications/fund/xaction/FundInitiativeBackerTransaction.php', 'FundInitiativeCloseController' => 'applications/fund/controller/FundInitiativeCloseController.php', 'FundInitiativeCommentController' => 'applications/fund/controller/FundInitiativeCommentController.php', + 'FundInitiativeDescriptionTransaction' => 'applications/fund/xaction/FundInitiativeDescriptionTransaction.php', 'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php', 'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php', 'FundInitiativeFulltextEngine' => 'applications/fund/search/FundInitiativeFulltextEngine.php', 'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php', + 'FundInitiativeMerchantTransaction' => 'applications/fund/xaction/FundInitiativeMerchantTransaction.php', + 'FundInitiativeNameTransaction' => 'applications/fund/xaction/FundInitiativeNameTransaction.php', 'FundInitiativePHIDType' => 'applications/fund/phid/FundInitiativePHIDType.php', 'FundInitiativeQuery' => 'applications/fund/query/FundInitiativeQuery.php', + 'FundInitiativeRefundTransaction' => 'applications/fund/xaction/FundInitiativeRefundTransaction.php', 'FundInitiativeRemarkupRule' => 'applications/fund/remarkup/FundInitiativeRemarkupRule.php', 'FundInitiativeReplyHandler' => 'applications/fund/mail/FundInitiativeReplyHandler.php', + 'FundInitiativeRisksTransaction' => 'applications/fund/xaction/FundInitiativeRisksTransaction.php', 'FundInitiativeSearchEngine' => 'applications/fund/query/FundInitiativeSearchEngine.php', + 'FundInitiativeStatusTransaction' => 'applications/fund/xaction/FundInitiativeStatusTransaction.php', 'FundInitiativeTransaction' => 'applications/fund/storage/FundInitiativeTransaction.php', 'FundInitiativeTransactionComment' => 'applications/fund/storage/FundInitiativeTransactionComment.php', 'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php', + 'FundInitiativeTransactionType' => 'applications/fund/xaction/FundInitiativeTransactionType.php', 'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php', 'FundSchemaSpec' => 'applications/fund/storage/FundSchemaSpec.php', 'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php', @@ -6066,9 +6077,12 @@ 'FundBackerPHIDType' => 'PhabricatorPHIDType', 'FundBackerProduct' => 'PhortuneProductImplementation', 'FundBackerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'FundBackerRefundTransaction' => 'FundBackerTransactionType', 'FundBackerSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'FundBackerTransaction' => 'PhabricatorApplicationTransaction', + 'FundBackerStatusTransaction' => 'FundBackerTransactionType', + 'FundBackerTransaction' => 'PhabricatorModularTransaction', 'FundBackerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'FundBackerTransactionType' => 'PhabricatorModularTransactionType', 'FundController' => 'PhabricatorController', 'FundCreateInitiativesCapability' => 'PhabricatorPolicyCapability', 'FundDAO' => 'PhabricatorLiskDAO', @@ -6086,20 +6100,28 @@ 'PhabricatorFulltextInterface', ), 'FundInitiativeBackController' => 'FundController', + 'FundInitiativeBackerTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeCloseController' => 'FundController', 'FundInitiativeCommentController' => 'FundController', + 'FundInitiativeDescriptionTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeEditController' => 'FundController', 'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor', 'FundInitiativeFulltextEngine' => 'PhabricatorFulltextEngine', 'FundInitiativeListController' => 'FundController', + 'FundInitiativeMerchantTransaction' => 'FundInitiativeTransactionType', + 'FundInitiativeNameTransaction' => 'FundInitiativeTransactionType', 'FundInitiativePHIDType' => 'PhabricatorPHIDType', 'FundInitiativeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'FundInitiativeRefundTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'FundInitiativeReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'FundInitiativeRisksTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'FundInitiativeTransaction' => 'PhabricatorApplicationTransaction', + 'FundInitiativeStatusTransaction' => 'FundInitiativeTransactionType', + 'FundInitiativeTransaction' => 'PhabricatorModularTransaction', 'FundInitiativeTransactionComment' => 'PhabricatorApplicationTransactionComment', 'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'FundInitiativeTransactionType' => 'PhabricatorModularTransactionType', 'FundInitiativeViewController' => 'FundController', 'FundSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation', diff --git a/src/applications/fund/controller/FundInitiativeBackController.php b/src/applications/fund/controller/FundInitiativeBackController.php --- a/src/applications/fund/controller/FundInitiativeBackController.php +++ b/src/applications/fund/controller/FundInitiativeBackController.php @@ -96,7 +96,7 @@ $xactions = array(); $xactions[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) ->setNewValue(FundBacker::STATUS_IN_CART); $editor = id(new FundBackerEditor()) diff --git a/src/applications/fund/controller/FundInitiativeCloseController.php b/src/applications/fund/controller/FundInitiativeCloseController.php --- a/src/applications/fund/controller/FundInitiativeCloseController.php +++ b/src/applications/fund/controller/FundInitiativeCloseController.php @@ -25,7 +25,7 @@ $is_close = !$initiative->isClosed(); if ($request->isFormPost()) { - $type_status = FundInitiativeTransaction::TYPE_STATUS; + $type_status = FundInitiativeStatusTransaction::TRANSACTIONTYPE; if ($is_close) { $new_status = FundInitiative::STATUS_CLOSED; diff --git a/src/applications/fund/controller/FundInitiativeEditController.php b/src/applications/fund/controller/FundInitiativeEditController.php --- a/src/applications/fund/controller/FundInitiativeEditController.php +++ b/src/applications/fund/controller/FundInitiativeEditController.php @@ -68,10 +68,10 @@ $v_merchant = $request->getStr('merchantPHID'); $v_projects = $request->getArr('projects'); - $type_name = FundInitiativeTransaction::TYPE_NAME; - $type_desc = FundInitiativeTransaction::TYPE_DESCRIPTION; - $type_risk = FundInitiativeTransaction::TYPE_RISKS; - $type_merchant = FundInitiativeTransaction::TYPE_MERCHANT; + $type_name = FundInitiativeNameTransaction::TRANSACTIONTYPE; + $type_desc = FundInitiativeDescriptionTransaction::TRANSACTIONTYPE; + $type_risk = FundInitiativeRisksTransaction::TRANSACTIONTYPE; + $type_merchant = FundInitiativeMerchantTransaction::TRANSACTIONTYPE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; diff --git a/src/applications/fund/controller/FundInitiativeViewController.php b/src/applications/fund/controller/FundInitiativeViewController.php --- a/src/applications/fund/controller/FundInitiativeViewController.php +++ b/src/applications/fund/controller/FundInitiativeViewController.php @@ -29,8 +29,8 @@ $initiative->getName()); if ($initiative->isClosed()) { - $status_icon = 'fa-times'; - $status_color = 'bluegrey'; + $status_icon = 'fa-ban'; + $status_color = 'indigo'; } else { $status_icon = 'fa-check'; $status_color = 'bluegrey'; diff --git a/src/applications/fund/editor/FundBackerEditor.php b/src/applications/fund/editor/FundBackerEditor.php --- a/src/applications/fund/editor/FundBackerEditor.php +++ b/src/applications/fund/editor/FundBackerEditor.php @@ -11,67 +11,4 @@ return pht('Fund Backing'); } - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = FundBackerTransaction::TYPE_STATUS; - $types[] = FundBackerTransaction::TYPE_REFUND; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - return $object->getStatus(); - case FundBackerTransaction::TYPE_REFUND: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - case FundBackerTransaction::TYPE_REFUND: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - return; - case FundBackerTransaction::TYPE_REFUND: - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - case FundBackerTransaction::TYPE_REFUND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - } diff --git a/src/applications/fund/editor/FundInitiativeEditor.php b/src/applications/fund/editor/FundInitiativeEditor.php --- a/src/applications/fund/editor/FundInitiativeEditor.php +++ b/src/applications/fund/editor/FundInitiativeEditor.php @@ -11,16 +11,16 @@ return pht('Fund Initiatives'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this initiative.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); - - $types[] = FundInitiativeTransaction::TYPE_NAME; - $types[] = FundInitiativeTransaction::TYPE_DESCRIPTION; - $types[] = FundInitiativeTransaction::TYPE_RISKS; - $types[] = FundInitiativeTransaction::TYPE_STATUS; - $types[] = FundInitiativeTransaction::TYPE_BACKER; - $types[] = FundInitiativeTransaction::TYPE_REFUND; - $types[] = FundInitiativeTransaction::TYPE_MERCHANT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_COMMENT; @@ -28,204 +28,6 @@ return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case FundInitiativeTransaction::TYPE_NAME: - return $object->getName(); - case FundInitiativeTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case FundInitiativeTransaction::TYPE_RISKS: - return $object->getRisks(); - case FundInitiativeTransaction::TYPE_STATUS: - return $object->getStatus(); - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - return null; - case FundInitiativeTransaction::TYPE_MERCHANT: - return $object->getMerchantPHID(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundInitiativeTransaction::TYPE_NAME: - case FundInitiativeTransaction::TYPE_DESCRIPTION: - case FundInitiativeTransaction::TYPE_RISKS: - case FundInitiativeTransaction::TYPE_STATUS: - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - case FundInitiativeTransaction::TYPE_MERCHANT: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $type = $xaction->getTransactionType(); - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_RISKS: - $object->setRisks($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_MERCHANT: - $object->setMerchantPHID($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - $amount = $xaction->getMetadataValue( - FundInitiativeTransaction::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - if ($type == FundInitiativeTransaction::TYPE_REFUND) { - $total = $object->getTotalAsCurrency()->subtract($amount); - } else { - $total = $object->getTotalAsCurrency()->add($amount); - } - - $object->setTotalAsCurrency($total); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $type = $xaction->getTransactionType(); - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - case FundInitiativeTransaction::TYPE_DESCRIPTION: - case FundInitiativeTransaction::TYPE_RISKS: - case FundInitiativeTransaction::TYPE_STATUS: - case FundInitiativeTransaction::TYPE_MERCHANT: - return; - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - $backer = id(new FundBackerQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($xaction->getNewValue())) - ->executeOne(); - if (!$backer) { - throw new Exception(pht('Unable to load %s!', 'FundBacker')); - } - - $subx = array(); - - if ($type == FundInitiativeTransaction::TYPE_BACKER) { - $subx[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) - ->setNewValue(FundBacker::STATUS_PURCHASED); - } else { - $amount = $xaction->getMetadataValue( - FundInitiativeTransaction::PROPERTY_AMOUNT); - $subx[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) - ->setNewValue($amount); - } - - $editor = id(new FundBackerEditor()) - ->setActor($this->requireActor()) - ->setContentSource($this->getContentSource()) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true); - - $editor->applyTransactions($backer, $subx); - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Initiative name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case FundInitiativeTransaction::TYPE_MERCHANT: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Payable merchant is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } else if ($xactions) { - $merchant_phid = last($xactions)->getNewValue(); - - // Make sure the actor has permission to edit the merchant they're - // selecting. You aren't allowed to send payments to an account you - // do not control. - $merchants = id(new PhortuneMerchantQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($merchant_phid)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->execute(); - if (!$merchants) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'You must specify a merchant account you control as the '. - 'recipient of funds from this initiative.'), - last($xactions)); - $errors[] = $error; - } - } - break; - } - - return $errors; - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/fund/phortune/FundBackerProduct.php b/src/applications/fund/phortune/FundBackerProduct.php --- a/src/applications/fund/phortune/FundBackerProduct.php +++ b/src/applications/fund/phortune/FundBackerProduct.php @@ -105,7 +105,7 @@ $xactions = array(); $xactions[] = id(new FundInitiativeTransaction()) - ->setTransactionType(FundInitiativeTransaction::TYPE_BACKER) + ->setTransactionType(FundInitiativeBackerTransaction::TRANSACTIONTYPE) ->setMetadataValue( FundInitiativeTransaction::PROPERTY_AMOUNT, $backer->getAmountAsCurrency()->serializeForStorage()) @@ -134,7 +134,7 @@ $xactions = array(); $xactions[] = id(new FundInitiativeTransaction()) - ->setTransactionType(FundInitiativeTransaction::TYPE_REFUND) + ->setTransactionType(FundInitiativeRefundTransaction::TRANSACTIONTYPE) ->setMetadataValue( FundInitiativeTransaction::PROPERTY_AMOUNT, $amount->serializeForStorage()) diff --git a/src/applications/fund/storage/FundBackerTransaction.php b/src/applications/fund/storage/FundBackerTransaction.php --- a/src/applications/fund/storage/FundBackerTransaction.php +++ b/src/applications/fund/storage/FundBackerTransaction.php @@ -1,10 +1,7 @@ getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_MERCHANT: - if ($old) { - $phids[] = $old; - } - if ($new) { - $phids[] = $new; - } - break; - case self::TYPE_REFUND: - $phids[] = $this->getMetadataValue(self::PROPERTY_BACKER); - break; - } - - return $phids; - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this initiative.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this initiative from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - break; - case self::TYPE_RISKS: - return pht( - '%s edited the risks for this initiative.', - $this->renderHandleLink($author_phid)); - case self::TYPE_DESCRIPTION: - return pht( - '%s edited the description of this initiative.', - $this->renderHandleLink($author_phid)); - case self::TYPE_STATUS: - switch ($new) { - case FundInitiative::STATUS_OPEN: - return pht( - '%s reopened this initiative.', - $this->renderHandleLink($author_phid)); - case FundInitiative::STATUS_CLOSED: - return pht( - '%s closed this initiative.', - $this->renderHandleLink($author_phid)); - } - break; - case self::TYPE_BACKER: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - return pht( - '%s backed this initiative with %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay()); - case self::TYPE_REFUND: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - $backer_phid = $this->getMetadataValue(self::PROPERTY_BACKER); - - return pht( - '%s refunded %s to %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay(), - $this->renderHandleLink($backer_phid)); - case self::TYPE_MERCHANT: - if ($old === null) { - return pht( - '%s set this initiative to pay to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - } else { - return pht( - '%s changed the merchant receiving funds from this '. - 'initiative from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s renamed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_STATUS: - switch ($new) { - case FundInitiative::STATUS_OPEN: - return pht( - '%s reopened %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case FundInitiative::STATUS_CLOSED: - return pht( - '%s closed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_BACKER: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - return pht( - '%s backed %s with %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $amount->formatForDisplay()); - case self::TYPE_REFUND: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - $backer_phid = $this->getMetadataValue(self::PROPERTY_BACKER); - - return pht( - '%s refunded %s to %s for %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay(), - $this->renderHandleLink($backer_phid), - $this->renderHandleLink($object_phid)); - } - - return parent::getTitleForFeed(); + public function getBaseTransactionClass() { + return 'FundInitiativeTransactionType'; } public function getMailTags() { @@ -219,31 +45,4 @@ return $tags; } - - public function shouldHide() { - $old = $this->getOldValue(); - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_RISKS: - return ($old === null); - } - return parent::shouldHide(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_RISKS: - return ($this->getOldValue() !== null); - } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); - } } diff --git a/src/applications/fund/xaction/FundBackerRefundTransaction.php b/src/applications/fund/xaction/FundBackerRefundTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundBackerRefundTransaction.php @@ -0,0 +1,13 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + +} diff --git a/src/applications/fund/xaction/FundBackerTransactionType.php b/src/applications/fund/xaction/FundBackerTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundBackerTransactionType.php @@ -0,0 +1,4 @@ +getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $total = $object->getTotalAsCurrency()->add($amount); + $object->setTotalAsCurrency($total); + } + + public function applyExternalEffects($object, $value) { + $backer = id(new FundBackerQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($value)) + ->executeOne(); + if (!$backer) { + throw new Exception(pht('Unable to load %s!', 'FundBacker')); + } + + $subx = array(); + $subx[] = id(new FundBackerTransaction()) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) + ->setNewValue(FundBacker::STATUS_PURCHASED); + + $content_source = $this->getEditor()->getContentSource(); + + $editor = id(new FundBackerEditor()) + ->setActor($this->getActor()) + ->setContentSource($content_source) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($backer, $subx); + } + + public function getTitle() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + return pht( + '%s backed this initiative with %s.', + $this->renderAuthor(), + $amount->formatForDisplay()); + } + + public function getTitleForFeed() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + return pht( + '%s backed %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-heart'; + } + + public function getColor() { + return 'red'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php b/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php @@ -0,0 +1,75 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function shouldHide() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + if (!strlen($old) && !strlen($new)) { + return true; + } + return false; + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s set the initiative description.', + $this->renderAuthor()); + } else { + return pht( + '%s updated the initiative description.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + return pht( + '%s updated the initiative description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO INITIATIVE 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/fund/xaction/FundInitiativeMerchantTransaction.php b/src/applications/fund/xaction/FundInitiativeMerchantTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeMerchantTransaction.php @@ -0,0 +1,93 @@ +getMerchantPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setMerchantPHID($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + $new_merchant = $this->renderHandleList(array($new)); + + $old = $this->getOldValue(); + $old_merchant = $this->renderHandleList(array($old)); + + if ($old) { + return pht( + '%s changed the merchant receiving funds from this '. + 'initiative from %s to %s.', + $this->renderAuthor(), + $old_merchant, + $new_merchant); + } else { + return pht( + '%s set the merchant receiving funds from this '. + 'initiative to %s.', + $this->renderAuthor(), + $new_merchant); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + $new_merchant = $this->renderHandleList(array($new)); + + $old = $this->getOldValue(); + $old_merchant = $this->renderHandleList(array($old)); + + return pht( + '%s changed the merchant receiving funds from %s '. + 'initiative from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $old_merchant, + $new_merchant); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getMerchantPHID(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Initiatives must have a payable merchant.')); + } + + foreach ($xactions as $xaction) { + $merchant_phid = $xaction->getNewValue(); + + // Make sure the actor has permission to edit the merchant they're + // selecting. You aren't allowed to send payments to an account you + // do not control. + $merchants = id(new PhortuneMerchantQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($merchant_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->execute(); + if (!$merchants) { + $errors[] = $this->newInvalidError( + pht('You must specify a merchant account you control as the '. + 'recipient of funds from this initiative.')); + } + } + + return $errors; + } + + public function getIcon() { + return 'fa-bank'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeNameTransaction.php b/src/applications/fund/xaction/FundInitiativeNameTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeNameTransaction.php @@ -0,0 +1,71 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created this initiative.', + $this->renderAuthor()); + } else { + return pht( + '%s renamed this initiative from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s renamed %s initiative 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('Initiatives 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->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeRefundTransaction.php b/src/applications/fund/xaction/FundInitiativeRefundTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeRefundTransaction.php @@ -0,0 +1,77 @@ +getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $total = $object->getTotalAsCurrency()->subtract($amount); + $object->setTotalAsCurrency($total); + } + + public function applyExternalEffects($object, $value) { + $backer = id(new FundBackerQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($value)) + ->executeOne(); + if (!$backer) { + throw new Exception(pht('Unable to load %s!', 'FundBacker')); + } + + $subx = array(); + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $subx[] = id(new FundBackerTransaction()) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) + ->setNewValue($amount); + + $content_source = $this->getEditor()->getContentSource(); + + $editor = id(new FundBackerEditor()) + ->setActor($this->getActor()) + ->setContentSource($content_source) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($backer, $subx); + } + + public function getTitle() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $backer_phid = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_BACKER); + + return pht( + '%s refunded %s to %s.', + $this->renderAuthor(), + $amount->formatForDisplay(), + $this->renderHandleLink($backer_phid)); + } + + public function getTitleForFeed() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $backer_phid = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_BACKER); + + return pht( + '%s refunded %s to %s for %s.', + $this->renderAuthor(), + $amount->formatForDisplay(), + $this->renderHandleLink($backer_phid), + $this->renderObject()); + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeRisksTransaction.php b/src/applications/fund/xaction/FundInitiativeRisksTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeRisksTransaction.php @@ -0,0 +1,80 @@ +getRisks(); + } + + public function applyInternalEffects($object, $value) { + $object->setRisks($value); + } + + public function shouldHide() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + if (!strlen($old) && !strlen($new)) { + return true; + } + return false; + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s set the initiative risks/challenges.', + $this->renderAuthor()); + } else { + return pht( + '%s updated the initiative risks/challenges.', + $this->renderAuthor()); + } + + } + + public function getTitleForFeed() { + return pht( + '%s updated the initiative risks/challenges for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO INITIATIVE RISKS/CHALLENGES'); + } + + 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; + } + + public function getIcon() { + return 'fa-ambulance'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeStatusTransaction.php b/src/applications/fund/xaction/FundInitiativeStatusTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeStatusTransaction.php @@ -0,0 +1,51 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return pht( + '%s closed this initiative.', + $this->renderAuthor()); + } else { + return pht( + '%s reopened this initiative.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return pht( + '%s closed the initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s reopened the initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return 'fa-ban'; + } else { + return 'fa-check'; + } + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeTransactionType.php b/src/applications/fund/xaction/FundInitiativeTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeTransactionType.php @@ -0,0 +1,4 @@ +