public function testModifierFailure() { if (!ShopTools::DBConn()->supportsTransactions()) { $this->markTestSkipped('The Database doesn\'t support transactions.'); } Config::inst()->update('Order', 'modifiers', array('OrderModifierTest_TestModifier')); $order = $this->createOrder(); $order->calculate(); $order->write(); // 408 from items + 10 from modifier + 25% from tax $this->assertEquals('522.5', $order->Total); $amounts = array(); foreach ($order->Modifiers()->sort('Sort') as $modifier) { $amounts[] = (string) $modifier->Amount; } $this->assertEquals(array('10', '104.5'), $amounts); OrderModifierTest_TestModifier::$value = 42; try { // Calculate will now fail! $order->calculate(); } catch (Exception $e) { } // reload order from DB $order = Order::get()->byID($order->ID); // Order Total should not have changed $this->assertEquals('522.5', $order->Total); $amounts = array(); foreach ($order->Modifiers()->sort('Sort') as $modifier) { $amounts[] = (string) $modifier->Amount; } $this->assertEquals(array('10', '104.5'), $amounts, 'Modifiers aren\'t allowed to change upon failure'); }
/** * Takes an order from being a cart to awaiting payment. * * @param Member $member - assign a member to the order * * @return boolean - success/failure */ public function placeOrder() { if (!$this->order) { $this->error(_t("OrderProcessor.NoOrderStarted", "A new order has not yet been started.")); return false; } if (!$this->canPlace($this->order)) { //final cart validation return false; } if ($this->order->Locale) { ShopTools::install_locale($this->order->Locale); } // recalculate order to be sure we have the correct total $this->order->calculate(); if (ShopTools::DBConn()->supportsTransactions()) { ShopTools::DBConn()->transactionStart(); } //update status if ($this->order->TotalOutstanding(false)) { $this->order->Status = 'Unpaid'; } else { $this->order->Status = 'Paid'; } if (!$this->order->Placed) { $this->order->Placed = SS_Datetime::now()->Rfc2822(); //record placed order datetime if ($request = Controller::curr()->getRequest()) { $this->order->IPAddress = $request->getIP(); //record client IP } } // Add an error handler that throws an exception upon error, so that we can catch errors as exceptions // in the following block. set_error_handler(function ($severity, $message, $file, $line) { throw new ErrorException($message, 0, $severity, $file, $line); }, E_ALL & ~(E_STRICT | E_NOTICE)); try { //re-write all attributes and modifiers to make sure they are up-to-date before they can't be changed again $items = $this->order->Items(); if ($items->exists()) { foreach ($items as $item) { $item->onPlacement(); $item->write(); } } $modifiers = $this->order->Modifiers(); if ($modifiers->exists()) { foreach ($modifiers as $modifier) { $modifier->write(); } } //add member to order & customers group if ($member = Member::currentUser()) { if (!$this->order->MemberID) { $this->order->MemberID = $member->ID; } $cgroup = ShopConfig::current()->CustomerGroup(); if ($cgroup->exists()) { $member->Groups()->add($cgroup); } } //allow decorators to do stuff when order is saved. $this->order->extend('onPlaceOrder'); $this->order->write(); } catch (Exception $ex) { // Rollback the transaction if an error occurred if (ShopTools::DBConn()->supportsTransactions()) { ShopTools::DBConn()->transactionRollback(); } $this->error($ex->getMessage()); return false; } finally { // restore the error handler, no matter what restore_error_handler(); } // Everything went through fine, complete the transaction if (ShopTools::DBConn()->supportsTransactions()) { ShopTools::DBConn()->transactionEnd(); } //remove from session $cart = ShoppingCart::curr(); if ($cart && $cart->ID == $this->order->ID) { // clear the cart, but don't write the order in the process (order is finalized and should NOT be overwritten) ShoppingCart::singleton()->clear(false); } //send confirmation if configured and receipt hasn't been sent if (self::config()->send_confirmation && !$this->order->ReceiptSent) { $this->notifier->sendConfirmation(); } //notify admin, if configured if (self::config()->send_admin_notification) { $this->notifier->sendAdminNotification(); } // Save order reference to session OrderManipulation::add_session_order($this->order); return true; //report success }
public function testPlaceFailure() { if (!ShopTools::DBConn()->supportsTransactions()) { $this->markTestSkipped('The Database doesn\'t support transactions.'); } // Add the erroneous extension Order::add_extension('OrderProcessorTest_PlaceFailExtension'); Config::inst()->update('Product', 'order_item', 'OrderProcessorTest_CustomOrderItem'); //log out the admin user Member::currentUser()->logOut(); $joemember = $this->objFromFixture('Member', 'joebloggs'); $joemember->logIn(); $this->shoppingcart->add($this->mp3player); $cart = ShoppingCart::curr(); $cart->calculate(); $this->assertDOSContains(array(array('ClassName' => 'OrderProcessorTest_CustomOrderItem')), $cart->Items()); $versions = Product_OrderItem::get()->filter('OrderID', $cart->ID)->column('ProductVersion'); // The Product_OrderItem should not reference a product version while the order is not placed $this->assertEquals(array(0), $versions); $this->assertTrue($cart->has_extension('OrderProcessorTest_PlaceFailExtension')); // Placing the order will fail. $this->assertFalse($this->placeOrder('Joseph', 'Blog', '*****@*****.**', '100 Melrose Place', null, 'Martinsonville', 'New Mexico', null, 'EG', 'newpassword', 'newpassword', $joemember), "Member order placed successfully"); $order = Order::get()->byID($cart->ID); //update order variable to db-stored version $this->assertNotNull($this->shoppingcart->current(), "Shopping is still present"); $this->assertNotNull($order); $this->assertNull($order->Placed); $this->assertEquals($order->Status, 'Cart', 'Status should still be "Cart"'); // When order failed, everything that was written during the placement should be rolled back $versions = Product_OrderItem::get()->filter('OrderID', $cart->ID)->column('ProductVersion'); // The Product_OrderItem should still not reference a product if the rollback worked $this->assertEquals(array(0), $versions); $this->assertEquals(0, OrderProcessorTest_CustomOrderItem::get()->filter('OrderID', $cart->ID)->first()->IsPlaced); Order::remove_extension('OrderProcessorTest_PlaceFailExtension'); $this->shoppingcart->clear(false); }