public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $product = id(new PhortuneProductQuery())->setViewer($user)->withIDs(array($this->productID))->executeOne();
     if (!$product) {
         return new Aphront404Response();
     }
     $title = pht('Product: %s', $product->getProductName());
     $header = id(new PHUIHeaderView())->setHeader($product->getProductName());
     $account = $this->loadActiveAccount($user);
     $edit_uri = $this->getApplicationURI('product/edit/' . $product->getID() . '/');
     $cart_uri = $this->getApplicationURI($account->getID() . '/buy/' . $product->getID() . '/');
     $actions = id(new PhabricatorActionListView())->setUser($user)->setObjectURI($request->getRequestURI())->addAction(id(new PhabricatorActionView())->setName(pht('Edit Product'))->setHref($edit_uri)->setIcon('fa-pencil'))->addAction(id(new PhabricatorActionView())->setUser($user)->setName(pht('Purchase'))->setHref($cart_uri)->setIcon('fa-shopping-cart')->setWorkflow(true));
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->setActionList($actions);
     $crumbs->addTextCrumb(pht('Products'), $this->getApplicationURI('product/'));
     $crumbs->addTextCrumb(pht('#%d', $product->getID()), $request->getRequestURI());
     $properties = id(new PHUIPropertyListView())->setUser($user)->setActionList($actions)->addProperty(pht('Type'), $product->getTypeName())->addProperty(pht('Price'), PhortuneCurrency::newFromUSDCents($product->getPriceInCents())->formatForDisplay());
     $xactions = id(new PhortuneProductTransactionQuery())->setViewer($user)->withObjectPHIDs(array($product->getPHID()))->execute();
     $engine = id(new PhabricatorMarkupEngine())->setViewer($user);
     $xaction_view = id(new PhabricatorApplicationTransactionView())->setUser($user)->setObjectPHID($product->getPHID())->setTransactions($xactions)->setMarkupEngine($engine);
     $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties);
     return $this->buildApplicationPage(array($crumbs, $object_box, $xaction_view), array('title' => $title));
 }
 protected function applyCustomInternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     $type = $xaction->getTransactionType();
     switch ($type) {
         case FundInitiativeTransaction::TYPE_NAME:
             $object->setName($xaction->getNewValue());
             return;
         case FundInitiativeTransaction::TYPE_DESCRIPTION:
             $object->setDescription($xaction->getNewValue());
             return;
         case FundInitiativeTransaction::TYPE_RISKS:
             $object->setRisks($xaction->getNewValue());
             return;
         case FundInitiativeTransaction::TYPE_MERCHANT:
             $object->setMerchantPHID($xaction->getNewValue());
             return;
         case FundInitiativeTransaction::TYPE_STATUS:
             $object->setStatus($xaction->getNewValue());
             return;
         case FundInitiativeTransaction::TYPE_BACKER:
         case FundInitiativeTransaction::TYPE_REFUND:
             $amount = $xaction->getMetadataValue(FundInitiativeTransaction::PROPERTY_AMOUNT);
             $amount = PhortuneCurrency::newFromString($amount);
             if ($type == FundInitiativeTransaction::TYPE_REFUND) {
                 $total = $object->getTotalAsCurrency()->subtract($amount);
             } else {
                 $total = $object->getTotalAsCurrency()->add($amount);
             }
             $object->setTotalAsCurrency($total);
             return;
     }
     return parent::applyCustomInternalTransaction($object, $xaction);
 }
 public function processControllerRequest(PhortuneProviderController $controller, AphrontRequest $request)
 {
     $cart = $controller->loadCart($request->getInt('cartID'));
     if (!$cart) {
         return new Aphront404Response();
     }
     switch ($controller->getAction()) {
         case 'checkout':
             $return_uri = $this->getControllerURI('charge', array('cartID' => $cart->getID()));
             $cancel_uri = $this->getControllerURI('cancel', array('cartID' => $cart->getID()));
             $total_in_cents = $cart->getTotalPriceInCents();
             $price = PhortuneCurrency::newFromUSDCents($total_in_cents);
             $result = $this->newPaypalAPICall()->setRawPayPalQuery('SetExpressCheckout', array('PAYMENTREQUEST_0_AMT' => $price->formatBareValue(), 'PAYMENTREQUEST_0_CURRENCYCODE' => $price->getCurrency(), 'RETURNURL' => $return_uri, 'CANCELURL' => $cancel_uri, 'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale'))->resolve();
             $uri = new PhutilURI('https://www.sandbox.paypal.com/cgi-bin/webscr');
             $uri->setQueryParams(array('cmd' => '_express-checkout', 'token' => $result['TOKEN']));
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($uri);
         case 'charge':
             var_dump($_REQUEST);
             break;
         case 'cancel':
             var_dump($_REQUEST);
             break;
     }
     throw new Exception("The rest of this isn't implemented yet.");
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getViewer();
     $id = $request->getURIData('id');
     $initiative = id(new FundInitiativeQuery())->setViewer($viewer)->withIDs(array($id))->executeOne();
     if (!$initiative) {
         return new Aphront404Response();
     }
     $merchant = id(new PhortuneMerchantQuery())->setViewer($viewer)->withPHIDs(array($initiative->getMerchantPHID()))->executeOne();
     if (!$merchant) {
         return new Aphront404Response();
     }
     $initiative_uri = '/' . $initiative->getMonogram();
     if ($initiative->isClosed()) {
         return $this->newDialog()->setTitle(pht('Initiative Closed'))->appendParagraph(pht('You can not back a closed initiative.'))->addCancelButton($initiative_uri);
     }
     $accounts = PhortuneAccountQuery::loadAccountsForUser($viewer, PhabricatorContentSource::newFromRequest($request));
     $v_amount = null;
     $e_amount = true;
     $v_account = head($accounts)->getPHID();
     $errors = array();
     if ($request->isFormPost()) {
         $v_amount = $request->getStr('amount');
         $v_account = $request->getStr('accountPHID');
         if (empty($accounts[$v_account])) {
             $errors[] = pht('You must specify an account.');
         } else {
             $account = $accounts[$v_account];
         }
         if (!strlen($v_amount)) {
             $errors[] = pht('You must specify how much money you want to contribute to the ' . 'initiative.');
             $e_amount = pht('Required');
         } else {
             try {
                 $currency = PhortuneCurrency::newFromUserInput($viewer, $v_amount);
                 $currency->assertInRange('1.00 USD', null);
             } catch (Exception $ex) {
                 $errors[] = $ex->getMessage();
                 $e_amount = pht('Invalid');
             }
         }
         if (!$errors) {
             $backer = FundBacker::initializeNewBacker($viewer)->setInitiativePHID($initiative->getPHID())->attachInitiative($initiative)->setAmountAsCurrency($currency)->save();
             $product = id(new PhortuneProductQuery())->setViewer($viewer)->withClassAndRef('FundBackerProduct', $initiative->getPHID())->executeOne();
             $cart_implementation = id(new FundBackerCart())->setInitiative($initiative);
             $cart = $account->newCart($viewer, $cart_implementation, $merchant);
             $purchase = $cart->newPurchase($viewer, $product);
             $purchase->setBasePriceAsCurrency($currency)->setMetadataValue('backerPHID', $backer->getPHID())->save();
             $xactions = array();
             $xactions[] = id(new FundBackerTransaction())->setTransactionType(FundBackerTransaction::TYPE_STATUS)->setNewValue(FundBacker::STATUS_IN_CART);
             $editor = id(new FundBackerEditor())->setActor($viewer)->setContentSourceFromRequest($request);
             $editor->applyTransactions($backer, $xactions);
             $cart->activateCart();
             return id(new AphrontRedirectResponse())->setURI($cart->getCheckoutURI());
         }
     }
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormSelectControl())->setName('accountPHID')->setLabel(pht('Account'))->setValue($v_account)->setOptions(mpull($accounts, 'getName', 'getPHID')))->appendChild(id(new AphrontFormTextControl())->setName('amount')->setLabel(pht('Amount'))->setValue($v_amount)->setError($e_amount));
     return $this->newDialog()->setTitle(pht('Back %s %s', $initiative->getMonogram(), $initiative->getName()))->setErrors($errors)->appendChild($form->buildLayoutView())->addCancelButton($initiative_uri)->addSubmitButton(pht('Continue'));
 }
