コード例 #1
0
ファイル: FrmProducts.class.php プロジェクト: Jemt/JSShop
 public function Render()
 {
     // Get Category ID
     $catId = SMEnvironment::GetQueryValue("SMShopCategory");
     // Load products
     $ds = new SMDataSource("SMShopProducts");
     $where = $catId !== null && $catId !== "Overview" ? "CategoryId = '" . $ds->Escape($catId) . "'" : "";
     $products = $ds->Select("*", $where);
     if ($catId !== "Overview" && count($products) > 0 && $products[0]["CategoryId"] !== $catId) {
         // SEO: Make CategoryId case sensitive
         $products = array();
     }
     // Add additional data
     foreach ($products as $prod) {
         // Notice: Data in DataSource uses lowercase keys.
         // Therefore place holders in template, to which data is mapped,
         // will be transformed to lowercase keys (see lowerCasePlaceHolders(..)).
         // Entries added below therefore also have to use lowercase keys.
         if ($prod["Vat"] === "" || (double) $prod["Vat"] === 0.0) {
             $prod["fullprice"] = $prod["Price"];
         } else {
             $prod["fullprice"] = (string) round((double) $prod["Price"] + (double) $prod["Price"] * ((double) $prod["Vat"] / 100), 2);
         }
         $prod["buy"] = $this->lang->GetTranslation("Buy");
         $prod["readmore"] = $this->lang->GetTranslation("ReadMore");
     }
     // Set page title
     $title = $catId === "Overview" ? $this->lang->GetTranslation("Overview") : (count($products) > 0 ? $products[0]["Category"] : $this->lang->GetTranslation("NoProducts"));
     $this->context->GetTemplate()->ReplaceTag(new SMKeyValue("Title", $title));
     $output = "<h1>" . $title . "</h1>";
     // Load view and populate data
     $extPath = SMExtensionManager::GetExtensionPath($this->context->GetExtensionName());
     SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$StyleSheet, $extPath . "/JSShop/Views/ProductList.css", true);
     $view = new SMTemplate($extPath . "/JSShop/Views/ProductList.html");
     $this->lowerCasePlaceHolders($view);
     // Data in DataSource uses lowercase keys, so place holders must use the same casing
     $view->ReplaceTagsRepeated("Products", $products);
     // Insert images
     $images = array();
     foreach ($products as $prod) {
         if ($prod["Images"] === "") {
             continue;
         }
         $images = array();
         foreach (explode(";", $prod["Images"]) as $src) {
             $images[] = new SMKeyValueCollection();
             $images[count($images) - 1]["image"] = $src;
         }
         $view->ReplaceTagsRepeated("Images" . $prod["Id"], $images);
     }
     // Add JSShop init script
     $output .= "\n\t\t<script type=\"text/javascript\">\n\n\t\tJSShop.Initialize(function()\n\t\t{\n\t\t\tJSShop.Presenters.ProductList.Initialize(document.getElementById('JSShopProductList'));\n\t\t});\n\n\t\t</script>\n\t\t";
     // Return result
     return $output . $view->GetContent();
 }
