/**
  * Add default records to database. This function is called whenever the
  * database is built, after the database tables have all been created.
  * 
  * @uses DataExtension->requireDefaultRecords()
  */
 public function requireDefaultRecords()
 {
     /* Inherit Default Record Creation */
     parent::requireDefaultRecords();
     /* If no records exist, create defaults */
     if (!StoreSettings::get_settings()) {
         //Fetch SiteConfig
         $SiteConfig = SiteConfig::current_site_config();
         $n = new StoreSettings();
         $n->StoreSettings_StoreAvailable = "1";
         $n->StoreSettings_StoreAvailableMessage = "Our store is currently offline for maintenance and will be back online soon.";
         $n->StoreSettings_StoreName = $SiteConfig->Title . " Online Store";
         $n->StoreSettings_StoreCountry = "GB";
         $n->StoreSettings_ProductWeight = "Grams";
         $n->StoreSettings_ProductDimensions = "Centimetres";
         $n->DisplaySettings_FeaturedProducts = "5";
         $n->DisplaySettings_NewProducts = "5";
         $n->DisplaySettings_CartQuantity = "1";
         $n->DisplaySettings_ShowPrice = "1";
         $n->DisplaySettings_ShowSKU = "1";
         $n->DisplaySettings_ShowWeight = "1";
         $n->DisplaySettings_ShowDimensions = "1";
         $n->DisplaySettings_ProductSort = "Created DESC";
         $n->DisplaySettings_ProductPagePhotoWidth = "250";
         $n->DisplaySettings_ProductPagePhotoHeight = "250";
         $n->DisplaySettings_ProductThumbnailPhotoWidth = "125";
         $n->DisplaySettings_ProductThumbnailPhotoHeight = "125";
         $n->DisplaySettings_ProductEnlargedPhotoWidth = "1280";
         $n->DisplaySettings_ProductEnlargedPhotoHeight = "768";
         $n->CheckoutSettings_InitialStatus = "1";
         $n->CheckoutSettings_GuestCheckout = "1";
         $n->CheckoutSettings_GuestCheckoutAccount = "1";
         $n->CheckoutSettings_OrderComments = "1";
         $n->EmailNotification_AccountCreated = "1";
         $n->EmailNotification_OrderPlaced = "1";
         $n->EmailNotification_OrderStatuses = "3,8,4,7,2,6,5";
         $n->Stock_StockManagement = "1";
         $n->Stock_PendingOrdersFreezeStock = "90";
         $n->Stock_LowStockThreshold = "2";
         $n->Stock_OutOfStockThreshold = "0";
         $n->Stock_OutofStockMessage = "Out of Stock";
         $n->Stock_ProductOutOfStock = "3";
         $n->Stock_OptionOutOfStock = "2";
         $n->Stock_StockLevelDisplay = "3";
         $n->TaxSettings_InclusiveExclusive = "1";
         $n->TaxSettings_ShippingInclusiveExclusive = "1";
         $n->TaxSettings_CalculateUsing = "1";
         $n->write();
         unset($n);
         DB::alteration_message('Created default store configuration', 'created');
     }
 }
 public function __construct($controller, $name, $order)
 {
     /* Store Settings Object */
     $conf = StoreSettings::get_settings();
     /* Comments Box, if enabled */
     if ($conf->CheckoutSettings_OrderComments) {
         $comments = TextareaField::create("CustomerComments", "Order Comments");
         $comments->setRightTitle("These comments will be seen by staff.");
     } else {
         $comments = HiddenField::create("CustomerComments", "");
     }
     /* Terms and Conditions, if enabled */
     if ($conf->CheckoutSettings_TermsAndConditions) {
         $terms = CheckboxField::create("Terms", "I agree to " . $conf->StoreSettings_StoreName . "'s " . "<a href=" . DataObject::get_by_id("SiteTree", $conf->CheckoutSettings_TermsAndConditionsSiteTree)->URLSegment . ">" . "Terms &amp; Conditions</a>.");
     } else {
         $terms = HiddenField::create("Terms", "");
     }
     /* Fields */
     $fields = FieldList::create($comments, OptionsetField::create("PaymentMethod", "Payment Method", Gateway::create()->getGateways($order)), $terms ? HeaderField::create("Terms and Conditions", 5) : HiddenField::create("TermsHeaderField", ""), $terms);
     /* Actions */
     $actions = FieldList::create(FormAction::create('payment', 'Place Order &amp; Continue to Payment'));
     /* Required Fields */
     $required = new RequiredFields(array("PaymentMethod", $terms ? "Terms" : null));
     /*
      * Now we create the actual form with our fields and actions defined 
      * within this class.
      */
     return parent::__construct($controller, $name, $fields, $actions, $required);
 }
 /**
  * getImageEnlarged
  * If a photo has been uploaded, return the main photo
  * for this product at the enlarged dimensions specified in
  * the StoreSettings. Otherwise, return null. 
  *
  * @param Int $custom_width A custom width in pixels. Used as an override to StoreSettings.
  * @param Int $custom_height A custom height in pixels. Used as an overide to StoreSettings.
  *
  * @return Image|String
  */
 public function getImageEnlarged($custom_width = null, $custom_height = null)
 {
     if ($this->ID) {
         return $this->SetSize($custom_width ? $custom_width : StoreSettings::get_settings()->DisplaySettings_ProductEnlargedPhotoWidth, $custom_height ? $custom_height : StoreSettings::get_settings()->DisplaySettings_ProductEnlargedPhotoHeight);
     } else {
         return null;
     }
 }
 public function __construct($controller, $name, $order)
 {
     /* Fields */
     $fields = FieldList::create(ReadonlyField::create("Shipping", "Shipping Total (" . Product::getDefaultCurrency() . ")", $shipping_total = Order::create()->calculateShippingTotal($order->ID, $order->Courier)), FieldGroup::create("Tax (" . Product::getDefaultCurrency() . ")", ReadonlyField::create("ProductTaxInclusive", "Product Tax (Inclusive)", Order::create()->calculateProductTax(1, $order))->setRightTitle("Basket total is inclusive of this tax."), ReadonlyField::create("ProductTaxExclusive", "Product Tax (Exclusive)", $exc_product_tax = Order::create()->calculateProductTax(2, $order))->setRightTitle("Basket total is exclusive of this tax."), ReadonlyField::create("ShippingTax", "Shipping Tax", $shipping_tax = Order::create()->calculateShippingTax(Order::create()->calculateShippingTotal($order->ID, $order->Courier), $order))->setRightTitle(StoreSettings::get_settings()->TaxSettings_ShippingInclusiveExclusive == 1 ? "Shipping price is inclusive of this tax." : "Shipping price is exclusive of this tax.")), ReadonlyField::create("Total", "Final Total", Order::create()->calculateOrderTotal($order)));
     /* Actions */
     $actions = FieldList::create();
     /* Required Fields */
     $required = new RequiredFields(array());
     /*
      * Now we create the actual form with our fields and actions defined 
      * within this class.
      */
     return parent::__construct($controller, $name, $fields, $actions, $required);
 }
 public function __construct($controller, $name, $order_id)
 {
     $Order = Order::get_by_id("Order", $order_id);
     /* Fields */
     $fields = FieldList::create(HiddenField::create("business", "business", DataObject::get_one("Gateway_PayPal")->EmailAddress), HiddenField::create("cmd", "cmd", "_xclick"), HiddenField::create("notify_url", "notify_url", Director::absoluteURL(Store_OrderController::create()->link() . "/payment/response?gateway=Gateway_PayPal")), HiddenField::create("custom", "custom", $order_id), HiddenField::create("item_name", "item_name", "Order No. " . $order_id . " @ " . StoreSettings::get_settings()->StoreSettings_StoreName), HiddenField::create("amount", "amount", Order::create()->calculateOrderTotal($Order)), HiddenField::create("currency_code", "currency_code", DataObject::get_one("StoreCurrency", "(`SystemCreated`='1')")->Code), HiddenField::create("no_note", "no_note", "1"), HiddenField::create("no_shipping", "no_shipping", "1"), HiddenField::create("return", "return", Director::absoluteURL(Store_OrderController::create()->link()) . "/payment/success?gateway=Gateway_PayPal"), HiddenField::create("rm", "rm", "2"), HiddenField::create("cbt", "cbt", "Return to " . StoreSettings::get_settings()->StoreSettings_StoreName), HiddenField::create("cancel_return", "cancel_return", Director::absoluteURL(Store_OrderController::create()->link()) . "/payment/cancelled?gateway=Gateway_PayPal"));
     /* Actions */
     $actions = FieldList::create(FormAction::create('', 'If you are not transferred to PayPal in 5 seconds, click here.'));
     /* Required Fields */
     $required = new RequiredFields(array("business", "cmd", "notify_url", "item_name", "amount", "currency_code"));
     /*
      * Now we create the actual form with our fields and actions defined 
      * within this class.
      */
     return parent::__construct($controller, $name, $fields, $actions, $required);
 }
 /**
  * ACTION /view
  * Fetch the requested product and render its product page.
  * If it doesn't exist, return HTTP 404.
  *
  * @return HTMLText
  */
 public function view()
 {
     /**
      * StoreSettings 
      */
     $conf = StoreSettings::get_settings();
     /**
      * Get the URLSegment of the Product from the request 
      */
     $URLSegment = $this->request->param('ID');
     /**
      * If URLSegment doesn't exist redirect with Error 404 redirect to the StoreFront.
      */
     if (!$URLSegment) {
         return $this->httpError(404);
     }
     /* The Product selected */
     $Product = DataObject::get_one("Product", "`URLSegment`='{$URLSegment}'");
     /**
      * If the Product doesn't exist, fail with httpError(404).
      */
     if (!$Product) {
         return $this->httpError(404);
     } else {
         /**
          * If product is out of stock, and admin has defined it should be completely
          * hidden, then return HTTP error 302 and temporarily redirect to the storefront.
          * Error 302 should prevent Search Engines modifying their entry for this product
          * whilst its hidden.
          */
         if ($Product->StockLevel <= $conf->Stock_OutOfStockThreshold && $conf->Stock_ProductOutOfStock == 1) {
             return $this->redirect(Director::BaseURL() . DataObject::get_one("SiteTree", "ClassName='Store'")->URLSegment, 302);
         }
         /**
          * If Product visibility is set to false return with httpError(404) otherwise
          * return the Product page with renderWith()
          */
         return !$Product->Visible ? $this->httpError(404) : $this->customise(array("Title" => $Product->Title, "Product" => $Product))->renderWith(array("Store_Product", "Page"));
     }
 }
 /**
  * If the store's stock management is enabled then fetch the total 
  * stock of the product and produce an array for the dropdown menu.
  * No more than 20, values however. 
  *
  * If the store has stock management disabled then only show 20 
  * options as standard.
  *
  * @param Int $product_id The ID of the product to add to the basket.
  * @return Array|Boolean
  */
 public function getQtyArray($product_id)
 {
     /* Store Settings */
     $conf = StoreSettings::get_settings();
     /*
      * If the store's stock management is enabled get the stock level, otherwise use 20. */
     $qty = $conf->Stock_StockManagement == 1 ? $this->getStockLevel($product_id) : 20;
     /* If stock level is 0, return false */
     if ($qty == 0) {
         return false;
     }
     /* Stock Level Array */
     $stock = array();
     /* Loop and push items on to array */
     for ($i = 1; $i <= $qty; $i++) {
         //Push
         $stock[$i] = $i;
         //If $i=20, break loop
         if ($i == 20) {
             break;
         }
     }
     return $stock;
 }
 /**
  * calculateOrderTotal
  * Calculate Order Total 
  *
  * @param Object $order If provided, use this order object in calculations.
  * @return float
  */
 public function calculateOrderTotal($order = null)
 {
     if ($this->exists() || !is_null($order)) {
         //Subtotal of all products
         $subtotal = !isset($order) ? $this->calculateSubTotal() : $this->calculateSubTotal($order->ID);
         //Total of tax yet to be added (Exclusive of Tax)
         $excl_tax = !isset($order) ? $this->calculateProductTax(2) : $this->calculateProductTax(2, $order);
         //Shipping cost
         $shipping = !isset($order) ? $this->calculateShippingTotal() : $this->calculateShippingTotal($order->ID, $order->Courier);
         //Shipping tax (0 if tax is inclusive, or the value of tax if not)
         $shipping_tax = StoreSettings::get_settings()->TaxSettings_ShippingInclusiveExclusive == 1 ? 0 : !isset($order) ? $this->calculateShippingTax($shipping) : $this->calculateShippingTax($shipping, $order);
         return StoreCurrency::convertToCurrency($subtotal + $excl_tax + $shipping + $shipping_tax);
     }
 }
 public function savesettings($data, $form)
 {
     $StoreSettings = StoreSettings::get_settings();
     $form->saveInto($StoreSettings);
     try {
         $StoreSettings->write();
     } catch (ValidationException $ex) {
         $form->sessionMessage($ex->getResult()->message(), 'bad');
         return $this->getResponseNegotiator()->respond($this->request);
     }
     $this->response->addHeader('X-Status', rawurlencode("Store Settings Saved Successfully"));
     return $this->getResponseNegotiator()->respond($this->request);
 }
 /**
  * stockLevelViewable
  * Are we allowed to display the stock level?
  *
  * @return String
  */
 public function stockLevelViewable()
 {
     $conf = StoreSettings::get_settings();
     switch ($conf->Stock_StockLevelDisplay) {
         /* Always permitted to display stock levels */
         case 1:
             return true;
             break;
             /* Only display stock levels when low in stock */
         /* Only display stock levels when low in stock */
         case 2:
             return $this->StockLevel <= $conf->Stock_LowStockThreshold ? true : false;
             break;
             /* Never display stock levels */
         /* Never display stock levels */
         case 3:
             return false;
             break;
     }
 }
 public static function get_settings()
 {
     return StoreSettings::get_settings();
 }
 /** 
  * FORM ACTION /selectcourier
  * Take the selected Courier and assign it to the current order
  * recrods Courier field. Then, as we also have both the billing and
  * and shipping address details available, calculate the TaxClassRate and
  * TaxClassName based on the stores Tax Configuration.
  */
 public function selectcourier($data, $form)
 {
     /* Get TempBasketID */
     $TempBasketID = Store_BasketController::get_temp_basket_id();
     /**
      * ONE - Check the submitted courier actually exists before proceeding
      */
     if (DB::Query("\n        \tSELECT COUNT(*) \n        \tFROM Courier \n        \tWHERE (`ID`='" . $data["Courier"] . "' \n        \tAND Enabled='1')\n        ")->value() > 0) {
         /* Update the Order record with the Courier choice, showing an error if it fails. */
         if (!DB::Query("\n\t\t\t\tUPDATE `order` \n\t\t\t\tSET Courier='" . $data["Courier"] . "' \n\t\t\t\tWHERE TempBasketID='{$TempBasketID}'\n\t\t\t")) {
             return $this->redirect($this->link() . "/place/error/");
         }
     }
     /**
      * TWO - Update Order tax information, based on Store Settings, so customers see tax information for 
      * the Zone/Class/Rate applicable to them. 
      */
     /* Get the Customer_AddressBook Objects */
     $shipping = DataObject::get_one("Order", "(`TempBasketID`='" . $TempBasketID . "')")->ShippingAddress();
     $billing = DataObject::get_one("Order", "(`TempBasketID`='" . $TempBasketID . "')")->BillingAddress();
     /* 
      * How is product tax to be calculated, based on Shipping/Billing/Store Address?
      *
      * VALUES:
      * 1 - Billing Address
      * 2 - Shipping Address
      * 3 - Store Address
      */
     $calculate = StoreSettings::get_settings()->TaxSettings_CalculateUsing;
     if ($calculate == 1) {
         $tax_address_country = $billing->Country;
     } elseif ($calculate == 2) {
         $tax_address_country = $shipping->ShippingAddress()->Country;
     } else {
         $tax_address_country = StoreSettings::get_settings()->StoreSettings_StoreCountry;
     }
     //Based on Store Address
     /* Get the ID of the Tax Zone for the tax country if it exists. Otherwise, use the All zone. */
     $count = new SQLQuery("COUNT(*)");
     $count->setFrom("`TaxZones`")->addWhere("`Title`='{$tax_address_country}'");
     if ($count->execute()->value() > 0) {
         $tax_zone_id = DataObject::get_one("TaxZones", "(`Title`='{$tax_address_country}')")->ID;
     } else {
         //This is the ID of the 'All' zone.
         $tax_zone_id = 1;
     }
     /* Using the Tax Zone ID, loop through the Order_Items and update the TaxClassRate and TaxClassName based on the Zone. */
     $order_items = new SQLQuery();
     $order_items->setFrom("Order_Items")->addWhere("(`TempBasketID`='" . $TempBasketID . "')");
     $result = $order_items->execute();
     foreach ($result as $row) {
         /* First, get the ID of the products TaxClass. */
         $TaxClassID = DataObject::get_one("TaxClasses", $row["TaxClass"])->ID;
         /* Next get the TaxClassRate and TaxClassName within the given zone. */
         $TaxClassInfo = DataObject::get_one("TaxRates", "(`TaxClass`='" . $TaxClassID . "' AND `TaxZoneID`='" . $tax_zone_id . "')");
         $rate = $TaxClassInfo->Rate;
         $title = $TaxClassInfo->Title;
         /* Finally, we update the Order_Item itself with these new values. */
         DB::Query("\n\t\t\t\t\tUPDATE Order_Items \n\t\t\t\t\tSET TaxClassName='" . $title . "', \n\t\t\t\t\tTaxClassRate='" . $rate . "' \n\t\t\t\t\tWHERE `ID`='" . $row["ID"] . "'\n\t\t\t\t");
     }
     /**
      * THREE - Redirect to Step Five.
      */
     return $this->redirect($this->link() . "/place/five");
 }
 /**
  * getNewProducts
  * Retrieve latest products from Product DataObject
  */
 public function getNewProducts()
 {
     return DataObject::get("Product", Product::get_out_of_stock_filter(), "Created DESC", "", StoreSettings::get_settings()->DisplaySettings_NewProducts);
 }
 public static function productTaxInfo($order_id, $class_id, $data)
 {
     /* 
      * How is tax to be calculated, based on Shipping/Billing/Store Address 
      *
      * VALUES:
      * 1 - Billing Address
      * 2 - Shipping Address
      * 3 - Store Address
      */
     $calculate = StoreSettings::get_settings()->TaxSettings_CalculateUsing;
     switch ($calculate) {
         case 1:
             $tax_address_country = DataObject::get_by_id("Customer_AddressBook", DataObject::get_by_id("Order", $order_id)->BillingAddressID)->Country;
             break;
         case 2:
             $tax_address_country = DataObject::get_by_id("Customer_AddressBook", DataObject::get_by_id("Order", $order_id)->ShippingAddressID)->Country;
             break;
         case 3:
             $tax_address_country = StoreSettings::get_settings()->StoreSettings_StoreCountry;
             break;
     }
     /* Get the ID of the Tax Zone for the tax country if it exists. Otherwise, use the All zone. */
     $count = new SQLQuery("COUNT(*)");
     $count->setFrom("`TaxZones`")->addWhere("`Title`='{$tax_address_country}'");
     if ($count->execute()->value() > 0) {
         $tax_zone_id = new SQLQuery("id");
         $tax_zone_id->setFrom("`TaxZones`")->addWhere("Title`='{$tax_address_country}'");
         $tax_zone_id = $tax_zone_id->execute()->value();
     } else {
         $tax_zone_id = 1;
         //This is the ID of the 'All' zone.
     }
     /* If a tax rate does not exist for the tax class in the shipping country tax zone default to the 'All' zone */
     $count = new SQLQuery("COUNT(*)");
     $count->setFrom("`TaxRates`")->addWhere("`TaxZoneID`='{$tax_zone_id}' AND `TaxClass`='{$class_id}'");
     if ($count->execute()->value() > 0) {
         $query = new SQLQuery($data);
         $query->setFrom("`TaxRates`")->addWhere("`TaxZoneID`='{$tax_zone_id}' AND `TaxClass`='{$class_id}'");
         return $query->execute()->value();
     } else {
         $query = new SQLQuery($data);
         $query->setFrom("`TaxRates`")->addWhere("`TaxZoneID`='1' AND `TaxClass`='{$class_id}'");
         return $query->execute()->value();
     }
 }
 public function customerOrderStatusUpdate($order_no, $status, $override = false)
 {
     //Get Store Settings
     $settings = StoreSettings::get_settings();
     //Get the details of both the order, the customer who placed it and the status
     $order = DataObject::get_by_id("Order", $order_no);
     $customer = DataObject::get_by_id("Customer", $order->CustomerID);
     $status = DataObject::get_one("Order_Statuses", "(`SystemTitle`='" . $status . "')");
     /**
      * If override is set, set the send flag to true.
      * Otherwise, check the store notification settings tpo
      * see if we're allowed to send this status update email. 
      */
     if ($override) {
         $send = true;
     } else {
         //Convert store notification settings to array
         $enabled_statuses = explode(",", $settings->EmailNotification_OrderStatuses);
         //Is the new status in this array, if yes, send send to true.
         $send = in_array($status->ID, $enabled_statuses) ? true : false;
     }
     /**
      * If $send is equal to true send the email notification.
      */
     if ($send) {
         //Send The Email
         $email = new Email();
         $email->setFrom($settings->EmailNotification_SendEmailsFrom)->setTo($customer->Email)->setSubject('Order [' . $order_no . '] has been updated')->setTemplate('Email_Order_StatusUpdate')->populateTemplate(new ArrayData(array('StoreName' => $settings->StoreSettings_StoreName, 'Customer' => $customer, 'Order' => $order, 'OrderStatus' => $status, 'OrderLink' => '', 'OrderItems' => DataObject::get("Order_Items", "(`OrderID`='" . $order->ID . "')"), 'OrderCourier' => DataObject::get_one("Courier", "(`id`='" . $order->Courier . "')")->Title, 'OrderTrackingNo' => $order->TrackingNo ? $order->TrackingNo : "No tracking number provided for this order", 'ProductTax' => StoreCurrency::convertToCurrency($order->calculateProductTax(1) + $order->calculateProductTax(2)), 'BillingAddress' => DataObject::get_one("Customer_AddressBook", "(`id`='" . $order->BillingAddressID . "')"), 'ShippingAddress' => DataObject::get_one("Customer_AddressBook", "(`id`='" . $order->BillingAddressID . "')"), 'CurrencySymbol' => Product::getDefaultCurrency())));
         $email->send();
         //Store the email in the order email log
         $this->SentTo = $customer->Email . " (CUSTOMER)";
         $this->Subject = 'Order [' . $order_no . '] has been updated';
         $this->Body = $email->body;
         $this->OrderID = $order_no;
         $this->write();
         return true;
     } else {
         return false;
     }
 }