{"record":{"id":"fb6456922a18c985","repo":"phacility/phabricator","slug":"this-order-can-not-be-refunded-because-the-applica","errorCode":null,"errorMessage":"This order can not be refunded because the application has not finished building it yet.","messagePattern":"This order can not be refunded because the application has not finished building it yet\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"src/applications/phortune/storage/PhortuneCart.php","lineNumber":530,"sourceCode":"    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.'));\n    }\n\n    return $this->getImplementation()->assertCanRefundOrder($this);\n  }\n\n  public function assertCanVoidOrder() {\n    if (!$this->getIsInvoice()) {\n      throw new Exception(\n        pht(\n          'This order can not be voided because it is not an invoice.'));\n    }","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/phortune/storage/PhortuneCart.php#L512-L548","documentation":"assertCanRefundOrder() throws when the cart is still STATUS_BUILDING: the application has not finished constructing the order, so no money has moved and there is nothing to refund. This mirrors the cancel guard and is paired with canRefundOrder() for non-throwing checks.","triggerScenarios":"Calling assertCanRefundOrder() (directly or via a refund controller) on a cart whose status is PhortuneCart::STATUS_BUILDING.","commonSituations":"Refund links or buttons rendered on order lists that include carts still under construction; automated refund tooling that does not filter by status.","solutions":["Gate refund actions on $cart->canRefundOrder() and only show them for placed orders.","Let the cart finish building and be purchased before exposing refund operations.","Filter BUILDING carts out of any order list that offers refund actions."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!$cart->canRefundOrder()) {\n  // cart still building: nothing has been charged, nothing to refund\n  return $this->newDialog()->setTitle(pht('Unable to Refund Order'));\n}","typeGuard":"function isRefundableCart(PhortuneCart $cart) {\n  return $cart->canRefundOrder();\n}","tryCatchPattern":null,"preventionTips":["Show refund actions only on placed/charged carts via canRefundOrder().","Filter BUILDING carts out of refund-eligible lists.","Let application-driven carts finish construction before exposing operations."],"tags":["phortune","phabricator","php","payments","cart","refund","order-lifecycle"],"backgroundTag":"invalid-cart-status","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}