Page MenuHomePhabricator

D10670.diff
No OneTemporary

D10670.diff

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
@@ -79,6 +79,8 @@
public function didPurchaseProduct(
PhortuneProduct $product,
PhortunePurchase $purchase) {
+ // TODO: This viewer may be wrong if the purchase completes after a hold
+ // we should load the backer explicitly.
$viewer = $this->getViewer();
$backer = id(new FundBackerQuery())
diff --git a/src/applications/phortune/controller/PhortuneAccountViewController.php b/src/applications/phortune/controller/PhortuneAccountViewController.php
--- a/src/applications/phortune/controller/PhortuneAccountViewController.php
+++ b/src/applications/phortune/controller/PhortuneAccountViewController.php
@@ -169,6 +169,8 @@
->withStatuses(
array(
PhortuneCart::STATUS_PURCHASING,
+ PhortuneCart::STATUS_CHARGED,
+ PhortuneCart::STATUS_HOLD,
PhortuneCart::STATUS_PURCHASED,
))
->execute();
@@ -197,6 +199,7 @@
$rowc[] = '';
$rows[] = array(
+ $cart->getID(),
phutil_tag(
'strong',
array(),
@@ -206,6 +209,7 @@
'strong',
array(),
$cart->getTotalPriceAsCurrency()->formatForDisplay()),
+ PhortuneCart::getNameForStatus($cart->getStatus()),
phabricator_datetime($cart->getDateModified(), $viewer),
);
foreach ($purchases as $purchase) {
@@ -219,6 +223,7 @@
$handles[$purchase->getPHID()]->renderLink(),
$price,
'',
+ '',
);
}
}
@@ -227,21 +232,25 @@
->setRowClasses($rowc)
->setHeaders(
array(
- pht('Cart'),
+ pht('ID'),
+ pht('Order'),
pht('Purchase'),
pht('Amount'),
+ pht('Status'),
pht('Updated'),
))
->setColumnClasses(
array(
'',
+ '',
'wide',
'right',
+ '',
'right',
));
$header = id(new PHUIHeaderView())
- ->setHeader(pht('Purchase History'));
+ ->setHeader(pht('Order History'));
return id(new PHUIObjectBoxView())
->setHeader($header)
diff --git a/src/applications/phortune/controller/PhortuneCartUpdateController.php b/src/applications/phortune/controller/PhortuneCartUpdateController.php
--- a/src/applications/phortune/controller/PhortuneCartUpdateController.php
+++ b/src/applications/phortune/controller/PhortuneCartUpdateController.php
@@ -22,7 +22,41 @@
return new Aphront404Response();
}
- // TODO: This obviously doesn't do anything for now.
+ $charges = id(new PhortuneChargeQuery())
+ ->setViewer($viewer)
+ ->withCartPHIDs(array($cart->getPHID()))
+ ->needCarts(true)
+ ->withStatuses(
+ array(
+ PhortuneCharge::STATUS_HOLD,
+ PhortuneCharge::STATUS_CHARGED,
+ ))
+ ->execute();
+
+ if ($charges) {
+ $providers = id(new PhortunePaymentProviderConfigQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(mpull($charges, 'getProviderPHID'))
+ ->execute();
+ $providers = mpull($providers, null, 'getPHID');
+ } else {
+ $providers = array();
+ }
+
+ foreach ($charges as $charge) {
+ if ($charge->isRefund()) {
+ // Don't update refunds.
+ continue;
+ }
+
+ $provider_config = idx($providers, $charge->getProviderPHID());
+ if (!$provider_config) {
+ throw new Exception(pht('Unable to load provider for charge!'));
+ }
+
+ $provider = $provider_config->buildProvider();
+ $provider->updateCharge($charge);
+ }
return id(new AphrontRedirectResponse())
->setURI($cart->getDetailURI());
diff --git a/src/applications/phortune/controller/PhortuneCartViewController.php b/src/applications/phortune/controller/PhortuneCartViewController.php
--- a/src/applications/phortune/controller/PhortuneCartViewController.php
+++ b/src/applications/phortune/controller/PhortuneCartViewController.php
@@ -83,8 +83,7 @@
$header = id(new PHUIHeaderView())
->setUser($viewer)
- ->setHeader(pht('Order Detail'))
- ->setPolicyObject($cart);
+ ->setHeader(pht('Order Detail'));
$cart_box = id(new PHUIObjectBoxView())
->setHeader($header)
diff --git a/src/applications/phortune/provider/PhortuneBalancedPaymentProvider.php b/src/applications/phortune/provider/PhortuneBalancedPaymentProvider.php
--- a/src/applications/phortune/provider/PhortuneBalancedPaymentProvider.php
+++ b/src/applications/phortune/provider/PhortuneBalancedPaymentProvider.php
@@ -102,10 +102,7 @@
}
public function runConfigurationTest() {
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/httpful/bootstrap.php';
- require_once $root.'/externals/restful/bootstrap.php';
- require_once $root.'/externals/balanced-php/bootstrap.php';
+ $this->loadBalancedAPILibraries();
// TODO: This only tests that the secret key is correct. It's not clear
// how to test that the marketplace is correct.
@@ -140,11 +137,7 @@
protected function executeCharge(
PhortunePaymentMethod $method,
PhortuneCharge $charge) {
-
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/httpful/bootstrap.php';
- require_once $root.'/externals/restful/bootstrap.php';
- require_once $root.'/externals/balanced-php/bootstrap.php';
+ $this->loadBalancedAPILibraries();
$price = $charge->getAmountAsCurrency();
@@ -182,11 +175,7 @@
protected function executeRefund(
PhortuneCharge $charge,
PhortuneCharge $refund) {
-
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/httpful/bootstrap.php';
- require_once $root.'/externals/restful/bootstrap.php';
- require_once $root.'/externals/balanced-php/bootstrap.php';
+ $this->loadBalancedAPILibraries();
$debit_uri = $charge->getMetadataValue('balanced.debitURI');
if (!$debit_uri) {
@@ -214,6 +203,24 @@
$refund->save();
}
+ public function updateCharge(PhortuneCharge $charge) {
+ $this->loadBalancedAPILibraries();
+
+ $debit_uri = $charge->getMetadataValue('balanced.debitURI');
+ if (!$debit_uri) {
+ throw new Exception(pht('No Balanced debit URI!'));
+ }
+
+ try {
+ Balanced\Settings::$api_key = $this->getSecretKey();
+ $balanced_debit = Balanced\Debit::get($debit_uri);
+ } catch (RESTful\Exceptions\HTTPError $error) {
+ throw new Exception($error->response->body->description);
+ }
+
+ // TODO: Deal with disputes / chargebacks / surprising refunds.
+ }
+
private function getMarketplaceID() {
return $this
->getProviderConfig()
@@ -255,14 +262,10 @@
AphrontRequest $request,
PhortunePaymentMethod $method,
array $token) {
+ $this->loadBalancedAPILibraries();
$errors = array();
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/httpful/bootstrap.php';
- require_once $root.'/externals/restful/bootstrap.php';
- require_once $root.'/externals/balanced-php/bootstrap.php';
-
$account_phid = $method->getAccountPHID();
$author_phid = $method->getAuthorPHID();
$description = $account_phid.':'.$author_phid;
@@ -357,4 +360,11 @@
return null;
}
+ private function loadBalancedAPILibraries() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ require_once $root.'/externals/httpful/bootstrap.php';
+ require_once $root.'/externals/restful/bootstrap.php';
+ require_once $root.'/externals/balanced-php/bootstrap.php';
+ }
+
}
diff --git a/src/applications/phortune/provider/PhortunePayPalPaymentProvider.php b/src/applications/phortune/provider/PhortunePayPalPaymentProvider.php
--- a/src/applications/phortune/provider/PhortunePayPalPaymentProvider.php
+++ b/src/applications/phortune/provider/PhortunePayPalPaymentProvider.php
@@ -192,6 +192,62 @@
$result['REFUNDTRANSACTIONID']);
}
+ public function updateCharge(PhortuneCharge $charge) {
+ $transaction_id = $charge->getMetadataValue('paypal.transactionID');
+ if (!$transaction_id) {
+ throw new Exception(pht('Charge has no transaction ID!'));
+ }
+
+ $params = array(
+ 'TRANSACTIONID' => $transaction_id,
+ );
+
+ $result = $this
+ ->newPaypalAPICall()
+ ->setRawPayPalQuery('GetTransactionDetails', $params)
+ ->resolve();
+
+ $is_charge = false;
+ $is_fail = false;
+ switch ($result['PAYMENTSTATUS']) {
+ case 'Processed':
+ case 'Completed':
+ case 'Completed-Funds-Held':
+ $is_charge = true;
+ break;
+ case 'Partially-Refunded':
+ case 'Refunded':
+ case 'Reversed':
+ case 'Canceled-Reversal':
+ // TODO: Handle these.
+ return;
+ case 'In-Progress':
+ case 'Pending':
+ // TODO: Also handle these better?
+ return;
+ case 'Denied':
+ case 'Expired':
+ case 'Failed':
+ case 'None':
+ case 'Voided':
+ default:
+ $is_fail = true;
+ break;
+ }
+
+ if ($charge->getStatus() == PhortuneCharge::STATUS_HOLD) {
+ $cart = $charge->getCart();
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ if ($is_charge) {
+ $cart->didApplyCharge($charge);
+ } else if ($is_fail) {
+ $cart->didFailCharge($charge);
+ }
+ unset($unguarded);
+ }
+ }
+
private function getPaypalAPIUsername() {
return $this
->getProviderConfig()
@@ -278,6 +334,7 @@
'PAYMENTREQUEST_0_CURRENCYCODE' => $price->getCurrency(),
'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
'PAYMENTREQUEST_0_CUSTOM' => $charge->getPHID(),
+ 'PAYMENTREQUEST_0_DESC' => $cart->getName(),
'RETURNURL' => $return_uri,
'CANCELURL' => $cancel_uri,
diff --git a/src/applications/phortune/provider/PhortunePaymentProvider.php b/src/applications/phortune/provider/PhortunePaymentProvider.php
--- a/src/applications/phortune/provider/PhortunePaymentProvider.php
+++ b/src/applications/phortune/provider/PhortunePaymentProvider.php
@@ -149,7 +149,9 @@
abstract protected function executeRefund(
PhortuneCharge $charge,
- PhortuneCharge $charge);
+ PhortuneCharge $refund);
+
+ abstract public function updateCharge(PhortuneCharge $charge);
/* -( Adding Payment Methods )--------------------------------------------- */
diff --git a/src/applications/phortune/provider/PhortuneStripePaymentProvider.php b/src/applications/phortune/provider/PhortuneStripePaymentProvider.php
--- a/src/applications/phortune/provider/PhortuneStripePaymentProvider.php
+++ b/src/applications/phortune/provider/PhortuneStripePaymentProvider.php
@@ -116,8 +116,7 @@
}
public function runConfigurationTest() {
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/stripe-php/lib/Stripe.php';
+ $this->loadStripeAPILibraries();
$secret_key = $this->getSecretKey();
$account = Stripe_Account::retrieve($secret_key);
@@ -131,9 +130,7 @@
protected function executeCharge(
PhortunePaymentMethod $method,
PhortuneCharge $charge) {
-
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/stripe-php/lib/Stripe.php';
+ $this->loadStripeAPILibraries();
$price = $charge->getAmountAsCurrency();
@@ -160,6 +157,7 @@
protected function executeRefund(
PhortuneCharge $charge,
PhortuneCharge $refund) {
+ $this->loadStripeAPILibraries();
$charge_id = $charge->getMetadataValue('stripe.chargeID');
if (!$charge_id) {
@@ -167,9 +165,6 @@
pht('Unable to refund charge; no Stripe chargeID!'));
}
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/stripe-php/lib/Stripe.php';
-
$refund_cents = $refund
->getAmountAsCurrency()
->negate()
@@ -192,6 +187,22 @@
$charge->save();
}
+ public function updateCharge(PhortuneCharge $charge) {
+ $this->loadStripeAPILibraries();
+
+ $charge_id = $charge->getMetadataValue('stripe.chargeID');
+ if (!$charge_id) {
+ throw new Exception(
+ pht('Unable to update charge; no Stripe chargeID!'));
+ }
+
+ $secret_key = $this->getSecretKey();
+ $stripe_charge = Stripe_Charge::retrieve($charge_id, $secret_key);
+
+ // TODO: Deal with disputes / chargebacks / surprising refunds.
+
+ }
+
private function getPublishableKey() {
return $this
->getProviderConfig()
@@ -221,12 +232,10 @@
AphrontRequest $request,
PhortunePaymentMethod $method,
array $token) {
+ $this->loadStripeAPILibraries();
$errors = array();
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/stripe-php/lib/Stripe.php';
-
$secret_key = $this->getSecretKey();
$stripe_token = $token['stripeCardToken'];
@@ -362,4 +371,9 @@
return null;
}
+ private function loadStripeAPILibraries() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ require_once $root.'/externals/stripe-php/lib/Stripe.php';
+ }
+
}
diff --git a/src/applications/phortune/provider/PhortuneTestPaymentProvider.php b/src/applications/phortune/provider/PhortuneTestPaymentProvider.php
--- a/src/applications/phortune/provider/PhortuneTestPaymentProvider.php
+++ b/src/applications/phortune/provider/PhortuneTestPaymentProvider.php
@@ -62,6 +62,10 @@
return;
}
+ public function updateCharge(PhortuneCharge $charge) {
+ return;
+ }
+
public function getAllConfigurableProperties() {
return array();
}
diff --git a/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php b/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php
--- a/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php
+++ b/src/applications/phortune/provider/PhortuneWePayPaymentProvider.php
@@ -49,8 +49,7 @@
}
public function runConfigurationTest() {
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/wepay/wepay.php';
+ $this->loadWePayAPILibraries();
WePay::useStaging(
$this->getWePayClientID(),
@@ -189,20 +188,12 @@
protected function executeRefund(
PhortuneCharge $charge,
PhortuneCharge $refund) {
+ $wepay = $this->loadWePayAPILibraries();
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/wepay/wepay.php';
-
- WePay::useStaging(
- $this->getWePayClientID(),
- $this->getWePayClientSecret());
-
- $wepay = new WePay($this->getWePayAccessToken());
-
- $charge_id = $charge->getMetadataValue('wepay.checkoutID');
+ $checkout_id = $this->getWePayCheckoutID($charge);
$params = array(
- 'checkout_id' => $charge_id,
+ 'checkout_id' => $checkout_id,
'refund_reason' => pht('Refund'),
'amount' => $refund->getAmountAsCurrency()->negate()->formatBareValue(),
);
@@ -210,6 +201,18 @@
$wepay->request('checkout/refund', $params);
}
+ public function updateCharge(PhortuneCharge $charge) {
+ $wepay = $this->loadWePayAPILibraries();
+
+ $params = array(
+ 'checkout_id' => $this->getWePayCheckoutID($charge),
+ );
+ $wepay_checkout = $wepay->request('checkout', $params);
+
+ // TODO: Deal with disputes / chargebacks / surprising refunds.
+ }
+
+
/* -( One-Time Payments )-------------------------------------------------- */
public function canProcessOneTimePayments() {
@@ -236,6 +239,7 @@
public function processControllerRequest(
PhortuneProviderActionController $controller,
AphrontRequest $request) {
+ $wepay = $this->loadWePayAPILibraries();
$viewer = $request->getUser();
@@ -244,15 +248,6 @@
return new Aphront404Response();
}
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/wepay/wepay.php';
-
- WePay::useStaging(
- $this->getWePayClientID(),
- $this->getWePayClientSecret());
-
- $wepay = new WePay($this->getWePayAccessToken());
-
$charge = $controller->loadActiveCharge($cart);
switch ($controller->getAction()) {
case 'checkout':
@@ -388,5 +383,23 @@
pht('Unsupported action "%s".', $controller->getAction()));
}
+ private function loadWePayAPILibraries() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ require_once $root.'/externals/wepay/wepay.php';
+
+ WePay::useStaging(
+ $this->getWePayClientID(),
+ $this->getWePayClientSecret());
+
+ return new WePay($this->getWePayAccessToken());
+ }
+
+ private function getWePayCheckoutID(PhortuneCharge $charge) {
+ $checkout_id = $charge->getMetadataValue('wepay.checkoutID');
+ if ($checkout_id === null) {
+ throw new Exception(pht('No WePay Checkout ID present on charge!'));
+ }
+ return $checkout_id;
+ }
}
diff --git a/src/applications/phortune/storage/PhortuneCart.php b/src/applications/phortune/storage/PhortuneCart.php
--- a/src/applications/phortune/storage/PhortuneCart.php
+++ b/src/applications/phortune/storage/PhortuneCart.php
@@ -149,13 +149,12 @@
$copy = clone $this;
$copy->reload();
- if ($copy->getStatus() !== self::STATUS_PURCHASING) {
+ if (($copy->getStatus() !== self::STATUS_PURCHASING) &&
+ ($copy->getStatus() !== self::STATUS_HOLD)) {
throw new Exception(
pht(
- 'Cart has wrong status ("%s") to call didApplyCharge(), '.
- 'expected "%s".',
- $copy->getStatus(),
- self::STATUS_PURCHASING));
+ 'Cart has wrong status ("%s") to call didApplyCharge().',
+ $copy->getStatus()));
}
$charge->save();
@@ -182,13 +181,12 @@
$copy = clone $this;
$copy->reload();
- if ($copy->getStatus() !== self::STATUS_PURCHASING) {
+ if (($copy->getStatus() !== self::STATUS_PURCHASING) &&
+ ($copy->getStatus() !== self::STATUS_HOLD)) {
throw new Exception(
pht(
- 'Cart has wrong status ("%s") to call didFailCharge(), '.
- 'expected "%s".',
- $copy->getStatus(),
- self::STATUS_PURCHASING));
+ 'Cart has wrong status ("%s") to call didFailCharge().',
+ $copy->getStatus()));
}
$charge->save();
diff --git a/src/applications/phortune/storage/PhortuneCharge.php b/src/applications/phortune/storage/PhortuneCharge.php
--- a/src/applications/phortune/storage/PhortuneCharge.php
+++ b/src/applications/phortune/storage/PhortuneCharge.php
@@ -84,6 +84,10 @@
return idx(self::getStatusNameMap(), $status, pht('Unknown'));
}
+ public function isRefund() {
+ return $this->getAmountAsCurrency()->negate()->isPositive();
+ }
+
public function getStatusForDisplay() {
if ($this->getStatus() == self::STATUS_CHARGED) {
if ($this->getRefundedChargePHID()) {

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 20, 11:36 PM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7666115
Default Alt Text
D10670.diff (19 KB)

Event Timeline