Page MenuHomePhabricator

D10003.diff
No OneTemporary

D10003.diff

diff --git a/resources/sql/autopatches/20140721.phortune.4.cartstatus.sql b/resources/sql/autopatches/20140721.phortune.4.cartstatus.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140721.phortune.4.cartstatus.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_phortune.phortune_cart
+ ADD status VARCHAR(32) NOT NULL COLLATE utf8_bin;
diff --git a/resources/sql/autopatches/20140721.phortune.5.cstatusdefault.sql b/resources/sql/autopatches/20140721.phortune.5.cstatusdefault.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140721.phortune.5.cstatusdefault.sql
@@ -0,0 +1,2 @@
+UPDATE {$NAMESPACE}_phortune.phortune_cart
+ SET status = 'cart:ready' WHERE status = '';
diff --git a/resources/sql/autopatches/20140721.phortune.6.onetimecharge.sql b/resources/sql/autopatches/20140721.phortune.6.onetimecharge.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140721.phortune.6.onetimecharge.sql
@@ -0,0 +1,3 @@
+ALTER TABLE {$NAMESPACE}_phortune.phortune_charge
+ ADD paymentProviderKey VARCHAR(128) NOT NULL COLLATE utf8_bin
+ AFTER cartPHID;
diff --git a/resources/sql/autopatches/20140721.phortune.7.nullmethod.sql b/resources/sql/autopatches/20140721.phortune.7.nullmethod.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140721.phortune.7.nullmethod.sql
@@ -0,0 +1,4 @@
+/* Make this nullable to support one-time providers. */
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_charge
+ CHANGE paymentMethodPHID paymentMethodPHID VARCHAR(64) COLLATE utf8_bin;
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
@@ -2488,7 +2488,6 @@
'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php',
'PholioUploadedImageView' => 'applications/pholio/view/PholioUploadedImageView.php',
'PhortuneAccount' => 'applications/phortune/storage/PhortuneAccount.php',
- 'PhortuneAccountBuyController' => 'applications/phortune/controller/PhortuneAccountBuyController.php',
'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php',
'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php',
'PhortuneAccountTransaction' => 'applications/phortune/storage/PhortuneAccountTransaction.php',
@@ -2496,7 +2495,10 @@
'PhortuneAccountViewController' => 'applications/phortune/controller/PhortuneAccountViewController.php',
'PhortuneBalancedPaymentProvider' => 'applications/phortune/provider/PhortuneBalancedPaymentProvider.php',
'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php',
+ 'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php',
+ 'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php',
'PhortuneCartQuery' => 'applications/phortune/query/PhortuneCartQuery.php',
+ 'PhortuneCartViewController' => 'applications/phortune/controller/PhortuneCartViewController.php',
'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php',
'PhortuneChargeQuery' => 'applications/phortune/query/PhortuneChargeQuery.php',
'PhortuneConstants' => 'applications/phortune/constants/PhortuneConstants.php',
@@ -5371,7 +5373,6 @@
'PhortuneDAO',
'PhabricatorPolicyInterface',
),
- 'PhortuneAccountBuyController' => 'PhortuneController',
'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor',
'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhortuneAccountTransaction' => 'PhabricatorApplicationTransaction',
@@ -5382,7 +5383,10 @@
'PhortuneDAO',
'PhabricatorPolicyInterface',
),
+ 'PhortuneCartCheckoutController' => 'PhortuneCartController',
+ 'PhortuneCartController' => 'PhortuneController',
'PhortuneCartQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhortuneCartViewController' => 'PhortuneCartController',
'PhortuneCharge' => array(
'PhortuneDAO',
'PhabricatorPolicyInterface',
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
@@ -41,7 +41,10 @@
),
'buy/(?P<productID>\d+)/' => 'PhortuneProductPurchaseController',
),
- 'cart/(?P<id>\d+)/' => 'PhortuneAccountBuyController',
+ 'cart/(?P<id>\d+)/' => array(
+ '' => 'PhortuneCartViewController',
+ 'checkout/' => 'PhortuneCartCheckoutController',
+ ),
'account/' => array(
'' => 'PhortuneAccountListController',
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneAccountEditController',
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
@@ -152,45 +152,7 @@
->withAccountPHIDs(array($account->getPHID()))
->execute();
- $rows = array();
- foreach ($charges as $charge) {
- $rows[] = array(
- $charge->getID(),
- $charge->getCartPHID(),
- $charge->getPaymentMethodPHID(),
- PhortuneCurrency::newFromUSDCents($charge->getAmountInCents())
- ->formatForDisplay(),
- $charge->getStatus(),
- phabricator_datetime($charge->getDateCreated(), $viewer),
- );
- }
-
- $charge_table = id(new AphrontTableView($rows))
- ->setHeaders(
- array(
- pht('Charge ID'),
- pht('Cart'),
- pht('Method'),
- pht('Amount'),
- pht('Status'),
- pht('Created'),
- ))
- ->setColumnClasses(
- array(
- '',
- '',
- '',
- 'wide right',
- '',
- '',
- ));
-
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('Charge History'));
-
- return id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->appendChild($charge_table);
+ return $this->buildChargesTable($charges);
}
private function buildAccountHistorySection(PhortuneAccount $account) {
diff --git a/src/applications/phortune/controller/PhortuneAccountBuyController.php b/src/applications/phortune/controller/PhortuneCartCheckoutController.php
rename from src/applications/phortune/controller/PhortuneAccountBuyController.php
rename to src/applications/phortune/controller/PhortuneCartCheckoutController.php
--- a/src/applications/phortune/controller/PhortuneAccountBuyController.php
+++ b/src/applications/phortune/controller/PhortuneCartCheckoutController.php
@@ -1,7 +1,7 @@
<?php
-final class PhortuneAccountBuyController
- extends PhortuneController {
+final class PhortuneCartCheckoutController
+ extends PhortuneCartController {
private $id;
@@ -64,60 +64,23 @@
$charge->openTransaction();
$charge->save();
- // TODO: We should be setting some kind of status on the cart here.
+ $cart->setStatus(PhortuneCart::STATUS_PURCHASING);
$cart->save();
$charge->saveTransaction();
$provider->applyCharge($method, $charge);
- throw new Exception('Executed a charge! Your money is gone forever!');
- }
- }
-
+ $cart->setStatus(PhortuneCart::STATUS_PURCHASED);
+ $cart->save();
- $rows = array();
- $total = 0;
- foreach ($cart->getPurchases() as $purchase) {
- $rows[] = array(
- pht('A Purchase'),
- PhortuneCurrency::newFromUSDCents($purchase->getBasePriceInCents())
- ->formatForDisplay(),
- $purchase->getQuantity(),
- PhortuneCurrency::newFromUSDCents($purchase->getTotalPriceInCents())
- ->formatForDisplay(),
- );
+ $view_uri = $this->getApplicationURI('cart/'.$cart->getID().'/');
- $total += $purchase->getTotalPriceInCents();
+ return id(new AphrontRedirectResponse())->setURI($view_uri);
+ }
}
- $rows[] = array(
- phutil_tag('strong', array(), pht('Total')),
- '',
- '',
- phutil_tag('strong', array(),
- PhortuneCurrency::newFromUSDCents($total)->formatForDisplay()),
- );
-
- $table = new AphrontTableView($rows);
- $table->setHeaders(
- array(
- pht('Item'),
- pht('Price'),
- pht('Qty.'),
- pht('Total'),
- ));
- $table->setColumnClasses(
- array(
- 'wide',
- 'right',
- 'right',
- 'right',
- ));
-
- $cart_box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Your Cart'))
- ->setFormErrors($errors)
- ->appendChild($table);
+ $cart_box = $this->buildCartContents($cart);
+ $cart_box->setFormErrors($errors);
$title = pht('Buy Stuff');
diff --git a/src/applications/phortune/controller/PhortuneCartController.php b/src/applications/phortune/controller/PhortuneCartController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/PhortuneCartController.php
@@ -0,0 +1,52 @@
+<?php
+
+abstract class PhortuneCartController
+ extends PhortuneController {
+
+ protected function buildCartContents(PhortuneCart $cart) {
+
+ $rows = array();
+ $total = 0;
+ foreach ($cart->getPurchases() as $purchase) {
+ $rows[] = array(
+ pht('A Purchase'),
+ PhortuneCurrency::newFromUSDCents($purchase->getBasePriceInCents())
+ ->formatForDisplay(),
+ $purchase->getQuantity(),
+ PhortuneCurrency::newFromUSDCents($purchase->getTotalPriceInCents())
+ ->formatForDisplay(),
+ );
+
+ $total += $purchase->getTotalPriceInCents();
+ }
+
+ $rows[] = array(
+ phutil_tag('strong', array(), pht('Total')),
+ '',
+ '',
+ phutil_tag('strong', array(),
+ PhortuneCurrency::newFromUSDCents($total)->formatForDisplay()),
+ );
+
+ $table = new AphrontTableView($rows);
+ $table->setHeaders(
+ array(
+ pht('Item'),
+ pht('Price'),
+ pht('Qty.'),
+ pht('Total'),
+ ));
+ $table->setColumnClasses(
+ array(
+ 'wide',
+ 'right',
+ 'right',
+ 'right',
+ ));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Cart Contents'))
+ ->appendChild($table);
+ }
+
+}
diff --git a/src/applications/phortune/controller/PhortuneCartViewController.php b/src/applications/phortune/controller/PhortuneCartViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/PhortuneCartViewController.php
@@ -0,0 +1,50 @@
+<?php
+
+final class PhortuneCartViewController
+ extends PhortuneCartController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $cart = id(new PhortuneCartQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($this->id))
+ ->needPurchases(true)
+ ->executeOne();
+ if (!$cart) {
+ return new Aphront404Response();
+ }
+
+ $cart_box = $this->buildCartContents($cart);
+
+ $charges = id(new PhortuneChargeQuery())
+ ->setViewer($viewer)
+ ->withCartPHIDs(array($cart->getPHID()))
+ ->execute();
+
+ $charges_table = $this->buildChargesTable($charges);
+
+ $account = $cart->getAccount();
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb(pht('Cart'));
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $cart_box,
+ $charges_table,
+ ),
+ array(
+ 'title' => pht('Cart'),
+ ));
+
+ }
+}
diff --git a/src/applications/phortune/controller/PhortuneController.php b/src/applications/phortune/controller/PhortuneController.php
--- a/src/applications/phortune/controller/PhortuneController.php
+++ b/src/applications/phortune/controller/PhortuneController.php
@@ -52,5 +52,52 @@
return $account;
}
+ protected function buildChargesTable(array $charges) {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $rows = array();
+ foreach ($charges as $charge) {
+ $rows[] = array(
+ $charge->getID(),
+ $charge->getCartPHID(),
+ $charge->getPaymentProviderKey(),
+ $charge->getPaymentMethodPHID(),
+ PhortuneCurrency::newFromUSDCents($charge->getAmountInCents())
+ ->formatForDisplay(),
+ $charge->getStatus(),
+ phabricator_datetime($charge->getDateCreated(), $viewer),
+ );
+ }
+
+ $charge_table = id(new AphrontTableView($rows))
+ ->setHeaders(
+ array(
+ pht('Charge ID'),
+ pht('Cart'),
+ pht('Provider'),
+ pht('Method'),
+ pht('Amount'),
+ pht('Status'),
+ pht('Created'),
+ ))
+ ->setColumnClasses(
+ array(
+ '',
+ '',
+ '',
+ '',
+ 'wide right',
+ '',
+ '',
+ ));
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Charge History'));
+
+ return id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($charge_table);
+ }
}
diff --git a/src/applications/phortune/controller/PhortuneProductPurchaseController.php b/src/applications/phortune/controller/PhortuneProductPurchaseController.php
--- a/src/applications/phortune/controller/PhortuneProductPurchaseController.php
+++ b/src/applications/phortune/controller/PhortuneProductPurchaseController.php
@@ -39,6 +39,7 @@
$cart = new PhortuneCart();
$cart->openTransaction();
+ $cart->setStatus(PhortuneCart::STATUS_READY);
$cart->setAccountPHID($account->getPHID());
$cart->setAuthorPHID($user->getPHID());
$cart->save();
@@ -57,7 +58,8 @@
$cart->saveTransaction();
- $cart_uri = $this->getApplicationURI('/cart/'.$cart->getID().'/');
+ $cart_id = $cart->getID();
+ $cart_uri = $this->getApplicationURI('/cart/'.$cart_id.'/checkout/');
return id(new AphrontRedirectResponse())->setURI($cart_uri);
}
diff --git a/src/applications/phortune/controller/PhortuneProviderController.php b/src/applications/phortune/controller/PhortuneProviderController.php
--- a/src/applications/phortune/controller/PhortuneProviderController.php
+++ b/src/applications/phortune/controller/PhortuneProviderController.php
@@ -56,7 +56,19 @@
public function loadCart($id) {
- return id(new PhortuneCart());
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ return id(new PhortuneCartQuery())
+ ->setViewer($viewer)
+ ->needPurchases(true)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
}
}
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
@@ -121,7 +121,7 @@
'cartID' => $cart->getID(),
));
- $total_in_cents = $cart->getTotalInCents();
+ $total_in_cents = $cart->getTotalPriceInCents();
$price = PhortuneCurrency::newFromUSDCents($total_in_cents);
$result = $this
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
@@ -111,11 +111,15 @@
PhortuneProviderController $controller,
AphrontRequest $request) {
+ $viewer = $request->getUser();
+
$cart = $controller->loadCart($request->getInt('cartID'));
if (!$cart) {
return new Aphront404Response();
}
+ $cart_uri = '/phortune/cart/'.$cart->getID().'/';
+
$root = dirname(phutil_get_library_root('phabricator'));
require_once $root.'/externals/wepay/wepay.php';
@@ -139,7 +143,7 @@
'cartID' => $cart->getID(),
));
- $total_in_cents = $cart->getTotalInCents();
+ $total_in_cents = $cart->getTotalPriceInCents();
$price = PhortuneCurrency::newFromUSDCents($total_in_cents);
$params = array(
@@ -153,7 +157,12 @@
'fee_payer' => 'Payee',
'redirect_uri' => $return_uri,
'fallback_uri' => $cancel_uri,
- 'auto_capture' => false,
+
+ // NOTE: If we don't `auto_capture`, we might get a result back in
+ // either an "authorized" or a "reserved" state. We can't capture
+ // an "authorized" result, so just autocapture.
+
+ 'auto_capture' => true,
'require_shipping' => 0,
'shipping_fee' => 0,
'charge_tax' => 0,
@@ -163,18 +172,57 @@
$result = $wepay->request('checkout/create', $params);
- // NOTE: We might want to store "$result->checkout_id" on the Cart.
+ // TODO: We must store "$result->checkout_id" on the Cart since the
+ // user might not end up back here. Really this needs a bunch of junk.
$uri = new PhutilURI($result->checkout_uri);
return id(new AphrontRedirectResponse())->setURI($uri);
case 'charge':
+ $checkout_id = $request->getInt('checkout_id');
+ $params = array(
+ 'checkout_id' => $checkout_id,
+ );
- // NOTE: We get $_REQUEST['checkout_id'] here, but our parameters are
- // dropped so we should stop depending on them or shove them into the
- // URI.
-
- var_dump($_REQUEST);
- break;
+ $checkout = $wepay->request('checkout', $params);
+ if ($checkout->reference_id != $cart->getPHID()) {
+ throw new Exception(
+ pht('Checkout reference ID does not match cart PHID!'));
+ }
+
+ switch ($checkout->state) {
+ case 'authorized':
+ case 'reserved':
+ case 'captured':
+ break;
+ default:
+ throw new Exception(
+ pht(
+ 'Checkout is in bad state "%s"!',
+ $result->state));
+ }
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+
+ $charge = id(new PhortuneCharge())
+ ->setAmountInCents((int)$checkout->gross * 100)
+ ->setAccountPHID($cart->getAccount()->getPHID())
+ ->setAuthorPHID($viewer->getPHID())
+ ->setPaymentProviderKey($this->getProviderKey())
+ ->setCartPHID($cart->getPHID())
+ ->setStatus(PhortuneCharge::STATUS_CHARGING)
+ ->save();
+
+ $cart->openTransaction();
+ $charge->setStatus(PhortuneCharge::STATUS_CHARGED);
+ $charge->save();
+
+ $cart->setStatus(PhortuneCart::STATUS_PURCHASED);
+ $cart->save();
+ $cart->saveTransaction();
+
+ unset($unguarded);
+
+ return id(new AphrontRedirectResponse())->setURI($cart_uri);
case 'cancel':
var_dump($_REQUEST);
break;
diff --git a/src/applications/phortune/query/PhortuneChargeQuery.php b/src/applications/phortune/query/PhortuneChargeQuery.php
--- a/src/applications/phortune/query/PhortuneChargeQuery.php
+++ b/src/applications/phortune/query/PhortuneChargeQuery.php
@@ -6,6 +6,7 @@
private $ids;
private $phids;
private $accountPHIDs;
+ private $cartPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -22,6 +23,11 @@
return $this;
}
+ public function withCartPHIDs(array $cart_phids) {
+ $this->cartPHIDs = $cart_phids;
+ return $this;
+ }
+
protected function loadPage() {
$table = new PhortuneCharge();
$conn = $table->establishConnection('r');
@@ -83,6 +89,13 @@
$this->accountPHIDs);
}
+ if ($this->cartPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'charge.cartPHID IN (%Ls)',
+ $this->cartPHIDs);
+ }
+
return $this->formatWhereClause($where);
}
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
@@ -3,8 +3,13 @@
final class PhortuneCart extends PhortuneDAO
implements PhabricatorPolicyInterface {
+ const STATUS_READY = 'cart:ready';
+ const STATUS_PURCHASING = 'cart:purchasing';
+ const STATUS_PURCHASED = 'cart:purchased';
+
protected $accountPHID;
protected $authorPHID;
+ protected $status;
protected $metadata;
private $account = self::ATTACHABLE;
@@ -24,10 +29,6 @@
PhabricatorPHIDConstants::PHID_TYPE_CART);
}
- public function getTotalInCents() {
- return 123;
- }
-
public function attachPurchases(array $purchases) {
assert_instances_of($purchases, 'PhortunePurchase');
$this->purchases = $purchases;
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
@@ -18,6 +18,7 @@
protected $accountPHID;
protected $authorPHID;
protected $cartPHID;
+ protected $paymentProviderKey;
protected $paymentMethodPHID;
protected $amountInCents;
protected $status;

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 30, 3:36 PM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7386994
Default Alt Text
D10003.diff (21 KB)

Event Timeline