Version Notes
This update includes:
- Only add one price tag for each product
- Enabled currency conversion
Download this release
Release Info
| Developer | inoutput.io |
| Extension | Fruugo_Integration |
| Version | 1.0.6 |
| Comparing to | |
| See all releases | |
Code changes from version 1.0.5 to 1.0.6
- app/code/community/Fruugo/Integration/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/Catalog/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/Catalog/Product/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/Sales/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/Sales/Order/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Block/Sales/Order/View/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Helper/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Helper/Logger.php +40 -2
- app/code/community/Fruugo/Integration/Helper/ProductsFeedGenerator.php +634 -137
- app/code/community/Fruugo/Integration/Helper/ProductsFeedGeneratorProfiler.php +340 -0
- app/code/community/Fruugo/Integration/Model/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Backend/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/ExportPageSize.php +52 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/MaxErrors.php +52 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/MaxResourcesLoad.php +46 -0
- app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/SleepTimeSec.php +52 -0
- app/code/community/Fruugo/Integration/Model/CronJobObserver.php +1 -5
- app/code/community/Fruugo/Integration/controllers/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/controllers/.gitignore +3 -1
- app/code/community/Fruugo/Integration/controllers/ProductsController.php +26 -32
- app/code/community/Fruugo/Integration/data/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/catalog/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/catalog/product/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/order/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/order/view/.DS_Store +0 -0
- app/code/community/Fruugo/Integration/etc/config.xml +6 -1
- app/code/community/Fruugo/Integration/etc/system.xml +40 -0
- app/design/adminhtml/default/default/template/integration/.DS_Store +0 -0
- app/design/adminhtml/default/default/template/integration/catalog/.DS_Store +0 -0
- app/design/adminhtml/default/default/template/integration/catalog/product/.DS_Store +0 -0
- app/design/adminhtml/default/default/template/integration/sales/.DS_Store +0 -0
- app/design/adminhtml/default/default/template/integration/sales/order/.DS_Store +0 -0
- app/design/adminhtml/default/default/template/integration/sales/order/view/.DS_Store +0 -0
- package.xml +6 -12
app/code/community/Fruugo/Integration/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/Catalog/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/Catalog/Product/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/Sales/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/Sales/Order/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Block/Sales/Order/View/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Helper/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Helper/Logger.php
CHANGED
|
@@ -22,8 +22,46 @@
|
|
| 22 |
|
| 23 |
class Fruugo_Integration_Helper_Logger extends Mage_Core_Helper_Abstract
|
| 24 |
{
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
{
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
}
|
| 29 |
}
|
| 22 |
|
| 23 |
class Fruugo_Integration_Helper_Logger extends Mage_Core_Helper_Abstract
|
| 24 |
{
|
| 25 |
+
const ALWAYS = 0;
|
| 26 |
+
const ERROR = 1;
|
| 27 |
+
const WARNING = 2;
|
| 28 |
+
const INFO = 3;
|
| 29 |
+
const DEBUG = 4;
|
| 30 |
+
|
| 31 |
+
public static $LOG_LEVEL = self::WARNING;
|
| 32 |
+
public static $CODE = array(
|
| 33 |
+
self::ALWAYS => 'NOTICE',
|
| 34 |
+
self::ERROR => 'ERROR',
|
| 35 |
+
self::WARNING=> 'WARNING',
|
| 36 |
+
self::INFO => 'INFO',
|
| 37 |
+
self::DEBUG => 'DEBUG',
|
| 38 |
+
);
|
| 39 |
+
|
| 40 |
+
public static function log($message, $level = self::INFO)
|
| 41 |
+
{
|
| 42 |
+
if ($level <= self::$LOG_LEVEL) {
|
| 43 |
+
Mage::log("Fruugo - " . self::$CODE[$level] . ': ' . $message);
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
public static function getFormattedReport($report)
|
| 48 |
{
|
| 49 |
+
$repStr = "\n\n---------------------------[ Fruugo Product Export Results ]---------------------------\n";
|
| 50 |
+
$repStr .= "Status: " . $report['status'] . "\n";
|
| 51 |
+
$repStr .= "Total products exported: " . $report['total_exported'] . "\n";
|
| 52 |
+
$repStr .= "Total products processed: " . $report['total_processed'] . "\n";
|
| 53 |
+
$repStr .= "Start time: " . $report['start_time_utc'] . "\n";
|
| 54 |
+
$repStr .= "End time: " . $report['end_time_utc'] . "\n";
|
| 55 |
+
$repStr .= "Total processing time: " . $report['processing_time_sec'] . " seconds\n";
|
| 56 |
+
$repStr .= "Total paused time: " . $report['time_paused_sec'] . " seconds\n";
|
| 57 |
+
$repStr .= "Max memory used: " . $report['max_ram_usage_mb'] . " MB\n";
|
| 58 |
+
$repStr .= "Avg memory used: " . round($report['avg_ram_usage_mb'], 2) . " MB\n";
|
| 59 |
+
$repStr .= "Avg resource load: " . round($report['avg_load'], 2) . "\n";
|
| 60 |
+
$repStr .= "Error count: " . $report['error_count'] . "\n";
|
| 61 |
+
$repStr .= "Resource threshold triggers: " . $report['load_above_threshold_count'] . "\n";
|
| 62 |
+
$repStr .= "XML File size: " . round($report['xml_file_size_mb'], 2) . " MB\n";
|
| 63 |
+
$repStr .= "----------------------------------------------------------------------------------------\n\n";
|
| 64 |
+
|
| 65 |
+
return $repStr;
|
| 66 |
}
|
| 67 |
}
|
app/code/community/Fruugo/Integration/Helper/ProductsFeedGenerator.php
CHANGED
|
@@ -24,64 +24,236 @@ require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/Logger.php'
|
|
| 24 |
|
| 25 |
class Fruugo_Integration_ProductsFeedGenerator extends Mage_Core_Helper_Abstract
|
| 26 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
public function generateProdcutsFeed($cached = false)
|
| 28 |
{
|
| 29 |
-
$
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
} else {
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
$productsXml;
|
| 35 |
|
| 36 |
-
$devMode
|
| 37 |
-
|
| 38 |
-
$productsXml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>'
|
| 39 |
-
.'<Products xmlns="http://schemas.fruugo.com/fruugoflat"></Products>');
|
| 40 |
} else {
|
| 41 |
-
$productsXml =
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
| 43 |
}
|
| 44 |
|
| 45 |
-
$
|
| 46 |
-
->getCollection()
|
| 47 |
-
->addAttributeToSelect('*') // select all attributes
|
| 48 |
-
->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED) // only select enabled products
|
| 49 |
-
->addAttributeToFilter('type_id', Mage_Catalog_Model_Product_Type::TYPE_SIMPLE); // only select simple products
|
| 50 |
|
| 51 |
// Get store langauge map or use null if none
|
| 52 |
$storelangsSettings = Mage::getStoreConfig('integration_options/products_options/language_store');
|
| 53 |
$storelangsMapping = empty($storelangsSettings) ? null : unserialize($storelangsSettings);
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
-
$
|
| 63 |
-
$
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
$
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
| 78 |
}
|
|
|
|
|
|
|
| 79 |
}
|
| 80 |
|
| 81 |
-
|
| 82 |
{
|
| 83 |
-
// M: Mandatory R: Recommended O: Optional
|
| 84 |
$parentProduct = $this->_getParentProduct($product);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
// ProductId *M
|
| 87 |
if (isset($parentProduct)) {
|
|
@@ -115,33 +287,27 @@ class Fruugo_Integration_ProductsFeedGenerator extends Mage_Core_Helper_Abstract
|
|
| 115 |
|
| 116 |
// Category *R
|
| 117 |
$categoryEntity = $product->getCategoryCollection()
|
|
|
|
| 118 |
->addAttributeToSort('level', 'DESC')
|
| 119 |
->addAttributeToSort('position', 'DESC')
|
| 120 |
->addAttributeToFilter('is_active', '1')
|
| 121 |
->getFirstItem();
|
| 122 |
|
| 123 |
-
$
|
| 124 |
-
->
|
| 125 |
-
|
| 126 |
-
if ($category->getName() !== null) {
|
| 127 |
-
$productXml->addChild('Category', htmlspecialchars($category->getName()));
|
| 128 |
}
|
| 129 |
|
| 130 |
// Imageurl1 *M
|
| 131 |
// Imageurl2, Imageurl3, Imageurl4, Imageurl5 *R
|
| 132 |
-
$images = $this->_getProductImages($product, $parentProduct);
|
| 133 |
$imageIndex = 0;
|
| 134 |
|
| 135 |
-
foreach ($images as $
|
| 136 |
if ($imageIndex >= 5) {
|
| 137 |
break;
|
| 138 |
}
|
| 139 |
|
| 140 |
-
$
|
| 141 |
-
|
| 142 |
-
$productXml->addChild('Imageurl'.($imageIndex + 1), $imageUrl);
|
| 143 |
-
$imageIndex++;
|
| 144 |
-
}
|
| 145 |
}
|
| 146 |
|
| 147 |
// StockStatus & StockQuantity *M
|
|
@@ -150,9 +316,14 @@ class Fruugo_Integration_ProductsFeedGenerator extends Mage_Core_Helper_Abstract
|
|
| 150 |
if ($stockItem === null || !$stockItem->getIsInStock()) {
|
| 151 |
$productXml->addChild('StockStatus', 'OUTOFSTOCK');
|
| 152 |
} else {
|
| 153 |
-
$productXml->addChild('StockStatus', 'INSTOCK');
|
| 154 |
$stocklevel = (int)$stockItem->getQty();
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
}
|
| 157 |
|
| 158 |
// RestockDate *O
|
|
@@ -165,178 +336,504 @@ class Fruugo_Integration_ProductsFeedGenerator extends Mage_Core_Helper_Abstract
|
|
| 165 |
}
|
| 166 |
|
| 167 |
// Description Node
|
| 168 |
-
$stores = Mage::app()->getStores(false);
|
| 169 |
-
|
| 170 |
$addedLanguages = array();
|
| 171 |
-
|
|
|
|
| 172 |
// store 'fruugo' is for Fruugo orders
|
| 173 |
-
if ($store->getCode()
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
$localeCode = Mage::getStoreConfig('general/locale/code', $store->getId());
|
| 177 |
-
$language = substr($localeCode, 0, strpos($localeCode, '_'));
|
| 178 |
-
|
| 179 |
-
// Make sure no language is added more than once
|
| 180 |
-
if (!in_array($language, $addedLanguages)) {
|
| 181 |
-
// Add description when no store selected for language OR the store is selected for the langauge in storelangsMapping array
|
| 182 |
-
if ($storelangsMapping == null || $storelangsMapping[$localeCode] == "" || $storelangsMapping[$localeCode] == $store->getCode()) {
|
| 183 |
-
// Language *R
|
| 184 |
-
$descriptionXml = $productXml->addChild('Description');
|
| 185 |
-
$descriptionXml->addChild('Language', $language);
|
| 186 |
-
|
| 187 |
-
$descriptionXml->addChild('Title', htmlspecialchars($product->getName()));
|
| 188 |
-
|
| 189 |
-
// description
|
| 190 |
-
$nestedDescriptionXml = $descriptionXml->addChild('Description');
|
| 191 |
-
$descriptionType = Mage::getStoreConfig('integration_options/products_options/descrption_type');
|
| 192 |
-
|
| 193 |
-
if ($descriptionType == 'long') {
|
| 194 |
-
$this->_addCData($nestedDescriptionXml, $product->getDescription());
|
| 195 |
-
} elseif ($descriptionType == 'short') {
|
| 196 |
-
$this->_addCData($nestedDescriptionXml, $product->getShortDescription());
|
| 197 |
-
} elseif ($descriptionType == 'merge_short_first') {
|
| 198 |
-
$this->_addCData($nestedDescriptionXml, $product->getShortDescription() . PHP_EOL . $product->getDescription());
|
| 199 |
-
} else {
|
| 200 |
-
$this->_addCData($nestedDescriptionXml, $product->getDescription() . PHP_EOL . $product->getShortDescription());
|
| 201 |
-
}
|
| 202 |
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
$descriptionXml->addChild('AttributeColor', $product->getAttributeText('color'));
|
| 206 |
-
}
|
| 207 |
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
$descriptionXml->addChild('AttributeSize', $product->getAttributeText('size'));
|
| 213 |
-
}
|
| 214 |
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
|
|
|
|
|
|
|
|
|
| 225 |
|
| 226 |
-
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
}
|
| 230 |
}
|
| 231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
$addedCurrencies = array();
|
| 233 |
-
foreach ($stores as $store) {
|
| 234 |
-
if ($store->getCode()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
$currencyCode = $store->getCurrentCurrencyCode();
|
|
|
|
|
|
|
|
|
|
| 236 |
if (in_array($currencyCode, $addedCurrencies)) {
|
| 237 |
continue;
|
| 238 |
} else {
|
| 239 |
array_push($addedCurrencies, $currencyCode);
|
| 240 |
}
|
| 241 |
-
|
| 242 |
// Price Node
|
| 243 |
$priceXml = $productXml->addChild('Price');
|
| 244 |
// Currency *R
|
| 245 |
$priceXml->addChild('Currency', $currencyCode);
|
| 246 |
// Country
|
| 247 |
-
|
| 248 |
-
if (isset($existingProductCountries) && $existingProductCountries->getFruugoCountries() != null) {
|
| 249 |
-
$existingList = $existingProductCountries->getFruugoCountries();
|
| 250 |
$priceXml->addChild('Country', $existingList);
|
| 251 |
}
|
| 252 |
|
| 253 |
// Normal price.
|
| 254 |
-
$
|
| 255 |
-
$
|
| 256 |
-
$priceXml->addChild('NormalPriceWithoutVAT', number_format($
|
| 257 |
-
|
| 258 |
-
// VATRate.
|
| 259 |
-
$taxCalculation = Mage::getModel('tax/calculation');
|
| 260 |
-
$request = $taxCalculation->getRateRequest(null, null, null, $store);
|
| 261 |
-
$taxClassId = $product->getTaxClassId();
|
| 262 |
-
$percent = $taxCalculation->getRate($request->setProductClassId($taxClassId));
|
| 263 |
-
$priceXml->addChild('VATRate', number_format($percent, 2, '.', ''));
|
| 264 |
|
| 265 |
// Discount price
|
| 266 |
-
$finalPriceExclTax = $taxHelper->getPrice($product, $product->getFinalPrice(), false);
|
| 267 |
-
$rulePriceExclTax = Mage::getModel('catalogrule/rule')->calcProductPriceRule($product, $normalPriceExclTax);
|
| 268 |
$discountedPriceExclTax = null;
|
|
|
|
|
|
|
|
|
|
| 269 |
|
| 270 |
if ($rulePriceExclTax == null || $finalPriceExclTax < $rulePriceExclTax) {
|
| 271 |
$discountedPriceExclTax = $finalPriceExclTax;
|
| 272 |
} else {
|
| 273 |
$discountedPriceExclTax = $rulePriceExclTax;
|
| 274 |
}
|
| 275 |
-
|
| 276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
// DiscountPriceStartDate *O
|
| 278 |
if ($product->getSpecialFromDate()) {
|
| 279 |
$fromTime = strtotime($product->getSpecialFromDate());
|
| 280 |
-
$formatedFromTimeStr = date('Y-m-d'
|
| 281 |
$priceXml->addChild('DiscountPriceStartDate', $formatedFromTimeStr);
|
| 282 |
}
|
| 283 |
|
| 284 |
// DiscountPriceEndDate *O
|
| 285 |
if ($product->getSpecialToDate()) {
|
| 286 |
$toTime = strtotime($product->getSpecialToDate());
|
| 287 |
-
$fromatedToTimeStr = date('Y-m-d'
|
| 288 |
$priceXml->addChild('DiscountPriceEndDate', $fromatedToTimeStr);
|
| 289 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
}
|
|
|
|
|
|
|
|
|
|
| 291 |
}
|
| 292 |
}
|
| 293 |
|
| 294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
}
|
| 296 |
|
| 297 |
-
|
|
|
|
| 298 |
{
|
| 299 |
-
$
|
|
|
|
|
|
|
| 300 |
$images = array();
|
| 301 |
-
$skuImages = array_values($productObj->getMediaGalleryImages()->getItems());
|
| 302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
if (!empty($skuImages)) {
|
| 304 |
foreach ($skuImages as $skuImage) {
|
| 305 |
-
|
|
|
|
|
|
|
|
|
|
| 306 |
}
|
| 307 |
}
|
| 308 |
|
| 309 |
if (isset($parentProduct)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
$parentImages = array_values($parentProduct->getMediaGalleryImages()->getItems());
|
| 311 |
if (!empty($parentImages)) {
|
| 312 |
foreach ($parentImages as $parentImage) {
|
| 313 |
-
|
|
|
|
|
|
|
|
|
|
| 314 |
}
|
| 315 |
}
|
| 316 |
}
|
| 317 |
|
| 318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
}
|
| 320 |
|
| 321 |
-
|
| 322 |
{
|
| 323 |
$parentProduct = null;
|
| 324 |
|
| 325 |
$parentIds = Mage::getResourceSingleton('catalog/product_type_configurable')
|
| 326 |
-
|
| 327 |
|
| 328 |
if (isset($parentIds[0])) {
|
| 329 |
-
$parentProduct = Mage::
|
|
|
|
| 330 |
}
|
| 331 |
|
| 332 |
-
return
|
| 333 |
}
|
| 334 |
|
| 335 |
-
|
| 336 |
{
|
| 337 |
$node = dom_import_simplexml($xml);
|
| 338 |
$no = $node->ownerDocument;
|
| 339 |
$node->appendChild($no->createCDATASection(htmlspecialchars($cdata_text)));
|
| 340 |
return $xml;
|
| 341 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
}
|
| 24 |
|
| 25 |
class Fruugo_Integration_ProductsFeedGenerator extends Mage_Core_Helper_Abstract
|
| 26 |
{
|
| 27 |
+
protected $MONITOR_RESOURCES = true; // Should the script check resource usage while running
|
| 28 |
+
protected $MAX_RESOURCES = 0.5; // Maximum load average allowed in the last minute
|
| 29 |
+
protected $SLEEP_TIME_SEC = 20; // Time to sleep for if over load limit
|
| 30 |
+
|
| 31 |
+
protected $MAX_ERRORS = 30; // The number of errors after which the script will abort, set to -1 to disable
|
| 32 |
+
protected $PAGE_SIZE = 100; // The number of products to process per batch
|
| 33 |
+
// whether or not to track the last id processed to avoid a double process if items are deleted
|
| 34 |
+
// in between selecting batches, incurs a small performance cost.
|
| 35 |
+
protected $TRACK_LAST_ID = true;
|
| 36 |
+
|
| 37 |
+
protected $stores = null;
|
| 38 |
+
protected $taxHelper = null;
|
| 39 |
+
protected $taxCalculation = null;
|
| 40 |
+
protected $devMode = null;
|
| 41 |
+
protected $currentTimer = array();
|
| 42 |
+
protected $categoryRule = null;
|
| 43 |
+
protected $tmpProductsXmlPath = null;
|
| 44 |
+
protected $productsXmlPath = null;
|
| 45 |
+
protected $report = null;
|
| 46 |
+
protected $currencyConverter = null;
|
| 47 |
+
protected $storeBaseCurrencies = null;
|
| 48 |
+
protected $shouldConvertCurrency = true;
|
| 49 |
+
|
| 50 |
+
protected static $ALWAYS = Fruugo_Integration_Helper_Logger::ALWAYS;
|
| 51 |
+
protected static $ERROR = Fruugo_Integration_Helper_Logger::ERROR;
|
| 52 |
+
protected static $WARNING = Fruugo_Integration_Helper_Logger::WARNING;
|
| 53 |
+
protected static $INFO = Fruugo_Integration_Helper_Logger::INFO;
|
| 54 |
+
protected static $DEBUG = Fruugo_Integration_Helper_Logger::DEBUG;
|
| 55 |
+
|
| 56 |
+
|
| 57 |
public function generateProdcutsFeed($cached = false)
|
| 58 |
{
|
| 59 |
+
$devMode = Mage::getStoreConfig('integration_options/orders_options/dev_mode');
|
| 60 |
+
$this->devMode = ($devMode == '1') ? true : false;
|
| 61 |
+
|
| 62 |
+
$this->productsXmlPath = Mage::getModuleDir('', 'Fruugo_Integration') . '/controllers/products.xml';
|
| 63 |
+
if ($cached === true && file_exists($this->productsXmlPath)) {
|
| 64 |
+
return $this->productsXmlPath;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// BEGIN LOCK CHECK
|
| 68 |
+
// This makes sure that another copy of this script is not executing already
|
| 69 |
+
$lockFile = Mage::getModuleDir('', 'Fruugo_Integration') . '/controllers/products.lock';
|
| 70 |
+
if (!file_exists($lockFile)) {
|
| 71 |
+
touch($lockFile);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
$f = fopen($lockFile, 'w');
|
| 75 |
+
if ($f === false) {
|
| 76 |
+
$this->_writeLog('Did not start Fruugo products export because the script is already running.', self::$WARNING);
|
| 77 |
+
die('Cannot create lock file');
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
if (!flock($f, LOCK_EX | LOCK_NB)) {
|
| 81 |
+
$this->_writeLog('Did not start Fruugo products export because the script is already running.', self::$WARNING);
|
| 82 |
+
die('Cannot create lock file');
|
| 83 |
} else {
|
| 84 |
+
$this->_writeLog('Beginning export of products feed...', self::$ALWAYS);
|
| 85 |
+
}
|
| 86 |
+
// END LOCK CHECK
|
| 87 |
+
|
| 88 |
+
if ($this->devMode) {
|
| 89 |
+
Fruugo_Integration_Helper_Logger::$LOG_LEVEL = self::$DEBUG;
|
| 90 |
+
$this->MONITOR_RESOURCES = false;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
try {
|
| 94 |
+
$time = time();
|
| 95 |
+
$this->_setupGlobalData();
|
| 96 |
+
$this->report['start_time_utc'] = date("Y-m-d H:i:s", time());
|
| 97 |
$productsXml;
|
| 98 |
|
| 99 |
+
if ($this->devMode) {
|
| 100 |
+
$productsXml = '<?xml version="1.0" encoding="UTF-8"?><Products xmlns="http://schemas.fruugo.com/fruugoflat">';
|
|
|
|
|
|
|
| 101 |
} else {
|
| 102 |
+
$productsXml = '<?xml version="1.0" encoding="UTF-8"?><Products>';
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
if (file_exists($this->tmpProductsXmlPath)) {
|
| 106 |
+
unlink($this->tmpProductsXmlPath);
|
| 107 |
}
|
| 108 |
|
| 109 |
+
$this->_writeProductsXml($productsXml);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
// Get store langauge map or use null if none
|
| 112 |
$storelangsSettings = Mage::getStoreConfig('integration_options/products_options/language_store');
|
| 113 |
$storelangsMapping = empty($storelangsSettings) ? null : unserialize($storelangsSettings);
|
| 114 |
|
| 115 |
+
$numOfProds = 0;
|
| 116 |
+
$currentPage = 0;
|
| 117 |
+
$numResults = $this->PAGE_SIZE;
|
| 118 |
+
$numIterations = 0;
|
| 119 |
+
$totalMemory = 0;
|
| 120 |
+
$xmlBuffer = '';
|
| 121 |
+
$errorsCount = 0;
|
| 122 |
+
$totalProcessed = 0;
|
| 123 |
+
$finalException = null; // This is a hack because old versions of PHP(<5.5) don't have finally
|
| 124 |
+
$lastProcessedId = 0;
|
| 125 |
+
|
| 126 |
+
do {
|
| 127 |
+
$products = Mage::getModel('catalog/product')->getCollection();
|
| 128 |
+
$products->addAttributeToSelect('*'); // select all attributes
|
| 129 |
+
if ($this->TRACK_LAST_ID) {
|
| 130 |
+
$products->addAttributeToFilter('entity_id', array('gt' => $lastProcessedId)); // make sure we don't double process items due to deletions during the process
|
| 131 |
}
|
| 132 |
+
$products->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED); // only select enabled products
|
| 133 |
+
$products->addAttributeToFilter('type_id', Mage_Catalog_Model_Product_Type::TYPE_SIMPLE);
|
| 134 |
+
$products->setOrder('entity_id', 'ASC');
|
| 135 |
+
if ($this->TRACK_LAST_ID) {
|
| 136 |
+
$products->getSelect()->limit($this->PAGE_SIZE);
|
| 137 |
+
} else {
|
| 138 |
+
$products->getSelect()->limit($this->PAGE_SIZE, $currentPage);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
$this->_writeLog("Processing page " . $currentPage. ', max memory used ' . ((memory_get_peak_usage(true) /1024)/1024) . 'MB.', self::$DEBUG);
|
| 142 |
|
| 143 |
+
$numResults = 0;
|
| 144 |
+
foreach ($products as $product) {
|
| 145 |
+
$numResults++;
|
| 146 |
+
$totalProcessed++;
|
| 147 |
+
$lastProcessedId = $product->getId();
|
| 148 |
+
|
| 149 |
+
$disabledOnFruugo = false;
|
| 150 |
+
$productCountries = Mage::getModel('integration/countries')->load($product->getId(), 'product_id');
|
| 151 |
+
|
| 152 |
+
if (isset($productCountries) && $productCountries->getFruugoCountries() == 'Disabled') {
|
| 153 |
+
$disabledOnFruugo = true;
|
| 154 |
+
continue;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
unset($productCountries);
|
| 158 |
+
if ($this->_shouldInclude($product)) {
|
| 159 |
+
try {
|
| 160 |
+
$productXml = $this->_fillProductXml($product, $storelangsMapping);
|
| 161 |
+
|
| 162 |
+
if ($productXml) {
|
| 163 |
+
$xmlBuffer .= $productXml;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
$numOfProds++;
|
| 167 |
+
} catch (Exception $ex) {
|
| 168 |
+
$errorsCount += 1;
|
| 169 |
+
Mage::logException($ex);
|
| 170 |
+
|
| 171 |
+
if (count($this->report['errors']) < 10) {
|
| 172 |
+
$errorLog = array(
|
| 173 |
+
'product_id' => $product->getId(),
|
| 174 |
+
'stack_trace' => $ex->getTraceAsString(),
|
| 175 |
+
'message' => $ex->getMessage(),
|
| 176 |
+
);
|
| 177 |
+
array_push($this->report['errors'], $errorLog);
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
if ($this->MAX_ERRORS != -1 && $errorsCount > $this->MAX_ERRORS) {
|
| 181 |
+
$this->_writeLog('Product export aborting due to hitting maximum error threshold of ' . $this->MAX_ERRORS, self::$ERROR);
|
| 182 |
+
throw new Exception('Fruugo product export aborting due to hitting maximum error threshold of ' . $this->MAX_ERRORS, 500, $ex);
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
}
|
| 187 |
}
|
| 188 |
+
|
| 189 |
+
$this->_writeProductsXml($xmlBuffer);
|
| 190 |
+
$numIterations += 1;
|
| 191 |
+
$xmlBuffer = '';
|
| 192 |
+
$totalMemory += ((memory_get_usage(false) /1024)/1024);
|
| 193 |
+
|
| 194 |
+
$currentPage = $currentPage + $this->PAGE_SIZE;
|
| 195 |
+
|
| 196 |
+
//clear collection and free memory
|
| 197 |
+
$products->resetData();
|
| 198 |
+
$products->clear();
|
| 199 |
+
unset($products);
|
| 200 |
+
|
| 201 |
+
$this->checkServerLoad();
|
| 202 |
+
|
| 203 |
+
} while ($numResults >= $this->PAGE_SIZE);
|
| 204 |
+
|
| 205 |
+
// write file end and rename
|
| 206 |
+
$this->_writeProductsXml('</Products>');
|
| 207 |
+
rename($this->tmpProductsXmlPath, $this->productsXmlPath);
|
| 208 |
+
|
| 209 |
+
$this->report['xml_file_size_mb'] = ((filesize($this->productsXmlPath) /1024)/1024);
|
| 210 |
+
} catch (Exception $ex) {
|
| 211 |
+
$this->report['status'] = 'failed';
|
| 212 |
+
$numOfProds = 0;
|
| 213 |
+
$finalException = $ex;
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
// This should probably go in a finally block but older
|
| 217 |
+
// version of PHP don't support it,
|
| 218 |
+
$this->report['total_exported'] = $numOfProds;
|
| 219 |
+
$this->report['processing_time_sec'] = (time() - $time);
|
| 220 |
+
$this->report['end_time_utc'] = date("Y-m-d H:i:s", time());
|
| 221 |
+
$this->report['avg_ram_usage_mb'] = $totalMemory / $numIterations;
|
| 222 |
+
$this->report['max_ram_usage_mb'] = ((memory_get_peak_usage(true) /1024)/1024);
|
| 223 |
+
$this->report['total_processed'] = $totalProcessed;
|
| 224 |
+
$this->report['error_count'] = $errorsCount;
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
if (!$this->report['status']) {
|
| 228 |
+
if ($errorsCount == 0) {
|
| 229 |
+
$this->report['status'] = 'success';
|
| 230 |
+
} else {
|
| 231 |
+
$this->report['status'] = 'success_with_errors';
|
| 232 |
}
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
$this->_writeReport($this->report);
|
| 236 |
+
$this->_writeLog(Fruugo_Integration_Helper_Logger::getFormattedReport($this->report), self::$INFO);
|
| 237 |
|
| 238 |
+
if ($finalException !== null) {
|
| 239 |
+
$this->_writeLog('The Fruugo product export has stopped due to an error: ' . $ex->getMessage(), self::$ERROR);
|
| 240 |
+
Mage::logException($ex);
|
| 241 |
+
throw $ex;
|
| 242 |
}
|
| 243 |
+
|
| 244 |
+
return $this->productsXmlPath;
|
| 245 |
}
|
| 246 |
|
| 247 |
+
protected function _fillProductXml($product, $storelangsMapping)
|
| 248 |
{
|
|
|
|
| 249 |
$parentProduct = $this->_getParentProduct($product);
|
| 250 |
+
$images = $this->_getProductImages($product, $parentProduct);
|
| 251 |
+
|
| 252 |
+
if (count($images) == 0) {
|
| 253 |
+
return false;
|
| 254 |
+
}
|
| 255 |
+
// M: Mandatory R: Recommended O: Optional
|
| 256 |
+
$productXml = new SimpleXMLElement('<Product></Product>');
|
| 257 |
|
| 258 |
// ProductId *M
|
| 259 |
if (isset($parentProduct)) {
|
| 287 |
|
| 288 |
// Category *R
|
| 289 |
$categoryEntity = $product->getCategoryCollection()
|
| 290 |
+
->addAttributeToSelect('name')
|
| 291 |
->addAttributeToSort('level', 'DESC')
|
| 292 |
->addAttributeToSort('position', 'DESC')
|
| 293 |
->addAttributeToFilter('is_active', '1')
|
| 294 |
->getFirstItem();
|
| 295 |
|
| 296 |
+
if ($categoryEntity->getName() !== null) {
|
| 297 |
+
$productXml->addChild('Category', htmlspecialchars($categoryEntity->getName()));
|
|
|
|
|
|
|
|
|
|
| 298 |
}
|
| 299 |
|
| 300 |
// Imageurl1 *M
|
| 301 |
// Imageurl2, Imageurl3, Imageurl4, Imageurl5 *R
|
|
|
|
| 302 |
$imageIndex = 0;
|
| 303 |
|
| 304 |
+
foreach ($images as $imageUrl) {
|
| 305 |
if ($imageIndex >= 5) {
|
| 306 |
break;
|
| 307 |
}
|
| 308 |
|
| 309 |
+
$productXml->addChild('Imageurl'.($imageIndex + 1), $imageUrl);
|
| 310 |
+
$imageIndex++;
|
|
|
|
|
|
|
|
|
|
| 311 |
}
|
| 312 |
|
| 313 |
// StockStatus & StockQuantity *M
|
| 316 |
if ($stockItem === null || !$stockItem->getIsInStock()) {
|
| 317 |
$productXml->addChild('StockStatus', 'OUTOFSTOCK');
|
| 318 |
} else {
|
|
|
|
| 319 |
$stocklevel = (int)$stockItem->getQty();
|
| 320 |
+
if ($stocklevel <= 0) {
|
| 321 |
+
$productXml->addChild('StockStatus', 'OUTOFSTOCK');
|
| 322 |
+
$productXml->addChild('StockQuantity', 0);
|
| 323 |
+
} else {
|
| 324 |
+
$productXml->addChild('StockStatus', 'INSTOCK');
|
| 325 |
+
$productXml->addChild('StockQuantity', $stocklevel);
|
| 326 |
+
}
|
| 327 |
}
|
| 328 |
|
| 329 |
// RestockDate *O
|
| 336 |
}
|
| 337 |
|
| 338 |
// Description Node
|
|
|
|
|
|
|
| 339 |
$addedLanguages = array();
|
| 340 |
+
$descriptionNodeCount = 0;
|
| 341 |
+
foreach ($this->stores as $store) {
|
| 342 |
// store 'fruugo' is for Fruugo orders
|
| 343 |
+
if ($store->getCode() == 'fruugo') {
|
| 344 |
+
continue;
|
| 345 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
|
| 347 |
+
$localeCode = Mage::getStoreConfig('general/locale/code', $store->getId());
|
| 348 |
+
$language = substr($localeCode, 0, strpos($localeCode, '_'));
|
|
|
|
|
|
|
| 349 |
|
| 350 |
+
// Make sure no language is added more than once
|
| 351 |
+
if (in_array($language, $addedLanguages)) {
|
| 352 |
+
continue;
|
| 353 |
+
}
|
|
|
|
|
|
|
| 354 |
|
| 355 |
+
// Make sure product has description based on store config
|
| 356 |
+
$descriptionType = Mage::getStoreConfig('integration_options/products_options/descrption_type', $store);
|
| 357 |
+
$descriptionsArray = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), array(
|
| 358 |
+
'description',
|
| 359 |
+
'short_description',
|
| 360 |
+
), $store->getId());
|
| 361 |
+
|
| 362 |
+
// This is a workaround for a bug in getAttributeRawValue which returns the wrong values for product attributes that have been
|
| 363 |
+
// modified in another site so to save db hits we try and get them and if they differ from the main product we are processing we
|
| 364 |
+
// then load them individually
|
| 365 |
+
if (isset($descriptionsArray['description']) && ($product->getDescription() != $descriptionsArray['description'])) {
|
| 366 |
+
$descriptionsArray['description'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'description', $store->getId());
|
| 367 |
+
}
|
| 368 |
|
| 369 |
+
if (isset($descriptionsArray['short_description']) && ($product->getShortDescription() != $descriptionsArray['short_description'])) {
|
| 370 |
+
$descriptionsArray['short_description'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'short_description', $store->getId());
|
| 371 |
+
}
|
| 372 |
+
|
| 373 |
+
// check product description not null for each store
|
| 374 |
+
if ($descriptionType == 'long' && $descriptionsArray['description'] === null) {
|
| 375 |
+
continue;
|
| 376 |
+
} elseif ($descriptionType == 'short' && $descriptionsArray['short_description'] === null) {
|
| 377 |
+
continue;
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
// Add description when no store selected for language OR the store is selected for the langauge in storelangsMapping array
|
| 381 |
+
if ($storelangsMapping == null || $storelangsMapping[$localeCode] == "" || $storelangsMapping[$localeCode] == $store->getCode()) {
|
| 382 |
+
// Language *R
|
| 383 |
+
$descriptionXml = $productXml->addChild('Description');
|
| 384 |
+
$descriptionXml->addChild('Language', $language);
|
| 385 |
+
|
| 386 |
+
$attributes = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), array(
|
| 387 |
+
'shoe_size',
|
| 388 |
+
'size',
|
| 389 |
+
'color',
|
| 390 |
+
'fit',
|
| 391 |
+
'length',
|
| 392 |
+
'width',
|
| 393 |
+
), $store->getId());
|
| 394 |
+
|
| 395 |
+
// This is a workaround for a bug in getAttributeRawValue which returns the wrong values for product attributes that have been
|
| 396 |
+
// modified in another site so to save db hits we try and get them and if they differ from the main product we are processing we
|
| 397 |
+
// then load them individually
|
| 398 |
+
if (isset($attributes['fit']) && ($product->getFit() != $attributes['fit'])) {
|
| 399 |
+
$attributes['fit'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'fit', $store->getId());
|
| 400 |
}
|
| 401 |
+
|
| 402 |
+
if (isset($attributes['color']) && ($product->getColor() != $attributes['color'])) {
|
| 403 |
+
$attributes['color'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'color', $store->getId());
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
if (isset($attributes['size']) && ($product->getSize() != $attributes['size'])) {
|
| 407 |
+
$attributes['size'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'size', $store->getId());
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
if (isset($attributes['shoe_size']) && ($product->getShoe_size() != $attributes['shoe_size'])) {
|
| 411 |
+
$attributes['shoe_size'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'shoe_size', $store->getId());
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
if (isset($attributes['length']) && ($product->getLength() != $attributes['length'])) {
|
| 415 |
+
$attributes['length'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'length', $store->getId());
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
if (isset($attributes['width']) && ($product->getWidth() != $attributes['width'])) {
|
| 419 |
+
$attributes['width'] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'width', $store->getId());
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
// title
|
| 423 |
+
$name = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'name', $store->getId());
|
| 424 |
+
$descriptionXml->addChild('Title', htmlspecialchars($name));
|
| 425 |
+
|
| 426 |
+
// description
|
| 427 |
+
$nestedDescriptionXml = $descriptionXml->addChild('Description');
|
| 428 |
+
|
| 429 |
+
if ($descriptionType == 'long') {
|
| 430 |
+
$this->_addCData($nestedDescriptionXml, $descriptionsArray['description']);
|
| 431 |
+
} elseif ($descriptionType == 'short') {
|
| 432 |
+
$this->_addCData($nestedDescriptionXml, $descriptionsArray['short_description']);
|
| 433 |
+
} elseif ($descriptionType == 'merge_short_first') {
|
| 434 |
+
$this->_addCData($nestedDescriptionXml, $descriptionsArray['short_description'] . PHP_EOL . $descriptionsArray['description']);
|
| 435 |
+
} else {
|
| 436 |
+
$this->_addCData($nestedDescriptionXml, $descriptionsArray['description'] . PHP_EOL . $descriptionsArray['short_description']);
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
// AttributeColor *R
|
| 440 |
+
if (!empty($attributes['color'])) {
|
| 441 |
+
$descriptionXml->addChild('AttributeColor', $this->_getAttributesText($language, 'color', $attributes['color'], $store->getId()));
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
// AttributeSize *R
|
| 445 |
+
if (!empty($attributes['shoe_size'])) {
|
| 446 |
+
$descriptionXml->addChild('AttributeSize', $this->_getAttributesText($language, 'shoe_size', $attributes['shoe_size'], $store->getId()));
|
| 447 |
+
} elseif (!empty($attributes['size'])) {
|
| 448 |
+
$descriptionXml->addChild('AttributeSize', $this->_getAttributesText($language, 'size', $attributes['size'], $store->getId()));
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
// optional attributes: Arrtibute1 - Attribute10 *O
|
| 452 |
+
if (!empty($attributes['fit'])) {
|
| 453 |
+
$descriptionXml->addChild('Attribute1', $this->_getAttributesText($language, 'fit', $attributes['fit'], $store->getId()));
|
| 454 |
+
}
|
| 455 |
+
if (!empty($attributes['length'])) {
|
| 456 |
+
$descriptionXml->addChild('Attribute2', $this->_getAttributesText($language, 'length', $attributes['length'], $store->getId()));
|
| 457 |
+
}
|
| 458 |
+
if (!empty($attributes['width'])) {
|
| 459 |
+
$descriptionXml->addChild('Attribute3', $this->_getAttributesText($language, 'width', $attributes['width'], $store->getId()));
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
array_push($addedLanguages, $language);
|
| 463 |
+
$descriptionNodeCount++;
|
| 464 |
}
|
| 465 |
}
|
| 466 |
|
| 467 |
+
// Ignore if no descriptions added
|
| 468 |
+
if ($descriptionNodeCount == 0) {
|
| 469 |
+
return false;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
$existingProductCountries = Mage::getModel('integration/countries')->load($product->getId(), 'product_id');
|
| 473 |
+
|
| 474 |
+
if (isset($existingProductCountries)) {
|
| 475 |
+
$existingList = $existingProductCountries->getFruugoCountries();
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
$addedCurrencies = array();
|
| 479 |
+
foreach ($this->stores as $store) {
|
| 480 |
+
if ($store->getCode() == 'fruugo') {
|
| 481 |
+
continue;
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
// Add price for store in language mapping.
|
| 485 |
+
$localeCode = Mage::getStoreConfig('general/locale/code', $store->getId());
|
| 486 |
+
if ($storelangsMapping == null || $storelangsMapping[$localeCode] == $store->getCode()) {
|
| 487 |
$currencyCode = $store->getCurrentCurrencyCode();
|
| 488 |
+
$baseCurrencyCode = $this->storeBaseCurrencies[$store->getId()];
|
| 489 |
+
|
| 490 |
+
// Skip if currency has been added.
|
| 491 |
if (in_array($currencyCode, $addedCurrencies)) {
|
| 492 |
continue;
|
| 493 |
} else {
|
| 494 |
array_push($addedCurrencies, $currencyCode);
|
| 495 |
}
|
| 496 |
+
|
| 497 |
// Price Node
|
| 498 |
$priceXml = $productXml->addChild('Price');
|
| 499 |
// Currency *R
|
| 500 |
$priceXml->addChild('Currency', $currencyCode);
|
| 501 |
// Country
|
| 502 |
+
if (isset($existingList)) {
|
|
|
|
|
|
|
| 503 |
$priceXml->addChild('Country', $existingList);
|
| 504 |
}
|
| 505 |
|
| 506 |
// Normal price.
|
| 507 |
+
$normalPriceExclTax = $this->taxHelper->getPrice($product, $product->getPrice(), false, null, null, null, $store);
|
| 508 |
+
$normalPriceExclTaxConv = $this->_convertCurrency($normalPriceExclTax, $baseCurrencyCode, $currencyCode);
|
| 509 |
+
$priceXml->addChild('NormalPriceWithoutVAT', number_format($normalPriceExclTaxConv, 2, '.', ''));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 510 |
|
| 511 |
// Discount price
|
|
|
|
|
|
|
| 512 |
$discountedPriceExclTax = null;
|
| 513 |
+
$finalPrice = $product->getFinalPrice();
|
| 514 |
+
$finalPriceExclTax = $this->taxHelper->getPrice($product, $finalPrice, false, null, null, null, $store);
|
| 515 |
+
$rulePriceExclTax = $this->categoryRule->clearInstance()->calcProductPriceRule($product, $normalPriceExclTax);
|
| 516 |
|
| 517 |
if ($rulePriceExclTax == null || $finalPriceExclTax < $rulePriceExclTax) {
|
| 518 |
$discountedPriceExclTax = $finalPriceExclTax;
|
| 519 |
} else {
|
| 520 |
$discountedPriceExclTax = $rulePriceExclTax;
|
| 521 |
}
|
| 522 |
+
|
| 523 |
+
// VATRate.
|
| 524 |
+
$request = $this->taxCalculation->clearInstance()->getRateRequest(null, null, null, $store);
|
| 525 |
+
$taxClassId = $product->getTaxClassId();
|
| 526 |
+
$percent = $this->taxCalculation->clearInstance()->getRate($request->setProductClassId($taxClassId));
|
| 527 |
+
|
| 528 |
+
if ($discountedPriceExclTax && $normalPriceExclTax > $discountedPriceExclTax) {
|
| 529 |
+
$discountedPriceExclTaxConv = $this->_convertCurrency($discountedPriceExclTax, $baseCurrencyCode, $currencyCode);
|
| 530 |
+
$priceXml->addChild('DiscountPriceWithoutVAT', number_format($discountedPriceExclTaxConv, 2, '.', ''));
|
| 531 |
+
|
| 532 |
+
$priceXml->addChild('VATRate', number_format($percent, 2, '.', ''));
|
| 533 |
// DiscountPriceStartDate *O
|
| 534 |
if ($product->getSpecialFromDate()) {
|
| 535 |
$fromTime = strtotime($product->getSpecialFromDate());
|
| 536 |
+
$formatedFromTimeStr = date('Y-m-d', $fromTime);
|
| 537 |
$priceXml->addChild('DiscountPriceStartDate', $formatedFromTimeStr);
|
| 538 |
}
|
| 539 |
|
| 540 |
// DiscountPriceEndDate *O
|
| 541 |
if ($product->getSpecialToDate()) {
|
| 542 |
$toTime = strtotime($product->getSpecialToDate());
|
| 543 |
+
$fromatedToTimeStr = date('Y-m-d', $toTime);
|
| 544 |
$priceXml->addChild('DiscountPriceEndDate', $fromatedToTimeStr);
|
| 545 |
}
|
| 546 |
+
} else {
|
| 547 |
+
// This looks strange because the VATRate is also added above but the sequence
|
| 548 |
+
// defined in the XSD requires it appears after DiscountPriceWithoutVAT if it is present
|
| 549 |
+
$priceXml->addChild('VATRate', number_format($percent, 2, '.', ''));
|
| 550 |
}
|
| 551 |
+
|
| 552 |
+
// Only need one price tag for each product now.
|
| 553 |
+
break;
|
| 554 |
}
|
| 555 |
}
|
| 556 |
|
| 557 |
+
$productStr = $productXml->asXML();
|
| 558 |
+
|
| 559 |
+
if ($productStr) {
|
| 560 |
+
$productStr = str_replace('<?xml version="1.0"?>', '', trim($productStr));
|
| 561 |
+
}
|
| 562 |
+
|
| 563 |
+
foreach ($productXml->children as $child) {
|
| 564 |
+
unset($child);
|
| 565 |
+
}
|
| 566 |
+
unset($productXml);
|
| 567 |
+
|
| 568 |
+
return $productStr;
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
protected function _convertCurrency($price, $baseCurrencyCode, $currencyCode)
|
| 572 |
+
{
|
| 573 |
+
if ($this->shouldConvertCurrency && $baseCurrencyCode != $currencyCode) {
|
| 574 |
+
return $this->currencyConverter->currencyConvert(
|
| 575 |
+
$price,
|
| 576 |
+
$baseCurrencyCode,
|
| 577 |
+
$currencyCode
|
| 578 |
+
);
|
| 579 |
+
}
|
| 580 |
+
|
| 581 |
+
return $price;
|
| 582 |
+
}
|
| 583 |
+
|
| 584 |
+
// This caches the options label translation for selectable product attributes.
|
| 585 |
+
// They are cached by attribute name, language and then value.
|
| 586 |
+
protected function _getAttributesText($language, $attributeName, $optionId, $storeId)
|
| 587 |
+
{
|
| 588 |
+
// These are the asset keys that are cached, you should only cache attributes
|
| 589 |
+
// that have selectable items
|
| 590 |
+
if (!isset($this->attributeMap)) {
|
| 591 |
+
$this->attributeMap = array(
|
| 592 |
+
'color' => array(),
|
| 593 |
+
'shoe_size' => array(),
|
| 594 |
+
'size' => array(),
|
| 595 |
+
'fit' => array(),
|
| 596 |
+
);
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
if (!isset($this->attributeMap[$attributeName])) {
|
| 600 |
+
return $optionId;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
if (!isset($this->attributeMap[$attributeName][$language])) {
|
| 604 |
+
$this->attributeMap[$attributeName][$language] = array();
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
if (!isset($this->attributeMap[$attributeName][$language][$optionId])) {
|
| 608 |
+
$this->attributeMap[$attributeName][$language][$optionId] = null;
|
| 609 |
+
} else {
|
| 610 |
+
return $this->attributeMap[$attributeName][$language][$optionId];
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
$attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $attributeName);
|
| 614 |
+
$collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
|
| 615 |
+
->setPositionOrder('asc')
|
| 616 |
+
->setAttributeFilter($attributeId)
|
| 617 |
+
->setStoreFilter($storeId)
|
| 618 |
+
->load()
|
| 619 |
+
->toOptionArray();
|
| 620 |
+
|
| 621 |
+
$found = false;
|
| 622 |
+
foreach ($collection as $option) {
|
| 623 |
+
if ($option['value'] == $optionId) {
|
| 624 |
+
$found = true;
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
$this->attributeMap[$attributeName][$language][$option['value']] = $option['label'];
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
if (!$found) {
|
| 631 |
+
return $optionId;
|
| 632 |
+
}
|
| 633 |
+
|
| 634 |
+
return $this->attributeMap[$attributeName][$language][$optionId];
|
| 635 |
}
|
| 636 |
|
| 637 |
+
protected $tempProductObj = false;
|
| 638 |
+
protected function _getProductImages($product, $parentProduct)
|
| 639 |
{
|
| 640 |
+
if (!isset($this->tempProductObj) || $this->tempProductObj === false) {
|
| 641 |
+
$this->tempProductObj = Mage::getModel('catalog/product');
|
| 642 |
+
}
|
| 643 |
$images = array();
|
|
|
|
| 644 |
|
| 645 |
+
// This is a workaround to avoid the memory leaks that seem to occur when fully
|
| 646 |
+
// loading an image gallery on a product model.
|
| 647 |
+
$productObj = $this->tempProductObj->clearInstance()->setId($product->getId());
|
| 648 |
+
$attributes = $productObj->getTypeInstance(true)->getSetAttributes($productObj);
|
| 649 |
+
$media_gallery = $attributes['media_gallery'];
|
| 650 |
+
$backend = $media_gallery->getBackend();
|
| 651 |
+
$backend->afterLoad($productObj);
|
| 652 |
+
|
| 653 |
+
// Add base image
|
| 654 |
+
$baseImage = Mage::getResourceModel('catalog/product')->getAttributeRawValue($product->getId(), 'image', 0);
|
| 655 |
+
$productMediaConfig = Mage::getSingleton('catalog/product_media_config');
|
| 656 |
+
if (!empty($baseImage) && $baseImage !== 'no_selection') {
|
| 657 |
+
$baseImageUrl = $productMediaConfig->getMediaUrl($baseImage);
|
| 658 |
+
array_push($images, $baseImageUrl);
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
// Add gallery
|
| 662 |
+
$galleryImages = $productObj->getMediaGalleryImages();
|
| 663 |
+
$skuImages = array_values($galleryImages->getItems());
|
| 664 |
if (!empty($skuImages)) {
|
| 665 |
foreach ($skuImages as $skuImage) {
|
| 666 |
+
$imageUrl = $skuImage->getUrl();
|
| 667 |
+
if (strpos($imageUrl, 'placeholder/image') !== true) {
|
| 668 |
+
array_push($images, $imageUrl);
|
| 669 |
+
}
|
| 670 |
}
|
| 671 |
}
|
| 672 |
|
| 673 |
if (isset($parentProduct)) {
|
| 674 |
+
// Add parent base image
|
| 675 |
+
$attributes = $parentProduct->getTypeInstance(true)->getSetAttributes($parentProduct);
|
| 676 |
+
$media_gallery = $attributes['media_gallery'];
|
| 677 |
+
$backend = $media_gallery->getBackend();
|
| 678 |
+
$backend->afterLoad($parentProduct);
|
| 679 |
+
|
| 680 |
+
$parentBaseImage = Mage::getResourceModel('catalog/product')->getAttributeRawValue($parentProduct->getId(), 'image', 0);
|
| 681 |
+
if (!empty($parentBaseImage) && $parentBaseImage !== 'no_selection') {
|
| 682 |
+
$baseImageUrl = $productMediaConfig->getMediaUrl($parentBaseImage);
|
| 683 |
+
array_push($images, $baseImageUrl);
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
// Add parent gallery
|
| 687 |
$parentImages = array_values($parentProduct->getMediaGalleryImages()->getItems());
|
| 688 |
if (!empty($parentImages)) {
|
| 689 |
foreach ($parentImages as $parentImage) {
|
| 690 |
+
$imageUrl = $parentImage->getUrl();
|
| 691 |
+
if (strpos($imageUrl, 'placeholder/image') !== true) {
|
| 692 |
+
array_push($images, $imageUrl);
|
| 693 |
+
}
|
| 694 |
}
|
| 695 |
}
|
| 696 |
}
|
| 697 |
|
| 698 |
+
$productObj->clearInstance();
|
| 699 |
+
unset($productObj);
|
| 700 |
+
|
| 701 |
+
// If base image is not 'disabled' there will be duplicates
|
| 702 |
+
$unique = array_keys(array_flip($images)); // array_unique is supposed to be slower
|
| 703 |
+
return $unique;
|
| 704 |
+
}
|
| 705 |
+
|
| 706 |
+
protected function _shouldInclude($product)
|
| 707 |
+
{
|
| 708 |
+
if ($product->getSku() === null || $product->getName() === null || $product->getPrice() === null) {
|
| 709 |
+
return false;
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
if ($product->getDescription() === null && $product->getShortDescription() === null) {
|
| 713 |
+
return false;
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
return true;
|
| 717 |
}
|
| 718 |
|
| 719 |
+
protected function _getParentProduct($product)
|
| 720 |
{
|
| 721 |
$parentProduct = null;
|
| 722 |
|
| 723 |
$parentIds = Mage::getResourceSingleton('catalog/product_type_configurable')
|
| 724 |
+
->getParentIdsByChild($product->getId());
|
| 725 |
|
| 726 |
if (isset($parentIds[0])) {
|
| 727 |
+
$parentProduct = Mage::getSingleton('catalog/product')->clearInstance()->setId($parentIds[0]);
|
| 728 |
+
return $parentProduct;
|
| 729 |
}
|
| 730 |
|
| 731 |
+
return null;
|
| 732 |
}
|
| 733 |
|
| 734 |
+
protected function _addCData($xml, $cdata_text)
|
| 735 |
{
|
| 736 |
$node = dom_import_simplexml($xml);
|
| 737 |
$no = $node->ownerDocument;
|
| 738 |
$node->appendChild($no->createCDATASection(htmlspecialchars($cdata_text)));
|
| 739 |
return $xml;
|
| 740 |
}
|
| 741 |
+
|
| 742 |
+
protected function _writeProductsXml($xmlStr)
|
| 743 |
+
{
|
| 744 |
+
file_put_contents($this->tmpProductsXmlPath, $xmlStr, FILE_APPEND | LOCK_EX);
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
protected function _writeReport($report)
|
| 748 |
+
{
|
| 749 |
+
file_put_contents($this->reportPath, json_encode($report));
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
protected function _writeLog($message, $level = Fruugo_Integration_Helper_Logger::DEBUG)
|
| 753 |
+
{
|
| 754 |
+
Fruugo_Integration_Helper_Logger::log($message, $level);
|
| 755 |
+
}
|
| 756 |
+
|
| 757 |
+
protected function _setupGlobalData()
|
| 758 |
+
{
|
| 759 |
+
// Cache the stores list to avoid frequent lookups
|
| 760 |
+
$this->stores = array();
|
| 761 |
+
$this->storeBaseCurrencies = array();
|
| 762 |
+
foreach (Mage::app()->getStores(true) as $store) {
|
| 763 |
+
array_push($this->stores, $store);
|
| 764 |
+
$this->storeBaseCurrencies[$store->getId()] = $store->getBaseCurrencyCode();
|
| 765 |
+
}
|
| 766 |
+
|
| 767 |
+
$this->PAGE_SIZE = Mage::getStoreConfig('integration_options/products_options/export_page_size');
|
| 768 |
+
$this->MAX_RESOURCES = Mage::getStoreConfig('integration_options/products_options/max_resources_load');
|
| 769 |
+
$this->SLEEP_TIME_SEC = Mage::getStoreConfig('integration_options/products_options/sleep_time_sec');
|
| 770 |
+
$this->MAX_ERRORS = Mage::getStoreConfig('integration_options/products_options/max_errors');
|
| 771 |
+
|
| 772 |
+
$this->taxHelper = Mage::helper('tax');
|
| 773 |
+
$this->currencyConverter = Mage::helper('directory');
|
| 774 |
+
$this->taxCalculation = Mage::getSingleton('tax/calculation');
|
| 775 |
+
$this->categoryRule = Mage::getSingleton('catalogrule/rule');
|
| 776 |
+
$this->tmpProductsXmlPath = Mage::getModuleDir('', 'Fruugo_Integration') . '/controllers/tmp_products.xml';
|
| 777 |
+
$this->reportPath = Mage::getModuleDir('', 'Fruugo_Integration') . '/controllers/report.json';
|
| 778 |
+
$this->report = array(
|
| 779 |
+
'processing_time_sec' => 0,
|
| 780 |
+
'start_time_utc' => 0,
|
| 781 |
+
'end_time_utc' => 0,
|
| 782 |
+
'total_exported' => 0,
|
| 783 |
+
'total_processed' => 0,
|
| 784 |
+
'max_ram_usage_mb' => 0,
|
| 785 |
+
'avg_ram_usage_mb' => 0,
|
| 786 |
+
'error_count' => 0,
|
| 787 |
+
'errors' => array(),
|
| 788 |
+
'status' => '',
|
| 789 |
+
'avg_load' => 0,
|
| 790 |
+
'load_above_threshold_count' => 0,
|
| 791 |
+
'time_paused_sec' => 0,
|
| 792 |
+
'xml_file_size_mb' => 0,
|
| 793 |
+
);
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
// This monitors system resources and pauses execution if the utilisation is
|
| 797 |
+
// above the configured threshold.
|
| 798 |
+
// Recommended for systems with large numbers of products
|
| 799 |
+
// Note: this feature is not available on windows servers.
|
| 800 |
+
protected $loadCheckCount = 0;
|
| 801 |
+
protected $loadCheckTotal = 0.0;
|
| 802 |
+
protected function checkServerLoad()
|
| 803 |
+
{
|
| 804 |
+
if (stristr(PHP_OS, 'win')) {
|
| 805 |
+
return;
|
| 806 |
+
}
|
| 807 |
+
$systemLoad = sys_getloadavg();
|
| 808 |
+
$this->loadCheckTotal += $systemLoad[0];
|
| 809 |
+
$this->loadCheckCount++;
|
| 810 |
+
|
| 811 |
+
$this->report['avg_load'] = $this->loadCheckTotal / $this->loadCheckCount;
|
| 812 |
+
|
| 813 |
+
if ($this->devMode) {
|
| 814 |
+
$this->_writeLog('Server load is ' . $systemLoad[0], self::$DEBUG);
|
| 815 |
+
}
|
| 816 |
+
|
| 817 |
+
if (!$this->MONITOR_RESOURCES) {
|
| 818 |
+
return;
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
$systemLoad = sys_getloadavg();
|
| 822 |
+
if ($this->devMode && $systemLoad[0] > $this->MAX_RESOURCES) {
|
| 823 |
+
$this->_writeLog(
|
| 824 |
+
'High server load detected. Usage of ' . $systemLoad[0] .
|
| 825 |
+
' is greater than configured maximum of ' . $this->MAX_RESOURCES .
|
| 826 |
+
'. The product export job will now pause for ' . $this->SLEEP_TIME_SEC . ' seconds.',
|
| 827 |
+
self::$DEBUG
|
| 828 |
+
);
|
| 829 |
+
$this->report['load_above_threshold_count'] += 1;
|
| 830 |
+
|
| 831 |
+
sleep($this->SLEEP_TIME_SEC);
|
| 832 |
+
|
| 833 |
+
$this->report['time_paused_sec'] += $this->SLEEP_TIME_SEC;
|
| 834 |
+
$this->_writeLog('Fruugo export resumed after waiting ' . $this->SLEEP_TIME_SEC . ' seconds.', self::$DEBUG);
|
| 835 |
+
}
|
| 836 |
+
}
|
| 837 |
+
|
| 838 |
+
|
| 839 |
}
|
app/code/community/Fruugo/Integration/Helper/ProductsFeedGeneratorProfiler.php
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* NOTICE OF LICENSE
|
| 4 |
+
*
|
| 5 |
+
* Magento extension which extracts a product feed from Magento, imports the feed into Fruugo and uses the Fruugo Order API to export all Fruugo orders into Magento.
|
| 6 |
+
*
|
| 7 |
+
* Copyright (C) 2015 Fruugo.com Ltd
|
| 8 |
+
*
|
| 9 |
+
* This program is free software: you can redistribute it and/or modify
|
| 10 |
+
* it under the terms of the GNU General Public License as published by
|
| 11 |
+
* the Free Software Foundation, either version 3 of the License, or
|
| 12 |
+
* (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This program is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 |
+
* See the GNU General Public License for more details.bitbu
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU General Public License along with this program.
|
| 20 |
+
* If not, see <http://www.gnu.org/licenses/>.
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/Logger.php';
|
| 24 |
+
|
| 25 |
+
/*
|
| 26 |
+
* This class is for profiling and testing the performance of the feed generation. Make sure you run
|
| 27 |
+
* this after you make changes to check for memory leaks and performance issues.
|
| 28 |
+
* It can be run by hitting this URL: http://127.0.0.1:8080/index.php/fruugo-integration/products/profiler
|
| 29 |
+
* NOTE: you must be in dev mode for this to work.
|
| 30 |
+
*/
|
| 31 |
+
class Fruugo_Integration_ProductsFeedGeneratorProfiler extends Fruugo_Integration_ProductsFeedGenerator
|
| 32 |
+
{
|
| 33 |
+
protected $currentTimer = array();
|
| 34 |
+
|
| 35 |
+
protected $openTimers = array();
|
| 36 |
+
|
| 37 |
+
protected $executionTree = array();
|
| 38 |
+
|
| 39 |
+
public function generateProdcutsFeed($cached = false) {
|
| 40 |
+
$devMode = Mage::getStoreConfig('integration_options/orders_options/dev_mode');
|
| 41 |
+
if($devMode != '1') {
|
| 42 |
+
throw new Exception('You must be in dev mode to use this feature');
|
| 43 |
+
}
|
| 44 |
+
Fruugo_Integration_Helper_Logger::$LOG_LEVEL = self::$DEBUG;
|
| 45 |
+
|
| 46 |
+
$this->_writeLog('--------------------------------------------', self::$DEBUG);
|
| 47 |
+
//$this->_testReport();
|
| 48 |
+
//return false;
|
| 49 |
+
$this->_writeLog('Profiling the product feed generator...', self::$DEBUG);
|
| 50 |
+
$this->_startTimer('generateProdcutsFeed');
|
| 51 |
+
$val = parent::generateProdcutsFeed($cached);
|
| 52 |
+
$this->_stopTimer('generateProdcutsFeed');
|
| 53 |
+
$this->_writeTimerLog();
|
| 54 |
+
return $val;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
protected function _fillProductXml($product, $storelangsMapping) {
|
| 58 |
+
$this->_startTimer('_fillProductXml');
|
| 59 |
+
$val = parent::_fillProductXml($product, $storelangsMapping);
|
| 60 |
+
$this->_stopTimer('_fillProductXml');
|
| 61 |
+
return $val;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
protected function _getAttributesText($language, $attributeName, $optionId, $storeId) {
|
| 65 |
+
$this->_startTimer('_getAttributesText');
|
| 66 |
+
$val = parent::_getAttributesText($language, $attributeName, $optionId, $storeId);
|
| 67 |
+
$this->_stopTimer('_getAttributesText');
|
| 68 |
+
return $val;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
protected function _convertCurrency($price, $baseCurrencyCode, $currencyCode) {
|
| 72 |
+
$this->_startTimer('_convertCurrency');
|
| 73 |
+
$val = parent::_convertCurrency($price, $baseCurrencyCode, $currencyCode);
|
| 74 |
+
$this->_stopTimer('_convertCurrency');
|
| 75 |
+
return $val;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
protected function _getProductImages($product, $parentProduct) {
|
| 79 |
+
$this->_startTimer('_getProductImages');
|
| 80 |
+
$val = parent::_getProductImages($product, $parentProduct);
|
| 81 |
+
$this->_stopTimer('_getProductImages');
|
| 82 |
+
return $val;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
protected function _getParentProduct($product)
|
| 86 |
+
{
|
| 87 |
+
$this->_startTimer('_getParentProduct');
|
| 88 |
+
$val = parent::_getParentProduct($product);
|
| 89 |
+
$this->_stopTimer('_getParentProduct');
|
| 90 |
+
return $val;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
protected function _startTimer($id, $message=null)
|
| 94 |
+
{
|
| 95 |
+
if (!array_key_exists($id, $this->currentTimer)) {
|
| 96 |
+
$this->currentTimer[$id] = array(
|
| 97 |
+
'start_time' => 0,
|
| 98 |
+
'stop_time' => 0,
|
| 99 |
+
'total' => 0,
|
| 100 |
+
'length' => 0,
|
| 101 |
+
'count' => 0,
|
| 102 |
+
'callers' => array(),
|
| 103 |
+
'start_memory' => 0,
|
| 104 |
+
'total_memory_leaked' => 0,
|
| 105 |
+
);
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
$this->currentTimer[$id]['start_memory'] = memory_get_usage(false);
|
| 109 |
+
|
| 110 |
+
if(count($this->openTimers) > 0) {
|
| 111 |
+
$caller = $this->openTimers[0];
|
| 112 |
+
if(!array_key_exists($caller, $this->currentTimer[$id]['callers'])) {
|
| 113 |
+
$this->currentTimer[$id]['callers'][$caller] = 1;
|
| 114 |
+
}
|
| 115 |
+
$this->currentTimer[$id]['callers'][$caller]++;
|
| 116 |
+
|
| 117 |
+
$this->_addToTree($id, $caller);
|
| 118 |
+
}
|
| 119 |
+
else {
|
| 120 |
+
$this->_addToTree($id, null);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
array_unshift($this->openTimers, $id);
|
| 124 |
+
|
| 125 |
+
$this->currentTimer[$id]['start_time'] = microtime(true);
|
| 126 |
+
if($message) {
|
| 127 |
+
$this->_writeLog($message, self::$DEBUG);
|
| 128 |
+
}
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
protected function _stopTimer($id, $message=null, $threshhold = 1000, $threshholdMessage = '')
|
| 132 |
+
{
|
| 133 |
+
if (!array_key_exists($id, $this->currentTimer)) {
|
| 134 |
+
return;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
$start_memory = $this->currentTimer[$id]['start_memory'];
|
| 138 |
+
$this->currentTimer[$id]['total_memory_leaked'] += memory_get_usage(false) - $start_memory;
|
| 139 |
+
|
| 140 |
+
$this->currentTimer[$id]['stop_time'] = microtime(true);
|
| 141 |
+
$stopTimer = ($this->currentTimer[$id]['stop_time'] - $this->currentTimer[$id]['start_time']);
|
| 142 |
+
$this->currentTimer[$id]['length'] = $stopTimer;
|
| 143 |
+
$this->currentTimer[$id]['total'] += $this->currentTimer[$id]['length'];
|
| 144 |
+
$this->currentTimer[$id]['count'] += 1;
|
| 145 |
+
|
| 146 |
+
if (round($stopTimer) >= $threshhold) {
|
| 147 |
+
$this->_writeLog('=================================================', self::$DEBUG);
|
| 148 |
+
$this->_writeLog($id . ' exceeded threshold of ' . $threshhold . ' with the time of ' . $stopTimer . ' threshholdMessage ' . $threshholdMessage, self::$DEBUG);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
if($message) {
|
| 152 |
+
$this->_writeLog($message . ' in ' . $stopTimer . ' seconds.' . ' Running total: ' . $this->currentTimer[$id]['total'], self::$DEBUG);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
array_shift($this->openTimers);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
protected function _writeTimerLog()
|
| 159 |
+
{
|
| 160 |
+
$this->_writeLog('Profiling Statistics', self::$DEBUG);
|
| 161 |
+
foreach ($this->currentTimer as $key => $value) {
|
| 162 |
+
$this->_writeLog("\n", self::$DEBUG);
|
| 163 |
+
$this->_writeLog('--------------------------------------------------', self::$DEBUG);
|
| 164 |
+
$this->_writeLog('Stats for ' . $key);
|
| 165 |
+
$this->_writeLog('Total executing time:' . round($value['total'], 7), self::$DEBUG);
|
| 166 |
+
$this->_writeLog('Average execution time: ' . round($value['total']/$value['count'], 7), self::$DEBUG);
|
| 167 |
+
$this->_writeLog('Times executed: ' . $value['count'], self::$DEBUG);
|
| 168 |
+
$this->_writeLog('Memory leaked: ' . (($value['total_memory_leaked'] / 1024) / 1024) . ' MB', self::$DEBUG);
|
| 169 |
+
$this->_writeLog('Called by: ', self::$DEBUG);
|
| 170 |
+
foreach ($value['callers'] as $caller => $callerCount) {
|
| 171 |
+
$this->_writeLog("\t" . $caller . ' x ' . $callerCount, self::$DEBUG);
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
$this->_writeLog("\n", self::$DEBUG);
|
| 176 |
+
$this->_writeLog('--------------------------------------------', self::$DEBUG);
|
| 177 |
+
$this->_generateTree();
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
protected function _generateTree() {
|
| 181 |
+
foreach($this->executionTree[0] as $parentkey => $val) {
|
| 182 |
+
$this->_writeLog($parentkey, self::$DEBUG);
|
| 183 |
+
$this->_writeTree(1, $parentkey, $parentkey, 0);
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// Note: the tree view is not a finished feature, and there may be display issues
|
| 188 |
+
protected function _writeTree($x, $parent, $caller, $indentLen) {
|
| 189 |
+
|
| 190 |
+
if($x >= count($this->executionTree)) {
|
| 191 |
+
return;
|
| 192 |
+
}
|
| 193 |
+
if(!array_key_exists($caller, $this->executionTree[$x])) {
|
| 194 |
+
return;
|
| 195 |
+
}
|
| 196 |
+
foreach($this->executionTree[$x][$caller]['children'] as $key => $val) {
|
| 197 |
+
$len = strlen($caller) + $indentLen;
|
| 198 |
+
$indent = str_pad("", $len, " ");
|
| 199 |
+
$line = str_pad("", strlen($caller)/3, "-");
|
| 200 |
+
$arrow = '|' . $line . '(x ' . $val['call_count'] . ')' . $line . '> ';
|
| 201 |
+
$this->_writeLog( $indent . $arrow . $key, self::$DEBUG);
|
| 202 |
+
$this->_writeTree($x + 1, $caller, $key, strlen($caller . $arrow));
|
| 203 |
+
}
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
protected function _addToTree($id, $caller=null) {
|
| 207 |
+
$depth = count($this->openTimers);
|
| 208 |
+
if(!isset($this->executionTree[$depth])) {
|
| 209 |
+
$this->executionTree[$depth] = array();
|
| 210 |
+
}
|
| 211 |
+
$data = array(
|
| 212 |
+
'name' => $id,
|
| 213 |
+
'depth' => $depth,
|
| 214 |
+
'children' => array(),
|
| 215 |
+
'parents' => array()
|
| 216 |
+
);
|
| 217 |
+
|
| 218 |
+
$childData = array(
|
| 219 |
+
'name' => $id,
|
| 220 |
+
'depth' => $depth,
|
| 221 |
+
'children' => array(),
|
| 222 |
+
'parents' => array(),
|
| 223 |
+
'call_count' => 0,
|
| 224 |
+
);
|
| 225 |
+
|
| 226 |
+
if($caller === null) {
|
| 227 |
+
$this->executionTree[$depth] = array();
|
| 228 |
+
$this->executionTree[$depth][$id] = $data;
|
| 229 |
+
return;
|
| 230 |
+
}
|
| 231 |
+
else{
|
| 232 |
+
if(!array_key_exists($caller, $this->executionTree[$depth])) {
|
| 233 |
+
$this->executionTree[$depth][$caller] = $data;
|
| 234 |
+
}
|
| 235 |
+
if(!array_key_exists($id, $this->executionTree[$depth][$caller]['children'])) {
|
| 236 |
+
$this->executionTree[$depth][$caller]['children'][$id] = $childData;
|
| 237 |
+
}
|
| 238 |
+
$this->executionTree[$depth][$caller]['children'][$id]['call_count'] += 1;
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
// Some fixtures data for testing the report generation
|
| 243 |
+
protected function _testReport() {
|
| 244 |
+
|
| 245 |
+
$this->executionTree = Array (
|
| 246 |
+
0 => Array
|
| 247 |
+
(
|
| 248 |
+
'generateProdcutsFeed' => Array
|
| 249 |
+
(
|
| 250 |
+
'name' => 'generateProdcutsFeed',
|
| 251 |
+
'depth' => 0,
|
| 252 |
+
'children' => Array(),
|
| 253 |
+
'parents' => Array(),
|
| 254 |
+
)
|
| 255 |
+
),
|
| 256 |
+
|
| 257 |
+
1 => Array
|
| 258 |
+
(
|
| 259 |
+
'generateProdcutsFeed' => Array
|
| 260 |
+
(
|
| 261 |
+
'name' => '_fillProductXml',
|
| 262 |
+
'depth' => 1,
|
| 263 |
+
'children' => Array
|
| 264 |
+
(
|
| 265 |
+
'_fillProductXml' => Array
|
| 266 |
+
(
|
| 267 |
+
'name' => '_fillProductXml',
|
| 268 |
+
'depth' => 1,
|
| 269 |
+
'children' => Array(),
|
| 270 |
+
'parents' => Array(),
|
| 271 |
+
|
| 272 |
+
'call_count' => 477,
|
| 273 |
+
)
|
| 274 |
+
|
| 275 |
+
),
|
| 276 |
+
|
| 277 |
+
'parents' => Array(),
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
),
|
| 281 |
+
|
| 282 |
+
2 => Array
|
| 283 |
+
(
|
| 284 |
+
'_fillProductXml' => Array
|
| 285 |
+
(
|
| 286 |
+
'name' => '_getParentProduct',
|
| 287 |
+
'depth' => 2,
|
| 288 |
+
'children' => Array
|
| 289 |
+
(
|
| 290 |
+
'_getParentProduct' => Array
|
| 291 |
+
(
|
| 292 |
+
'name' => '_getParentProduct',
|
| 293 |
+
'depth' => 2,
|
| 294 |
+
'children' => Array(),
|
| 295 |
+
'parents' => Array(),
|
| 296 |
+
'call_count' => 477,
|
| 297 |
+
),
|
| 298 |
+
|
| 299 |
+
'_getProductImages' => Array
|
| 300 |
+
(
|
| 301 |
+
'name' => '_getProductImages',
|
| 302 |
+
'depth' => 2,
|
| 303 |
+
'children' => Array(),
|
| 304 |
+
'parents' => Array(),
|
| 305 |
+
'call_count' => 477,
|
| 306 |
+
),
|
| 307 |
+
|
| 308 |
+
'_getAttributesText' => Array
|
| 309 |
+
(
|
| 310 |
+
'name' => '_getAttributesText',
|
| 311 |
+
'depth' => 2,
|
| 312 |
+
'children' => Array(),
|
| 313 |
+
'parents' => Array(),
|
| 314 |
+
'call_count' => 3762,
|
| 315 |
+
),
|
| 316 |
+
|
| 317 |
+
'_convertCurrency' => Array
|
| 318 |
+
(
|
| 319 |
+
'name' => '_convertCurrency',
|
| 320 |
+
'depth' => 2,
|
| 321 |
+
'children' => Array(),
|
| 322 |
+
'parents' => Array(),
|
| 323 |
+
'call_count' => 1455,
|
| 324 |
+
),
|
| 325 |
+
|
| 326 |
+
),
|
| 327 |
+
|
| 328 |
+
'parents' => Array
|
| 329 |
+
(
|
| 330 |
+
),
|
| 331 |
+
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
)
|
| 335 |
+
|
| 336 |
+
);
|
| 337 |
+
|
| 338 |
+
$this->_generateTree();
|
| 339 |
+
}
|
| 340 |
+
}
|
app/code/community/Fruugo/Integration/Model/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Model/Adminhtml/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Backend/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/ExportPageSize.php
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* NOTICE OF LICENSE
|
| 4 |
+
*
|
| 5 |
+
* Magento extension which extracts a product feed from Magento, imports the feed into Fruugo and uses the Fruugo Order API to export all Fruugo orders into Magento.
|
| 6 |
+
*
|
| 7 |
+
* Copyright (C) 2015 Fruugo.com Ltd
|
| 8 |
+
*
|
| 9 |
+
* This program is free software: you can redistribute it and/or modify
|
| 10 |
+
* it under the terms of the GNU General Public License as published by
|
| 11 |
+
* the Free Software Foundation, either version 3 of the License, or
|
| 12 |
+
* (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This program is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 |
+
* See the GNU General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU General Public License along with this program.
|
| 20 |
+
* If not, see <http://www.gnu.org/licenses/>.
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
/**
|
| 24 |
+
* Used in creating options for Hour config value selection
|
| 25 |
+
*
|
| 26 |
+
*/
|
| 27 |
+
class Fruugo_Integration_Model_Adminhtml_System_Config_Source_ExportPageSize
|
| 28 |
+
{
|
| 29 |
+
/**
|
| 30 |
+
* Options getter
|
| 31 |
+
*
|
| 32 |
+
* @return array
|
| 33 |
+
*/
|
| 34 |
+
public function toOptionArray()
|
| 35 |
+
{
|
| 36 |
+
$exportPageSize = array();
|
| 37 |
+
|
| 38 |
+
array_push($exportPageSize, array('value' => 20, 'label' => 20));
|
| 39 |
+
array_push($exportPageSize, array('value' => 30, 'label' => 30));
|
| 40 |
+
array_push($exportPageSize, array('value' => 50, 'label' => 50));
|
| 41 |
+
array_push($exportPageSize, array('value' => 70, 'label' => 70));
|
| 42 |
+
array_push($exportPageSize, array('value' => 100, 'label' => 100));
|
| 43 |
+
array_push($exportPageSize, array('value' => 150, 'label' => 150));
|
| 44 |
+
array_push($exportPageSize, array('value' => 200, 'label' => 200));
|
| 45 |
+
array_push($exportPageSize, array('value' => 300, 'label' => 300));
|
| 46 |
+
array_push($exportPageSize, array('value' => 500, 'label' => 500));
|
| 47 |
+
array_push($exportPageSize, array('value' => 1000, 'label' => 1000));
|
| 48 |
+
array_push($exportPageSize, array('value' => 3000, 'label' => 3000));
|
| 49 |
+
|
| 50 |
+
return $exportPageSize;
|
| 51 |
+
}
|
| 52 |
+
}
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/MaxErrors.php
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* NOTICE OF LICENSE
|
| 4 |
+
*
|
| 5 |
+
* Magento extension which extracts a product feed from Magento, imports the feed into Fruugo and uses the Fruugo Order API to export all Fruugo orders into Magento.
|
| 6 |
+
*
|
| 7 |
+
* Copyright (C) 2015 Fruugo.com Ltd
|
| 8 |
+
*
|
| 9 |
+
* This program is free software: you can redistribute it and/or modify
|
| 10 |
+
* it under the terms of the GNU General Public License as published by
|
| 11 |
+
* the Free Software Foundation, either version 3 of the License, or
|
| 12 |
+
* (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This program is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 |
+
* See the GNU General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU General Public License along with this program.
|
| 20 |
+
* If not, see <http://www.gnu.org/licenses/>.
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
/**
|
| 24 |
+
* Used in creating options for Hour config value selection
|
| 25 |
+
*
|
| 26 |
+
*/
|
| 27 |
+
class Fruugo_Integration_Model_Adminhtml_System_Config_Source_MaxErrors
|
| 28 |
+
{
|
| 29 |
+
/**
|
| 30 |
+
* Options getter
|
| 31 |
+
*
|
| 32 |
+
* @return array
|
| 33 |
+
*/
|
| 34 |
+
public function toOptionArray()
|
| 35 |
+
{
|
| 36 |
+
$maxErrors = array();
|
| 37 |
+
|
| 38 |
+
array_push($maxErrors, array('value' => -1, 'label' => -1));
|
| 39 |
+
array_push($maxErrors, array('value' => 5, 'label' => 5));
|
| 40 |
+
array_push($maxErrors, array('value' => 10, 'label' => 10));
|
| 41 |
+
array_push($maxErrors, array('value' => 15, 'label' => 15));
|
| 42 |
+
array_push($maxErrors, array('value' => 20, 'label' => 20));
|
| 43 |
+
array_push($maxErrors, array('value' => 25, 'label' => 25));
|
| 44 |
+
array_push($maxErrors, array('value' => 30, 'label' => 30));
|
| 45 |
+
array_push($maxErrors, array('value' => 40, 'label' => 40));
|
| 46 |
+
array_push($maxErrors, array('value' => 50, 'label' => 50));
|
| 47 |
+
array_push($maxErrors, array('value' => 70, 'label' => 70));
|
| 48 |
+
array_push($maxErrors, array('value' => 100, 'label' => 100));
|
| 49 |
+
|
| 50 |
+
return $maxErrors;
|
| 51 |
+
}
|
| 52 |
+
}
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/MaxResourcesLoad.php
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* NOTICE OF LICENSE
|
| 4 |
+
*
|
| 5 |
+
* Magento extension which extracts a product feed from Magento, imports the feed into Fruugo and uses the Fruugo Order API to export all Fruugo orders into Magento.
|
| 6 |
+
*
|
| 7 |
+
* Copyright (C) 2015 Fruugo.com Ltd
|
| 8 |
+
*
|
| 9 |
+
* This program is free software: you can redistribute it and/or modify
|
| 10 |
+
* it under the terms of the GNU General Public License as published by
|
| 11 |
+
* the Free Software Foundation, either version 3 of the License, or
|
| 12 |
+
* (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This program is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 |
+
* See the GNU General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU General Public License along with this program.
|
| 20 |
+
* If not, see <http://www.gnu.org/licenses/>.
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
/**
|
| 24 |
+
* Used in creating options for Hour config value selection
|
| 25 |
+
*
|
| 26 |
+
*/
|
| 27 |
+
class Fruugo_Integration_Model_Adminhtml_System_Config_Source_MaxResourcesLoad
|
| 28 |
+
{
|
| 29 |
+
/**
|
| 30 |
+
* Options getter
|
| 31 |
+
*
|
| 32 |
+
* @return array
|
| 33 |
+
*/
|
| 34 |
+
public function toOptionArray()
|
| 35 |
+
{
|
| 36 |
+
$maxResources = array();
|
| 37 |
+
|
| 38 |
+
array_push($maxResources, array('value' => 0.25, 'label' => '0.25'));
|
| 39 |
+
array_push($maxResources, array('value' => 0.5, 'label' => '0.5'));
|
| 40 |
+
array_push($maxResources, array('value' => 1.0, 'label' => '1.0'));
|
| 41 |
+
array_push($maxResources, array('value' => 1.5, 'label' => '1.5'));
|
| 42 |
+
array_push($maxResources, array('value' => 2.0, 'label' => '2.0'));
|
| 43 |
+
|
| 44 |
+
return $maxResources;
|
| 45 |
+
}
|
| 46 |
+
}
|
app/code/community/Fruugo/Integration/Model/Adminhtml/System/Config/Source/SleepTimeSec.php
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* NOTICE OF LICENSE
|
| 4 |
+
*
|
| 5 |
+
* Magento extension which extracts a product feed from Magento, imports the feed into Fruugo and uses the Fruugo Order API to export all Fruugo orders into Magento.
|
| 6 |
+
*
|
| 7 |
+
* Copyright (C) 2015 Fruugo.com Ltd
|
| 8 |
+
*
|
| 9 |
+
* This program is free software: you can redistribute it and/or modify
|
| 10 |
+
* it under the terms of the GNU General Public License as published by
|
| 11 |
+
* the Free Software Foundation, either version 3 of the License, or
|
| 12 |
+
* (at your option) any later version.
|
| 13 |
+
*
|
| 14 |
+
* This program is distributed in the hope that it will be useful,
|
| 15 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 17 |
+
* See the GNU General Public License for more details.
|
| 18 |
+
*
|
| 19 |
+
* You should have received a copy of the GNU General Public License along with this program.
|
| 20 |
+
* If not, see <http://www.gnu.org/licenses/>.
|
| 21 |
+
*/
|
| 22 |
+
|
| 23 |
+
/**
|
| 24 |
+
* Used in creating options for Hour config value selection
|
| 25 |
+
*
|
| 26 |
+
*/
|
| 27 |
+
class Fruugo_Integration_Model_Adminhtml_System_Config_Source_SleepTimeSec
|
| 28 |
+
{
|
| 29 |
+
/**
|
| 30 |
+
* Options getter
|
| 31 |
+
*
|
| 32 |
+
* @return array
|
| 33 |
+
*/
|
| 34 |
+
public function toOptionArray()
|
| 35 |
+
{
|
| 36 |
+
$sleepTimeSecs = array();
|
| 37 |
+
|
| 38 |
+
array_push($sleepTimeSecs, array('value' => 5, 'label' => 5));
|
| 39 |
+
array_push($sleepTimeSecs, array('value' => 10, 'label' => 10));
|
| 40 |
+
array_push($sleepTimeSecs, array('value' => 15, 'label' => 15));
|
| 41 |
+
array_push($sleepTimeSecs, array('value' => 20, 'label' => 20));
|
| 42 |
+
array_push($sleepTimeSecs, array('value' => 25, 'label' => 25));
|
| 43 |
+
array_push($sleepTimeSecs, array('value' => 30, 'label' => 30));
|
| 44 |
+
array_push($sleepTimeSecs, array('value' => 40, 'label' => 40));
|
| 45 |
+
array_push($sleepTimeSecs, array('value' => 50, 'label' => 50));
|
| 46 |
+
array_push($sleepTimeSecs, array('value' => 60, 'label' => 60));
|
| 47 |
+
array_push($sleepTimeSecs, array('value' => 90, 'label' => 90));
|
| 48 |
+
array_push($sleepTimeSecs, array('value' => 120, 'label' => 120));
|
| 49 |
+
|
| 50 |
+
return $sleepTimeSecs;
|
| 51 |
+
}
|
| 52 |
+
}
|
app/code/community/Fruugo/Integration/Model/CronJobObserver.php
CHANGED
|
@@ -30,14 +30,10 @@ class Fruugo_Integration_Model_CronJobObserver
|
|
| 30 |
{
|
| 31 |
// Export products xml
|
| 32 |
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGenerator();
|
| 33 |
-
$xml = $productsFeedGenerator->generateProdcutsFeed(false)->asXML();
|
| 34 |
|
| 35 |
try {
|
| 36 |
Fruugo_Integration_Helper_Logger::log("Writing exported products to file.");
|
| 37 |
-
$
|
| 38 |
-
$myfile = fopen($outputDir, "w");
|
| 39 |
-
fwrite($myfile, $xml);
|
| 40 |
-
fclose($myfile);
|
| 41 |
Fruugo_Integration_Helper_Logger::log("Writing products data feed finished.");
|
| 42 |
} catch (Exception $e) {
|
| 43 |
Mage::logException($e);
|
| 30 |
{
|
| 31 |
// Export products xml
|
| 32 |
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGenerator();
|
|
|
|
| 33 |
|
| 34 |
try {
|
| 35 |
Fruugo_Integration_Helper_Logger::log("Writing exported products to file.");
|
| 36 |
+
$productsFeedGenerator->generateProdcutsFeed(false);
|
|
|
|
|
|
|
|
|
|
| 37 |
Fruugo_Integration_Helper_Logger::log("Writing products data feed finished.");
|
| 38 |
} catch (Exception $e) {
|
| 39 |
Mage::logException($e);
|
app/code/community/Fruugo/Integration/controllers/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/controllers/.gitignore
CHANGED
|
@@ -1 +1,3 @@
|
|
| 1 |
-
*.xml
|
|
|
|
|
|
| 1 |
+
*.xml
|
| 2 |
+
report.json
|
| 3 |
+
products.lock
|
app/code/community/Fruugo/Integration/controllers/ProductsController.php
CHANGED
|
@@ -21,6 +21,7 @@
|
|
| 21 |
*/
|
| 22 |
|
| 23 |
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/ProductsFeedGenerator.php';
|
|
|
|
| 24 |
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/FruugoCountriesSeeder.php';
|
| 25 |
|
| 26 |
class Fruugo_Integration_ProductsController extends Mage_Core_Controller_Front_Action
|
|
@@ -28,50 +29,43 @@ class Fruugo_Integration_ProductsController extends Mage_Core_Controller_Front_A
|
|
| 28 |
public function indexAction()
|
| 29 |
{
|
| 30 |
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGenerator();
|
| 31 |
-
$
|
| 32 |
-
$this->
|
| 33 |
-
$this->streamXmlFile($productsXml->asXML());
|
| 34 |
}
|
| 35 |
|
| 36 |
-
public function
|
| 37 |
{
|
| 38 |
-
$productsFeedGenerator = new
|
| 39 |
-
$cachedFile = $productsFeedGenerator->generateProdcutsFeed(
|
| 40 |
-
|
| 41 |
-
$productsXmlStr = file_get_contents($cachedFile);
|
| 42 |
-
$this->streamXmlFile($productsXmlStr);
|
| 43 |
-
} else {
|
| 44 |
-
$this->indexAction();
|
| 45 |
-
}
|
| 46 |
}
|
| 47 |
|
| 48 |
-
|
| 49 |
{
|
| 50 |
-
$
|
| 51 |
-
$
|
| 52 |
-
|
| 53 |
-
fclose($productsFeedFile);
|
| 54 |
}
|
| 55 |
|
| 56 |
-
private function streamXmlFile($
|
| 57 |
{
|
| 58 |
-
if (
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
}
|
| 63 |
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
|
| 72 |
-
$
|
| 73 |
-
|
| 74 |
-
|
| 75 |
exit;
|
| 76 |
}
|
| 77 |
|
| 21 |
*/
|
| 22 |
|
| 23 |
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/ProductsFeedGenerator.php';
|
| 24 |
+
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/ProductsFeedGeneratorProfiler.php';
|
| 25 |
require_once Mage::getModuleDir('', 'Fruugo_Integration') . '/Helper/FruugoCountriesSeeder.php';
|
| 26 |
|
| 27 |
class Fruugo_Integration_ProductsController extends Mage_Core_Controller_Front_Action
|
| 29 |
public function indexAction()
|
| 30 |
{
|
| 31 |
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGenerator();
|
| 32 |
+
$cachedFile = $productsFeedGenerator->generateProdcutsFeed(false);
|
| 33 |
+
$this->streamXmlFile($cachedFile);
|
|
|
|
| 34 |
}
|
| 35 |
|
| 36 |
+
public function profilerAction()
|
| 37 |
{
|
| 38 |
+
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGeneratorProfiler();
|
| 39 |
+
$cachedFile = $productsFeedGenerator->generateProdcutsFeed(false);
|
| 40 |
+
$this->streamXmlFile($cachedFile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
}
|
| 42 |
|
| 43 |
+
public function dataFeedAction()
|
| 44 |
{
|
| 45 |
+
$productsFeedGenerator = new Fruugo_Integration_ProductsFeedGenerator();
|
| 46 |
+
$cachedFile = $productsFeedGenerator->generateProdcutsFeed(true);
|
| 47 |
+
$this->streamXmlFile($cachedFile);
|
|
|
|
| 48 |
}
|
| 49 |
|
| 50 |
+
private function streamXmlFile($cachedFile)
|
| 51 |
{
|
| 52 |
+
if (!is_file($cachedFile) || !is_readable($cachedFile)) {
|
| 53 |
+
// return 404
|
| 54 |
+
$this->norouteAction();
|
| 55 |
+
return;
|
| 56 |
}
|
| 57 |
|
| 58 |
+
$this->getResponse()
|
| 59 |
+
->setHttpResponseCode(200)
|
| 60 |
+
->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true)
|
| 61 |
+
->setHeader('Pragma', 'public', true)
|
| 62 |
+
->setHeader('Content-type', 'application/force-download')
|
| 63 |
+
->setHeader('Content-Length', filesize($cachedFile))
|
| 64 |
+
->setHeader('Content-Disposition', 'attachment' . '; filename=' . basename($cachedFile));
|
| 65 |
|
| 66 |
+
$this->getResponse()->clearBody();
|
| 67 |
+
$this->getResponse()->sendHeaders();
|
| 68 |
+
readfile($cachedFile);
|
| 69 |
exit;
|
| 70 |
}
|
| 71 |
|
app/code/community/Fruugo/Integration/data/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/catalog/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/catalog/product/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/order/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/design/adminhtml/default/default/template/integration/sales/order/view/.DS_Store
DELETED
|
Binary file
|
app/code/community/Fruugo/Integration/etc/config.xml
CHANGED
|
@@ -24,7 +24,7 @@
|
|
| 24 |
<config>
|
| 25 |
<modules>
|
| 26 |
<Fruugo_Integration>
|
| 27 |
-
<version>1.0.
|
| 28 |
</Fruugo_Integration>
|
| 29 |
</modules>
|
| 30 |
<global>
|
|
@@ -145,6 +145,11 @@
|
|
| 145 |
<products_options>
|
| 146 |
<export_frequency>12</export_frequency>
|
| 147 |
<descrption_type>long</descrption_type>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
</products_options>
|
| 149 |
<orders_options>
|
| 150 |
<fetch_frequency>4</fetch_frequency>
|
| 24 |
<config>
|
| 25 |
<modules>
|
| 26 |
<Fruugo_Integration>
|
| 27 |
+
<version>1.0.6</version> <!-- Version number of your module -->
|
| 28 |
</Fruugo_Integration>
|
| 29 |
</modules>
|
| 30 |
<global>
|
| 145 |
<products_options>
|
| 146 |
<export_frequency>12</export_frequency>
|
| 147 |
<descrption_type>long</descrption_type>
|
| 148 |
+
<export_page_size>100</export_page_size>
|
| 149 |
+
<max_resources_load>0.5</max_resources_load>
|
| 150 |
+
<sleep_time_sec>20</sleep_time_sec>
|
| 151 |
+
<max_errors>30</max_errors>
|
| 152 |
+
<track_last_id>1</track_last_id>
|
| 153 |
</products_options>
|
| 154 |
<orders_options>
|
| 155 |
<fetch_frequency>4</fetch_frequency>
|
app/code/community/Fruugo/Integration/etc/system.xml
CHANGED
|
@@ -119,6 +119,46 @@
|
|
| 119 |
<show_in_store>1</show_in_store>
|
| 120 |
<comment>Choose a default store for a language to export product description.</comment>
|
| 121 |
</language_store>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
</fields>
|
| 123 |
</products_options>
|
| 124 |
<orders_options translate="label" module="integration">
|
| 119 |
<show_in_store>1</show_in_store>
|
| 120 |
<comment>Choose a default store for a language to export product description.</comment>
|
| 121 |
</language_store>
|
| 122 |
+
<export_page_size translate="label">
|
| 123 |
+
<label>Export Page Size</label>
|
| 124 |
+
<frontend_type>select</frontend_type>
|
| 125 |
+
<source_model>Fruugo_Integration_Model_Adminhtml_System_Config_Source_ExportPageSize</source_model>
|
| 126 |
+
<sort_order>60</sort_order>
|
| 127 |
+
<show_in_default>1</show_in_default>
|
| 128 |
+
<show_in_website>0</show_in_website>
|
| 129 |
+
<show_in_store>0</show_in_store>
|
| 130 |
+
<comment>The number of products to process and write to xml per batch.</comment>
|
| 131 |
+
</export_page_size>
|
| 132 |
+
<max_resources_load translate="label">
|
| 133 |
+
<label>Max Resources</label>
|
| 134 |
+
<frontend_type>select</frontend_type>
|
| 135 |
+
<source_model>Fruugo_Integration_Model_Adminhtml_System_Config_Source_MaxResourcesLoad</source_model>
|
| 136 |
+
<sort_order>70</sort_order>
|
| 137 |
+
<show_in_default>1</show_in_default>
|
| 138 |
+
<show_in_website>0</show_in_website>
|
| 139 |
+
<show_in_store>0</show_in_store>
|
| 140 |
+
<comment>Maximum average system load (the number of processes in the system run queue, based on /proc/loadavg) allowed over the last minute, not available on Windows Servers because php sys_getloadavg() function is not implemented on Windows platforms.</comment>
|
| 141 |
+
</max_resources_load>
|
| 142 |
+
<sleep_time_sec translate="label">
|
| 143 |
+
<label>Sleep time seconds</label>
|
| 144 |
+
<frontend_type>select</frontend_type>
|
| 145 |
+
<source_model>Fruugo_Integration_Model_Adminhtml_System_Config_Source_SleepTimeSec</source_model>
|
| 146 |
+
<sort_order>80</sort_order>
|
| 147 |
+
<show_in_default>1</show_in_default>
|
| 148 |
+
<show_in_website>0</show_in_website>
|
| 149 |
+
<show_in_store>0</show_in_store>
|
| 150 |
+
<comment>Time to sleep for if over load limit during products export</comment>
|
| 151 |
+
</sleep_time_sec>
|
| 152 |
+
<max_errors translate="label">
|
| 153 |
+
<label>Max Errors Allowed</label>
|
| 154 |
+
<frontend_type>select</frontend_type>
|
| 155 |
+
<source_model>Fruugo_Integration_Model_Adminhtml_System_Config_Source_MaxErrors</source_model>
|
| 156 |
+
<sort_order>90</sort_order>
|
| 157 |
+
<show_in_default>1</show_in_default>
|
| 158 |
+
<show_in_website>0</show_in_website>
|
| 159 |
+
<show_in_store>0</show_in_store>
|
| 160 |
+
<comment>The number of errors after which the exporting products process will abort, set to -1 to disable</comment>
|
| 161 |
+
</max_errors>
|
| 162 |
</fields>
|
| 163 |
</products_options>
|
| 164 |
<orders_options translate="label" module="integration">
|
app/design/adminhtml/default/default/template/integration/.DS_Store
DELETED
|
Binary file
|
app/design/adminhtml/default/default/template/integration/catalog/.DS_Store
DELETED
|
Binary file
|
app/design/adminhtml/default/default/template/integration/catalog/product/.DS_Store
DELETED
|
Binary file
|
app/design/adminhtml/default/default/template/integration/sales/.DS_Store
DELETED
|
Binary file
|
app/design/adminhtml/default/default/template/integration/sales/order/.DS_Store
DELETED
|
Binary file
|
app/design/adminhtml/default/default/template/integration/sales/order/view/.DS_Store
DELETED
|
Binary file
|
package.xml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>Fruugo_Integration</name>
|
| 4 |
-
<version>1.0.
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license uri="http://www.gnu.org/licenses/">GNU</license>
|
| 7 |
<channel>community</channel>
|
|
@@ -16,19 +16,13 @@ This plugin mainly performs two tasks:
|
|
| 16 |
- Read from Fruugo Rrders API periodically on a specified frequency, and notifies Magento order events to Fruugo Orders API.</description>
|
| 17 |
<notes>This update includes:
|
| 18 |

|
| 19 |
-
-
|
| 20 |

|
| 21 |
-
-
|
| 22 |
-

|
| 23 |
-
- Added options to choose product description and short description merge order
|
| 24 |
-

|
| 25 |
-
- Add product discount price when it is set
|
| 26 |
-

|
| 27 |
-
- Custom Fruugo shipping method for Fruugo orders</notes>
|
| 28 |
<authors><author><name>inoutput.io</name><user>inoutput</user><email>support@inoutput.io</email></author><author><name>fruugo.com</name><user>Fruugo</user><email>support@fruugo.com</email></author></authors>
|
| 29 |
-
<date>2015-
|
| 30 |
-
<time>10:
|
| 31 |
-
<contents><target name="magecommunity"><dir name="Fruugo"><dir name="Integration"><dir name="Block"><dir name="Catalog"><dir name="Product"><file name="Tab.php" hash="412d5a38c07f78fd56e3509809038008"
|
| 32 |
<compatible/>
|
| 33 |
<dependencies><required><php><min>5.4.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.8</min><max/></package></required></dependencies>
|
| 34 |
</package>
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>Fruugo_Integration</name>
|
| 4 |
+
<version>1.0.6</version>
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license uri="http://www.gnu.org/licenses/">GNU</license>
|
| 7 |
<channel>community</channel>
|
| 16 |
- Read from Fruugo Rrders API periodically on a specified frequency, and notifies Magento order events to Fruugo Orders API.</description>
|
| 17 |
<notes>This update includes:
|
| 18 |

|
| 19 |
+
- Only add one price tag for each product
|
| 20 |

|
| 21 |
+
- Enabled currency conversion</notes>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
<authors><author><name>inoutput.io</name><user>inoutput</user><email>support@inoutput.io</email></author><author><name>fruugo.com</name><user>Fruugo</user><email>support@fruugo.com</email></author></authors>
|
| 23 |
+
<date>2015-12-21</date>
|
| 24 |
+
<time>10:13:13</time>
|
| 25 |
+
<contents><target name="magecommunity"><dir name="Fruugo"><dir name="Integration"><dir name="Block"><dir name="Catalog"><dir name="Product"><file name="Tab.php" hash="412d5a38c07f78fd56e3509809038008"/></dir></dir><file name="Languagestoremapping.php" hash="7852846c2428b4fc15434a1e78a37de7"/><file name="Refreshcountriesbutton.php" hash="5a7e3af708dd470725981ec187b2c07d"/><dir name="Sales"><dir name="Order"><dir name="View"><file name="Tabs.php" hash="d98faeeede3c06d5f28f8f9731438314"/></dir></dir></dir></dir><dir name="Helper"><file name="ConfigLoader.php" hash="f930d687b44fe0a3a9e70383e0500a7c"/><file name="Data.php" hash="866fe8e1ea50749218d6efcab8454f28"/><file name="Defines.php" hash="a97616fe105332db06292c68eabecdf1"/><file name="FruugoCountriesSeeder.php" hash="68949469a1b1ce6a605fccd132e9e3c0"/><file name="Logger.php" hash="a83fdd017e59261e059a8d18d223dd59"/><file name="OrdersFeedProcessor.php" hash="c0969f7217b6e4eb1c875e00afc21227"/><file name="ProductsFeedGenerator.php" hash="a1238387664193d9afb988a4c2114242"/><file name="ProductsFeedGeneratorProfiler.php" hash="33cbf6db6cecda919011d23432d9bdb9"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><file name="OrderCron.php" hash="8187697b999171b8940be7e5306a3bc7"/><file name="ProductCron.php" hash="a8bdd62ad14cdb85d9ef0ae2b85cecad"/></dir><dir name="Source"><file name="ExportPageSize.php" hash="a322cb1b507d33444078ba6494b461fd"/><file name="Hour.php" hash="fab1337425532af32cf8642b8b244930"/><file name="MaxErrors.php" hash="03213889323c47349b5aaa7d7b6752f5"/><file name="MaxResourcesLoad.php" hash="8b941802b5a45f2744abe83b117dceba"/><file name="ProductDescriptionType.php" hash="4a2810baeabe1a74b1b06b92cc2e4481"/><file name="SleepTimeSec.php" hash="9c9790275cf3ec3347746bee53cb50ae"/></dir></dir></dir></dir><file name="Countries.php" hash="a23378525c616fd87c5589933aec48c6"/><file name="CronJobObserver.php" hash="303c9619a9abb2489365b08c94507b31"/><file name="Observer.php" hash="1e16ebea05d59b472cc9f279965cd17e"/><file name="Payment.php" hash="4e7d2d72e7662ea71c178d85c9b9bd6c"/><dir name="Resource"><dir name="Countries"><file name="Collection.php" hash="618a95f1535d4c63724a2f7eaebf6c2b"/></dir><file name="Countries.php" hash="dc3da7aec3c3472a4ccd73e2b2f255f0"/><dir name="Shipment"><file name="Collection.php" hash="66d038f890e36403f9ffb2e283e88daf"/></dir><file name="Shipment.php" hash="d8c13444ba5089cf606241f2c7c9a87d"/></dir><file name="Shipment.php" hash="23b1c0b4bc4e29cb137c9b3819723a63"/></dir><dir name="controllers"><file name="OrdersController.php" hash="a2d9d2f4c916c376f146cfccecb4110d"/><file name="PackinglistController.php" hash="d76ac40e81f51635a073fb20492883f8"/><file name="ProductsController.php" hash="111475a85b64e4c14753f333568842ec"/><file name=".gitignore" hash="a1d994a3c45d2cb16e44c5a311159532"/></dir><dir name="data"><dir name="fruugo_attributes_setup"><file name="data-install-0.1.1.php" hash="73a6210fdb6c5a2edfa0222a6a239e9a"/></dir></dir><dir name="design"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="integration.xml" hash="3f173b27f9f483c00b33b713c0bad737"/></dir><dir name="template"><dir name="integration"><dir name="catalog"><dir name="product"><file name="fruugo-allowed-countries.phtml" hash="066098b4583e6bd3882c01645bd9ed1d"/></dir></dir><dir name="sales"><dir name="order"><dir name="view"><dir name="tab"><file name="packinglist.phtml" hash="9ec64369d5c23043976b08573f3435dd"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></dir><dir name="etc"><file name="config.xml" hash="57014c6e82e14791ec5ddf82b15e8a83"/><file name="system.xml" hash="fbc772bf4764682c912c97be3959ce12"/></dir><dir name="sql"><dir name="fruugo_attributes_setup"><file name="install-0.1.1.php" hash="326629d7305e3c3b20aaf8d97de1f17b"/></dir></dir><file name=".gitignore" hash="f0cb20b35e2469e9e9617f658ed452a5"/></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="integration.xml" hash="3f173b27f9f483c00b33b713c0bad737"/></dir><dir name="template"><dir name="integration"><dir name="catalog"><dir name="product"><file name="fruugo-allowed-countries.phtml" hash="066098b4583e6bd3882c01645bd9ed1d"/></dir></dir><dir name="sales"><dir name="order"><dir name="view"><dir name="tab"><file name="packinglist.phtml" hash="9ec64369d5c23043976b08573f3435dd"/></dir></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Fruugo_Integration.xml" hash="b01dcb5088d487517bd87af216d6d7c8"/></dir></target></contents>
|
| 26 |
<compatible/>
|
| 27 |
<dependencies><required><php><min>5.4.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.8</min><max/></package></required></dependencies>
|
| 28 |
</package>
|
