/** * Validate this form field, make sure the {@link Item} exists, is in the current * {@link Order} and the item is valid for adding to the cart. * * @see FormField::validate() * @return Boolean */ function validate($validator) { $valid = true; $item = $this->Item(); $currentOrder = CartControllerExtension::get_current_order(); $items = $currentOrder->Items(); //Check that item exists and is in the current order if (!$item || !$item->exists() || !$items->find('ID', $item->ID)) { $errorMessage = _t('Form.ITEM_IS_NOT_IN_ORDER', 'This product is not in the Order.'); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } else { if ($item) { $validation = $item->validateForCart(); if (!$validation->valid()) { $errorMessage = $validation->message(); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } } } return $valid; }
/** * Check that current order is valid * * @param Array $data Submitted data * @return Boolean Returns TRUE if the submitted data is valid, otherwise FALSE. */ function php($data) { //TODO move the form error messages to CheckoutForm::validate() $valid = parent::php($data); $fields = $this->form->Fields(); //Check the order is valid $currentOrder = CartControllerExtension::get_current_order(); if (!$currentOrder) { $this->form->sessionMessage(_t('Form.ORDER_IS_NOT_VALID', 'Your cart seems to be empty, please add an item from the shop'), 'bad'); //Have to set an error for Form::validate() $this->errors[] = true; $valid = false; } else { $validation = $currentOrder->validateForCart(); if (!$validation->valid()) { $this->form->sessionMessage(_t('Form.ORDER_IS_NOT_VALID', 'There seems to be a problem with your order. ' . $validation->message()), 'bad'); //Have to set an error for Form::validate() $this->errors[] = true; $valid = false; } } return $valid; }
/** * Try to checkout with valid flat fee shipping option */ function testCheckoutFlatFeeShipping() { $productA = $this->objFromFixture('Product', 'productA'); $taxRate = $this->objFromFixture('FlatFeeTaxRate', 'gstNewZealand'); $countryNZ = $this->objFromFixture('Country_Shipping', 'newZealand'); $buyer = $this->objFromFixture('Customer', 'buyer'); $checkoutPage = DataObject::get_one('CheckoutPage'); $accountPage = DataObject::get_one('AccountPage'); $this->loginAs('admin'); $productA->doPublish(); $checkoutPage->doPublish(); $accountPage->doPublish(); $this->logOut(); $this->assertTrue($productA->isPublished()); $this->loginAs($buyer); $orders = $buyer->Orders(); $this->assertEquals(1, $orders->Count()); $this->get(Director::makeRelative($productA->Link())); $this->submitForm('AddToCartForm_AddToCartForm', null, array('Quantity' => 1)); $order = CartControllerExtension::get_current_order(); $items = $order->Items(); $this->assertEquals(1, $items->Count()); $this->assertEquals($productA->ID, $items->First()->Object()->ID); $this->get(Director::makeRelative($checkoutPage->Link())); //Set a modification for this Order via updateOrderFormCart $data = $this->getFormDataNested('CheckoutForm_OrderForm'); $this->post(Director::makeRelative($checkoutPage->Link() . 'updateOrderFormCart'), $data); $this->get(Director::makeRelative($checkoutPage->Link())); $this->submitForm('CheckoutForm_OrderForm', null, array('Shipping[Country]' => $countryNZ->ID, 'Modifiers[FlatFeeTax]' => $taxRate->ID)); $orders = $buyer->Orders(); $orders->sort('ID', "ASC"); $this->assertEquals(2, $orders->Count()); $order = $orders->Last(); $this->assertEquals(15, $taxRate->Rate); $realTotal = $order->SubTotal->getAmount() * 1.15; $this->assertEquals($orders->Last()->Total->getAmount(), $realTotal); }
/** * Add a product variation to the cart, change the cart so that it is out of date * then delete it */ function testRemoveAbandonedCartsWithProductVariationsTask() { $teeshirtA = $this->objFromFixture('Product', 'teeshirtA'); $this->logInAs('admin'); $teeshirtA->doPublish(); $this->logOut(); $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton'); $this->assertEquals('Enabled', $teeshirtAVariation->Status); $this->assertEquals(5, $teeshirtAVariation->StockLevel()->Level); //Add variation to the cart $this->get(Director::makeRelative($teeshirtA->Link())); $data = array('Quantity' => 1); foreach ($teeshirtAVariation->Options() as $option) { $data["Options[{$option->AttributeID}]"] = $option->ID; } $this->submitForm('AddToCartForm_AddToCartForm', null, $data); $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton'); $this->assertEquals(4, $teeshirtAVariation->StockLevel()->Level); $order = CartControllerExtension::get_current_order(); $this->logInAs('admin'); $order->LastActive = '2011-12-22 17:02:49'; $order->Status = 'Cart'; $order->write(); $this->logOut(); Order::delete_abandoned(); DataObject::flush_and_destroy_cache(); $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton'); $this->assertEquals(5, $teeshirtAVariation->StockLevel()->Level); }
/** * Update the order form cart, called via AJAX with current order form data. * Renders the cart and sends that back for displaying on the order form page. * * @param SS_HTTPRequest $data Form data sent via AJAX POST. * @return String Rendered cart for the order form, template include 'CheckoutFormOrder'. */ function updateOrderFormCart(SS_HTTPRequest $data) { if ($data->isPOST()) { $fields = array(); $validator = new OrderFormValidator(); $member = Customer::currentUser() ? Customer::currentUser() : singleton('Customer'); $order = CartControllerExtension::get_current_order(); //Update the Order $order->addAddressesAtCheckout($data->postVars()); $order->addModifiersAtCheckout($data->postVars()); //TODO update personal details, notes and payment type? //Create the part of the form that displays the Order $this->addItemFields($fields, $validator, $order); $this->addModifierFields($fields, $validator, $order); //This is going to go through and add modifiers based on current Form DATA //TODO This should be constructed for non-dropdown fields as well //Update modifier form fields so that the dropdown values are correct $newModifierData = array(); $subTotalModifiers = isset($fields['SubTotalModifiers']) ? $fields['SubTotalModifiers'] : array(); $totalModifiers = isset($fields['Modifiers']) ? $fields['Modifiers'] : array(); $modifierFields = array_merge($subTotalModifiers, $totalModifiers); foreach ($modifierFields as $field) { if (method_exists($field, 'updateValue')) { $field->updateValue($order); } $modifierClassName = get_class($field->getModifier()); $newModifierData['Modifiers'][$modifierClassName] = $field->Value(); } //Add modifiers to the order again so that the new values are used $order->addModifiersAtCheckout($newModifierData); $actions = new FieldSet(new FormAction('ProcessOrder', _t('CheckoutPage.PROCEED_TO_PAY', "Proceed to pay"))); $form = new CheckoutForm($this, 'OrderForm', $fields, $actions, $validator, $order); $form->disableSecurityToken(); $form->validate(); return $form->renderWith('CheckoutFormOrder'); } }
/** * Try checkout with invalid flat fee shipping option */ function testCheckoutInvalidFlatFeeShipping() { $productA = $this->objFromFixture('Product', 'productA'); $shippingMainCentreAustralia = $this->objFromFixture('FlatFeeShippingRate', 'MainCentreAustralia'); $shippingAmount = $shippingMainCentreAustralia->Amount->getAmount(); $checkoutPage = DataObject::get_one('CheckoutPage'); $accountPage = DataObject::get_one('AccountPage'); $this->loginAs('admin'); $productA->doPublish(); $checkoutPage->doPublish(); $accountPage->doPublish(); $this->logOut(); $this->assertTrue($productA->isPublished()); $this->loginAs($this->objFromFixture('Customer', 'buyer')); $buyer = $this->objFromFixture('Customer', 'buyer'); $orders = $buyer->Orders(); $this->assertEquals(1, $orders->Count()); $this->get(Director::makeRelative($productA->Link())); $this->submitForm('AddToCartForm_AddToCartForm', null, array('Quantity' => 1)); $order = CartControllerExtension::get_current_order(); $items = $order->Items(); $this->assertEquals(1, $items->Count()); $this->assertEquals($productA->ID, $items->First()->Object()->ID); $checkoutPage = DataObject::get_one('CheckoutPage'); $this->get(Director::makeRelative($checkoutPage->Link())); $this->submitForm('CheckoutForm_OrderForm', null, array('Shipping[Country]' => 'NZ', 'Modifiers[FlatFeeShipping]' => $shippingMainCentreAustralia->ID)); $orders = $buyer->Orders(); $orders->sort('ID', "ASC"); $this->assertEquals(1, $orders->Count()); $realTotal = $productA->Amount->getAmount(); $this->assertEquals($orders->Last()->Total->getAmount(), $realTotal); $this->assertEquals(0, $orders->Last()->Modifications()->Count()); }
/** * Try checking out an order without specifying a payment gateway */ function testCheckoutWithoutPaymentGateway() { $productA = $this->objFromFixture('Product', 'productA'); $this->loginAs('admin'); $productA->doPublish(); $this->logOut(); $buyer = $this->objFromFixture('Customer', 'buyer'); $this->assertEquals(1, $buyer->Orders()->Count()); $this->loginAs($this->objFromFixture('Customer', 'buyer')); $productALink = $productA->Link(); $this->get(Director::makeRelative($productALink)); $this->submitForm('AddToCartForm_AddToCartForm', null, array('Quantity' => 1)); $order = CartControllerExtension::get_current_order(); $items = $order->Items(); $this->assertEquals(1, $items->Count()); $checkoutPage = DataObject::get_one('CheckoutPage'); $this->get(Director::makeRelative($checkoutPage->Link())); //Submit the form without restrictions on what can be POST'd $data = $this->getFormData('CheckoutForm_OrderForm'); $data['PaymentMethod'] = ''; $this->post(Director::absoluteURL('/checkout/OrderForm'), $data); $this->assertEquals(1, $buyer->Orders()->Count()); }
/** * Add an item to the current cart ({@link Order}) for a given {@link Product}. * * @param Array $data * @param Form $form */ function add(array $data, Form $form) { CartControllerExtension::get_current_order()->addItem($this->getProduct(), $this->getQuantity(), $this->getProductOptions()); //Show feedback if redirecting back to the Product page if (!$this->getRequest()->requestVar('Redirect')) { $cartPage = DataObject::get_one('CartPage'); $message = $cartPage ? 'The product was added to <a href="' . $cartPage->Link() . '">your cart</a>.' : "The product was added to your cart."; $form->sessionMessage($message, 'good'); } $this->goToNextPage(); }
/** * Validate this field, check that the current {@link Item} is in the current * {@Link Order} and is valid for adding to the cart. * * @see FormField::validate() * @return Boolean */ function validate($validator) { $valid = true; $item = $this->Item(); $currentOrder = CartControllerExtension::get_current_order(); $items = $currentOrder->Items(); $quantity = $this->Value(); $removingItem = false; if ($quantity == 0) { $removingItem = true; } //Check that item exists and is in the current order if (!$item || !$item->exists() || !$items->find('ID', $item->ID)) { $errorMessage = _t('Form.ITEM_IS_NOT_IN_ORDER', 'This product is not in the Cart.'); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } else { if ($item && !$removingItem) { //If quantity is zero the item is removed already @see CartPage::saveCart() if (!$quantity || !is_numeric($quantity) || $quantity <= 0) { $errorMessage = _t('Form.ITEM_QUANTITY_INCORRECT', 'The quantity must be at least one (1).'); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } $validation = $item->validateForCart(); if (!$validation->valid()) { $errorMessage = $validation->message(); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } } } //Check that quantity for an item is not being pushed beyond available stock levels for a product $quantityChange = $quantity - $item->Quantity; if ($item) { $variation = $item->Variation(); $product = $item->Product(); $stockLevel = 0; if ($variation) { $stockLevel = $variation->StockLevel()->Level; } else { $stockLevel = $product->StockLevel()->Level; } if ($quantityChange > 0 && $quantityChange > $stockLevel && $stockLevel > -1) { //If the change in quantity is greater than the remaining stock level then there is a problem $errorMessage = _t('Form.ITEM_QUANTITY_INCORRECT', 'Quantity is greater than remaining stock.'); if ($msg = $this->getCustomValidationMessage()) { $errorMessage = $msg; } $validator->validationError($this->Name(), $errorMessage, "error"); $valid = false; } } return $valid; }
/** * Save the cart, update the order item quantities and the order total. * * @param Array $data Data submitted from the form via POST * @param Form $form Form that data was submitted from */ private function saveCart(array $data, Form $form) { $currentOrder = CartControllerExtension::get_current_order(); $quantities = isset($data['Quantity']) ? $data['Quantity'] : null; if ($quantities) { foreach ($quantities as $itemID => $quantity) { if ($item = $currentOrder->Items()->find('ID', $itemID)) { if ($quantity == 0) { $item->delete(); } else { $item->Quantity = $quantity; $item->write(); } } } } $currentOrder->updateTotal(); }
/** * Add addresses to this Order at the checkout. * * @param Array $data */ function addAddressesAtCheckout(array $data) { $member = Customer::currentUser() ? Customer::currentUser() : singleton('Customer'); $order = CartControllerExtension::get_current_order(); $billingCountries = Country::billing_countries(); $shippingCountries = Country::shipping_countries(); $shippingRegions = Region::shipping_regions(); //If there is a current billing and shipping address, update them, otherwise create new ones $existingBillingAddress = $this->BillingAddress(); $existingShippingAddress = $this->ShippingAddress(); if ($existingBillingAddress && $existingBillingAddress->exists()) { $newData = array(); if (isset($data['Billing']) && is_array($data['Billing'])) { foreach ($data['Billing'] as $fieldName => $value) { $newData[$fieldName] = $value; } } $newData['CountryID'] = $data['Billing']['Country']; $newData['CountryName'] = in_array($newData['CountryID'], array_keys($billingCountries)) ? $billingCountries[$newData['CountryID']] : null; if ($member->ID) { $newData['MemberID'] = $member->ID; } $existingBillingAddress->update($newData); $existingBillingAddress->write(); } else { $billingAddress = new Address(); $billingAddress->OrderID = $order->ID; if ($member->ID) { $billingAddress->MemberID = $member->ID; } $billingAddress->FirstName = $data['Billing']['FirstName']; $billingAddress->Surname = $data['Billing']['Surname']; $billingAddress->Company = $data['Billing']['Company']; $billingAddress->Address = $data['Billing']['Address']; $billingAddress->AddressLine2 = $data['Billing']['AddressLine2']; $billingAddress->City = $data['Billing']['City']; $billingAddress->PostalCode = $data['Billing']['PostalCode']; $billingAddress->State = $data['Billing']['State']; $billingAddress->CountryID = $data['Billing']['Country']; $billingAddress->CountryName = in_array($data['Billing']['Country'], array_keys($billingCountries)) ? $billingCountries[$data['Billing']['Country']] : null; $billingAddress->Type = 'Billing'; $billingAddress->write(); } if ($existingShippingAddress && $existingShippingAddress->exists()) { $newData = array(); if (isset($data['Shipping']) && is_array($data['Shipping'])) { foreach ($data['Shipping'] as $fieldName => $value) { $newData[$fieldName] = $value; } } $newData['CountryID'] = $data['Shipping']['Country']; $newData['CountryName'] = in_array($newData['CountryID'], array_keys($shippingCountries)) ? $shippingCountries[$newData['CountryID']] : null; if (isset($newData['Region']) && isset($shippingRegions[$newData['Country']])) { if (in_array($newData['Region'], array_keys($shippingRegions[$newData['Country']]))) { $newData['RegionName'] = $shippingRegions[$newData['Country']][$newData['Region']]; } } else { $newData['RegionName'] = null; } if ($member->ID) { $newData['MemberID'] = $member->ID; } $existingShippingAddress->update($newData); $existingShippingAddress->write(); } else { $shippingAddress = new Address(); $shippingAddress->OrderID = $order->ID; if ($member->ID) { $shippingAddress->MemberID = $member->ID; } $shippingAddress->FirstName = $data['Shipping']['FirstName']; $shippingAddress->Surname = $data['Shipping']['Surname']; $shippingAddress->Company = $data['Shipping']['Company']; $shippingAddress->Address = $data['Shipping']['Address']; $shippingAddress->AddressLine2 = $data['Shipping']['AddressLine2']; $shippingAddress->City = $data['Shipping']['City']; $shippingAddress->PostalCode = $data['Shipping']['PostalCode']; $shippingAddress->State = $data['Shipping']['State']; $shippingAddress->CountryID = $data['Shipping']['Country']; $shippingAddress->Region = isset($data['Shipping']['Region']) ? $data['Shipping']['Region'] : null; $shippingAddress->CountryName = in_array($data['Shipping']['Country'], array_keys($shippingCountries)) ? $shippingCountries[$data['Shipping']['Country']] : null; $shippingAddress->RegionName = isset($data['Shipping']['Region']) && isset($shippingRegions[$data['Shipping']['Country']]) && in_array($data['Shipping']['Region'], array_keys($shippingRegions[$data['Shipping']['Country']])) ? $shippingRegions[$data['Shipping']['Country']][$data['Shipping']['Region']] : null; $shippingAddress->Type = 'Shipping'; $shippingAddress->write(); } }
/** * Adding non published product to a cart should fail */ function testAddNonPublishedProductToCart() { $productA = $this->objFromFixture('Product', 'productA'); $this->assertEquals(false, $productA->isPublished()); $productALink = $productA->Link(); $this->get(Director::makeRelative($productALink)); $message = null; try { $this->submitForm('AddToCartForm_AddToCartForm', null, array('Quantity' => 1)); } catch (Exception $e) { $message = $e->getMessage(); } $this->assertStringEndsWith('Object not written.', $message); $order = CartControllerExtension::get_current_order(); $items = $order->Items(); $this->assertEquals(0, $items->Count()); }