@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add basic payment providers to Phortune

Summary: Abstract out the Stripiness of payment providers so we can add a Test provider (and maybe MtGox / Balanced / Paypal / etc). Ref T2787.

Test Plan: Ran unit tests.

Reviewers: btrahan, chad

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2787

Differential Revision: https://secure.phabricator.com/D5752

+225 -4
+13
src/__phutil_library_map__.php
··· 1586 1586 'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php', 1587 1587 'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php', 1588 1588 'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php', 1589 + 'PhortuneMultiplePaymentProvidersException' => 'applications/phortune/exception/PhortuneMultiplePaymentProvidersException.php', 1590 + 'PhortuneNoPaymentProviderException' => 'applications/phortune/exception/PhortuneNoPaymentProviderException.php', 1589 1591 'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php', 1590 1592 'PhortunePaymentMethodEditController' => 'applications/phortune/controller/PhortunePaymentMethodEditController.php', 1591 1593 'PhortunePaymentMethodListController' => 'applications/phortune/controller/PhortunePaymentMethodListController.php', 1592 1594 'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php', 1593 1595 'PhortunePaymentMethodViewController' => 'applications/phortune/controller/PhortunePaymentMethodViewController.php', 1596 + 'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php', 1597 + 'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php', 1594 1598 'PhortuneProduct' => 'applications/phortune/storage/PhortuneProduct.php', 1595 1599 'PhortuneProductEditController' => 'applications/phortune/controller/PhortuneProductEditController.php', 1596 1600 'PhortuneProductEditor' => 'applications/phortune/editor/PhortuneProductEditor.php', ··· 1601 1605 'PhortuneProductViewController' => 'applications/phortune/controller/PhortuneProductViewController.php', 1602 1606 'PhortunePurchase' => 'applications/phortune/storage/PhortunePurchase.php', 1603 1607 'PhortuneStripePaymentFormView' => 'applications/phortune/view/PhortuneStripePaymentFormView.php', 1608 + 'PhortuneStripePaymentProvider' => 'applications/phortune/provider/PhortuneStripePaymentProvider.php', 1609 + 'PhortuneTestExtraPaymentProvider' => 'applications/phortune/provider/__tests__/PhortuneTestExtraPaymentProvider.php', 1610 + 'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php', 1604 1611 'PhortuneUtil' => 'applications/phortune/util/PhortuneUtil.php', 1605 1612 'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php', 1606 1613 'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php', ··· 3300 3307 'PhortuneDAO' => 'PhabricatorLiskDAO', 3301 3308 'PhortuneLandingController' => 'PhortuneController', 3302 3309 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 3310 + 'PhortuneMultiplePaymentProvidersException' => 'Exception', 3311 + 'PhortuneNoPaymentProviderException' => 'Exception', 3303 3312 'PhortunePaymentMethod' => 3304 3313 array( 3305 3314 0 => 'PhortuneDAO', ··· 3309 3318 'PhortunePaymentMethodListController' => 'PhabricatorController', 3310 3319 'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3311 3320 'PhortunePaymentMethodViewController' => 'PhabricatorController', 3321 + 'PhortunePaymentProviderTestCase' => 'PhabricatorTestCase', 3312 3322 'PhortuneProduct' => 3313 3323 array( 3314 3324 0 => 'PhortuneDAO', ··· 3323 3333 'PhortuneProductViewController' => 'PhortuneController', 3324 3334 'PhortunePurchase' => 'PhortuneDAO', 3325 3335 'PhortuneStripePaymentFormView' => 'AphrontView', 3336 + 'PhortuneStripePaymentProvider' => 'PhortunePaymentProvider', 3337 + 'PhortuneTestExtraPaymentProvider' => 'PhortunePaymentProvider', 3338 + 'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider', 3326 3339 'PhrequentController' => 'PhabricatorController', 3327 3340 'PhrequentDAO' => 'PhabricatorLiskDAO', 3328 3341 'PhrequentListController' => 'PhrequentController',
+2 -2
src/applications/phortune/controller/PhortunePaymentMethodEditController.php
··· 96 96 ->setMetadata( 97 97 array( 98 98 'type' => 'stripe.customer', 99 - 'stripeCustomerID' => $customer->id, 100 - 'stripeTokenID' => $stripe_token, 99 + 'stripe.customerID' => $customer->id, 100 + 'stripe.tokenID' => $stripe_token, 101 101 )) 102 102 ->save(); 103 103
+23
src/applications/phortune/exception/PhortuneMultiplePaymentProvidersException.php
··· 1 + <?php 2 + 3 + final class PhortuneMultiplePaymentProvidersException extends Exception { 4 + 5 + public function __construct(PhortunePaymentMethod $method, array $providers) { 6 + assert_instances_of($providers, 'PhortunePaymentProvider'); 7 + $type = $method->getMetadataValue('type'); 8 + 9 + $provider_names = array(); 10 + foreach ($providers as $provider) { 11 + $provider_names[] = get_class($provider); 12 + } 13 + 14 + return parent::__construct( 15 + "More than one payment provider can handle charging payments for this ". 16 + "payment method. This is ambiguous and likely indicates that a payment ". 17 + "provider is not properly implemented. You may be able to use a ". 18 + "different payment method to complete this transaction. The payment ". 19 + "method type is '{$type}'. The providers claiming to handle it are: ". 20 + implode(', ', $provider_names).'.'); 21 + } 22 + 23 + }
+14
src/applications/phortune/exception/PhortuneNoPaymentProviderException.php
··· 1 + <?php 2 + 3 + final class PhortuneNoPaymentProviderException extends Exception { 4 + 5 + public function __construct(PhortunePaymentMethod $method) { 6 + $type = $method->getMetadataValue('type'); 7 + 8 + return parent::__construct( 9 + "No available payment provider can handle charging payments for this ". 10 + "payment method. You may be able to use a different payment method to ". 11 + "complete this transaction. The payment method type is '{$type}'."); 12 + } 13 + 14 + }
+18
src/applications/phortune/provider/PhortunePaymentProvider.php
··· 1 + <?php 2 + 3 + abstract class PhortunePaymentProvider { 4 + 5 + /** 6 + * Determine of a provider can handle a payment method. 7 + * 8 + * @return bool True if this provider can apply charges to the payment 9 + * method. 10 + */ 11 + abstract public function canHandlePaymentMethod( 12 + PhortunePaymentMethod $method); 13 + 14 + abstract protected function executeCharge( 15 + PhortunePaymentMethod $payment_method, 16 + PhortuneCharge $charge); 17 + 18 + }
+39
src/applications/phortune/provider/PhortuneStripePaymentProvider.php
··· 1 + <?php 2 + 3 + final class PhortuneStripePaymentProvider extends PhortunePaymentProvider { 4 + 5 + public function canHandlePaymentMethod(PhortunePaymentMethod $method) { 6 + $type = $method->getMetadataValue('type'); 7 + return ($type === 'stripe.customer'); 8 + } 9 + 10 + /** 11 + * @phutil-external-symbol class Stripe_Charge 12 + */ 13 + protected function executeCharge( 14 + PhortunePaymentMethod $method, 15 + PhortuneCharge $charge) { 16 + 17 + $secret_key = $this->getSecretKey(); 18 + $params = array( 19 + 'amount' => $charge->getAmountInCents(), 20 + 'currency' => 'usd', 21 + 'customer' => $method->getMetadataValue('stripe.customerID'), 22 + 'description' => $charge->getPHID(), 23 + 'capture' => true, 24 + ); 25 + 26 + $stripe_charge = Stripe_Charge::create($params, $secret_key); 27 + $id = $stripe_charge->id; 28 + if (!$id) { 29 + throw new Exception("Stripe charge call did not return an ID!"); 30 + } 31 + 32 + $charge->setMetadataValue('stripe.chargeID', $id); 33 + } 34 + 35 + private function getSecretKey() { 36 + return PhabricatorEnv::getEnvConfig('stripe.secret-key'); 37 + } 38 + 39 + }
+16
src/applications/phortune/provider/PhortuneTestPaymentProvider.php
··· 1 + <?php 2 + 3 + final class PhortuneTestPaymentProvider extends PhortunePaymentProvider { 4 + 5 + public function canHandlePaymentMethod(PhortunePaymentMethod $method) { 6 + $type = $method->getMetadataValue('type'); 7 + return ($type === 'test.cash' || $type === 'test.multiple'); 8 + } 9 + 10 + protected function executeCharge( 11 + PhortunePaymentMethod $payment_method, 12 + PhortuneCharge $charge) { 13 + return; 14 + } 15 + 16 + }
+47
src/applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php
··· 1 + <?php 2 + 3 + final class PhortunePaymentProviderTestCase extends PhabricatorTestCase { 4 + 5 + public function getPhabricatorTestCaseConfiguration() { 6 + return array( 7 + self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, 8 + ); 9 + } 10 + 11 + public function testNoPaymentProvider() { 12 + $method = id(new PhortunePaymentMethod()) 13 + ->setMetadataValue('type', 'hugs'); 14 + 15 + $caught = null; 16 + try { 17 + $provider = $method->buildPaymentProvider(); 18 + } catch (Exception $ex) { 19 + $caught = $ex; 20 + } 21 + 22 + $this->assertEqual( 23 + true, 24 + ($caught instanceof PhortuneNoPaymentProviderException), 25 + 'No provider should accept hugs; they are not a currency.'); 26 + } 27 + 28 + public function testMultiplePaymentProviders() { 29 + $method = id(new PhortunePaymentMethod()) 30 + ->setMetadataValue('type', 'test.multiple'); 31 + 32 + $caught = null; 33 + try { 34 + $provider = $method->buildPaymentProvider(); 35 + } catch (Exception $ex) { 36 + $caught = $ex; 37 + } 38 + 39 + $this->assertEqual( 40 + true, 41 + ($caught instanceof PhortuneMultiplePaymentProvidersException), 42 + 'Expect exception when more than one provider handles a payment method.'); 43 + } 44 + 45 + 46 + 47 + }
+16
src/applications/phortune/provider/__tests__/PhortuneTestExtraPaymentProvider.php
··· 1 + <?php 2 + 3 + final class PhortuneTestExtraPaymentProvider extends PhortunePaymentProvider { 4 + 5 + public function canHandlePaymentMethod(PhortunePaymentMethod $method) { 6 + $type = $method->getMetadataValue('type'); 7 + return ($type === 'test.multiple'); 8 + } 9 + 10 + protected function executeCharge( 11 + PhortunePaymentMethod $payment_method, 12 + PhortuneCharge $charge) { 13 + return; 14 + } 15 + 16 + }
+2 -1
src/applications/phortune/storage/PhortuneCharge.php
··· 11 11 12 12 const STATUS_PENDING = 'charge:pending'; 13 13 const STATUS_AUTHORIZED = 'charge:authorized'; 14 + const STATUS_CHARGING = 'charge:charging'; 14 15 const STATUS_CHARGED = 'charge:charged'; 15 16 const STATUS_FAILED = 'charge:failed'; 16 17 ··· 19 20 protected $paymentMethodPHID; 20 21 protected $amountInCents; 21 22 protected $status; 22 - protected $metadata; 23 + protected $metadata = array(); 23 24 24 25 public function getConfiguration() { 25 26 return array(
+35 -1
src/applications/phortune/storage/PhortunePaymentMethod.php
··· 16 16 protected $accountPHID; 17 17 protected $authorPHID; 18 18 protected $expiresEpoch; 19 - protected $metadata; 19 + protected $metadata = array(); 20 20 21 21 private $account; 22 22 ··· 48 48 49 49 public function getDescription() { 50 50 return pht('Expires %s', date('m/y'), $this->getExpiresEpoch()); 51 + } 52 + 53 + public function getMetadataValue($key, $default = null) { 54 + return idx($this->getMetadata(), $key, $default); 55 + } 56 + 57 + public function setMetadataValue($key, $value) { 58 + $this->metadata[$key] = $value; 59 + return $this; 60 + } 61 + 62 + public function buildPaymentProvider() { 63 + $providers = id(new PhutilSymbolLoader()) 64 + ->setAncestorClass('PhortunePaymentProvider') 65 + ->setConcreteOnly(true) 66 + ->selectAndLoadSymbols(); 67 + 68 + $accept = array(); 69 + foreach ($providers as $provider) { 70 + $obj = newv($provider['name'], array()); 71 + if ($obj->canHandlePaymentMethod($this)) { 72 + $accept[] = $obj; 73 + } 74 + } 75 + 76 + if (!$accept) { 77 + throw new PhortuneNoPaymentProviderException($this); 78 + } 79 + 80 + if (count($accept) > 1) { 81 + throw new PhortuneMultiplePaymentProvidersException($this, $accept); 82 + } 83 + 84 + return head($accept); 51 85 } 52 86 53 87