コード例 #2
0
ファイル: Payment.callback.php プロジェクト: Jemt/JSShop
function getOrder($orderId)
{
    $ds = new SMDataSource("SMShopOrders");
    $orders = $ds->Select("*", "Id = '" . $ds->Escape($orderId) . "'");
    if (count($orders) !== 1) {
        header("HTTP/1.1 500 Internal Server Error");
        echo "Order with ID '" . $orderId . "' could not be found";
        exit;
    }
    return $orders[0];
}
コード例 #3
0
ファイル: DataSource.callback.php プロジェクト: Jemt/JSShop
foreach ($props as $prop => $val) {
    SMShopValidateField($dsDef, $prop, $val);
    if ($dsDef["Fields"][$prop]["DataType"] === "string") {
        $props[$prop] = strip_tags($val);
    }
}
foreach ($match !== null ? $match : array() as $m) {
    SMShopValidateField($dsDef, $m["Field"], $m["Value"]);
    if ($m["Operator"] !== "=" && $m["Operator"] !== "!=" && $m["Operator"] !== "<" && $m["Operator"] !== "<=" && $m["Operator"] !== ">" && $m["Operator"] !== ">=") {
        header("HTTP/1.1 500 Internal Server Error");
        echo "Match operator '" . $m["Operator"] . "' is not supported";
        exit;
    }
}
// Initialize data source
$ds = new SMDataSource($dataSourceName);
if ($ds->GetDataSourceType() === SMDataSourceType::$Xml && $dsDef["XmlTimeOut"] > 0) {
    // Notice: Server configuration could potentially prevent this value from being changed,
    // in which case a timeout may occure if huge amounts of data is contained in DataSource,
    // and the server has limited resources.
    set_time_limit($dsDef["XmlTimeOut"]);
    // Make sure a potentially large XML based DataSource have sufficient time to process data
}
if ($ds->GetDataSourceType() === SMDataSourceType::$Xml && $dsDef["XmlMemoryRequired"] > 0) {
    $mem = $dsDef["XmlMemoryRequired"];
    // Notice: Server configuration could potentially prevent this value from being changed (e.g. using Suhosin), in which
    // case problems may occure if huge amounts of data is contained in DataSource, and the server has limited resources.
    $res = ini_set("memory_limit", $mem . "M");
    // Make sure a potentially large XML based DataSource have sufficient memory to process data
    if ($res === false && $mem >= 128) {
        $mem = $mem / 2;
コード例 #4
0
ファイル: Main.class.php プロジェクト: Jemt/JSShop
 public function InitComplete()
 {
     // Add basket and product categories to link pickers
     if ($this->smMenuExists === true && SMMenuLinkList::GetInstance()->GetReadyState() === true) {
         $ds = new SMDataSource("SMShopProducts");
         $products = $ds->Select("Category, CategoryId", "", "Category ASC");
         $menuLinkList = SMMenuLinkList::GetInstance();
         $added = array();
         foreach ($products as $prod) {
             if (in_array($prod["CategoryId"], $added, true) === true) {
                 continue;
             }
             $menuLinkList->AddLink($this->getTranslation("Title"), $prod["Category"], "shop/" . $prod["CategoryId"]);
             $added[] = $prod["CategoryId"];
         }
     }
     if ($this->smPagesExists === true && SMPagesLinkList::GetInstance()->GetReadyState() === true) {
         $ds = new SMDataSource("SMShopProducts");
         $products = $ds->Select("Category, CategoryId", "", "Category ASC");
         $pagesLinkList = SMPagesLinkList::GetInstance();
         $added = array();
         foreach ($products as $prod) {
             if (in_array($prod["CategoryId"], $added, true) === true) {
                 continue;
             }
             $pagesLinkList->AddLink($this->getTranslation("Title"), $prod["Category"], "shop/" . $prod["CategoryId"]);
             $added[] = $prod["CategoryId"];
         }
     }
     // Load JS and CSS resources
     SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$JavaScript, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/Fit.UI/Fit.UI.js");
     SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$StyleSheet, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/Fit.UI/Fit.UI.css", true);
     SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$JavaScript, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/JSShop.js");
     // Prepare callbacks
     $basePath = SMEnvironment::GetInstallationPath();
     // Use full path to prevent problems when calling WebServices under /shop/XYZ which would be redirected to / without preserving POST data (htaccess)
     $basePath .= $basePath !== "/" ? "/" : "";
     $dsCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/DataSource");
     $fsCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/Files");
     $payCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/Payment");
     // Prepare language
     $langCode = SMLanguageHandler::GetSystemLanguage();
     $shopLang = SMFileSystem::FileExists(dirname(__FILE__) . "/JSShop/Languages/" . $langCode . ".js") === true ? $langCode : "en";
     // Prepare cookie store
     $cookiePrefix = SMEnvironment::IsSubSite() === false ? "SMRoot" : "";
     // Prevent cookies on root site from causing naming conflicts with cookies on subsites
     $cookiePath = SMEnvironment::GetInstallationPath();
     // Prevent /shop virtual directory from being used as cookie path when adding products to basket by forcing cookie path
     // Prepare payment modules
     $paymentMethodsStr = SMAttributes::GetAttribute("SMShopPaymentMethods") !== null ? SMAttributes::GetAttribute("SMShopPaymentMethods") : "";
     if ($paymentMethodsStr !== "") {
         $paymentMethods = explode(";", $paymentMethodsStr);
         $paymentMethodsStr = "";
         $paymentModule = null;
         foreach ($paymentMethods as $pm) {
             $paymentModule = explode("=", $pm);
             // 0 = PSPI module name, 1 = title
             if (count($paymentModule) !== 2) {
                 continue;
             }
             // Not valid
             $paymentMethodsStr .= $paymentMethodsStr !== "" ? ", " : "";
             $paymentMethodsStr .= "{ Module: '" . $paymentModule[0] . "', Title: '" . $paymentModule[1] . "' }";
         }
     }
     // Configure JSShop
     $jsInit = "\n\t\t<script type=\"text/javascript\">\n\t\tJSShop.Settings.ShippingExpenseExpression = \"" . (SMAttributes::GetAttribute("SMShopShippingExpenseExpression") !== null ? SMAttributes::GetAttribute("SMShopShippingExpenseExpression") : "") . "\";\n\t\tJSShop.Settings.ShippingExpenseVat = " . (SMAttributes::GetAttribute("SMShopShippingExpenseVat") !== null && SMAttributes::GetAttribute("SMShopShippingExpenseVat") !== "" ? SMAttributes::GetAttribute("SMShopShippingExpenseVat") : "0") . ";\n\t\tJSShop.Settings.ShippingExpenseMessage = \"" . (SMAttributes::GetAttribute("SMShopShippingExpenseMessage") !== null ? SMAttributes::GetAttribute("SMShopShippingExpenseMessage") : "") . "\";\n\t\tJSShop.Settings.BasketUrl = \"" . SMExtensionManager::GetExtensionUrl($this->name) . "&SMShopBasket" . "\";\n\t\tJSShop.Settings.TermsUrl = \"" . (SMAttributes::GetAttribute("SMShopTermsPage") !== null ? SMAttributes::GetAttribute("SMShopTermsPage") : "") . "\";\n\t\tJSShop.Settings.PaymentUrl = \"" . $payCallback . "\";\n\t\tJSShop.Settings.PaymentMethods = [ " . $paymentMethodsStr . " ];\n\n\t\tJSShop.Language.Name = \"" . $shopLang . "\";\n\n\t\tJSShop.Cookies.Prefix(\"" . $cookiePrefix . "\" + JSShop.Cookies.Prefix());\n\t\tJSShop.Cookies.Path(\"" . $cookiePath . "\");\n\n\t\tJSShop.WebService.Products.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.WebService.Files.Upload = \"" . $fsCallback . "\"; // Expected to respond with file path on server\n\t\tJSShop.WebService.Files.Remove = \"" . $fsCallback . "\";\n\n\t\tJSShop.WebService.Orders.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.WebService.OrderEntries.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.Events.OnRequest = function(request, models, operation)\n\t\t{\n\t\t\t// Unicode encode data\n\n\t\t\tvar data = request.GetData();\n\t\t\tvar properties = data.Properties;\n\n\t\t\tFit.Array.ForEach(properties, function(prop)\n\t\t\t{\n\t\t\t\tif (typeof(properties[prop]) === \"string\")\n\t\t\t\t\tproperties[prop] = SMStringUtilities.UnicodeEncode(properties[prop]);\n\t\t\t});\n\n\t\t\t// Product model: Create URL friendly category name\n\n\t\t\tif ((operation === \"Create\" || operation === \"Update\") && Fit.Core.InstanceOf(models[0], JSShop.Models.Product) === true)\n\t\t\t{\n\t\t\t\tvar category = properties[\"Category\"];\n\t\t\t\tvar catId = category;\n\n\t\t\t\tcatId = catId.replace(/ /g, \"_\"); // Replace spaces with underscores\n\n\t\t\t\t// Support alternatives to danish characters\n\t\t\t\tcatId = catId.replace(/Æ/g, \"Ae\");\n\t\t\t\tcatId = catId.replace(/æ/g, \"ae\");\n\t\t\t\tcatId = catId.replace(/Ø/g, \"Eo\");\n\t\t\t\tcatId = catId.replace(/ø/g, \"oe\");\n\t\t\t\tcatId = catId.replace(/Å/g, \"Aa\");\n\t\t\t\tcatId = catId.replace(/å/g, \"aa\");\n\n\t\t\t\tcatId = catId.replace(/[^A-Za-z0-9_-]/g, \"\"); // Remove invalid characters (^ in a range means NOT)\n\n\t\t\t\tif (catId !== category)\n\t\t\t\t{\n\t\t\t\t\t// Two different categories can end up with the same Category ID, e.g. XæYæZ and X.Y.Z = XYZ.\n\t\t\t\t\t// This will especially be true if categories only consists of invalid characters (unicode),\n\t\t\t\t\t// in which case the Category ID will now be empty. Therefore, a hash code representing the\n\t\t\t\t\t// name of the category is used to create a unique and valid Category ID.\n\n\t\t\t\t\tvar hash = Fit.String.Hash(category);\n\t\t\t\t\tcatId = ((catId !== \"\") ? catId : \"cat\") + \"-\" + ((hash < 0) ? \"m\" : \"\") + Math.abs(hash);\n\t\t\t\t}\n\n\t\t\t\tproperties[\"CategoryId\"] = catId; // NOTICE: CategoryId is NOT defined in Product model, only here in JSON data\n\t\t\t}\n\n\t\t\trequest.SetData(data);\n\t\t};\n\n\t\tJSShop.Events.OnSuccess = function(request, models, operation)\n\t\t{\n\t\t\tif (operation === \"Retrieve\" || operation === \"RetrieveAll\")\n\t\t\t{\n\t\t\t\t// Decode unicode encoded data\n\n\t\t\t\tFit.Array.ForEach(models, function(model)\n\t\t\t\t{\n\t\t\t\t\tvar properties = model.GetProperties();\n\n\t\t\t\t\tFit.Array.ForEach(properties, function(prop)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (typeof(properties[prop]) === \"string\")\n\t\t\t\t\t\t\tmodel[prop](SMStringUtilities.UnicodeDecode(model[prop]())); // Never manipulate properties directly - using Setter function\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tJSShop.Events.OnError = function(request, models, operation)\n\t\t{\n\t\t\tFit.Controls.Dialog.Alert('WebService communication failed (' + operation + '):<br><br>' + request.GetResponseText().replace(\"<pre>\", \"<pre style='overflow: auto'>\"));\n\t\t};\n\t\t</script>\n\t\t";
     SMEnvironment::GetMasterTemplate()->AddToHeadSection($jsInit);
 }
コード例 #5
0
ファイル: Order.php プロジェクト: Jemt/JSShop
function SMShopFinalizeNewOrder(SMKeyValueCollection $order)
{
    $mailAddress = $order["Email"];
    $title = SMAttributes::GetAttribute("SMShopOrderConfirmationMailTitle");
    $content = SMAttributes::GetAttribute("SMShopOrderConfirmationMailContent");
    if ($content === null || $content === "" || SMStringUtilities::Validate($mailAddress, SMValueRestriction::$EmailAddress) === false) {
        return;
    }
    $lang = new SMLanguageHandler(SMExtensionManager::GetExecutingExtension());
    $eDs = new SMDataSource("SMShopOrderEntries");
    $pDs = new SMDataSource("SMShopProducts");
    // Order details
    $entries = $eDs->Select("*", "OrderId = '" . $eDs->Escape($order["Id"]) . "'");
    $products = null;
    $orderDetails = "";
    foreach ($entries as $entry) {
        $products = $pDs->Select("*", "Id = '" . $pDs->Escape($entry["ProductId"]) . "'");
        if (count($products) === 0) {
            header("HTTP/1.1 500 Internal Server Error");
            echo "Product could not be found";
            exit;
        }
        $orderDetails .= $orderDetails !== "" ? "<br>" : "";
        $orderDetails .= $entry["Units"] . " x " . $products[0]["Title"] . ", " . $order["Currency"] . " " . number_format(((int) $entry["Units"] * (double) $entry["UnitPrice"] - (double) $entry["Discount"]) * ((double) $entry["Vat"] / 100 + 1), 2, $lang->GetTranslation("DecimalSeparator"), "");
    }
    // Shipping expense
    if ($order["ShippingExpense"] !== "0") {
        $orderDetails .= "<br>";
        $orderDetails .= ($order["ShippingMessage"] !== "" ? $order["ShippingMessage"] : $lang->GetTranslation("Shipping")) . ", " . $order["Currency"] . " " . number_format((double) $order["ShippingExpense"] + (double) $order["ShippingVat"], 2, $lang->GetTranslation("DecimalSeparator"), "");
    }
    // Mail content - replace place holders
    $content = str_replace("{Company}", $order["Company"], $content);
    $content = str_replace("{FirstName}", $order["FirstName"], $content);
    $content = str_replace("{LastName}", $order["LastName"], $content);
    $content = str_replace("{Address}", $order["Address"], $content);
    $content = str_replace("{ZipCode}", $order["ZipCode"], $content);
    $content = str_replace("{City}", $order["City"], $content);
    $content = str_replace("{Phone}", $order["Phone"], $content);
    $content = str_replace("{Email}", $order["Email"], $content);
    $content = str_replace("{Message}", nl2br($order["Message"]), $content);
    $content = str_replace("{AltCompany}", $order["AltCompany"], $content);
    $content = str_replace("{AltFirstName}", $order["AltFirstName"], $content);
    $content = str_replace("{AltLastName}", $order["AltLastName"], $content);
    $content = str_replace("{AltAddress}", $order["AltAddress"], $content);
    $content = str_replace("{AltZipCode}", $order["AltZipCode"], $content);
    $content = str_replace("{AltCity}", $order["AltCity"], $content);
    $content = str_replace("{DeliveryCompany}", $order["AltAddress"] !== "" ? $order["AltCompany"] : $order["Company"], $content);
    // Use AltCompany (which is optional) only if AltAddress is set
    $content = str_replace("{DeliveryFirstName}", $order["AltFirstName"] !== "" ? $order["AltFirstName"] : $order["FirstName"], $content);
    $content = str_replace("{DeliveryLastName}", $order["AltLastName"] !== "" ? $order["AltLastName"] : $order["LastName"], $content);
    $content = str_replace("{DeliveryAddress}", $order["AltAddress"] !== "" ? $order["AltAddress"] : $order["Address"], $content);
    $content = str_replace("{DeliveryZipCode}", $order["AltZipCode"] !== "" ? $order["AltZipCode"] : $order["ZipCode"], $content);
    $content = str_replace("{DeliveryCity}", $order["AltCity"] !== "" ? $order["AltCity"] : $order["City"], $content);
    $content = str_replace("{OrderId}", $order["Id"], $content);
    $content = str_replace("{Currency}", $order["Currency"], $content);
    $content = str_replace("{Vat}", number_format((double) $order["Vat"], 2, $lang->GetTranslation("DecimalSeparator"), ""), $content);
    $content = str_replace("{Price}", number_format((double) $order["Price"] + (double) $order["Vat"], 2, $lang->GetTranslation("DecimalSeparator"), ""), $content);
    $content = str_replace("{Weight}", number_format((double) $order["Weight"], 2, $lang->GetTranslation("DecimalSeparator"), ""), $content);
    $content = str_replace("{WeightUnit}", $order["WeightUnit"], $content);
    $content = str_replace("{ShippingExpense}", number_format((double) $order["ShippingExpense"], 2, $lang->GetTranslation("DecimalSeparator"), ""), $content);
    $content = str_replace("{ShippingVat}", number_format((double) $order["ShippingVat"], 2, $lang->GetTranslation("DecimalSeparator"), ""), $content);
    $content = str_replace("{ShippingMessage}", $order["ShippingMessage"], $content);
    $content = str_replace("{DateYear}", date("Y"), $content);
    $content = str_replace("{DateMonth}", date("m"), $content);
    $content = str_replace("{DateDay}", date("d"), $content);
    $content = str_replace("{OrderDetails}", $orderDetails, $content);
    $mail = new SMMail();
    $mail->AddRecipient($mailAddress);
    $mail->SetSubject($title !== null && $title !== "" ? $title : $lang->GetTranslation("ConfirmationTitle"));
    $mail->SetContent($content);
    if (SMAttributes::GetAttribute("SMShopEmail") !== null && SMAttributes::GetAttribute("SMShopEmail") !== "" && SMStringUtilities::Validate(SMAttributes::GetAttribute("SMShopEmail"), SMValueRestriction::$EmailAddress) === true) {
        $mail->SetSender(SMAttributes::GetAttribute("SMShopEmail"));
    }
    $mail->Send();
}