{"record":{"id":"155428061ea03929","repo":"phacility/phabricator","slug":"this-order-can-not-be-cancelled-because-it-has-not","errorCode":null,"errorMessage":"This order can not be cancelled because it has not been placed.","messagePattern":"This order can not be cancelled because it has not been placed\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"src/applications/phortune/storage/PhortuneCart.php","lineNumber":519,"sourceCode":"\n  public function canVoidOrder() {\n    try {\n      $this->assertCanVoidOrder();\n      return true;\n    } catch (Exception $ex) {\n      return false;\n    }\n  }\n\n  public function assertCanCancelOrder() {\n    switch ($this->getStatus()) {\n      case self::STATUS_BUILDING:\n        throw new Exception(\n          pht(\n            'This order can not be cancelled because the application has not '.\n            'finished building it yet.'));\n      case self::STATUS_READY:\n        throw new Exception(\n          pht(\n            'This order can not be cancelled because it has not been placed.'));\n    }\n\n    return $this->getImplementation()->assertCanCancelOrder($this);\n  }\n\n  public function assertCanRefundOrder() {\n    switch ($this->getStatus()) {\n      case self::STATUS_BUILDING:\n        throw new Exception(\n          pht(\n            'This order can not be refunded because the application has not '.\n            'finished building it yet.'));\n      case self::STATUS_READY:\n        throw new Exception(\n          pht(\n            'This order can not be refunded because it has not been placed.'));","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/phortune/storage/PhortuneCart.php#L501-L537","documentation":"assertCanCancelOrder() throws when the cart is STATUS_READY: the order has been built but the user never completed checkout, so it has not been placed yet. Nothing has been charged, so there is no order to cancel - Phortune expects READY carts to simply expire or be checked out. Use canCancelOrder() to test without throwing.","triggerScenarios":"Calling assertCanCancelOrder() on a cart in PhortuneCart::STATUS_READY, e.g. a user opening an old unpaid checkout link and choosing cancel.","commonSituations":"Abandoned checkouts being cleaned up manually; links to ready carts resurfacing in email; scripts iterating all carts and calling cancel unconditionally.","solutions":["Check $cart->canCancelOrder() first and hide the cancel action for unplaced orders.","For READY carts, simply abandon them - no cancellation is required since nothing was purchased.","In bulk tooling, skip carts whose status is READY or BUILDING."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if ($cart->getStatus() === PhortuneCart::STATUS_READY) {\n  // unplaced order: nothing to cancel; let it expire or complete checkout\n}\nif (!$cart->canCancelOrder()) {\n  return $this->newDialog()->setTitle(pht('Unable to Cancel Order'));\n}","typeGuard":"function isPlacedCart(PhortuneCart $cart) {\n  return !in_array(\n    $cart->getStatus(),\n    array(PhortuneCart::STATUS_BUILDING, PhortuneCart::STATUS_READY));\n}","tryCatchPattern":null,"preventionTips":["Use canCancelOrder() before rendering cancel actions.","Treat READY carts as ignorable rather than cancellable.","Filter unplaced carts out of order-management lists."],"tags":["phortune","phabricator","php","payments","cart","order-lifecycle"],"backgroundTag":"invalid-cart-status","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}