Beispiel #5
0
 public function getTotalPriceInCents()
 {
     $prices = array();
     foreach ($this->getPurchases() as $purchase) {
         $prices[] = PhortuneCurrency::newFromUSDCents($purchase->getTotalPriceInCents());
     }
     return PhortuneCurrency::newFromList($prices)->getValue();
 }
 public function getTotalPriceAsCurrency()
 {
     $base = $this->getBasePriceAsCurrency();
     $price = PhortuneCurrency::newEmptyCurrency();
     for ($ii = 0; $ii < $this->getQuantity(); $ii++) {
         $price = $price->add($base);
     }
     return $price;
 }
 public static function newFromList(array $list)
 {
     assert_instances_of($list, 'PhortuneCurrency');
     $total = 0;
     foreach ($list as $item) {
         // TODO: This should check for integer overflows, etc.
         $total += $item->getValue();
     }
     return PhortuneCurrency::newFromUSDCents($total);
 }
 public function didRefundProduct(PhortuneProduct $product, PhortunePurchase $purchase, PhortuneCurrency $amount)
 {
     $viewer = $this->getViewer();
     $backer = id(new FundBackerQuery())->setViewer($viewer)->withPHIDs(array($purchase->getMetadataValue('backerPHID')))->executeOne();
     if (!$backer) {
         throw new Exception(pht('Unable to load %s!', 'FundBacker'));
     }
     $xactions = array();
     $xactions[] = id(new FundInitiativeTransaction())->setTransactionType(FundInitiativeTransaction::TYPE_REFUND)->setMetadataValue(FundInitiativeTransaction::PROPERTY_AMOUNT, $amount->serializeForStorage())->setMetadataValue(FundInitiativeTransaction::PROPERTY_BACKER, $backer->getBackerPHID())->setNewValue($backer->getPHID());
     $editor = id(new FundInitiativeEditor())->setActor($viewer)->setContentSource($this->getContentSource());
     $editor->applyTransactions($this->getInitiative(), $xactions);
 }
 public function testInvalidCurrencyFromUserInput()
 {
     $map = array('--1', '$$1', '1 JPY', 'buck fiddy', '1.2.3', '1 dollar');
     $user = new PhabricatorUser();
     foreach ($map as $input) {
         $caught = null;
         try {
             PhortuneCurrency::newFromUserInput($user, $input);
         } catch (Exception $ex) {
             $caught = $ex;
         }
         $this->assertTrue($caught instanceof Exception, "{$input}");
     }
 }
 protected function buildCartContents(PhortuneCart $cart)
 {
     $rows = array();
     $total = 0;
     foreach ($cart->getPurchases() as $purchase) {
         $rows[] = array($purchase->getFullDisplayName(), 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);
 }
 protected function buildChargesTable(array $charges, $show_cart = true)
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $rows = array();
     foreach ($charges as $charge) {
         $cart = $charge->getCart();
         $cart_id = $cart->getID();
         $cart_uri = $this->getApplicationURI("cart/{$cart_id}/");
         $cart_href = phutil_tag('a', array('href' => $cart_uri), pht('Cart %d', $cart_id));
         $rows[] = array($charge->getID(), $cart_href, $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('ID'), pht('Cart'), pht('Provider'), pht('Method'), pht('Amount'), pht('Status'), pht('Created')))->setColumnClasses(array('', 'strong', '', '', 'wide right', '', ''))->setColumnVisibility(array(true, $show_cart));
     $header = id(new PHUIHeaderView())->setHeader(pht('Charge History'));
     return id(new PHUIObjectBoxView())->setHeader($header)->appendChild($charge_table);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $initiative = id(new FundInitiativeQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne();
     if (!$initiative) {
         return new Aphront404Response();
     }
     $initiative_uri = '/' . $initiative->getMonogram();
     if ($initiative->isClosed()) {
         return $this->newDialog()->setTitle(pht('Initiative Closed'))->appendParagraph(pht('You can not back a closed initiative.'))->addCancelButton($initiative_uri);
     }
     $v_amount = null;
     $e_amount = true;
     $errors = array();
     if ($request->isFormPost()) {
         $v_amount = $request->getStr('amount');
         if (!strlen($v_amount)) {
             $errors[] = pht('You must specify how much money you want to contribute to the ' . 'initiative.');
             $e_amount = pht('Required');
         } else {
             try {
                 $currency = PhortuneCurrency::newFromUserInput($viewer, $v_amount);
             } catch (Exception $ex) {
                 $errors[] = $ex->getMessage();
                 $e_amount = pht('Invalid');
             }
         }
         if (!$errors) {
             $backer = FundBacker::initializeNewBacker($viewer)->setInitiativePHID($initiative->getPHID())->attachInitiative($initiative)->setAmountInCents($currency->getValue())->save();
             // TODO: Here, we'd create a purchase and cart.
             $xactions = array();
             $xactions[] = id(new FundBackerTransaction())->setTransactionType(FundBackerTransaction::TYPE_STATUS)->setNewValue(FundBacker::STATUS_IN_CART);
             $editor = id(new FundBackerEditor())->setActor($viewer)->setContentSourceFromRequest($request);
             $editor->applyTransactions($backer, $xactions);
             // TODO: Here, we'd ship the user into Phortune.
             return id(new AphrontRedirectResponse())->setURI($initiative_uri);
         }
     }
     $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextControl())->setName('amount')->setLabel(pht('Amount'))->setValue($v_amount)->setError($e_amount));
     return $this->newDialog()->setTitle(pht('Back Initiative'))->setErrors($errors)->appendChild($form->buildLayoutView())->addCancelButton($initiative_uri)->addSubmitButton(pht('Continue'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $pager = new AphrontCursorPagerView();
     $pager->readFromRequest($request);
     $query = id(new PhortuneProductQuery())->setViewer($user);
     $products = $query->executeWithCursorPager($pager);
     $title = pht('Product List');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb('Products', $this->getApplicationURI('product/'));
     $crumbs->addAction(id(new PHUIListItemView())->setName(pht('Create Product'))->setHref($this->getApplicationURI('product/edit/'))->setIcon('fa-plus-square'));
     $product_list = id(new PHUIObjectItemListView())->setUser($user)->setNoDataString(pht('No products.'));
     foreach ($products as $product) {
         $view_uri = $this->getApplicationURI('product/view/' . $product->getID() . '/');
         $price = $product->getPriceInCents();
         $item = id(new PHUIObjectItemView())->setObjectName($product->getID())->setHeader($product->getProductName())->setHref($view_uri)->addAttribute(PhortuneCurrency::newFromUSDCents($price)->formatForDisplay())->addAttribute($product->getTypeName());
         $product_list->addItem($item);
     }
     return $this->buildApplicationPage(array($crumbs, $product_list, $pager), array('title' => $title));
 }
 private function buildPurchaseHistorySection(PhortuneAccount $account)
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $carts = id(new PhortuneCartQuery())->setViewer($viewer)->withAccountPHIDs(array($account->getPHID()))->needPurchases(true)->withStatuses(array(PhortuneCart::STATUS_PURCHASING, PhortuneCart::STATUS_PURCHASED))->execute();
     $rows = array();
     $rowc = array();
     foreach ($carts as $cart) {
         $cart_link = phutil_tag('a', array('href' => $this->getApplicationURI('cart/' . $cart->getID() . '/')), pht('Cart %d', $cart->getID()));
         $rowc[] = 'highlighted';
         $rows[] = array(phutil_tag('strong', array(), $cart_link), '', '');
         foreach ($cart->getPurchases() as $purchase) {
             $id = $purchase->getID();
             $price = $purchase->getTotalPriceInCents();
             $price = PhortuneCurrency::newFromUSDCents($price)->formatForDisplay();
             $purchase_link = phutil_tag('a', array('href' => $this->getApplicationURI('purchase/' . $id . '/')), $purchase->getFullDisplayName());
             $rowc[] = '';
             $rows[] = array('', $purchase_link, $price);
         }
     }
     $table = id(new AphrontTableView($rows))->setRowClasses($rowc)->setHeaders(array(pht('Cart'), pht('Purchase'), pht('Amount')))->setColumnClasses(array('', 'wide', 'right'));
     $header = id(new PHUIHeaderView())->setHeader(pht('Purchase History'));
     return id(new PHUIObjectBoxView())->setHeader($header)->appendChild($table);
 }
