Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15379743
D10675.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D10675.diff
View Options
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
@@ -2557,6 +2557,7 @@
'PhortuneAccountViewController' => 'applications/phortune/controller/PhortuneAccountViewController.php',
'PhortuneBalancedPaymentProvider' => 'applications/phortune/provider/PhortuneBalancedPaymentProvider.php',
'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php',
+ 'PhortuneCartAcceptController' => 'applications/phortune/controller/PhortuneCartAcceptController.php',
'PhortuneCartCancelController' => 'applications/phortune/controller/PhortuneCartCancelController.php',
'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php',
'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php',
@@ -5616,6 +5617,7 @@
'PhortuneDAO',
'PhabricatorPolicyInterface',
),
+ 'PhortuneCartAcceptController' => 'PhortuneCartController',
'PhortuneCartCancelController' => 'PhortuneCartController',
'PhortuneCartCheckoutController' => 'PhortuneCartController',
'PhortuneCartController' => 'PhortuneController',
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
@@ -50,6 +50,7 @@
'checkout/' => 'PhortuneCartCheckoutController',
'(?P<action>cancel|refund)/' => 'PhortuneCartCancelController',
'update/' => 'PhortuneCartUpdateController',
+ 'accept/' => 'PhortuneCartAcceptController',
),
'account/' => array(
'' => 'PhortuneAccountListController',
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
@@ -176,6 +176,7 @@
PhortuneCart::STATUS_PURCHASING,
PhortuneCart::STATUS_CHARGED,
PhortuneCart::STATUS_HOLD,
+ PhortuneCart::STATUS_REVIEW,
PhortuneCart::STATUS_PURCHASED,
))
->execute();
diff --git a/src/applications/phortune/controller/PhortuneCartAcceptController.php b/src/applications/phortune/controller/PhortuneCartAcceptController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/PhortuneCartAcceptController.php
@@ -0,0 +1,57 @@
+<?php
+
+final class PhortuneCartAcceptController
+ 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();
+ }
+
+ // You must control the merchant to accept orders.
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $cart->getMerchant(),
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $cancel_uri = $cart->getDetailURI();
+
+ if ($cart->getStatus() !== PhortuneCart::STATUS_REVIEW) {
+ return $this->newDialog()
+ ->setTitle(pht('Order Not in Review'))
+ ->appendParagraph(
+ pht(
+ 'This order does not need manual review, so you can not '.
+ 'accept it.'))
+ ->addCancelButton($cancel_uri);
+ }
+
+ if ($request->isFormPost()) {
+ $cart->didReviewCart();
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Accept Order?'))
+ ->appendParagraph(
+ pht(
+ 'This order has been flagged for manual review. You should review '.
+ 'it carefully before accepting it.'))
+ ->addCancelButton($cancel_uri)
+ ->addSubmitButton(pht('Accept Order'));
+ }
+}
diff --git a/src/applications/phortune/controller/PhortuneCartCancelController.php b/src/applications/phortune/controller/PhortuneCartCancelController.php
--- a/src/applications/phortune/controller/PhortuneCartCancelController.php
+++ b/src/applications/phortune/controller/PhortuneCartCancelController.php
@@ -158,8 +158,9 @@
}
// TODO: If every HOLD and CHARGING transaction has been fully refunded
- // and we're in a HOLD, PURCHASING or CHARGED cart state we probably
- // need to kick the cart back to READY here?
+ // and we're in a HOLD, REVIEW, PURCHASING or CHARGED cart state we
+ // probably need to kick the cart back to READY here (or maybe kill
+ // it if it was in REVIEW)?
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
}
@@ -170,6 +171,7 @@
$body = pht(
'Really refund this order?');
$button = pht('Refund Order');
+ $cancel_text = pht('Cancel');
$form = id(new AphrontFormView())
->setUser($viewer)
@@ -181,6 +183,7 @@
->setValue($v_refund));
$form = $form->buildLayoutView();
+
} else {
$title = pht('Cancel Order?');
$body = pht(
diff --git a/src/applications/phortune/controller/PhortuneCartCheckoutController.php b/src/applications/phortune/controller/PhortuneCartCheckoutController.php
--- a/src/applications/phortune/controller/PhortuneCartCheckoutController.php
+++ b/src/applications/phortune/controller/PhortuneCartCheckoutController.php
@@ -42,6 +42,7 @@
case PhortuneCart::STATUS_CHARGED:
case PhortuneCart::STATUS_PURCHASING:
case PhortuneCart::STATUS_HOLD:
+ case PhortuneCart::STATUS_REVIEW:
case PhortuneCart::STATUS_PURCHASED:
// For these states, kick the user to the order page to give them
// information and options.
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
@@ -72,6 +72,19 @@
phutil_tag('strong', array(), pht('Update Status')));
}
break;
+ case PhortuneCart::STATUS_REVIEW:
+ if ($can_admin) {
+ $errors[] = pht(
+ 'This order has been flagged for manual review. Review the order '.
+ 'and choose %s to accept it or %s to reject it.',
+ phutil_tag('strong', array(), pht('Accept Order')),
+ phutil_tag('strong', array(), pht('Refund Order')));
+ } else if ($can_edit) {
+ $errors[] = pht(
+ 'This order requires manual processing and will complete once '.
+ 'the merchant accepts it.');
+ }
+ break;
case PhortuneCart::STATUS_PURCHASED:
$error_view = id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
@@ -197,6 +210,7 @@
$cancel_uri = $this->getApplicationURI("cart/{$id}/cancel/");
$refund_uri = $this->getApplicationURI("cart/{$id}/refund/");
$update_uri = $this->getApplicationURI("cart/{$id}/update/");
+ $accept_uri = $this->getApplicationURI("cart/{$id}/accept/");
$view->addAction(
id(new PhabricatorActionView())
@@ -207,6 +221,15 @@
->setHref($cancel_uri));
if ($can_admin) {
+ if ($cart->getStatus() == PhortuneCart::STATUS_REVIEW) {
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Accept Order'))
+ ->setIcon('fa-check')
+ ->setWorkflow(true)
+ ->setHref($accept_uri));
+ }
+
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Refund Order'))
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
@@ -472,7 +472,7 @@
return $response;
case 'cancel':
- if ($cart->getStatus() !== PhortuneCart::STATUS_PURCHASING) {
+ if ($cart->getStatus() === PhortuneCart::STATUS_PURCHASING) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
// TODO: Since the user cancelled this, we could conceivably just
// throw it away or make it more clear that it's a user cancel.
diff --git a/src/applications/phortune/query/PhortuneCartSearchEngine.php b/src/applications/phortune/query/PhortuneCartSearchEngine.php
--- a/src/applications/phortune/query/PhortuneCartSearchEngine.php
+++ b/src/applications/phortune/query/PhortuneCartSearchEngine.php
@@ -31,6 +31,8 @@
array(
PhortuneCart::STATUS_PURCHASING,
PhortuneCart::STATUS_CHARGED,
+ PhortuneCart::STATUS_HOLD,
+ PhortuneCart::STATUS_REVIEW,
PhortuneCart::STATUS_PURCHASED,
));
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
@@ -8,6 +8,7 @@
const STATUS_PURCHASING = 'cart:purchasing';
const STATUS_CHARGED = 'cart:charged';
const STATUS_HOLD = 'cart:hold';
+ const STATUS_REVIEW = 'cart:review';
const STATUS_PURCHASED = 'cart:purchased';
protected $accountPHID;
@@ -59,6 +60,7 @@
self::STATUS_PURCHASING => pht('Purchasing'),
self::STATUS_CHARGED => pht('Charged'),
self::STATUS_HOLD => pht('Hold'),
+ self::STATUS_REVIEW => pht('Review'),
self::STATUS_PURCHASED => pht('Purchased'),
);
}
@@ -163,11 +165,68 @@
$this->endReadLocking();
$this->saveTransaction();
- foreach ($this->purchases as $purchase) {
- $purchase->getProduct()->didPurchaseProduct($purchase);
+ // TODO: Perform purchase review. Here, we would apply rules to determine
+ // whether the charge needs manual review (maybe making the decision via
+ // Herald, configuration, or by examining provider fraud data). For now,
+ // always require review.
+ $needs_review = true;
+
+ if ($needs_review) {
+ $this->willReviewCart();
+ } else {
+ $this->didReviewCart();
}
- $this->setStatus(self::STATUS_PURCHASED)->save();
+ return $this;
+ }
+
+ public function willReviewCart() {
+ $this->openTransaction();
+ $this->beginReadLocking();
+
+ $copy = clone $this;
+ $copy->reload();
+
+ if (($copy->getStatus() !== self::STATUS_CHARGED)) {
+ throw new Exception(
+ pht(
+ 'Cart has wrong status ("%s") to call willReviewCart()!',
+ $copy->getStatus()));
+ }
+
+ $this->setStatus(self::STATUS_REVIEW)->save();
+
+ $this->endReadLocking();
+ $this->saveTransaction();
+
+ // TODO: Notify merchant to review order.
+
+ return $this;
+ }
+
+ public function didReviewCart() {
+ $this->openTransaction();
+ $this->beginReadLocking();
+
+ $copy = clone $this;
+ $copy->reload();
+
+ if (($copy->getStatus() !== self::STATUS_CHARGED) &&
+ ($copy->getStatus() !== self::STATUS_REVIEW)) {
+ throw new Exception(
+ pht(
+ 'Cart has wrong status ("%s") to call didReviewCart()!',
+ $copy->getStatus()));
+ }
+
+ foreach ($this->purchases as $purchase) {
+ $purchase->getProduct()->didPurchaseProduct($purchase);
+ }
+
+ $this->setStatus(self::STATUS_PURCHASED)->save();
+
+ $this->endReadLocking();
+ $this->saveTransaction();
return $this;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 14, 11:09 PM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7567713
Default Alt Text
D10675.diff (11 KB)
Attached To
Mode
D10675: Add a "Review" status to Phortune
Attached
Detach File
Event Timeline
Log In to Comment