Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15454003
D10003.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
21 KB
Referenced Files
None
Subscribers
None
D10003.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D10003: Phortune Cart Status, some one-time support
Attached
Detach File
Event Timeline
Log In to Comment