Beispiel #15
0
 public function getAmountRefundableAsCurrency()
 {
     $amount = $this->getAmountAsCurrency();
     $refunded = $this->getAmountRefundedAsCurrency();
     // We can't refund negative amounts of money, since it does not make
     // sense and is not possible in the various payment APIs.
     $refundable = $amount->subtract($refunded);
     if ($refundable->isPositive()) {
         return $refundable;
     } else {
         return PhortuneCurrency::newEmptyCurrency();
     }
 }
Beispiel #16
0
 public static function initializeNewInitiative(PhabricatorUser $actor)
 {
     $app = id(new PhabricatorApplicationQuery())->setViewer($actor)->withClasses(array('PhabricatorFundApplication'))->executeOne();
     $view_policy = $app->getPolicy(FundDefaultViewCapability::CAPABILITY);
     return id(new FundInitiative())->setOwnerPHID($actor->getPHID())->setViewPolicy($view_policy)->setEditPolicy($actor->getPHID())->setStatus(self::STATUS_OPEN)->setTotalAsCurrency(PhortuneCurrency::newEmptyCurrency());
 }
 public function testAddCurrency()
 {
     $cases = array(array('0.00 USD', '0.00 USD', '$0.00 USD'), array('1.00 USD', '1.00 USD', '$2.00 USD'), array('1.23 USD', '9.77 USD', '$11.00 USD'));
     foreach ($cases as $case) {
         list($l, $r, $expect) = $case;
         $l = PhortuneCurrency::newFromString($l);
         $r = PhortuneCurrency::newFromString($r);
         $sum = $l->add($r);
         $this->assertEqual($expect, $sum->formatForDisplay());
     }
 }
 public function getPriceAsCurrency(PhortuneProduct $product)
 {
     return PhortuneCurrency::newEmptyCurrency();
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getUser();
     $merchant = $this->loadMerchantAuthority();
     if (!$merchant) {
         return new Aphront404Response();
     }
     $merchant_id = $merchant->getID();
     $cancel_uri = $this->getApplicationURI("/merchant/{$merchant_id}/");
     // Load the user to invoice, or prompt the viewer to select one.
     $target_user = null;
     $user_phid = head($request->getArr('userPHID'));
     if (!$user_phid) {
         $user_phid = $request->getStr('userPHID');
     }
     if ($user_phid) {
         $target_user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withPHIDs(array($user_phid))->executeOne();
     }
     if (!$target_user) {
         $form = id(new AphrontFormView())->setUser($viewer)->appendRemarkupInstructions(pht('Choose a user to invoice.'))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('User'))->setDatasource(new PhabricatorPeopleDatasource())->setName('userPHID')->setLimit(1));
         return $this->newDialog()->setTitle(pht('Choose User'))->appendForm($form)->addCancelButton($cancel_uri)->addSubmitButton(pht('Continue'));
     }
     // Load the account to invoice, or prompt the viewer to select one.
     $target_account = null;
     $account_phid = $request->getStr('accountPHID');
     if ($account_phid) {
         $target_account = id(new PhortuneAccountQuery())->setViewer($viewer)->withPHIDs(array($account_phid))->withMemberPHIDs(array($target_user->getPHID()))->executeOne();
     }
     if (!$target_account) {
         $accounts = PhortuneAccountQuery::loadAccountsForUser($target_user, PhabricatorContentSource::newFromRequest($request));
         $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('userPHID', $target_user->getPHID())->appendRemarkupInstructions(pht('Choose which account to invoice.'))->appendControl(id(new AphrontFormMarkupControl())->setLabel(pht('User'))->setValue($viewer->renderHandle($target_user->getPHID())))->appendControl(id(new AphrontFormSelectControl())->setLabel(pht('Account'))->setName('accountPHID')->setValue($account_phid)->setOptions(mpull($accounts, 'getName', 'getPHID')));
         return $this->newDialog()->setTitle(pht('Choose Account'))->appendForm($form)->addCancelButton($cancel_uri)->addSubmitButton(pht('Continue'));
     }
     // Now we build the actual invoice.
     $title = pht('New Invoice');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($merchant->getName());
     $v_title = $request->getStr('title');
     $e_title = true;
     $v_name = $request->getStr('name');
     $e_name = true;
     $v_cost = $request->getStr('cost');
     $e_cost = true;
     $v_desc = $request->getStr('description');
     $v_quantity = 1;
     $e_quantity = null;
     $errors = array();
     if ($request->isFormPost() && $request->getStr('invoice')) {
         $v_quantity = $request->getStr('quantity');
         $e_title = null;
         $e_name = null;
         $e_cost = null;
         $e_quantity = null;
         if (!strlen($v_title)) {
             $e_title = pht('Required');
             $errors[] = pht('You must title this invoice.');
         }
         if (!strlen($v_name)) {
             $e_name = pht('Required');
             $errors[] = pht('You must provide a name for this purchase.');
         }
         if (!strlen($v_cost)) {
             $e_cost = pht('Required');
             $errors[] = pht('You must provide a cost for this purchase.');
         } else {
             try {
                 $v_currency = PhortuneCurrency::newFromUserInput($viewer, $v_cost);
             } catch (Exception $ex) {
                 $errors[] = $ex->getMessage();
                 $e_cost = pht('Invalid');
             }
         }
         if ((int) $v_quantity <= 0) {
             $e_quantity = pht('Invalid');
             $errors[] = pht('Quantity must be a positive integer.');
         }
         if (!$errors) {
             $unique = Filesystem::readRandomCharacters(16);
             $product = id(new PhortuneProductQuery())->setViewer($target_user)->withClassAndRef('PhortuneAdHocProduct', $unique)->executeOne();
             $cart_implementation = new PhortuneAdHocCart();
             $cart = $target_account->newCart($target_user, $cart_implementation, $merchant);
             $cart->setMetadataValue('adhoc.title', $v_title)->setMetadataValue('adhoc.description', $v_desc);
             $purchase = $cart->newPurchase($target_user, $product)->setBasePriceAsCurrency($v_currency)->setQuantity((int) $v_quantity)->setMetadataValue('adhoc.name', $v_name)->save();
             $cart->setIsInvoice(1)->save();
             $cart->activateCart();
             $cart_id = $cart->getID();
             $uri = "/merchant/{$merchant_id}/cart/{$cart_id}/";
             $uri = $this->getApplicationURI($uri);
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('userPHID', $target_user->getPHID())->addHiddenInput('accountPHID', $target_account->getPHID())->addHiddenInput('invoice', true)->appendControl(id(new AphrontFormMarkupControl())->setLabel(pht('User'))->setValue($viewer->renderHandle($target_user->getPHID())))->appendControl(id(new AphrontFormMarkupControl())->setLabel(pht('Account'))->setValue($viewer->renderHandle($target_account->getPHID())))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Invoice Title'))->setName('title')->setValue($v_title)->setError($e_title))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Purchase Name'))->setName('name')->setValue($v_name)->setError($e_name))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Purchase Cost'))->setName('cost')->setValue($v_cost)->setError($e_cost))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Quantity'))->setName('quantity')->setValue($v_quantity)->setError($e_quantity))->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Invoice Description'))->setName('description')->setValue($v_desc))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue(pht('Send Invoice')));
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('New Invoice'))->setFormErrors($errors)->setForm($form);
     return $this->buildApplicationPage(array($crumbs, $box), array('title' => $title));
 }
 public function getPriceAsCurrency(PhortuneProduct $product)
 {
     // Prices are calculated by the SubscriptionImplementation.
     return PhortuneCurrency::newEmptyCurrency();
 }
 public function willReadValue($value)
 {
     return PhortuneCurrency::newFromString($value);
 }
Beispiel #22
0
 public function getTotalPriceAsCurrency()
 {
     $prices = array();
     foreach ($this->getPurchases() as $purchase) {
         $prices[] = $purchase->getTotalPriceAsCurrency();
     }
     return PhortuneCurrency::newFromList($prices);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($this->productID) {
         $product = id(new PhortuneProductQuery())->setViewer($user)->withIDs(array($this->productID))->executeOne();
         if (!$product) {
             return new Aphront404Response();
         }
         $is_create = false;
         $cancel_uri = $this->getApplicationURI('product/view/' . $this->productID . '/');
     } else {
         $product = new PhortuneProduct();
         $is_create = true;
         $cancel_uri = $this->getApplicationURI('product/');
     }
     $v_name = $product->getProductName();
     $v_type = $product->getProductType();
     $v_price = (int) $product->getPriceInCents();
     $display_price = PhortuneCurrency::newFromUSDCents($v_price)->formatForDisplay();
     $e_name = true;
     $e_type = null;
     $e_price = true;
     $errors = array();
     if ($request->isFormPost()) {
         $v_name = $request->getStr('name');
         if (!strlen($v_name)) {
             $e_name = pht('Required');
             $errors[] = pht('Product must have a name.');
         } else {
             $e_name = null;
         }
         if ($is_create) {
             $v_type = $request->getStr('type');
             $type_map = PhortuneProduct::getTypeMap();
             if (empty($type_map[$v_type])) {
                 $e_type = pht('Invalid');
                 $errors[] = pht('Product type is invalid.');
             } else {
                 $e_type = null;
             }
         }
         $display_price = $request->getStr('price');
         try {
             $v_price = PhortuneCurrency::newFromUserInput($user, $display_price)->getValue();
             $e_price = null;
         } catch (Exception $ex) {
             $errors[] = pht('Price should be formatted as: $1.23');
             $e_price = pht('Invalid');
         }
         if (!$errors) {
             $xactions = array();
             $xactions[] = id(new PhortuneProductTransaction())->setTransactionType(PhortuneProductTransaction::TYPE_NAME)->setNewValue($v_name);
             $xactions[] = id(new PhortuneProductTransaction())->setTransactionType(PhortuneProductTransaction::TYPE_TYPE)->setNewValue($v_type);
             $xactions[] = id(new PhortuneProductTransaction())->setTransactionType(PhortuneProductTransaction::TYPE_PRICE)->setNewValue($v_price);
             $editor = id(new PhortuneProductEditor())->setActor($user)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request);
             $editor->applyTransactions($product, $xactions);
             return id(new AphrontRedirectResponse())->setURI($this->getApplicationURI('product/view/' . $product->getID() . '/'));
         }
     }
     if ($errors) {
         $errors = id(new AphrontErrorView())->setErrors($errors);
     }
     $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($v_name)->setError($e_name))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Type'))->setName('type')->setValue($v_type)->setError($e_type)->setOptions(PhortuneProduct::getTypeMap())->setDisabled(!$is_create))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Price'))->setName('price')->setValue($display_price)->setError($e_price))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_create ? pht('Create Product') : pht('Save Product'))->addCancelButton($cancel_uri));
     $title = pht('Edit Product');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Products'), $this->getApplicationURI('product/'));
     $crumbs->addTextCrumb($is_create ? pht('Create') : pht('Edit'), $request->getRequestURI());
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Edit Product'))->appendChild($form);
     return $this->buildApplicationPage(array($crumbs, $box), array('title' => $title));
 }
 public function getTitleForFeed()
 {
     $author_phid = $this->getAuthorPHID();
     $object_phid = $this->getObjectPHID();
     $old = $this->getOldValue();
     $new = $this->getNewValue();
     $type = $this->getTransactionType();
     switch ($type) {
         case self::TYPE_NAME:
             if ($old === null) {
                 return pht('%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             } else {
                 return pht('%s renamed %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             }
             break;
         case self::TYPE_DESCRIPTION:
             return pht('%s updated the description for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
         case self::TYPE_STATUS:
             switch ($new) {
                 case FundInitiative::STATUS_OPEN:
                     return pht('%s reopened %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
                 case FundInitiative::STATUS_CLOSED:
                     return pht('%s closed %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid));
             }
             break;
         case self::TYPE_BACKER:
             $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT);
             $amount = PhortuneCurrency::newFromString($amount);
             return pht('%s backed %s with %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $amount->formatForDisplay());
         case self::TYPE_REFUND:
             $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT);
             $amount = PhortuneCurrency::newFromString($amount);
             $backer_phid = $this->getMetadataValue(self::PROPERTY_BACKER);
             return pht('%s refunded %s to %s for %s.', $this->renderHandleLink($author_phid), $amount->formatForDisplay(), $this->renderHandleLink($backer_phid), $this->renderHandleLink($object_phid));
     }
     return parent::getTitleForFeed();
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $authority = $this->loadMerchantAuthority();
     $cart_query = id(new PhortuneCartQuery())->setViewer($viewer)->withIDs(array($this->id))->needPurchases(true);
     if ($authority) {
         $cart_query->withMerchantPHIDs(array($authority->getPHID()));
     }
     $cart = $cart_query->executeOne();
     if (!$cart) {
         return new Aphront404Response();
     }
     switch ($this->action) {
         case 'cancel':
             // You must be able to edit the account to cancel an order.
             PhabricatorPolicyFilter::requireCapability($viewer, $cart->getAccount(), PhabricatorPolicyCapability::CAN_EDIT);
             $is_refund = false;
             break;
         case 'refund':
             // You must be able to control the merchant to refund an order.
             PhabricatorPolicyFilter::requireCapability($viewer, $cart->getMerchant(), PhabricatorPolicyCapability::CAN_EDIT);
             $is_refund = true;
             break;
         default:
             return new Aphront404Response();
     }
     $cancel_uri = $cart->getDetailURI($authority);
     $merchant = $cart->getMerchant();
     try {
         if ($is_refund) {
             $title = pht('Unable to Refund Order');
             $cart->assertCanRefundOrder();
         } else {
             $title = pht('Unable to Cancel Order');
             $cart->assertCanCancelOrder();
         }
     } catch (Exception $ex) {
         return $this->newDialog()->setTitle($title)->appendChild($ex->getMessage())->addCancelButton($cancel_uri);
     }
     $charges = id(new PhortuneChargeQuery())->setViewer($viewer)->withCartPHIDs(array($cart->getPHID()))->withStatuses(array(PhortuneCharge::STATUS_HOLD, PhortuneCharge::STATUS_CHARGED))->execute();
     $amounts = mpull($charges, 'getAmountAsCurrency');
     $maximum = PhortuneCurrency::newFromList($amounts);
     $v_refund = $maximum->formatForDisplay();
     $errors = array();
     $e_refund = true;
     if ($request->isFormPost()) {
         if ($is_refund) {
             try {
                 $refund = PhortuneCurrency::newFromUserInput($viewer, $request->getStr('refund'));
                 $refund->assertInRange('0.00 USD', $maximum->formatForDisplay());
             } catch (Exception $ex) {
                 $errors[] = $ex->getMessage();
                 $e_refund = pht('Invalid');
             }
         } else {
             $refund = $maximum;
         }
         if (!$errors) {
             $charges = msort($charges, 'getID');
             $charges = array_reverse($charges);
             if ($charges) {
                 $providers = id(new PhortunePaymentProviderConfigQuery())->setViewer($viewer)->withPHIDs(mpull($charges, 'getProviderPHID'))->execute();
                 $providers = mpull($providers, null, 'getPHID');
             } else {
                 $providers = array();
             }
             foreach ($charges as $charge) {
                 $refundable = $charge->getAmountRefundableAsCurrency();
                 if (!$refundable->isPositive()) {
                     // This charge is a refund, or has already been fully refunded.
                     continue;
                 }
                 if ($refund->isGreaterThan($refundable)) {
                     $refund_amount = $refundable;
                 } else {
                     $refund_amount = $refund;
                 }
                 $provider_config = idx($providers, $charge->getProviderPHID());
                 if (!$provider_config) {
                     throw new Exception(pht('Unable to load provider for charge!'));
                 }
                 $provider = $provider_config->buildProvider();
                 $refund_charge = $cart->willRefundCharge($viewer, $provider, $charge, $refund_amount);
                 $refunded = false;
                 try {
                     $provider->refundCharge($charge, $refund_charge);
                     $refunded = true;
                 } catch (Exception $ex) {
                     phlog($ex);
                     $cart->didFailRefund($charge, $refund_charge);
                 }
                 if ($refunded) {
                     $cart->didRefundCharge($charge, $refund_charge);
                     $refund = $refund->subtract($refund_amount);
                 }
                 if (!$refund->isPositive()) {
                     break;
                 }
             }
             if ($refund->isPositive()) {
                 throw new Exception(pht('Unable to refund some charges!'));
             }
             // TODO: If every HOLD and CHARGING transaction has been fully refunded
             // 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);
         }
     }
     if ($is_refund) {
         $title = pht('Refund Order?');
         $body = pht('Really refund this order?');
         $button = pht('Refund Order');
         $cancel_text = pht('Cancel');
         $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextControl())->setName('refund')->setLabel(pht('Amount'))->setError($e_refund)->setValue($v_refund));
         $form = $form->buildLayoutView();
     } else {
         $title = pht('Cancel Order?');
         $body = pht('Really cancel this order? Any payment will be refunded.');
         $button = pht('Cancel Order');
         // Don't give the user a "Cancel" button in response to a "Cancel?"
         // prompt, as it's confusing.
         $cancel_text = pht('Do Not Cancel Order');
         $form = null;
     }
     return $this->newDialog()->setTitle($title)->setErrors($errors)->appendChild($body)->appendChild($form)->addSubmitButton($button)->addCancelButton($cancel_uri, $cancel_text);
 }
 protected function renderResultList(array $backers, PhabricatorSavedQuery $query, array $handles)
 {
     assert_instances_of($backers, 'FundBacker');
     $viewer = $this->requireViewer();
     $list = id(new PHUIObjectItemListView());
     foreach ($backers as $backer) {
         $backer_handle = $handles[$backer->getBackerPHID()];
         $currency = PhortuneCurrency::newFromUSDCents($backer->getAmountInCents());
         $header = pht('%s for %s', $currency->formatForDisplay(), $handles[$backer->getInitiativePHID()]->renderLink());
         $item = id(new PHUIObjectItemView())->setHeader($header)->addIcon('none', phabricator_datetime($backer->getDateCreated(), $viewer))->addByline(pht('Backer: %s', $backer_handle->renderLink()));
         $list->addItem($item);
     }
     return $list;
 }
 /**
  * @phutil-external-symbol class WePay
  */
 public function processControllerRequest(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';
     WePay::useStaging($this->getWePayClientID(), $this->getWePayClientSecret());
     $wepay = new WePay($this->getWePayAccessToken());
     switch ($controller->getAction()) {
         case 'checkout':
             $return_uri = $this->getControllerURI('charge', array('cartID' => $cart->getID()));
             $cancel_uri = $this->getControllerURI('cancel', array('cartID' => $cart->getID()));
             $total_in_cents = $cart->getTotalPriceInCents();
             $price = PhortuneCurrency::newFromUSDCents($total_in_cents);
             $params = array('account_id' => $this->getWePayAccountID(), 'short_description' => 'Services', 'type' => 'SERVICE', 'amount' => $price->formatBareValue(), 'long_description' => 'Services', 'reference_id' => $cart->getPHID(), 'app_fee' => 0, 'fee_payer' => 'Payee', 'redirect_uri' => $return_uri, 'fallback_uri' => $cancel_uri, 'auto_capture' => true, 'require_shipping' => 0, 'shipping_fee' => 0, 'charge_tax' => 0, 'mode' => 'regular', 'funding_sources' => 'bank,cc');
             $result = $wepay->request('checkout/create', $params);
             // 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())->setIsExternal(true)->setURI($uri);
         case 'charge':
             $checkout_id = $request->getInt('checkout_id');
             $params = array('checkout_id' => $checkout_id);
             $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())->setIsExternal(true)->setURI($cart_uri);
         case 'cancel':
             var_dump($_REQUEST);
             break;
     }
     throw new Exception("The rest of this isn't implemented yet.");
 }