Version Notes
- First public release of the Highstreet Magento extension
Download this release
Release Info
Developer | Christian Apers |
Extension | Highstreet |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/community/Technooze/Timage/Block/Data.php +10 -0
- app/code/community/Technooze/Timage/Helper/Data.php +134 -0
- app/code/community/Technooze/Timage/etc/config.xml +46 -0
- app/code/local/Highstreet/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/Helper/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/Helper/Data.php +138 -0
- app/code/local/Highstreet/Hsapi/Model/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/Model/Attributes.php +155 -0
- app/code/local/Highstreet/Hsapi/Model/Categories.php +169 -0
- app/code/local/Highstreet/Hsapi/Model/Checkout.php +440 -0
- app/code/local/Highstreet/Hsapi/Model/Images.php +49 -0
- app/code/local/Highstreet/Hsapi/Model/Observer.php +22 -0
- app/code/local/Highstreet/Hsapi/Model/Products.php +880 -0
- app/code/local/Highstreet/Hsapi/Model/SearchSuggestions.php +58 -0
- app/code/local/Highstreet/Hsapi/controllers/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/controllers/IndexController.php +414 -0
- app/code/local/Highstreet/Hsapi/etc/.DS_Store +0 -0
- app/code/local/Highstreet/Hsapi/etc/Configuration.json +3 -0
- app/code/local/Highstreet/Hsapi/etc/config.xml +79 -0
- app/etc/modules/Highstreet_Api.xml +10 -0
- app/etc/modules/Technooze_Timage.xml +17 -0
- app/locale/en_US/Highstreet_Hsapi.csv +93 -0
- app/locale/nl_NL/Highstreet_Hsapi.csv +94 -0
- package.xml +19 -0
app/code/community/Technooze/Timage/Block/Data.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category Technooze/Modules/magento-how-tos
|
4 |
+
* @package Technooze_Timage
|
5 |
+
* @author Damodar Bashyal
|
6 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
7 |
+
*/
|
8 |
+
class Technooze_Timage_Block_Data extends Mage_Core_Block_Template
|
9 |
+
{
|
10 |
+
}
|
app/code/community/Technooze/Timage/Helper/Data.php
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category Technooze/Modules/magento-how-tos
|
4 |
+
* @package Technooze_Timage
|
5 |
+
* @author Damodar Bashyal
|
6 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
7 |
+
*/
|
8 |
+
class Technooze_Timage_Helper_Data extends Mage_Core_Helper_Abstract
|
9 |
+
{
|
10 |
+
var
|
11 |
+
$width = null,
|
12 |
+
$height = null,
|
13 |
+
$rawImg = '',
|
14 |
+
$img = false,
|
15 |
+
$cacheDir = '',
|
16 |
+
$cachedImage = '',
|
17 |
+
$cachedImageUrl = '',
|
18 |
+
$ext = '',
|
19 |
+
$bgColor = array(255, 255, 255),
|
20 |
+
$imageObj = '',
|
21 |
+
$baseUrl = '',
|
22 |
+
$placeHolder = false;
|
23 |
+
|
24 |
+
public function init($img=false)
|
25 |
+
{
|
26 |
+
if($img)
|
27 |
+
{
|
28 |
+
$this->rawImg = $img;
|
29 |
+
}
|
30 |
+
|
31 |
+
if(empty($this->placeHolder))
|
32 |
+
{
|
33 |
+
$this->placeHolder = Mage::getDesign()->getSkinUrl('images/catalog/product/placeholder/image.jpg');
|
34 |
+
}
|
35 |
+
$this->imagePath($this->rawImg);
|
36 |
+
|
37 |
+
$this->imageObj = new Varien_Image($this->img, Varien_Image_Adapter::ADAPTER_GD2);
|
38 |
+
|
39 |
+
$path_parts = pathinfo($this->img);
|
40 |
+
|
41 |
+
$this->ext = $path_parts['extension'];
|
42 |
+
|
43 |
+
$this->cacheDir();
|
44 |
+
|
45 |
+
return $this;
|
46 |
+
}
|
47 |
+
|
48 |
+
public function resize($width=false, $height=false)
|
49 |
+
{
|
50 |
+
if($width)
|
51 |
+
{
|
52 |
+
$this->width = $width;
|
53 |
+
}
|
54 |
+
|
55 |
+
if($height)
|
56 |
+
{
|
57 |
+
$this->height = $height;
|
58 |
+
}
|
59 |
+
|
60 |
+
$this->cacheIt();
|
61 |
+
|
62 |
+
return $this->cachedImageUrl();
|
63 |
+
}
|
64 |
+
|
65 |
+
public function cachedImageUrl()
|
66 |
+
{
|
67 |
+
$img = str_replace(BP, '', $this->cachedImage);
|
68 |
+
$img = trim(str_replace('\\', '/', $img), '/');
|
69 |
+
|
70 |
+
return $this->baseUrl . $img;
|
71 |
+
}
|
72 |
+
|
73 |
+
public function cacheIt()
|
74 |
+
{
|
75 |
+
$this->cachedImage = $this->cacheDir . md5($this->img . $this->width . $this->height) . '.' .$this->ext;
|
76 |
+
|
77 |
+
if(file_exists($this->cachedImage))
|
78 |
+
{
|
79 |
+
return $this->cachedImage;
|
80 |
+
}
|
81 |
+
|
82 |
+
$this->resizer();
|
83 |
+
}
|
84 |
+
|
85 |
+
public function resizer()
|
86 |
+
{
|
87 |
+
try{
|
88 |
+
$this->imageObj->constrainOnly(true);
|
89 |
+
$this->imageObj->keepAspectRatio(true);
|
90 |
+
$this->imageObj->keepFrame(false);
|
91 |
+
$this->imageObj->keepTransparency(true);
|
92 |
+
$this->imageObj->backgroundColor($this->bgColor);
|
93 |
+
$this->imageObj->resize($this->width, $this->height);
|
94 |
+
$this->imageObj->save($this->cachedImage);
|
95 |
+
} catch(Exception $e){
|
96 |
+
return $e->getMessage();
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
public function imagePath($img='')
|
101 |
+
{
|
102 |
+
$this->baseUrl = str_replace('index.php/', '', Mage::getBaseUrl());
|
103 |
+
$img = str_replace($this->baseUrl, '', $img);
|
104 |
+
$img = trim(str_replace('/', DS, $img), DS);
|
105 |
+
|
106 |
+
$this->img = BP . DS . $img;
|
107 |
+
|
108 |
+
if((!file_exists($this->img) || !is_file($this->img)) && !empty($this->placeHolder))
|
109 |
+
{
|
110 |
+
$this->imagePath($this->placeHolder);
|
111 |
+
$this->placeHolder = false;
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
public function cacheDir()
|
116 |
+
{
|
117 |
+
$cache = BP . DS . 'media' . DS . 'catalog' . DS . 'cache' . DS;
|
118 |
+
|
119 |
+
if(!is_dir($cache))
|
120 |
+
{
|
121 |
+
mkdir($cache);
|
122 |
+
}
|
123 |
+
$this->cacheDir = $cache;
|
124 |
+
}
|
125 |
+
|
126 |
+
public function getOriginalSize() {
|
127 |
+
|
128 |
+
$width = $this->imageObj->getOriginalWidth();
|
129 |
+
$height = $this->imageObj->getOriginalHeight();
|
130 |
+
|
131 |
+
return array('width' => $width, 'height' => $height);
|
132 |
+
|
133 |
+
}
|
134 |
+
}
|
app/code/community/Technooze/Timage/etc/config.xml
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category Technooze/Modules/magento-how-tos
|
5 |
+
* @package Technooze_Timage
|
6 |
+
* @author Damodar Bashyal
|
7 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<modules>
|
12 |
+
<Technooze_Timage>
|
13 |
+
<version>0.1.0</version>
|
14 |
+
</Technooze_Timage>
|
15 |
+
</modules>
|
16 |
+
<frontend>
|
17 |
+
<routers>
|
18 |
+
<timage>
|
19 |
+
<use>standard</use>
|
20 |
+
<args>
|
21 |
+
<module>Technooze_Timage</module>
|
22 |
+
<frontName>timage</frontName>
|
23 |
+
</args>
|
24 |
+
</timage>
|
25 |
+
</routers>
|
26 |
+
<layout>
|
27 |
+
<updates>
|
28 |
+
<timage>
|
29 |
+
<file>timage.xml</file>
|
30 |
+
</timage>
|
31 |
+
</updates>
|
32 |
+
</layout>
|
33 |
+
</frontend>
|
34 |
+
<global>
|
35 |
+
<helpers>
|
36 |
+
<timage>
|
37 |
+
<class>Technooze_Timage_Helper</class>
|
38 |
+
</timage>
|
39 |
+
</helpers>
|
40 |
+
<blocks>
|
41 |
+
<timage>
|
42 |
+
<class>Technooze_Timage_Block</class>
|
43 |
+
</timage>
|
44 |
+
</blocks>
|
45 |
+
</global>
|
46 |
+
</config>
|
app/code/local/Highstreet/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/Helper/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/Helper/Data.php
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
7 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Highstreet_Hsapi_Helper_Data extends Mage_Core_Helper_Abstract
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
* Return single request param. This returns the key as we have rest url
|
14 |
+
* @param $params
|
15 |
+
*
|
16 |
+
* @return bool|int|string
|
17 |
+
*/
|
18 |
+
public function extractRequestParam($params)
|
19 |
+
{
|
20 |
+
if($this->requestHasParams($params)){
|
21 |
+
foreach($params as $key => $value){
|
22 |
+
return $key;
|
23 |
+
}
|
24 |
+
}
|
25 |
+
return false;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Check if request has a param && if param is an array bigger then 0
|
30 |
+
* @param $params
|
31 |
+
* @return bool
|
32 |
+
*/
|
33 |
+
public function requestHasParams($params)
|
34 |
+
{
|
35 |
+
if(is_array($params) && count($params) > 0)
|
36 |
+
{
|
37 |
+
return true;
|
38 |
+
}
|
39 |
+
return false;
|
40 |
+
}
|
41 |
+
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Returns the header for an image content type. Via the given source string param given it determines what the content type should be.
|
45 |
+
*
|
46 |
+
* @param string src url of the image
|
47 |
+
* @return string of the image type
|
48 |
+
*/
|
49 |
+
public function imageHeaderStringForImage($src = false) {
|
50 |
+
if (!$src) {
|
51 |
+
return 'image';
|
52 |
+
}
|
53 |
+
|
54 |
+
$urlComponents = explode(".", $src);
|
55 |
+
$extension = strtolower($urlComponents[count($urlComponents)-1]);
|
56 |
+
|
57 |
+
if ($extension == 'jpeg' || $extension == 'jpg') {
|
58 |
+
return 'image/jpeg';
|
59 |
+
} else if ($extension == 'png') {
|
60 |
+
return 'image/png';
|
61 |
+
} else if ($extension == 'gif') {
|
62 |
+
return 'image/gif';
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Saves a search query to the search suggestion table
|
68 |
+
*
|
69 |
+
* @param string searchString, the search query string
|
70 |
+
* @param integer categoryId, the categoryId. When not filled in it will use the root category id
|
71 |
+
*/
|
72 |
+
public function saveSearchSuggestion($searchString = false, $categoryId) {
|
73 |
+
if (!$searchString) {
|
74 |
+
return;
|
75 |
+
}
|
76 |
+
|
77 |
+
$catalogSearchSaveModel = Mage::getModel('catalogsearch/query');
|
78 |
+
try {
|
79 |
+
$catalogSearchSaveModel->setStoreId(Mage::app()->getStore()->getId());
|
80 |
+
$catalogSearchSaveModel->loadByQueryText($searchString);
|
81 |
+
|
82 |
+
$searchTermId = $catalogSearchSaveModel->getId();
|
83 |
+
if ($searchTermId) { // Search term already existed, update it
|
84 |
+
$popularity = $catalogSearchSaveModel->getData("popularity");
|
85 |
+
$catalogSearchSaveModel->setData("popularity", $popularity+1);
|
86 |
+
|
87 |
+
$catalogSearchSaveModel->save();
|
88 |
+
} else { // Search term did not yet exists, make a new one
|
89 |
+
|
90 |
+
// Check if there is an category ID set
|
91 |
+
if (empty($categoryId) || !is_numeric($categoryId)) {
|
92 |
+
$store = Mage::getModel('core/store')->load(Mage_Core_Model_App::DISTRO_STORE_ID);
|
93 |
+
$categoryId = $store->getRootCategoryId();
|
94 |
+
}
|
95 |
+
|
96 |
+
$data = array("query_text" => $searchString, "popularity" => 1);
|
97 |
+
|
98 |
+
if ($this->searchSuggestionTableHasHSAPIColumn()) {
|
99 |
+
$data["hsapi_category_id"] = $categoryId;
|
100 |
+
}
|
101 |
+
|
102 |
+
$catalogSearchSaveModel->addData($data);
|
103 |
+
$catalogSearchSaveModel->setIsProcessed(1);
|
104 |
+
$catalogSearchSaveModel->save();
|
105 |
+
}
|
106 |
+
|
107 |
+
} catch (Mage_Core_Exception $e) {
|
108 |
+
$this->_getSession()->addError($e->getMessage());
|
109 |
+
} catch (Exception $e) {
|
110 |
+
$this->_getSession()->addException($e,
|
111 |
+
Mage::helper('catalog')->__('An error occurred while saving the search query.')
|
112 |
+
);
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Returns a BOOL wether the "catalogsearch/query" table has the HSAPI category column
|
118 |
+
*
|
119 |
+
* @return bool
|
120 |
+
*/
|
121 |
+
public function searchSuggestionTableHasHSAPIColumn() {
|
122 |
+
try {
|
123 |
+
$catalogSearchReadModel = Mage::getModel('catalogsearch/query')->getCollection();
|
124 |
+
$catalogSearchReadModel->addFieldToSelect('hsapi_category_id');
|
125 |
+
$catalogSearchReadModel->getSelect()->limit(1);
|
126 |
+
$catalogSearchReadModel->getData();
|
127 |
+
return TRUE;
|
128 |
+
} catch (Exception $e) {
|
129 |
+
return FALSE;
|
130 |
+
}
|
131 |
+
|
132 |
+
return FALSE;
|
133 |
+
}
|
134 |
+
|
135 |
+
}
|
136 |
+
|
137 |
+
|
138 |
+
|
app/code/local/Highstreet/Hsapi/Model/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/Model/Attributes.php
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
7 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Highstreet_Hsapi_Model_Attributes extends Mage_Core_Model_Abstract
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
* Product entity type id
|
14 |
+
* We need to have it as a variable!
|
15 |
+
* As of mage_1.8.0 we have a different typeId
|
16 |
+
*
|
17 |
+
* @var int
|
18 |
+
*/
|
19 |
+
protected $_entityTypeId;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Class constructor
|
23 |
+
* We are setting the entityTypeId on construct. In case we want
|
24 |
+
* attributes for other entityTypes in the future we have it prepared.
|
25 |
+
*/
|
26 |
+
public function __construct()
|
27 |
+
{
|
28 |
+
$this->_entityTypeId = Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId();
|
29 |
+
}
|
30 |
+
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @return Mage_Catalog_Model_Product
|
34 |
+
*/
|
35 |
+
public function getAttributes()
|
36 |
+
{
|
37 |
+
$response = $this->_extractResponse($this->_getAttributes());
|
38 |
+
return $response;
|
39 |
+
}
|
40 |
+
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Return single attribute if found. else false
|
44 |
+
* @param null $code
|
45 |
+
* @return bool
|
46 |
+
*/
|
47 |
+
public function getAttribute($code=null)
|
48 |
+
{
|
49 |
+
if(null != $code){
|
50 |
+
$response = $this->_extractResponse($this->_getAttribute($code));
|
51 |
+
return $response['attributes'][0];
|
52 |
+
}
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Load attribute collection object
|
59 |
+
* @return Mage_Eav_Model_Resource_Entity_Attribute_Collection
|
60 |
+
*/
|
61 |
+
private function _getAttributes()
|
62 |
+
{
|
63 |
+
$attributes = Mage::getResourceModel('eav/entity_attribute_collection')
|
64 |
+
->setEntityTypeFilter($this->_entityTypeId)
|
65 |
+
->addStoreLabel(Mage::app()->getStore()->getId())
|
66 |
+
->addSetInfo(false) //no set data needed
|
67 |
+
->getData();
|
68 |
+
|
69 |
+
return $attributes;
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
/**
|
74 |
+
* load single attribute by code
|
75 |
+
* @param null $code
|
76 |
+
* @return Mage_Eav_Model_Entity_Attribute
|
77 |
+
*/
|
78 |
+
private function _getAttribute($code=null)
|
79 |
+
{
|
80 |
+
$attributes = Mage::getResourceModel('eav/entity_attribute_collection')
|
81 |
+
->setEntityTypeFilter($this->_entityTypeId)
|
82 |
+
->addStoreLabel(Mage::app()->getStore()->getId())
|
83 |
+
->setCodeFilter($code)
|
84 |
+
->addSetInfo(false) //no set data needed
|
85 |
+
->getData();
|
86 |
+
return $attributes;
|
87 |
+
}
|
88 |
+
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Extract the correct formatted array from the attribute data
|
92 |
+
* @param $attributes
|
93 |
+
* @return array|bool
|
94 |
+
*/
|
95 |
+
private function _extractResponse($attributes)
|
96 |
+
{
|
97 |
+
|
98 |
+
if(!is_array($attributes)){
|
99 |
+
//throw Mage::exception('', '');
|
100 |
+
return false;
|
101 |
+
}
|
102 |
+
|
103 |
+
$response = array('attributes' => array());
|
104 |
+
foreach($attributes as $attribute)
|
105 |
+
{
|
106 |
+
$result = array();
|
107 |
+
$result['id'] = (int)$attribute['attribute_id'];
|
108 |
+
$result['code'] = $attribute['attribute_code'];
|
109 |
+
$result['title'] = strval($attribute['store_label']);
|
110 |
+
$result['type'] = $attribute['frontend_input'];
|
111 |
+
|
112 |
+
//Get the optionValues for this attribute
|
113 |
+
$result['options'] = $this->_getAttributeOptionValues(
|
114 |
+
$attribute['attribute_id'],
|
115 |
+
$attribute['default_value']
|
116 |
+
);
|
117 |
+
|
118 |
+
//we need to push to respond as a json array without index
|
119 |
+
array_push($response['attributes'], $result);
|
120 |
+
}
|
121 |
+
return $response;
|
122 |
+
}
|
123 |
+
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Get the option values for the attribute
|
127 |
+
* @param null $attributeId
|
128 |
+
* @param int $defaultValue
|
129 |
+
*
|
130 |
+
* @return array
|
131 |
+
*/
|
132 |
+
private function _getAttributeOptionValues($attributeId=null, $defaultValue = null)
|
133 |
+
{
|
134 |
+
$optionValues = array();
|
135 |
+
//We need to load the attribute to be able to use it get the options
|
136 |
+
$attribute = Mage::getModel('eav/entity_attribute')->load($attributeId);
|
137 |
+
$options = Mage::getModel('eav/entity_attribute_source_table')
|
138 |
+
->setAttribute($attribute)
|
139 |
+
->getAllOptions(false, false); //getAllOptions($withEmpty = true, $defaultValues = false)
|
140 |
+
|
141 |
+
foreach($options as $key => $option)
|
142 |
+
{
|
143 |
+
$opt = array();
|
144 |
+
$opt['title'] = strval($option['label']);
|
145 |
+
$opt['value'] = (int)$option['value'];
|
146 |
+
$opt['sort_hint'] = (int)$key;
|
147 |
+
$opt['is_default'] = (int)($option['value'] == $defaultValue) ? 1 : 0;
|
148 |
+
|
149 |
+
$optionValues[] = (object)$opt;
|
150 |
+
}
|
151 |
+
return $optionValues;
|
152 |
+
}
|
153 |
+
|
154 |
+
|
155 |
+
}
|
app/code/local/Highstreet/Hsapi/Model/Categories.php
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
7 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Highstreet_Hsapi_Model_Categories extends Mage_Core_Model_Abstract
|
11 |
+
{
|
12 |
+
const CATEGORY_MEDIA_PATH = "/media/catalog/category/";
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Get category and children from id
|
16 |
+
* @param $categoryId
|
17 |
+
*
|
18 |
+
* @return bool
|
19 |
+
*/
|
20 |
+
public function getCategories($categoryId)
|
21 |
+
{
|
22 |
+
$categoryObject = Mage::getModel('catalog/category')->load($categoryId);
|
23 |
+
|
24 |
+
$productCollection = $categoryObject->getProductCollection()
|
25 |
+
->addAttributeToFilter('visibility', array('in' => array(
|
26 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG,
|
27 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH))
|
28 |
+
);
|
29 |
+
|
30 |
+
$name = $categoryObject->getData('name');
|
31 |
+
if (!empty($name)) {
|
32 |
+
$category = array();
|
33 |
+
$category['id'] = $categoryId;
|
34 |
+
$category['title'] = $categoryObject->getData('name');
|
35 |
+
|
36 |
+
if ($categoryObject->getImage()) {
|
37 |
+
$imageUrl = self::CATEGORY_MEDIA_PATH . $categoryObject->getImage();
|
38 |
+
} else {
|
39 |
+
$imageUrl = '';
|
40 |
+
}
|
41 |
+
$category['image'] = $imageUrl;
|
42 |
+
|
43 |
+
$category['product_count'] = $productCollection->count();
|
44 |
+
|
45 |
+
// category children
|
46 |
+
$children = $this->getChildrenCollectionForCategoryId($categoryId);
|
47 |
+
|
48 |
+
$config = Mage::helper('highstreet_hsapi/config');
|
49 |
+
$filtersCategories = $config->filtersCategories();
|
50 |
+
|
51 |
+
if ($children->count() > 0) {
|
52 |
+
$category['children'] = array();
|
53 |
+
|
54 |
+
foreach ($children as $child) {
|
55 |
+
if ($filtersCategories) {
|
56 |
+
if ($child->getData('level') == 2 && // Top Category Level
|
57 |
+
$child->getData('include_in_menu') == 0) {
|
58 |
+
continue;
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
if ($child->getImage()) {
|
63 |
+
$childImageUrl = self::CATEGORY_MEDIA_PATH . $child->getImage();
|
64 |
+
} else {
|
65 |
+
$childImageUrl = '';
|
66 |
+
}
|
67 |
+
array_push($category['children'], array(
|
68 |
+
'id' => $child->getData('entity_id'),
|
69 |
+
'title' => $child->getData('name'),
|
70 |
+
'image' => $childImageUrl,
|
71 |
+
));
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
return $category;
|
76 |
+
}
|
77 |
+
else {
|
78 |
+
return false;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Gets the entire category tree. Can be filtered for a specific category with param categoryId
|
84 |
+
*
|
85 |
+
* @param integer categoryId, a categoryId which will filter the tree
|
86 |
+
* @return array Array of categories
|
87 |
+
*/
|
88 |
+
public function getCategoryTree($categoryId = null) {
|
89 |
+
if ($categoryId == null) {
|
90 |
+
$categoryId = Mage::app()->getStore()->getRootCategoryId();
|
91 |
+
}
|
92 |
+
|
93 |
+
$categoryObject = Mage::getModel('catalog/category')->load($categoryId);
|
94 |
+
$children = $this->getChildrenCollectionForCategoryId($categoryId);
|
95 |
+
|
96 |
+
$productCollection = $categoryObject->getProductCollection()
|
97 |
+
->addAttributeToFilter('visibility', array('in' => array(
|
98 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG,
|
99 |
+
Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH))
|
100 |
+
);
|
101 |
+
|
102 |
+
$name = $categoryObject->getData('name');
|
103 |
+
if (!empty($name)) {
|
104 |
+
$category = array();
|
105 |
+
$category['id'] = $categoryId;
|
106 |
+
$category['title'] = $name;
|
107 |
+
$category['position'] = $categoryObject->getData('position');
|
108 |
+
|
109 |
+
if ($categoryObject->getImage()) {
|
110 |
+
$imageUrl = self::CATEGORY_MEDIA_PATH . $categoryObject->getImage();
|
111 |
+
} else {
|
112 |
+
$imageUrl = '';
|
113 |
+
}
|
114 |
+
$category['image'] = $imageUrl;
|
115 |
+
|
116 |
+
$category['product_count'] = $productCollection->count();
|
117 |
+
|
118 |
+
$config = Mage::helper('highstreet_hsapi/config');
|
119 |
+
$filtersCategories = $config->filtersCategories();
|
120 |
+
|
121 |
+
// category children
|
122 |
+
$category['children'] = array();
|
123 |
+
if ($children->count() > 0) {
|
124 |
+
foreach ($children as $child) {
|
125 |
+
if ($filtersCategories) {
|
126 |
+
if ($child->getData('level') == 2 && // Top Category Level
|
127 |
+
$child->getData('include_in_menu') == 0) {
|
128 |
+
continue;
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
$childRepresentation = $this->getCategoryTree($child->getData('entity_id'));
|
133 |
+
|
134 |
+
if (is_array($childRepresentation)) {
|
135 |
+
array_push($category['children'], $childRepresentation);
|
136 |
+
}
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
return $category;
|
141 |
+
}
|
142 |
+
else {
|
143 |
+
return false;
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Returns a category collection of children from the given category id
|
150 |
+
*
|
151 |
+
* @param integer categoryId, parent category ID for which children need to be get
|
152 |
+
* @return Mage_Catalog_Model_Resource_Category_Collection Category Collection
|
153 |
+
*/
|
154 |
+
private function getChildrenCollectionForCategoryId($categoryId = null) {
|
155 |
+
if ($categoryId === null) {
|
156 |
+
return null;
|
157 |
+
}
|
158 |
+
|
159 |
+
|
160 |
+
$children = Mage::getModel('catalog/category')->getCollection()->setStoreId(Mage::app()->getStore()->getId());
|
161 |
+
$children->addAttributeToSelect(array('entity_id', 'name', 'image', 'level', 'include_in_menu','position')) // Only get nescecary attributes from the table
|
162 |
+
->addAttributeToFilter('parent_id', $categoryId)
|
163 |
+
->addAttributeToSort('position')
|
164 |
+
->addAttributeToFilter('is_active', 1);
|
165 |
+
|
166 |
+
|
167 |
+
return $children;
|
168 |
+
}
|
169 |
+
}
|
app/code/local/Highstreet/Hsapi/Model/Checkout.php
ADDED
@@ -0,0 +1,440 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_API_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Api
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com)
|
7 |
+
* @copyright Copyright (c) 2014 Touchwonders (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
class Highstreet_Hsapi_Model_Checkout extends Mage_Core_Model_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Fills the current session with cart data. This session automatically gets set trough the Magento models, this also inserts the current data in the database e.d.
|
13 |
+
* The array should have the following format:
|
14 |
+
* {"products":[{"sku":"product_sku_1", "qty":5}, {"sku":"product_sku_2", "qty":9}, {"sku":"product_sku_3", "qty":32}, {"sku":"product_sku_4", "qty":3}, {"sku":"product_sku_5", "qty":1}]}
|
15 |
+
* With this format we will lateron be able to extend it for configurable products
|
16 |
+
*
|
17 |
+
* @param array An array of product SKU's to fill the cart
|
18 |
+
*/
|
19 |
+
public function fillCartWithProductsAndQuantities($products = false) {
|
20 |
+
if (!$products) {
|
21 |
+
return;
|
22 |
+
}
|
23 |
+
|
24 |
+
|
25 |
+
$cart = Mage::getModel('checkout/cart');
|
26 |
+
$cart->init();
|
27 |
+
$cart->truncate(); // Reset cart everytime this function is called
|
28 |
+
|
29 |
+
foreach ($products as $key => $value) {
|
30 |
+
if (empty($value["id"])) {
|
31 |
+
continue;
|
32 |
+
}
|
33 |
+
|
34 |
+
try {
|
35 |
+
$product = $this->loadProduct($value["id"]);
|
36 |
+
} catch (Exception $e) {
|
37 |
+
continue;
|
38 |
+
}
|
39 |
+
|
40 |
+
|
41 |
+
if (empty($value["quantity"]) || !is_numeric($value["quantity"]) || $value["quantity"] === 0) {
|
42 |
+
continue; //skip this product
|
43 |
+
}
|
44 |
+
|
45 |
+
$quantity = $value["quantity"];
|
46 |
+
|
47 |
+
try {
|
48 |
+
|
49 |
+
$parent = $this->_getParentProduct($product);
|
50 |
+
if($parent) {
|
51 |
+
$configurations = $this->_getConfiguration($product,$parent);
|
52 |
+
$configurations = array('super_attribute' => $configurations);
|
53 |
+
$options = array_merge(array("qty" => $quantity),$configurations);
|
54 |
+
$cart->addProduct($parent,$options);
|
55 |
+
} else {
|
56 |
+
$cart->addProduct($product, array("qty" => $quantity));
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
} catch (Exception $e) {
|
66 |
+
continue;
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
$cart->save();
|
71 |
+
Mage::getSingleton('checkout/session')->setCartWasUpdated(true);
|
72 |
+
}
|
73 |
+
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Can retrieve an existing quote, or create a new (temporary) quote with the given objects
|
77 |
+
* Purpose of this method is to return all products that exist in the cart, all shipping information and the totals
|
78 |
+
*
|
79 |
+
* @param array An array of product SKU's to fill the cart. Format identical to fillCartWithProductsAndQuantities
|
80 |
+
* @param quote_id (optional) The quote_id for which you would like to return the information
|
81 |
+
*/
|
82 |
+
public function getQuoteWithProductsAndQuantities($products = false, $quote_id = -1) {
|
83 |
+
if ($products === false && $quote_id == -1) {
|
84 |
+
return;
|
85 |
+
}
|
86 |
+
|
87 |
+
$response = array();
|
88 |
+
|
89 |
+
Mage::getSingleton('checkout/session')->setQuoteId(null);
|
90 |
+
|
91 |
+
|
92 |
+
$quote = null;
|
93 |
+
|
94 |
+
if($quote_id == -1) {
|
95 |
+
$cart = Mage::getModel('checkout/cart');
|
96 |
+
$cart->init();
|
97 |
+
$cart->truncate(); // Reset cart everytime this function is called
|
98 |
+
$quote = $cart->getQuote();
|
99 |
+
} else {
|
100 |
+
$quote = Mage::getModel('sales/quote')->load($quote_id);
|
101 |
+
if(!$quote->getId()) {
|
102 |
+
return null;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
$response["quote"] = array_values($this->getProductsInQuote($quote,$products));
|
107 |
+
|
108 |
+
$this->addAddressToQuoteIfNeeded($quote);
|
109 |
+
//Shipping carries
|
110 |
+
$response['selected_shipping_method'] = $this->getSelectedShippingMethod($quote);
|
111 |
+
$response['shipping'] = array_values($this->getShippingMethods($quote, $response['selected_shipping_method']));
|
112 |
+
$response["totals"] = $this->getQuoteTotals($quote);
|
113 |
+
|
114 |
+
|
115 |
+
return $response;
|
116 |
+
|
117 |
+
|
118 |
+
|
119 |
+
}
|
120 |
+
|
121 |
+
|
122 |
+
//Helpers below
|
123 |
+
|
124 |
+
private function getProductsInQuote($quote,$products = null) {
|
125 |
+
$responseQuote = array();
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
$quoteItems = array();
|
130 |
+
foreach($quote->getAllItems() as $quoteItem) {
|
131 |
+
$quoteItems[$quoteItem->getId()] = $quoteItem;
|
132 |
+
}
|
133 |
+
|
134 |
+
|
135 |
+
|
136 |
+
//loop through the requested products
|
137 |
+
foreach ($products as $key => $value) {
|
138 |
+
if (empty($value["id"])) {
|
139 |
+
continue;
|
140 |
+
}
|
141 |
+
|
142 |
+
try {
|
143 |
+
$product = $this->loadProduct($value["id"]);
|
144 |
+
} catch (Exception $e) {
|
145 |
+
$productInQuote["errorMessage"] = $e->getMessage();
|
146 |
+
$productInQuote["errorCode"] = 400; //something else went wrong
|
147 |
+
$productInQuote["quantity"] = 0;
|
148 |
+
}
|
149 |
+
|
150 |
+
$parent = $this->_getParentProduct($product);
|
151 |
+
if($parent)
|
152 |
+
$configurations = $this->_getConfiguration($product,$parent);
|
153 |
+
|
154 |
+
|
155 |
+
|
156 |
+
$requestedQuantity = $value["quantity"];
|
157 |
+
|
158 |
+
|
159 |
+
|
160 |
+
|
161 |
+
//Set up default response
|
162 |
+
$productInQuote = array();
|
163 |
+
$productInQuote["product_id"] = $value["id"];
|
164 |
+
$productInQuote["errorCode"] = 0;
|
165 |
+
$productInQuote["errorMessage"] = null;
|
166 |
+
|
167 |
+
|
168 |
+
|
169 |
+
try {
|
170 |
+
|
171 |
+
if (!$product) {
|
172 |
+
//product does not exist
|
173 |
+
|
174 |
+
$productInQuote["errorCode"] = 400;
|
175 |
+
$productInQuote["errorMessage"] = "The requested product does not exist";
|
176 |
+
$productInQuote["quantity"] = 0;
|
177 |
+
|
178 |
+
|
179 |
+
} else {
|
180 |
+
|
181 |
+
|
182 |
+
$itemInventory = Mage::getModel('cataloginventory/stock_item')->loadByProduct($product);
|
183 |
+
$quoteItem = $quote->getItemByProduct($product);
|
184 |
+
|
185 |
+
|
186 |
+
$actualQuantity = $requestedQuantity; //actual qty is what we are going to add
|
187 |
+
|
188 |
+
//adjust actual quantity if we are requesting more than in stock
|
189 |
+
$availableQuantity = $itemInventory->getQty();
|
190 |
+
$isInStock = $itemInventory->getIsInStock();
|
191 |
+
$isStockManaged = $itemInventory->getManageStock();
|
192 |
+
$backordersAllowed = $itemInventory->getBackorders();
|
193 |
+
|
194 |
+
|
195 |
+
if($isStockManaged) {
|
196 |
+
|
197 |
+
if(!$isInStock) {
|
198 |
+
$productInQuote["errorMessage"] = "Product is not in stock";
|
199 |
+
$productInQuote["errorCode"] = 101; //product cannot be added
|
200 |
+
$actualQuantity = 0;
|
201 |
+
} else {
|
202 |
+
//in stock, but should we cap it?
|
203 |
+
if(!$backordersAllowed && $requestedQuantity > $availableQuantity) {
|
204 |
+
$actualQuantity = $availableQuantity; //cap
|
205 |
+
$productInQuote["errorMessage"] = "Requested quantity is not available, added ".(int)$actualQuantity." instead of ".$requestedQuantity ." products with id ".$value["id"]." to the cart";
|
206 |
+
$productInQuote["errorCode"] = 102; //product can be added, but with a lower quantity
|
207 |
+
//Note: even though the actualQuantity might be set to 0, we still do not return a 101, because a qty of 0 does not necessarily make a product out of stock
|
208 |
+
//"Qty for Item's Status to Become Out of Stock" might be a negative integer
|
209 |
+
}
|
210 |
+
|
211 |
+
}
|
212 |
+
|
213 |
+
}
|
214 |
+
|
215 |
+
if($quoteItem) { //adjust existing entry
|
216 |
+
$quoteItem->setQty($actualQuantity);
|
217 |
+
} else { //or add new entry (but of course only when qty > 0)
|
218 |
+
if($actualQuantity > 0) { //do this check because the app might request a quantity of 0 for a product. If you call the function below with $actualQuantity = 0, it will still add one product to the cart
|
219 |
+
if($parent) {
|
220 |
+
$configurations = array('super_attribute' => $configurations);
|
221 |
+
$options = array_merge(array("qty" => $actualQuantity),$configurations);
|
222 |
+
|
223 |
+
|
224 |
+
$quoteItem = $quote->addProduct($parent,new Varien_Object($options));
|
225 |
+
} else {
|
226 |
+
$quoteItem = $quote->addProduct($product,new Varien_Object(array("qty" => $actualQuantity)));
|
227 |
+
}
|
228 |
+
|
229 |
+
//response output
|
230 |
+
$productInQuote = array_merge($this->getProductInQuoteResponse($quoteItem,$product),$productInQuote);
|
231 |
+
} else {
|
232 |
+
$productInQuote["quantity"] = 0;
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
|
237 |
+
if($quoteItem)
|
238 |
+
unset($quoteItems[$quoteItem->getId()]);
|
239 |
+
|
240 |
+
|
241 |
+
|
242 |
+
}
|
243 |
+
|
244 |
+
|
245 |
+
} catch (Exception $e) {
|
246 |
+
$productInQuote["errorMessage"] = $e->getMessage();
|
247 |
+
$productInQuote["errorCode"] = 400; //something else went wrong
|
248 |
+
$productInQuote["quantity"] = 0;
|
249 |
+
|
250 |
+
}
|
251 |
+
|
252 |
+
|
253 |
+
|
254 |
+
$responseQuote[] = $productInQuote;
|
255 |
+
|
256 |
+
|
257 |
+
}
|
258 |
+
|
259 |
+
foreach($quoteItems as $quoteItem) {
|
260 |
+
if(count($quoteItem->getChildren()) > 0)
|
261 |
+
continue;
|
262 |
+
|
263 |
+
$productInQuote = $this->getProductInQuoteResponse($quoteItem);
|
264 |
+
$responseQuote[] = $productInQuote;
|
265 |
+
}
|
266 |
+
|
267 |
+
|
268 |
+
return $responseQuote;
|
269 |
+
}
|
270 |
+
|
271 |
+
private function getProductInQuoteResponse($quoteItem = null, $product = null) {
|
272 |
+
if(!$quoteItem && !$product)
|
273 |
+
return null;
|
274 |
+
if(!$product)
|
275 |
+
$product = $quoteItem->getProduct();
|
276 |
+
|
277 |
+
|
278 |
+
$productInQuote = array();
|
279 |
+
$productInQuote["product_id"] = $product->getId();
|
280 |
+
|
281 |
+
if($quoteItem->getParentItem()) {
|
282 |
+
$quoteItem = $quoteItem->getParentItem();
|
283 |
+
$product = $quoteItem->getProduct();
|
284 |
+
}
|
285 |
+
|
286 |
+
$quantity = $quoteItem ? $quoteItem->getQty() : 0;
|
287 |
+
|
288 |
+
$productInQuote["finalPrice"] = $quantity > 0 ? $product->getFinalPrice($quantity) : $product->getFinalPrice();
|
289 |
+
$productInQuote["quantity"] = $quantity;
|
290 |
+
|
291 |
+
return $productInQuote;
|
292 |
+
}
|
293 |
+
|
294 |
+
private function getQuoteTotals($quote) {
|
295 |
+
|
296 |
+
|
297 |
+
$quote->collectTotals()->save(); //required to fetch the totals
|
298 |
+
|
299 |
+
//Totals
|
300 |
+
$totals = $quote->getTotals(); //Total object
|
301 |
+
$subtotal = $totals["subtotal"]->getValue(); //Subtotal value
|
302 |
+
$grandtotal = $totals["grand_total"]->getValue(); //Grandtotal value
|
303 |
+
|
304 |
+
$discount = 0;
|
305 |
+
if(isset($totals['discount']) && $totals['discount']->getValue()) {
|
306 |
+
$discount = $totals['discount']->getValue(); //Discount value if applied
|
307 |
+
}
|
308 |
+
$tax = 0;
|
309 |
+
if(isset($totals['tax']) && $totals['tax']->getValue()) {
|
310 |
+
$tax = $totals['tax']->getValue(); //Tax value if present
|
311 |
+
}
|
312 |
+
|
313 |
+
$totalItemsInCart = 0;
|
314 |
+
foreach($quote->getAllItems() as $quoteItem) {
|
315 |
+
if(count($quoteItem->getChildren()) > 0)
|
316 |
+
continue;
|
317 |
+
$totalItemsInCart++;
|
318 |
+
}
|
319 |
+
|
320 |
+
|
321 |
+
$responseTotals = array();
|
322 |
+
$responseTotals["totalItemsInCart"] = $totalItemsInCart;
|
323 |
+
$responseTotals["subtotal"] = $subtotal;
|
324 |
+
$responseTotals["grandtotal"] = $grandtotal;
|
325 |
+
$responseTotals["discount"] = $discount;
|
326 |
+
$responseTotals["tax"] = $tax;
|
327 |
+
|
328 |
+
return $responseTotals;
|
329 |
+
}
|
330 |
+
|
331 |
+
private function addAddressToQuoteIfNeeded(&$quote) {
|
332 |
+
$address = $quote->getShippingAddress();
|
333 |
+
|
334 |
+
if(!$address->getCountryId()) {
|
335 |
+
$address->setCity("Utrecht")
|
336 |
+
->setCountryId("NL")
|
337 |
+
->setPostcode("3512NT")
|
338 |
+
->setCollectShippingRates(true);
|
339 |
+
$quote->setShippingAddress($address);
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
private function getSelectedShippingMethod($quote) {
|
344 |
+
$quoteShippingAddress = $quote->getShippingAddress();
|
345 |
+
$quoteShippingAddress->collectTotals(); //to make sure all available shipping methods are listed
|
346 |
+
|
347 |
+
$quoteShippingAddress->collectShippingRates()->save(); //collect the rates
|
348 |
+
|
349 |
+
$chosenShippingMethod = $quoteShippingAddress->getShippingMethod();
|
350 |
+
|
351 |
+
if ($chosenShippingMethod === "") {
|
352 |
+
$chosenShippingMethod = null;
|
353 |
+
}
|
354 |
+
|
355 |
+
return $chosenShippingMethod;
|
356 |
+
}
|
357 |
+
|
358 |
+
private function getShippingMethods($quote, $selectedShippingMethod) {
|
359 |
+
$responseCarriers = array();
|
360 |
+
|
361 |
+
$quoteShippingAddress = $quote->getShippingAddress();
|
362 |
+
$quoteShippingAddress->collectTotals(); //to make sure all available shipping methods are listed
|
363 |
+
|
364 |
+
$quoteShippingAddress->collectShippingRates()->save(); //collect the rates
|
365 |
+
$groupedRates = $quoteShippingAddress->getGroupedAllShippingRates();
|
366 |
+
|
367 |
+
foreach ($groupedRates as $carrierCode => $rates ) {
|
368 |
+
foreach ($rates as $rate) {
|
369 |
+
$price = $rate->getPrice();
|
370 |
+
if ($rate->getCode() == $selectedShippingMethod) {
|
371 |
+
$quoteShippingAddress->setShippingMethod($selectedShippingMethod);
|
372 |
+
$quote->collectTotals()->save();
|
373 |
+
|
374 |
+
$price = $quoteShippingAddress->getShippingInclTax();
|
375 |
+
}
|
376 |
+
|
377 |
+
$responseRate = array();
|
378 |
+
$responseRate["carrier"] = $rate->getCarrier();
|
379 |
+
$responseRate["carrierTitle"] = $rate->getCarrierTitle();
|
380 |
+
$responseRate["carrierCode"] = $rate->getCode();
|
381 |
+
|
382 |
+
$responseRate["method"] = $rate->getMethod();
|
383 |
+
$responseRate["methodTitle"] = $rate->getMethodTitle();
|
384 |
+
$responseRate["methodDescription"] = $rate->getMethodDescription();
|
385 |
+
$responseRate["price"] = $price;
|
386 |
+
$responseCarriers[] = $responseRate;
|
387 |
+
}
|
388 |
+
}
|
389 |
+
|
390 |
+
return $responseCarriers;
|
391 |
+
}
|
392 |
+
|
393 |
+
private function loadProduct($productId = null) {
|
394 |
+
if(!$productId)
|
395 |
+
return null;
|
396 |
+
|
397 |
+
$productModel = Mage::getModel('catalog/product');
|
398 |
+
$product = $productModel->load($productId);
|
399 |
+
if (!$product->getId())
|
400 |
+
return null; //product does not exist
|
401 |
+
|
402 |
+
return $product;
|
403 |
+
|
404 |
+
}
|
405 |
+
|
406 |
+
private function _getParentProduct($product) {
|
407 |
+
$config = Mage::helper('highstreet_hsapi/config');
|
408 |
+
if ($config->alwaysAddSimpleProductsToCart()) {
|
409 |
+
return null;
|
410 |
+
}
|
411 |
+
|
412 |
+
$parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
|
413 |
+
$parent = null;
|
414 |
+
if(isset($parentIds[0])){
|
415 |
+
$parent = Mage::getModel('catalog/product')->load($parentIds[0]);
|
416 |
+
}
|
417 |
+
return $parent;
|
418 |
+
}
|
419 |
+
|
420 |
+
private function _getConfiguration($product,$parent) {
|
421 |
+
$configurations = array();
|
422 |
+
$conf = Mage::getModel('catalog/product_type_configurable')->setProduct($parent);
|
423 |
+
|
424 |
+
//build the configuration_attributes array
|
425 |
+
$configurableAttributes = $conf->getConfigurableAttributesAsArray($parent);
|
426 |
+
|
427 |
+
foreach($configurableAttributes as $attribute) {
|
428 |
+
|
429 |
+
$method = 'get' . uc_words($attribute['attribute_code'], '');
|
430 |
+
$attribute_value = $product->$method();
|
431 |
+
$attribute_id = $attribute['attribute_id'];
|
432 |
+
$configurations[$attribute_id] = $attribute_value;
|
433 |
+
|
434 |
+
}
|
435 |
+
|
436 |
+
return $configurations;
|
437 |
+
}
|
438 |
+
|
439 |
+
|
440 |
+
}
|
app/code/local/Highstreet/Hsapi/Model/Images.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com)
|
7 |
+
* @copyright Copyright (c) 2014 Touchwonders (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
class Highstreet_Hsapi_Model_Images extends Mage_Core_Model_Abstract
|
10 |
+
{
|
11 |
+
|
12 |
+
public function getImage($src, $size) {
|
13 |
+
if (!$src) {
|
14 |
+
return null;
|
15 |
+
} else {
|
16 |
+
$image = Mage::helper('timage')->init($src);
|
17 |
+
|
18 |
+
if ($src[0] !== "/") {
|
19 |
+
$src = "/" . $src;
|
20 |
+
}
|
21 |
+
|
22 |
+
$imageUrl = Mage::getBaseDir() . $src;
|
23 |
+
if(!file_exists($imageUrl) ) {
|
24 |
+
return null;
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
$originalSize = $image->getOriginalSize();
|
29 |
+
if ($size) {
|
30 |
+
list($width, $height) = explode('x', $size);
|
31 |
+
|
32 |
+
if (!empty($width) && !empty($height)) {
|
33 |
+
$image->resize($width, $height);
|
34 |
+
} else {
|
35 |
+
if ($originalSize['width'] >= $originalSize['height']) {
|
36 |
+
$image->resize($size, NULL);
|
37 |
+
} else {
|
38 |
+
$image->resize(NULL, $size);
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
$imageUrl = $image->cachedImage;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
return $imageUrl;
|
47 |
+
}
|
48 |
+
|
49 |
+
}
|
app/code/local/Highstreet/Hsapi/Model/Observer.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Highstreet_Hsapi_Model_Observer extends Varien_Event_Observer
|
3 |
+
{
|
4 |
+
public function __construct()
|
5 |
+
{
|
6 |
+
}
|
7 |
+
public function mergeQuote($observer)
|
8 |
+
{
|
9 |
+
$event = $observer->getEvent();
|
10 |
+
$quote = $event->getQuote();
|
11 |
+
exec("echo Quote".$quote->getId()." > /tmp/bla");
|
12 |
+
|
13 |
+
foreach ($quote->getAllItems() as $item) {
|
14 |
+
$quote->removeItem($item->getId());
|
15 |
+
}
|
16 |
+
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
}
|
21 |
+
|
22 |
+
?>
|
app/code/local/Highstreet/Hsapi/Model/Products.php
ADDED
@@ -0,0 +1,880 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
7 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
class Highstreet_Hsapi_Model_Products extends Mage_Core_Model_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* @var bool
|
13 |
+
*/
|
14 |
+
private $_addConfigurableAttributes = false;
|
15 |
+
private $_addConfigurations = false;
|
16 |
+
|
17 |
+
const PRODUCTS_MEDIA_PATH = '/media/catalog/product';
|
18 |
+
const NO_IMAGE_PATH = 'no_selection';
|
19 |
+
const RANGE_FALLBACK_RANGE = 100;
|
20 |
+
const SPECIAL_PRICE_FROM_DATE_FALLBACK = "1970-01-01 00:00:00";
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Gets a single product for a given productId and attributes
|
24 |
+
*
|
25 |
+
* @param integer ProductId, product id of the product to be gotten
|
26 |
+
* @param string Attributes, string of attributes straight from the URL
|
27 |
+
* @return array Product
|
28 |
+
*/
|
29 |
+
public function getSingleProduct($productId = false, $attributes, $child_product_attributes)
|
30 |
+
{
|
31 |
+
if (!$productId) {
|
32 |
+
return nil;
|
33 |
+
}
|
34 |
+
|
35 |
+
$product = Mage::getModel('catalog/product')->load($productId);
|
36 |
+
|
37 |
+
return $this->_getProductAttributes($product, $attributes, $child_product_attributes);
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Gets products with attributes for given order, range, filters, search and categoryId
|
42 |
+
*
|
43 |
+
* @param string Attributes, string of attributes straight from the URL
|
44 |
+
* @param string Child product attributes, string of attributes for the child products, comma sepperated
|
45 |
+
* @param string Order, order for the products
|
46 |
+
* @param string Range of products. Must formatted like "0,10" where 0 is the offset and 10 is the count
|
47 |
+
* @param string Search string for filtering on keywords
|
48 |
+
* @param integer CategoryId, category id of the category which will be used to filter
|
49 |
+
* @return array Product
|
50 |
+
*/
|
51 |
+
public function getProductsForResponse($attributes, $child_product_attributes, $order, $range, $filters, $search, $categoryId)
|
52 |
+
{
|
53 |
+
$addGalleryImages = false;
|
54 |
+
$searching = !empty($search);
|
55 |
+
|
56 |
+
// get attributes
|
57 |
+
if (!empty($attributes)) {
|
58 |
+
$attributesArray = explode(',', $attributes);
|
59 |
+
|
60 |
+
if(in_array('configurable_attributes',$attributesArray)){
|
61 |
+
$this->_addConfigurableAttributes = true;
|
62 |
+
}
|
63 |
+
if(in_array('configurations',$attributesArray)){
|
64 |
+
$this->_addConfigurations = true;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
// get order
|
69 |
+
if (!empty($order)) {
|
70 |
+
$order = explode(',', $order);
|
71 |
+
}
|
72 |
+
|
73 |
+
|
74 |
+
// apply search
|
75 |
+
if ($searching) {
|
76 |
+
|
77 |
+
////////
|
78 |
+
$_GET['q'] = $search; //this is the only to pass the search query
|
79 |
+
$query = Mage::helper('catalogsearch')->getQuery();
|
80 |
+
$query->setStoreId(Mage::app()->getStore()->getId());
|
81 |
+
|
82 |
+
//Code here inspired from ResultController.php
|
83 |
+
if ($query->getQueryText() != '') {
|
84 |
+
if (Mage::helper('catalogsearch')->isMinQueryLength()) {
|
85 |
+
$query->setId(0)
|
86 |
+
->setIsActive(1)
|
87 |
+
->setIsProcessed(1);
|
88 |
+
}
|
89 |
+
else {
|
90 |
+
if ($query->getId()) {
|
91 |
+
$query->setPopularity($query->getPopularity()+1);
|
92 |
+
}
|
93 |
+
else {
|
94 |
+
$query->setPopularity(1);
|
95 |
+
}
|
96 |
+
}
|
97 |
+
if (!Mage::helper('catalogsearch')->isMinQueryLength()) {
|
98 |
+
$query->prepare();
|
99 |
+
}
|
100 |
+
}
|
101 |
+
$query->save();
|
102 |
+
|
103 |
+
|
104 |
+
$catalogSearchModelCollection = Mage::getResourceModel('catalogsearch/fulltext_collection');
|
105 |
+
|
106 |
+
$catalogSearchModelCollection->addSearchFilter($search);
|
107 |
+
|
108 |
+
$collection = $catalogSearchModelCollection;
|
109 |
+
} else {
|
110 |
+
|
111 |
+
// initialize
|
112 |
+
$collection = Mage::getModel('catalog/product')->getCollection();
|
113 |
+
$collection->addStoreFilter();
|
114 |
+
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($collection);
|
115 |
+
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($collection);
|
116 |
+
|
117 |
+
}
|
118 |
+
|
119 |
+
|
120 |
+
|
121 |
+
|
122 |
+
$categoryNotSet = false;
|
123 |
+
|
124 |
+
if (empty($categoryId)) {
|
125 |
+
$categoryId = Mage::app()->getStore()->getRootCategoryId();
|
126 |
+
$categoryNotSet = true;
|
127 |
+
}
|
128 |
+
$category = Mage::getModel('catalog/category')->load($categoryId);
|
129 |
+
// apply search
|
130 |
+
if ($categoryId && !$categoryNotSet) {
|
131 |
+
$collection->addCategoryFilter($category);
|
132 |
+
}
|
133 |
+
|
134 |
+
if (!empty($range)) {
|
135 |
+
$range = explode(',', $range);
|
136 |
+
}
|
137 |
+
|
138 |
+
if (!empty($range)) {
|
139 |
+
$collection->getSelect()->limit($range[1], $range[0]);
|
140 |
+
} else {
|
141 |
+
$collection->getSelect()->limit(self::RANGE_FALLBACK_RANGE);
|
142 |
+
}
|
143 |
+
|
144 |
+
// apply attributes
|
145 |
+
if (!empty($attributesArray)) {
|
146 |
+
foreach ($attributesArray as $attribute) {
|
147 |
+
$collection->addAttributeToSelect($attribute);
|
148 |
+
if ($attribute == 'media_gallery') {
|
149 |
+
$addGalleryImages = true;
|
150 |
+
}
|
151 |
+
}
|
152 |
+
}
|
153 |
+
else {
|
154 |
+
|
155 |
+
// select all attributes
|
156 |
+
$collection->addAttributeToSelect('*');
|
157 |
+
$addGalleryImages = true;
|
158 |
+
}
|
159 |
+
|
160 |
+
//apply filters
|
161 |
+
if(!empty($filters)) {
|
162 |
+
foreach ($filters as $filter) {
|
163 |
+
if (array_key_exists('attribute', $filter)) {
|
164 |
+
foreach ($filter as $operator => $condition) {
|
165 |
+
if ($operator != 'attribute') {
|
166 |
+
$collection->addAttributeToFilter(array(array('attribute' => $filter['attribute'], $operator => $condition)));
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
|
174 |
+
// Apply type filter, we only want Simple and Configurable products in our API
|
175 |
+
$collection->addAttributeToFilter('type_id', array('simple', 'configurable'));
|
176 |
+
|
177 |
+
// apply order
|
178 |
+
if (!empty($order)) {
|
179 |
+
foreach ($order as $orderCondition) {
|
180 |
+
$orderBy = explode(':', $orderCondition);
|
181 |
+
$collection->setOrder($orderBy[0], $orderBy[1]);
|
182 |
+
}
|
183 |
+
} else {
|
184 |
+
if($searching) {
|
185 |
+
$collection->setOrder('relevance', 'desc');
|
186 |
+
} else {
|
187 |
+
|
188 |
+
$sortKey = $category->getDefaultSortBy();
|
189 |
+
if (!$sortKey) {
|
190 |
+
$sortKey = Mage::getStoreConfig('catalog/frontend/default_sort_by');
|
191 |
+
}
|
192 |
+
$collection->setOrder($sortKey, 'asc');
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
// Add 'out of stock' filter, if preffered
|
197 |
+
if (!Mage::getStoreConfig('cataloginventory/options/show_out_of_stock')) {
|
198 |
+
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($collection);
|
199 |
+
|
200 |
+
// Make a better fix for this. At this time this seems impossible, this doesn't work:
|
201 |
+
// $collection->addAttributeToFilter('is_salable', array('eq' => 1));
|
202 |
+
// Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($collection); // Another popular suggestion around the web, crashes the app for now and 'under water' does the same as l:276
|
203 |
+
// For now we look trough all the configurable products in the collection of a certain category and filter out the unneded products
|
204 |
+
$collectionConfigurable = Mage::getResourceModel('catalog/product_collection')->addAttributeToFilter('type_id', array('eq' => 'configurable'));
|
205 |
+
$collectionConfigurable->addCategoryFilter($category);
|
206 |
+
|
207 |
+
$outOfStockConfis = array();
|
208 |
+
foreach ($collectionConfigurable as $_configurableproduct) {
|
209 |
+
$product = Mage::getModel('catalog/product')->load($_configurableproduct->getId());
|
210 |
+
if (!$product->getData('is_salable')) {
|
211 |
+
$outOfStockConfis[] = $product->getId();
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
if (count($outOfStockConfis) > 0) {
|
216 |
+
$collection->addAttributeToFilter('entity_id', array('nin' => $outOfStockConfis));
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
|
221 |
+
// Add media gallery to collection we cant do this in an earlier stage because it gives really strange results (filter not working, range not working!)
|
222 |
+
if ($addGalleryImages) {
|
223 |
+
$this->_addMediaGalleryAttributeToCollection($collection);
|
224 |
+
}
|
225 |
+
|
226 |
+
if (!isset($productCount)) {
|
227 |
+
// get total product count
|
228 |
+
$productCount = $collection->getSize();
|
229 |
+
}
|
230 |
+
/**
|
231 |
+
* Format result array
|
232 |
+
*/
|
233 |
+
$products = array('products' => array());
|
234 |
+
|
235 |
+
foreach($collection as $product) {
|
236 |
+
array_push($products['products'], $this->_getProductAttributes($product, $attributes, $child_product_attributes));
|
237 |
+
}
|
238 |
+
|
239 |
+
$resultFilters = $this->getFilters($categoryId);
|
240 |
+
|
241 |
+
$products['filters'] = $resultFilters;
|
242 |
+
$products['product_count'] = $productCount;
|
243 |
+
|
244 |
+
$rangeLength = $range[1];
|
245 |
+
if ($rangeLength > count($products["products"])) {
|
246 |
+
$rangeLength = count($products["products"]);
|
247 |
+
}
|
248 |
+
|
249 |
+
$products['range'] = array("location" => $range[0], "length" => $rangeLength);
|
250 |
+
|
251 |
+
return $products;
|
252 |
+
}
|
253 |
+
|
254 |
+
|
255 |
+
/**
|
256 |
+
*
|
257 |
+
* Gets products for a set of product id's
|
258 |
+
*
|
259 |
+
* @param array productIds, product id's to filter on
|
260 |
+
* @param string Attributes, comma seperated string of attributes
|
261 |
+
* @param string Child products attributes, comma seperated string of attributes for the child products
|
262 |
+
* @param string range, formatted range string
|
263 |
+
* @return array Array of products
|
264 |
+
*
|
265 |
+
*/
|
266 |
+
|
267 |
+
public function getProductsFilteredByProductIds($productIds = false, $attributes, $child_product_attributes, $range) {
|
268 |
+
|
269 |
+
$products = array('products' => array());
|
270 |
+
|
271 |
+
if (!$productIds) {
|
272 |
+
$products['product_count'] = 0;
|
273 |
+
$products['range'] = array("location" => 0, "length" => 0);
|
274 |
+
return $products;
|
275 |
+
}
|
276 |
+
|
277 |
+
$collection = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('entity_id', array('in' => $productIds));
|
278 |
+
|
279 |
+
// get attributes
|
280 |
+
if (!empty($attributes)) {
|
281 |
+
$attributesArray = explode(',', $attributes);
|
282 |
+
}
|
283 |
+
|
284 |
+
// apply attributes
|
285 |
+
if (!empty($attributes)) {
|
286 |
+
foreach ($attributesArray as $attribute) {
|
287 |
+
$collection->addAttributeToSelect($attribute);
|
288 |
+
}
|
289 |
+
} else {
|
290 |
+
// select all attributes
|
291 |
+
$collection->addAttributeToSelect('*');
|
292 |
+
$this->_addMediaGalleryAttributeToCollection($collection);
|
293 |
+
}
|
294 |
+
|
295 |
+
if (!empty($range)) {
|
296 |
+
$range = explode(',', $range);
|
297 |
+
$collection->getSelect()->limit($range[1], $range[0]);
|
298 |
+
}
|
299 |
+
|
300 |
+
// Add 'out of stock' filter, if preffered
|
301 |
+
if (!Mage::getStoreConfig('cataloginventory/options/show_out_of_stock')) {
|
302 |
+
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($collection);
|
303 |
+
|
304 |
+
// For comments, see :285
|
305 |
+
$collectionConfigurable = Mage::getResourceModel('catalog/product_collection')->addAttributeToFilter('type_id', array('eq' => 'configurable'));
|
306 |
+
$collectionConfigurable->addAttributeToFilter('entity_id', array('in' => $productIds));
|
307 |
+
|
308 |
+
$outOfStockConfis = array();
|
309 |
+
foreach ($collectionConfigurable as $_configurableproduct) {
|
310 |
+
$product = Mage::getModel('catalog/product')->load($_configurableproduct->getId());
|
311 |
+
if (!$product->getData('is_salable')) {
|
312 |
+
$outOfStockConfis[] = $product->getId();
|
313 |
+
}
|
314 |
+
}
|
315 |
+
|
316 |
+
if (count($outOfStockConfis) > 0) {
|
317 |
+
$collection->addAttributeToFilter('entity_id', array('nin' => $outOfStockConfis));
|
318 |
+
}
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Format result array
|
323 |
+
*/
|
324 |
+
foreach($collection as $product) {
|
325 |
+
array_push($products['products'], $this->_getProductAttributes($product, $attributes, $child_product_attributes));
|
326 |
+
}
|
327 |
+
|
328 |
+
$products['product_count'] = $collection->getSize();;
|
329 |
+
|
330 |
+
$rangeLength = $range[1];
|
331 |
+
if ($rangeLength > count($products["products"])) {
|
332 |
+
$rangeLength = count($products["products"]);
|
333 |
+
}
|
334 |
+
|
335 |
+
$products['range'] = array("location" => $range[0], "length" => $rangeLength);
|
336 |
+
|
337 |
+
return $products;
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* Gets a batch of products for a given comma sepperated productIds, attributes and child product attributes
|
342 |
+
*
|
343 |
+
* @param string Ids, product ids, comma sepperated
|
344 |
+
* @param string Attributes, string of attributes, comma sepperated
|
345 |
+
* @param string Child product attributes, string of attributes for the child products, comma sepperated
|
346 |
+
* @return array Product
|
347 |
+
*/
|
348 |
+
|
349 |
+
public function getBatchProducts($ids = false, $attributes, $child_product_attributes) {
|
350 |
+
$idsArray = explode(',', $ids);
|
351 |
+
|
352 |
+
$products = array();
|
353 |
+
foreach ($idsArray as $value) {
|
354 |
+
$products[] = $this->_getProductAttributes(Mage::getModel('catalog/product')->load($value), $attributes, $child_product_attributes);
|
355 |
+
}
|
356 |
+
|
357 |
+
return $products;
|
358 |
+
}
|
359 |
+
|
360 |
+
|
361 |
+
public function getStockInfo($productId = false) {
|
362 |
+
if(!$productId) {
|
363 |
+
return;
|
364 |
+
}
|
365 |
+
$product = Mage::getModel('catalog/product')->load($productId);
|
366 |
+
|
367 |
+
if(!$product->getId())
|
368 |
+
return;
|
369 |
+
|
370 |
+
|
371 |
+
$products = array();
|
372 |
+
$response = array();
|
373 |
+
|
374 |
+
if($product->getTypeId() == 'configurable') {
|
375 |
+
$conf = Mage::getModel('catalog/product_type_configurable')->setProduct($product);
|
376 |
+
$simple_collection = $conf->getUsedProductCollection()->addFilterByRequiredOptions();
|
377 |
+
$products = $simple_collection;
|
378 |
+
} else if($product->getTypeId() == 'simple'){
|
379 |
+
$products[] = $product;
|
380 |
+
} else {
|
381 |
+
return; //Other product types not supported yet
|
382 |
+
}
|
383 |
+
|
384 |
+
|
385 |
+
foreach($products as $simpleproduct)
|
386 |
+
$response[] = $this->_getStockInformationForProduct($simpleproduct);
|
387 |
+
|
388 |
+
|
389 |
+
return array_values($response);
|
390 |
+
|
391 |
+
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Gets related products for a type and product id
|
396 |
+
*
|
397 |
+
* @param string Type, type of related products, can either be 'cross-sell', 'up-sell' or empty, in which case it will return 'regular' related products
|
398 |
+
* @param int productId, id used for base of related products
|
399 |
+
* @param string Attributes, comma seperated string of attributes
|
400 |
+
* @param string Child products attributes, comma seperated string of attributes for the child products
|
401 |
+
* @param string range, formatted range string
|
402 |
+
* @return array Array of product ids
|
403 |
+
*
|
404 |
+
*/
|
405 |
+
|
406 |
+
public function getRelatedProducts($type, $productId = false, $attributes, $child_product_attributes, $range) {
|
407 |
+
if (!$productId) {
|
408 |
+
return;
|
409 |
+
}
|
410 |
+
|
411 |
+
if ($type == "cross-sell") {
|
412 |
+
$productIds = $this->getCrossSellProductIds($productId);
|
413 |
+
} else if ($type == "up-sell") {
|
414 |
+
$productIds = $this->getUpSellProductIds($productId);
|
415 |
+
} else {
|
416 |
+
$productIds = $this->getRelatedProductIds($productId);
|
417 |
+
}
|
418 |
+
|
419 |
+
return $this->getProductsFilteredByProductIds($productIds, $attributes, $child_product_attributes, $range);
|
420 |
+
|
421 |
+
}
|
422 |
+
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Convenience functions
|
426 |
+
*/
|
427 |
+
|
428 |
+
/**
|
429 |
+
*
|
430 |
+
* Get related product id's for a product id
|
431 |
+
*
|
432 |
+
* @param int productId, id used to filter related products
|
433 |
+
* @return array Array of product ids
|
434 |
+
*
|
435 |
+
*/
|
436 |
+
|
437 |
+
public function getRelatedProductIds($productId = false) {
|
438 |
+
if (!$productId) {
|
439 |
+
return;
|
440 |
+
}
|
441 |
+
|
442 |
+
$productModel = Mage::getModel('catalog/product')->load($productId);
|
443 |
+
return $productModel->getRelatedProductIds();
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
*
|
448 |
+
* Get cross sell product id's for a product id
|
449 |
+
*
|
450 |
+
* @param int productId, id used to filter cross sell products
|
451 |
+
* @return array Array of product ids
|
452 |
+
*
|
453 |
+
*/
|
454 |
+
|
455 |
+
public function getCrossSellProductIds($productId = false) {
|
456 |
+
if (!$productId) {
|
457 |
+
return;
|
458 |
+
}
|
459 |
+
|
460 |
+
$productModel = Mage::getModel('catalog/product')->load($productId);
|
461 |
+
return $productModel->getCrossSellProductIds();
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
*
|
466 |
+
* Get up sell product id's for a product id
|
467 |
+
*
|
468 |
+
* @param int productId, id used to filter up sell products
|
469 |
+
* @return array Array of product ids
|
470 |
+
*
|
471 |
+
*/
|
472 |
+
|
473 |
+
public function getUpSellProductIds($productId = false) {
|
474 |
+
if (!$productId) {
|
475 |
+
return;
|
476 |
+
}
|
477 |
+
|
478 |
+
$productModel = Mage::getModel('catalog/product')->load($productId);
|
479 |
+
return $productModel->getUpSellProductIds();
|
480 |
+
}
|
481 |
+
|
482 |
+
|
483 |
+
|
484 |
+
/***********************************/
|
485 |
+
/**
|
486 |
+
* PRIVATE/protected FUNCTIONS
|
487 |
+
*/
|
488 |
+
/***********************************/
|
489 |
+
/**
|
490 |
+
* Returns filters
|
491 |
+
*
|
492 |
+
* @param int $categoryId
|
493 |
+
* @return array
|
494 |
+
* @author Andrey Posudevsky
|
495 |
+
*
|
496 |
+
*/
|
497 |
+
protected function getFilters($categoryId = false) {
|
498 |
+
|
499 |
+
if (!$categoryId) {
|
500 |
+
$categoryId = Mage::app()->getStore()->getRootCategoryId();
|
501 |
+
}
|
502 |
+
|
503 |
+
$layer = Mage::getModel('catalog/layer');
|
504 |
+
|
505 |
+
//$layered_nav = $this->getLayout()->createBlock('catalog/layer_view');
|
506 |
+
$layered_nav = Highstreet_Hsapi_IndexController::getLayout()->createBlock('catalog/layer_view');
|
507 |
+
$filters = $layered_nav->getFilters();
|
508 |
+
$category = Mage::getModel('catalog/category')->load($categoryId);
|
509 |
+
$layer->setCurrentCategory($category);
|
510 |
+
$attributes = $layer->getFilterableAttributes('price');
|
511 |
+
$resultFilters = array();
|
512 |
+
foreach ($attributes as $attribute) {
|
513 |
+
|
514 |
+
if ($attribute->getAttributeCode() == 'price') {
|
515 |
+
$filterBlockName = 'catalog/layer_filter_price';
|
516 |
+
} else {
|
517 |
+
$filterBlockName = 'catalog/layer_filter_attribute';
|
518 |
+
}
|
519 |
+
//$result = $this->getLayout()->createBlock($filterBlockName)->setLayer($layer)->setAttributeModel($attribute)->init();
|
520 |
+
$result = Highstreet_Hsapi_IndexController::getLayout()->createBlock($filterBlockName)->setLayer($layer)->setAttributeModel($attribute)->init();
|
521 |
+
$options = array();
|
522 |
+
foreach($result->getItems() as $option) {
|
523 |
+
$label = str_replace('<span class="price">', "", $option->getLabel());
|
524 |
+
$label = str_replace('</span>', "", $label);
|
525 |
+
|
526 |
+
$count = $option->getData('count');
|
527 |
+
array_push($options, array('filter' => $option->getValue(), 'label' => $label, 'product_count' => $count));
|
528 |
+
}
|
529 |
+
array_push($resultFilters, array($attribute->getAttributeCode() => $options));
|
530 |
+
}
|
531 |
+
|
532 |
+
return $resultFilters;
|
533 |
+
}
|
534 |
+
|
535 |
+
/**
|
536 |
+
*
|
537 |
+
* Gets attributes of a given product object.
|
538 |
+
*
|
539 |
+
* @param Mage_Catalog_Model_Product ResProduct, a product object
|
540 |
+
* @param string Attributes, an string of attributes to get for the product, comma delimited
|
541 |
+
* @param string Child_product_attributes, attributes for the child products, comma delimited
|
542 |
+
* @return array Array with information about the product, according to the Attributes array param
|
543 |
+
*
|
544 |
+
*/
|
545 |
+
|
546 |
+
private function _getProductAttributes($resProduct = false, $attributes = nil, $child_product_attributes) {
|
547 |
+
if (!$resProduct) {
|
548 |
+
return null;
|
549 |
+
}
|
550 |
+
|
551 |
+
|
552 |
+
if(empty($attributes)) {
|
553 |
+
$attributes = $this->_getSystemAttributes();
|
554 |
+
} else {
|
555 |
+
$attributes = explode(',', $attributes);
|
556 |
+
}
|
557 |
+
|
558 |
+
|
559 |
+
// if attributes specified
|
560 |
+
if (!empty($attributes) && count($attributes) > 0) {
|
561 |
+
foreach ($attributes as $attribute) {
|
562 |
+
|
563 |
+
//always set final price to the special price field
|
564 |
+
if ($attribute === "special_price" || $attribute === "final_price") {
|
565 |
+
$product[$attribute] = $resProduct->getFinalPrice(1);
|
566 |
+
|
567 |
+
if ($product[$attribute] === false) {
|
568 |
+
$product[$attribute] = null;
|
569 |
+
}
|
570 |
+
|
571 |
+
continue;
|
572 |
+
}
|
573 |
+
|
574 |
+
// Translate this into an array of "translations" if we run into more problems
|
575 |
+
$fieldName = $attribute;
|
576 |
+
if ($attribute == "type") {
|
577 |
+
$attribute = "type_id";
|
578 |
+
$fieldName = "type";
|
579 |
+
}
|
580 |
+
|
581 |
+
if ($resProduct->getResource()->getAttribute($attribute)) {
|
582 |
+
$value = $resProduct->getResource()->getAttribute($attribute)->getFrontend()->getValue($resProduct);
|
583 |
+
$product[$fieldName] = $value;
|
584 |
+
}
|
585 |
+
}
|
586 |
+
|
587 |
+
}
|
588 |
+
|
589 |
+
|
590 |
+
$product['id'] = $resProduct->getId();
|
591 |
+
|
592 |
+
|
593 |
+
//We will deprecate special_from_date and special_to_date soon, but for now we make sure that the special price is always applicable
|
594 |
+
//this is correct because special_price always has the value of the finalprice
|
595 |
+
$product["special_from_date"] = self::SPECIAL_PRICE_FROM_DATE_FALLBACK;
|
596 |
+
$product["special_to_date"] = null;
|
597 |
+
|
598 |
+
|
599 |
+
if (array_key_exists("special_price", $product) && array_key_exists("price", $product) && $product["special_price"] >= $product["price"]) {
|
600 |
+
$product["special_price"] = null;
|
601 |
+
}
|
602 |
+
|
603 |
+
|
604 |
+
|
605 |
+
|
606 |
+
if (in_array("is_salable", $attributes)) {
|
607 |
+
$product["is_salable"] = $resProduct->getData('is_salable');
|
608 |
+
}
|
609 |
+
|
610 |
+
|
611 |
+
|
612 |
+
if(in_array('configurable_attributes',$attributes)){
|
613 |
+
$this->_addConfigurableAttributes = true;
|
614 |
+
}
|
615 |
+
|
616 |
+
if(in_array('child_products',$attributes)){
|
617 |
+
$this->_addConfigurations = true;
|
618 |
+
}
|
619 |
+
|
620 |
+
if($resProduct->getTypeId() == 'configurable'){
|
621 |
+
$conf = Mage::getModel('catalog/product_type_configurable')->setProduct($resProduct);
|
622 |
+
|
623 |
+
//build the configuration_attributes array
|
624 |
+
$configurableAttributes = $conf->getConfigurableAttributesAsArray($resProduct);
|
625 |
+
|
626 |
+
$tmpConfigurableAttributes = array();
|
627 |
+
foreach($configurableAttributes as $attribute)
|
628 |
+
{
|
629 |
+
array_push($tmpConfigurableAttributes,$attribute['attribute_code']);
|
630 |
+
//array_push($simpleCollectionAttributes,$attribute['attribute_code']);
|
631 |
+
}
|
632 |
+
if($this->_addConfigurableAttributes == true){
|
633 |
+
$product['configurable_attributes'] = $tmpConfigurableAttributes;
|
634 |
+
}
|
635 |
+
|
636 |
+
//build the configuration_attributes array if we want to display these
|
637 |
+
if($this->_addConfigurations == true){
|
638 |
+
|
639 |
+
$product['child_products'] = array();
|
640 |
+
$simple_collection = $conf->getUsedProductCollection()
|
641 |
+
->addAttributeToSelect('*')
|
642 |
+
->addFilterByRequiredOptions();
|
643 |
+
|
644 |
+
foreach($simple_collection as $simple_product){
|
645 |
+
if(!Mage::getStoreConfig('cataloginventory/options/show_out_of_stock')
|
646 |
+
&& !$simple_product->isSaleable())
|
647 |
+
continue;
|
648 |
+
|
649 |
+
if(!$child_product_attributes)
|
650 |
+
$child_product_attributes = "entity_id,created_at,description,special_price,updated_at,image,sku,short_description,price,manufacturer";
|
651 |
+
|
652 |
+
$simpleProductRepresentation = $this->_getProductAttributes(Mage::getModel('catalog/product')->load($simple_product->getId()), $child_product_attributes);
|
653 |
+
$configuration = array();
|
654 |
+
|
655 |
+
|
656 |
+
foreach($tmpConfigurableAttributes as $attribute)
|
657 |
+
{
|
658 |
+
$method = 'get' . uc_words($attribute, '');
|
659 |
+
$configuration[$attribute] = $simple_product->$method();
|
660 |
+
}
|
661 |
+
|
662 |
+
$simpleProductRepresentation['configuration'] = $configuration;
|
663 |
+
array_push($product['child_products'],(object)$simpleProductRepresentation);
|
664 |
+
}
|
665 |
+
}
|
666 |
+
|
667 |
+
unset($tmpConfigurableAttributes);
|
668 |
+
}
|
669 |
+
|
670 |
+
$this->_convertProductDates($product);
|
671 |
+
|
672 |
+
$product = $this->_setImagePaths($product);
|
673 |
+
|
674 |
+
//media gallery
|
675 |
+
if(array_key_exists("media_gallery", $product)) {
|
676 |
+
$product["media_gallery"] = $this->_getMediaGalleryImagesForProductID($product["id"]);
|
677 |
+
}
|
678 |
+
|
679 |
+
return $product;
|
680 |
+
}
|
681 |
+
|
682 |
+
|
683 |
+
/**
|
684 |
+
* Converts product dates to timestamp
|
685 |
+
*
|
686 |
+
*/
|
687 |
+
private function _convertProductDates(& $product) {
|
688 |
+
|
689 |
+
if (!empty($product['created_at'])) {
|
690 |
+
$product['created_at'] = strtotime($product['created_at']);
|
691 |
+
}
|
692 |
+
if (!empty($product['updated_at'])) {
|
693 |
+
$product['updated_at'] = strtotime($product['updated_at']);
|
694 |
+
}
|
695 |
+
if (!empty($product['special_from_date'])) {
|
696 |
+
$product['special_from_date'] = strtotime($product['special_from_date']);
|
697 |
+
}
|
698 |
+
if (!empty($product['special_to_date'])) {
|
699 |
+
$product['special_to_date'] = strtotime($product['special_to_date']);
|
700 |
+
}
|
701 |
+
if (!empty($product['news_from_date'])) {
|
702 |
+
$product['news_from_date'] = strtotime($product['news_from_date']);
|
703 |
+
}
|
704 |
+
if (!empty($product['news_to_date'])) {
|
705 |
+
$product['news_to_date'] = strtotime($product['news_to_date']);
|
706 |
+
}
|
707 |
+
|
708 |
+
}
|
709 |
+
|
710 |
+
/**
|
711 |
+
* Load media gallery in collection
|
712 |
+
*/
|
713 |
+
private function _addMediaGalleryAttributeToCollection(Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $_productCollection) {
|
714 |
+
|
715 |
+
if (count($_productCollection == 0))
|
716 |
+
return $_productCollection;
|
717 |
+
|
718 |
+
$_mediaGalleryAttributeId = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'media_gallery')->getAttributeId();
|
719 |
+
$_read = Mage::getSingleton('core/resource')->getConnection('catalog_read');
|
720 |
+
|
721 |
+
$_mediaGalleryData = $_read->fetchAll('
|
722 |
+
SELECT
|
723 |
+
main.entity_id, `main`.`value_id`, `main`.`value` AS `file`,
|
724 |
+
`value`.`label`, `value`.`position`, `value`.`disabled`, `default_value`.`label` AS `label_default`,
|
725 |
+
`default_value`.`position` AS `position_default`,
|
726 |
+
`default_value`.`disabled` AS `disabled_default`
|
727 |
+
FROM `catalog_product_entity_media_gallery` AS `main`
|
728 |
+
LEFT JOIN `catalog_product_entity_media_gallery_value` AS `value`
|
729 |
+
ON main.value_id=value.value_id AND value.store_id=' . Mage::app()->getStore()->getId() . '
|
730 |
+
LEFT JOIN `catalog_product_entity_media_gallery_value` AS `default_value`
|
731 |
+
ON main.value_id=default_value.value_id AND default_value.store_id=0
|
732 |
+
WHERE (
|
733 |
+
main.attribute_id = ' . $_read->quote($_mediaGalleryAttributeId) . ')
|
734 |
+
AND (main.entity_id IN (' . $_read->quote($_productCollection->getAllIds()) . '))
|
735 |
+
ORDER BY IF(value.position IS NULL, default_value.position, value.position) ASC
|
736 |
+
');
|
737 |
+
|
738 |
+
|
739 |
+
$_mediaGalleryByProductId = array();
|
740 |
+
foreach ($_mediaGalleryData as $_galleryImage) {
|
741 |
+
$k = $_galleryImage['entity_id'];
|
742 |
+
unset($_galleryImage['entity_id']);
|
743 |
+
if (!isset($_mediaGalleryByProductId[$k])) {
|
744 |
+
$_mediaGalleryByProductId[$k] = array();
|
745 |
+
}
|
746 |
+
$_galleryImage['file'] = self::PRODUCTS_MEDIA_PATH . $_galleryImage['file'];
|
747 |
+
$_mediaGalleryByProductId[$k][] = $_galleryImage;
|
748 |
+
}
|
749 |
+
unset($_mediaGalleryData);
|
750 |
+
|
751 |
+
foreach ($_productCollection as &$_product) {
|
752 |
+
$_productId = $_product->getData('entity_id');
|
753 |
+
if (isset($_mediaGalleryByProductId[$_productId])) {
|
754 |
+
$_product->setData('media_gallery', array('images' => $_mediaGalleryByProductId[$_productId]));
|
755 |
+
}
|
756 |
+
}
|
757 |
+
unset($_mediaGalleryByProductId);
|
758 |
+
|
759 |
+
return $_productCollection;
|
760 |
+
}
|
761 |
+
|
762 |
+
/**
|
763 |
+
* Gets stock (voorraad) information about a certain product
|
764 |
+
*
|
765 |
+
* @param product A product
|
766 |
+
*
|
767 |
+
* @return array Array of stock data
|
768 |
+
*/
|
769 |
+
|
770 |
+
private function _getStockInformationForProduct($product) {
|
771 |
+
$stock = Mage::getModel('cataloginventory/stock_item')->loadByProduct($product);
|
772 |
+
$stockinfo = array();
|
773 |
+
|
774 |
+
$stockinfo['product_entity_id'] = $product->getId();
|
775 |
+
$stockinfo['quantity'] = $stock->getQty();
|
776 |
+
$stockinfo['is_in_stock'] = (boolean)$stock->getIsInStock();
|
777 |
+
$stockinfo['min_sale_quantity'] = $stock->getMinSaleQty();
|
778 |
+
$stockinfo['max_sale_quantity'] = $stock->getMaxSaleQty();
|
779 |
+
$stockinfo['manage_stock'] = (boolean)$stock->getManageStock();
|
780 |
+
$stockinfo['backorders'] = (boolean)$stock->getBackorders();
|
781 |
+
|
782 |
+
$stockinfo['quantity_increments'] = (boolean)$stock->getQtyIncrements();
|
783 |
+
$stockinfo['quantity_increments_value'] = (int)$stock->getQtyIncrements();
|
784 |
+
|
785 |
+
return $stockinfo;
|
786 |
+
}
|
787 |
+
|
788 |
+
/**
|
789 |
+
* Gets system attributes. This function is used when there are no attributes give as a param in the URL of the API call
|
790 |
+
*
|
791 |
+
* @return array Array with attribute names
|
792 |
+
*/
|
793 |
+
|
794 |
+
private function _getSystemAttributes() {
|
795 |
+
|
796 |
+
$entityTypeId = Mage::getModel('catalog/product')->getResource()->getEntityType()->getId();
|
797 |
+
|
798 |
+
// get only system attributes
|
799 |
+
$attributes = Mage::getResourceModel('eav/entity_attribute_collection')
|
800 |
+
->setEntityTypeFilter($entityTypeId)
|
801 |
+
->addFieldToFilter('main_table.is_user_defined', 0)
|
802 |
+
->addFieldToFilter('additional_table.is_visible', 1);
|
803 |
+
|
804 |
+
$attributeNames = array();
|
805 |
+
|
806 |
+
foreach($attributes as $attribute) {
|
807 |
+
$attributeNames[] = $attribute->getName();
|
808 |
+
}
|
809 |
+
|
810 |
+
return $attributeNames;
|
811 |
+
}
|
812 |
+
|
813 |
+
|
814 |
+
/**
|
815 |
+
* Sets the image paths properly with the relative path.
|
816 |
+
*
|
817 |
+
* @param product Array with product information
|
818 |
+
* @return product Same product, but with formatted image uri's
|
819 |
+
*/
|
820 |
+
private function _setImagePaths($product = false) {
|
821 |
+
if (!$product) {
|
822 |
+
return $product;
|
823 |
+
}
|
824 |
+
|
825 |
+
|
826 |
+
if (array_key_exists('image', $product) && !strstr($product['image'], self::PRODUCTS_MEDIA_PATH)) {
|
827 |
+
if($product['image'] != self::NO_IMAGE_PATH)
|
828 |
+
$product['image'] = self::PRODUCTS_MEDIA_PATH . $product['image'];
|
829 |
+
else
|
830 |
+
$product['image'] = null;
|
831 |
+
}
|
832 |
+
|
833 |
+
if (array_key_exists('thumbnail', $product) && !strstr($product['thumbnail'], self::PRODUCTS_MEDIA_PATH)) {
|
834 |
+
if($product['thumbnail'] != self::NO_IMAGE_PATH)
|
835 |
+
$product['thumbnail'] = self::PRODUCTS_MEDIA_PATH . $product['thumbnail'];
|
836 |
+
else
|
837 |
+
$product['thumbnail'] = null;
|
838 |
+
}
|
839 |
+
|
840 |
+
if (array_key_exists('small_image', $product) && !strstr($product['small_image'], self::PRODUCTS_MEDIA_PATH)) {
|
841 |
+
if($product['small_image'] != self::NO_IMAGE_PATH)
|
842 |
+
$product['small_image'] = self::PRODUCTS_MEDIA_PATH . $product['small_image'];
|
843 |
+
else
|
844 |
+
$product['small_image'] = null;
|
845 |
+
}
|
846 |
+
|
847 |
+
return $product;
|
848 |
+
}
|
849 |
+
|
850 |
+
/**
|
851 |
+
* Gets media gallery items for a given product id. Returns an array or media gallery items
|
852 |
+
*
|
853 |
+
* @param integer Product ID, ID of a product to get media gallery images for
|
854 |
+
* @return array Array of media gallery items
|
855 |
+
*/
|
856 |
+
|
857 |
+
public function _getMediaGalleryImagesForProductID($productId = null) {
|
858 |
+
if (!$productId) {
|
859 |
+
return null;
|
860 |
+
}
|
861 |
+
|
862 |
+
$output = array();
|
863 |
+
|
864 |
+
foreach (Mage::getModel('catalog/product')->load($productId)->getMediaGalleryImages()->getItems() as $key => $value) {
|
865 |
+
$imageData = $value->getData();
|
866 |
+
if (array_key_exists('file', $imageData) && !strstr($imageData['file'], self::PRODUCTS_MEDIA_PATH)) {
|
867 |
+
$imageData['file'] = self::PRODUCTS_MEDIA_PATH . $imageData['file'];
|
868 |
+
}
|
869 |
+
unset($imageData["path"]);
|
870 |
+
unset($imageData["url"]);
|
871 |
+
unset($imageData["id"]);
|
872 |
+
$output[] = $imageData;
|
873 |
+
}
|
874 |
+
|
875 |
+
return array("images" => $output);
|
876 |
+
}
|
877 |
+
|
878 |
+
|
879 |
+
|
880 |
+
}
|
app/code/local/Highstreet/Hsapi/Model/SearchSuggestions.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com)
|
7 |
+
* @copyright Copyright (c) 2014 Touchwonders (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
class Highstreet_Hsapi_Model_SearchSuggestions extends Mage_Core_Model_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Can take params for category, limit and search query. It manually takes those params from the URL
|
13 |
+
*
|
14 |
+
* @param integer Limit, limit for the results
|
15 |
+
* @param string Search, search query
|
16 |
+
* @param integer Category, limit results to category
|
17 |
+
* @return array Search suggestions
|
18 |
+
*/
|
19 |
+
public function getSearchSuggestions($paramLimit, $paramSearch, $paramCategory) {
|
20 |
+
// Initialize search object
|
21 |
+
$searchModel= Mage::getModel('catalogsearch/query');
|
22 |
+
|
23 |
+
$searchCollection = $searchModel->getCollection();
|
24 |
+
$searchCollection->addOrder('popularity', 'DESC'); // Order on popularity
|
25 |
+
|
26 |
+
// Set limit
|
27 |
+
$limit = 10;
|
28 |
+
if (!empty($paramLimit)) {
|
29 |
+
$limit = $paramLimit;
|
30 |
+
}
|
31 |
+
|
32 |
+
// Limit data to search term
|
33 |
+
if (!empty($paramSearch)) {
|
34 |
+
$searchCollection->addFieldToFilter('query_text', array("like" => $paramSearch . "%"));
|
35 |
+
}
|
36 |
+
|
37 |
+
$searchCollection->addFieldToFilter('store_id', Mage::app()->getStore()->getId());
|
38 |
+
|
39 |
+
|
40 |
+
$searchCollection->addFieldToFilter('display_in_terms', 1);
|
41 |
+
|
42 |
+
// Get data
|
43 |
+
$searchCollection->getSelect()->limit($limit);
|
44 |
+
|
45 |
+
$searchSuggestionData = array();
|
46 |
+
|
47 |
+
foreach ($searchCollection as $item) {
|
48 |
+
$searchSuggestionData["search_suggestions"][]["search_term"] = (string)$item->getData("query_text");
|
49 |
+
}
|
50 |
+
|
51 |
+
if (count($searchSuggestionData["search_suggestions"]) < 1) {
|
52 |
+
$searchSuggestionData["search_suggestions"][] = "";
|
53 |
+
}
|
54 |
+
|
55 |
+
return $searchSuggestionData;
|
56 |
+
}
|
57 |
+
|
58 |
+
}
|
app/code/local/Highstreet/Hsapi/controllers/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/controllers/IndexController.php
ADDED
@@ -0,0 +1,414 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Highstreet_HSAPI_module
|
4 |
+
*
|
5 |
+
* @package Highstreet_Hsapi
|
6 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
7 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
8 |
+
*/
|
9 |
+
|
10 |
+
class Highstreet_Hsapi_IndexController extends Mage_Core_Controller_Front_Action
|
11 |
+
{
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @return Highstreet_Hsapi_Helper_Data
|
15 |
+
*/
|
16 |
+
private function _getHelper()
|
17 |
+
{
|
18 |
+
return Mage::helper('highstreet_hsapi/data');
|
19 |
+
}
|
20 |
+
|
21 |
+
/** Disable actions */
|
22 |
+
public function indexAction() {
|
23 |
+
return false;
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Get CMS page call
|
28 |
+
*
|
29 |
+
* Examples:
|
30 |
+
* {url}?page_id=12
|
31 |
+
* {url}?content_key=home
|
32 |
+
* {url}?page_ids[title-1]=10&page_ids[title-2]=11&page_ids[title-3]=12
|
33 |
+
* {url}?content_keys[title-1]=home&content_keys[title-2]=home-2&content_keys[title-3]=home-3
|
34 |
+
*
|
35 |
+
*/
|
36 |
+
public function pageAction() {
|
37 |
+
|
38 |
+
$pageId = Mage::app()->getRequest()->getParam('page_id');
|
39 |
+
$contentKey = Mage::app()->getRequest()->getParam('content_key');
|
40 |
+
|
41 |
+
$pageIds = Mage::app()->getRequest()->getParam('page_ids');
|
42 |
+
$contentKeys = Mage::app()->getRequest()->getParam('content_keys');
|
43 |
+
|
44 |
+
if (($pageId === null && $contentKey === null) &&
|
45 |
+
($pageIds === null && $contentKeys === null)) {
|
46 |
+
$this->_JSONencodeAndRespond(array("title" => "Error", "content" => "No arguments found"));
|
47 |
+
} else if ($pageId !== null || $contentKey !== null) {
|
48 |
+
$page = Mage::getModel('cms/page');
|
49 |
+
$page->setStoreId(Mage::app()->getStore()->getId());
|
50 |
+
if ($pageId !== null) {
|
51 |
+
$page->load($pageId);
|
52 |
+
} else if ($contentKey !== null) {
|
53 |
+
$page->load($contentKey, 'identifier');
|
54 |
+
}
|
55 |
+
$this->_JSONencodeAndRespond(array("title" => $page->getData('title'), "content" => $page->getData('content')));
|
56 |
+
} else if ($pageIds !== null || $contentKeys !== null) {
|
57 |
+
$page = Mage::getModel('cms/page');
|
58 |
+
$page->setStoreId(Mage::app()->getStore()->getId());
|
59 |
+
|
60 |
+
$response = array();
|
61 |
+
if ($pageIds !== null) {
|
62 |
+
foreach ($pageIds as $key => $value) {
|
63 |
+
try {
|
64 |
+
$page->load($value, 'identifier');
|
65 |
+
$response[$key] = array("title" => $page->getData('title'), "content" => $page->getData('content'));
|
66 |
+
} catch (Exception $e) {
|
67 |
+
$response[$key] = array("title" => "Page not found", "content" => "");
|
68 |
+
}
|
69 |
+
}
|
70 |
+
} else if ($contentKeys !== null) {
|
71 |
+
foreach ($contentKeys as $key => $value) {
|
72 |
+
try {
|
73 |
+
$page->load($value, 'identifier');
|
74 |
+
$response[$key] = array("title" => $page->getData('title'), "contentKey" => $value, "content" => $page->getData('content'));
|
75 |
+
} catch (Exception $e) {
|
76 |
+
$response[$key] = array("title" => "Page not found", "content" => "");
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
$this->_JSONencodeAndRespond($response);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
public function pingAction() {
|
86 |
+
$this->_JSONencodeAndRespond(array("OK"));
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Categories
|
91 |
+
*/
|
92 |
+
public function categoryAction()
|
93 |
+
{
|
94 |
+
return $this->categoriesAction();
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Categories action
|
99 |
+
*/
|
100 |
+
public function categoriesAction()
|
101 |
+
{
|
102 |
+
//Get categoryId and check
|
103 |
+
$categoryId = Mage::app()->getRequest()->getParam('id');
|
104 |
+
|
105 |
+
$categories = null;
|
106 |
+
$categoryModel = Mage::getModel('highstreet_hsapi/categories');
|
107 |
+
|
108 |
+
if ($categoryId === 'tree') {
|
109 |
+
$categories = $categoryModel->getCategoryTree();
|
110 |
+
} else if(!$categoryId || $categoryId !== '') {
|
111 |
+
$categories = $categoryModel->getCategories($categoryId);
|
112 |
+
}
|
113 |
+
|
114 |
+
if($categories == null) {
|
115 |
+
$this->_respondWith404();
|
116 |
+
return false;
|
117 |
+
}
|
118 |
+
|
119 |
+
$this->_JSONencodeAndRespond($categories);
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Category Products action. (A proxy for Products)
|
124 |
+
*/
|
125 |
+
public function categoryProductsAction()
|
126 |
+
{
|
127 |
+
return $this->productsAction();
|
128 |
+
}
|
129 |
+
|
130 |
+
public function checkoutAction() {
|
131 |
+
$requestObject = Mage::app()->getRequest();
|
132 |
+
$data = json_decode($requestObject->getParam('products'), true);
|
133 |
+
|
134 |
+
$checkoutModel = Mage::getModel('highstreet_hsapi/checkout');
|
135 |
+
$checkoutModel->fillCartWithProductsAndQuantities($data["checkout"]);
|
136 |
+
|
137 |
+
$locale = Mage::app()->getLocale()->getLocaleCode();
|
138 |
+
|
139 |
+
$country = $requestObject->getParam('country');
|
140 |
+
$country = preg_replace("/[^a-zA-Z]/", "", $country);
|
141 |
+
$country = strtoupper($country);
|
142 |
+
|
143 |
+
if ($country === "") { // No country given in URL, fallback on store country from locale
|
144 |
+
$locale = Mage::app()->getLocale()->getLocaleCode();
|
145 |
+
$country = strtoupper(substr($locale, strpos($locale, "_")+1));
|
146 |
+
}
|
147 |
+
|
148 |
+
Mage::getSingleton('core/session')->setHSCheckoutCountry($country);
|
149 |
+
|
150 |
+
$urlOptions = array();
|
151 |
+
if (!empty($_SERVER['HTTPS'])) { // Server is not HTTPS
|
152 |
+
$urlOptions['_secure'] = TRUE;
|
153 |
+
}
|
154 |
+
|
155 |
+
$config = Mage::helper('highstreet_hsapi/config');
|
156 |
+
$checkoutUrl = $config->checkoutUrl();
|
157 |
+
|
158 |
+
Mage::app()->getFrontController()->getResponse()->setRedirect(Mage::getUrl($checkoutUrl, $urlOptions));
|
159 |
+
}
|
160 |
+
|
161 |
+
|
162 |
+
public function cartAction() {
|
163 |
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
164 |
+
return $this->postCart();
|
165 |
+
}
|
166 |
+
else if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
167 |
+
return $this->getCart();
|
168 |
+
}
|
169 |
+
|
170 |
+
}
|
171 |
+
|
172 |
+
|
173 |
+
public function postCart() {
|
174 |
+
$requestObject = Mage::app()->getRequest();
|
175 |
+
$data = json_decode($requestObject->getParam('products'), true);
|
176 |
+
|
177 |
+
$checkoutModel = Mage::getModel('highstreet_hsapi/checkout');
|
178 |
+
$cart = $checkoutModel->getQuoteWithProductsAndQuantities($data["checkout"]);
|
179 |
+
|
180 |
+
$this->_JSONencodeAndRespond($cart);
|
181 |
+
|
182 |
+
}
|
183 |
+
|
184 |
+
public function getCart() {
|
185 |
+
$requestObject = Mage::app()->getRequest();
|
186 |
+
$quote_id = $requestObject->getParam('quote_id');
|
187 |
+
if(!$quote_id) {
|
188 |
+
$this->_respondWith404();
|
189 |
+
return false;
|
190 |
+
}
|
191 |
+
|
192 |
+
$checkoutModel = Mage::getModel('highstreet_hsapi/checkout');
|
193 |
+
$cart = $checkoutModel->getQuoteWithProductsAndQuantities(null,$quote_id);
|
194 |
+
|
195 |
+
$this->_JSONencodeAndRespond($cart);
|
196 |
+
|
197 |
+
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Get single product
|
202 |
+
*/
|
203 |
+
public function productAction()
|
204 |
+
{
|
205 |
+
$requestObject = Mage::app()->getRequest();
|
206 |
+
$model = Mage::getModel('highstreet_hsapi/products');
|
207 |
+
|
208 |
+
$id = $requestObject->getParam('id');
|
209 |
+
$attributes = $requestObject->getParam('attributes');
|
210 |
+
$child_product_attributes = $requestObject->getParam('child_product_attributes');
|
211 |
+
|
212 |
+
$response = $model->getSingleProduct($id, $attributes,$child_product_attributes);
|
213 |
+
|
214 |
+
if ($response == null) {
|
215 |
+
$this->_respondWith404();
|
216 |
+
return false;
|
217 |
+
}
|
218 |
+
|
219 |
+
$this->_JSONencodeAndRespond($response);
|
220 |
+
}
|
221 |
+
|
222 |
+
/*
|
223 |
+
* Returns stock information for a given product
|
224 |
+
*/
|
225 |
+
public function stockAction()
|
226 |
+
{
|
227 |
+
$requestObject = Mage::app()->getRequest();
|
228 |
+
$model = Mage::getModel('highstreet_hsapi/products');
|
229 |
+
|
230 |
+
$stockinfo = $model->getStockInfo($requestObject->getParam('id'));
|
231 |
+
|
232 |
+
if ($stockinfo == null) {
|
233 |
+
$this->_respondWith404();
|
234 |
+
return false;
|
235 |
+
}
|
236 |
+
|
237 |
+
$response = array();
|
238 |
+
$response["stock"] = $stockinfo;
|
239 |
+
|
240 |
+
|
241 |
+
$this->_JSONencodeAndRespond($response);
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Get multiple products based on a category
|
246 |
+
*/
|
247 |
+
public function productsAction()
|
248 |
+
{
|
249 |
+
$requestObject = Mage::app()->getRequest();
|
250 |
+
$model = Mage::getModel('highstreet_hsapi/products');
|
251 |
+
|
252 |
+
$products = $model->getProductsForResponse($requestObject->getParam('attributes'),
|
253 |
+
$requestObject->getParam('child_product_attributes'),
|
254 |
+
$requestObject->getParam('order'),
|
255 |
+
$requestObject->getParam('range'),
|
256 |
+
$requestObject->getParam('filter'),
|
257 |
+
$requestObject->getParam('search'),
|
258 |
+
$requestObject->getParam('id'));
|
259 |
+
|
260 |
+
if ($products == null) {
|
261 |
+
$this->_respondWith404();
|
262 |
+
return false;
|
263 |
+
}
|
264 |
+
|
265 |
+
$this->_JSONencodeAndRespond($products);
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Get a batch of products based on product ids
|
270 |
+
*/
|
271 |
+
|
272 |
+
public function batchProductsAction()
|
273 |
+
{
|
274 |
+
$requestObject = Mage::app()->getRequest();
|
275 |
+
$model = Mage::getModel('highstreet_hsapi/products');
|
276 |
+
|
277 |
+
$products = $model->getBatchProducts($requestObject->getParam('ids'),
|
278 |
+
$requestObject->getParam('attributes'),
|
279 |
+
$requestObject->getParam('child_product_attributes'));
|
280 |
+
|
281 |
+
if ($products == null) {
|
282 |
+
$this->_respondWith404();
|
283 |
+
return false;
|
284 |
+
}
|
285 |
+
|
286 |
+
$this->_JSONencodeAndRespond($products);
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* Returns related / cross-sell / up-sell products
|
291 |
+
*/
|
292 |
+
public function relatedProductsAction()
|
293 |
+
{
|
294 |
+
$requestObject = Mage::app()->getRequest();
|
295 |
+
$productsModel = Mage::getModel('highstreet_hsapi/products');
|
296 |
+
|
297 |
+
$response = $productsModel->getRelatedProducts($requestObject->getParam('type'),
|
298 |
+
$requestObject->getParam('id'),
|
299 |
+
$requestObject->getParam('attributes'),
|
300 |
+
$requestObject->getParam('child_product_attributes'),
|
301 |
+
$requestObject->getParam('range'));
|
302 |
+
|
303 |
+
if ($response == null) {
|
304 |
+
$this->_respondWith404();
|
305 |
+
return false;
|
306 |
+
}
|
307 |
+
|
308 |
+
$this->_JSONencodeAndRespond($response);
|
309 |
+
}
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Media
|
313 |
+
*/
|
314 |
+
public function imagesAction() {
|
315 |
+
$requestObject = $this->getRequest();
|
316 |
+
|
317 |
+
$imageUrl = Mage::getModel('highstreet_hsapi/images')->getImage(urldecode($requestObject->getParam('src')), $requestObject->getParam('size'));
|
318 |
+
|
319 |
+
if ($imageUrl === null || !file_exists($imageUrl)) {
|
320 |
+
$this->_respondWith404();
|
321 |
+
return false;
|
322 |
+
}
|
323 |
+
|
324 |
+
$this->getResponse()->setHeader('Content-Type', $this->_getHelper()->imageHeaderStringForImage($imageUrl), true);
|
325 |
+
$this->getResponse()->setBody(file_get_contents($imageUrl));
|
326 |
+
}
|
327 |
+
|
328 |
+
|
329 |
+
/**
|
330 |
+
* attributes
|
331 |
+
*/
|
332 |
+
public function attributesAction()
|
333 |
+
{
|
334 |
+
$helper = $this->_getHelper();
|
335 |
+
$attributesModel = Mage::getModel('highstreet_hsapi/attributes');
|
336 |
+
|
337 |
+
/** @var $params */
|
338 |
+
$params = $helper->extractRequestParam(Mage::app()->getRequest()->getParams());
|
339 |
+
|
340 |
+
if(is_string($params))
|
341 |
+
{
|
342 |
+
//get Single Attribute
|
343 |
+
$attributes = $attributesModel->getAttribute($params);
|
344 |
+
$responseBody = $attributes;
|
345 |
+
}
|
346 |
+
else{
|
347 |
+
//Get all attributes
|
348 |
+
$attributes = $attributesModel->getAttributes();
|
349 |
+
$responseBody = $attributes;
|
350 |
+
}
|
351 |
+
|
352 |
+
if($attributes == null){
|
353 |
+
$this->_respondWith404();
|
354 |
+
return false;
|
355 |
+
}
|
356 |
+
|
357 |
+
$this->_JSONencodeAndRespond($responseBody);
|
358 |
+
}
|
359 |
+
|
360 |
+
/**
|
361 |
+
* Returns search suggestions
|
362 |
+
* http://docs.test.touchwonders.com/highstreet/#api-Search-Search_suggestions
|
363 |
+
*
|
364 |
+
* @author Tim Wachter
|
365 |
+
*
|
366 |
+
*/
|
367 |
+
public function searchsuggestionsAction() {
|
368 |
+
$requestObject = Mage::app()->getRequest();
|
369 |
+
$searchModel = Mage::getModel('highstreet_hsapi/searchSuggestions');
|
370 |
+
|
371 |
+
$response = $searchModel->getSearchSuggestions($requestObject->getParam('limit'), $requestObject->getParam('search'), $requestObject->getParam('category'));
|
372 |
+
|
373 |
+
if($response == null){
|
374 |
+
$this->_respondWith404();
|
375 |
+
return false;
|
376 |
+
}
|
377 |
+
|
378 |
+
$this->_JSONencodeAndRespond($response, FALSE);
|
379 |
+
}
|
380 |
+
|
381 |
+
/**
|
382 |
+
* Header and http functions
|
383 |
+
*/
|
384 |
+
private function _respondWith404()
|
385 |
+
{
|
386 |
+
$this->getResponse()->setHeader('HTTP/1.1','404 Not Found');
|
387 |
+
$this->getResponse()->sendHeaders();
|
388 |
+
return;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Sets the proper headers
|
393 |
+
*/
|
394 |
+
private function _setHeader()
|
395 |
+
{
|
396 |
+
Mage::getSingleton('core/session')->setLastStoreCode(Mage::app()->getStore()->getCode());
|
397 |
+
header_remove('Pragma'); // removes 'no-cache' header
|
398 |
+
$this->getResponse()->setHeader('Content-Type','application/json', true);
|
399 |
+
}
|
400 |
+
|
401 |
+
/**
|
402 |
+
* Sets headers and body with proper JSON encoding
|
403 |
+
*/
|
404 |
+
private function _JSONencodeAndRespond($data, $numeric_check = TRUE) {
|
405 |
+
//set response body
|
406 |
+
$this->_setHeader();
|
407 |
+
if ($numeric_check === FALSE) {
|
408 |
+
$this->getResponse()->setBody(json_encode($data));
|
409 |
+
} else {
|
410 |
+
$this->getResponse()->setBody(json_encode($data, JSON_NUMERIC_CHECK));
|
411 |
+
}
|
412 |
+
}
|
413 |
+
|
414 |
+
}
|
app/code/local/Highstreet/Hsapi/etc/.DS_Store
ADDED
Binary file
|
app/code/local/Highstreet/Hsapi/etc/Configuration.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"filters_categories": true,
|
3 |
+
}
|
app/code/local/Highstreet/Hsapi/etc/config.xml
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* Highstreet_HSAPI_module
|
5 |
+
*
|
6 |
+
* @package Highstreet_Hsapi
|
7 |
+
* @author Tim Wachter (tim@touchwonders.com) ~ Touchwonders
|
8 |
+
* @copyright Copyright (c) 2013 Touchwonders b.v. (http://www.touchwonders.com/)
|
9 |
+
*/
|
10 |
+
-->
|
11 |
+
<config>
|
12 |
+
<modules>
|
13 |
+
<Highstreet_Hsapi>
|
14 |
+
<version>1.0.0</version>
|
15 |
+
</Highstreet_Hsapi>
|
16 |
+
</modules>
|
17 |
+
<frontend>
|
18 |
+
<routers>
|
19 |
+
<hsapi>
|
20 |
+
<use>standard</use>
|
21 |
+
<args>
|
22 |
+
<module>Highstreet_Hsapi</module>
|
23 |
+
<frontName>hsapi</frontName>
|
24 |
+
</args>
|
25 |
+
</hsapi>
|
26 |
+
</routers>
|
27 |
+
<translate>
|
28 |
+
<modules>
|
29 |
+
<Highstreet_Hsapi>
|
30 |
+
<files>
|
31 |
+
<default>Highstreet_Hsapi.csv</default>
|
32 |
+
</files>
|
33 |
+
</Highstreet_Hsapi>
|
34 |
+
</modules>
|
35 |
+
</translate>
|
36 |
+
<layout>
|
37 |
+
<updates>
|
38 |
+
<hsapi>
|
39 |
+
<file>highstreet/checkout.xml</file>
|
40 |
+
</hsapi>
|
41 |
+
</updates>
|
42 |
+
</layout>
|
43 |
+
</frontend>
|
44 |
+
<global>
|
45 |
+
<models>
|
46 |
+
<highstreet_hsapi>
|
47 |
+
<class>Highstreet_Hsapi_Model</class>
|
48 |
+
</highstreet_hsapi>
|
49 |
+
</models>
|
50 |
+
<helpers>
|
51 |
+
<highstreet_hsapi>
|
52 |
+
<class>Highstreet_Hsapi_Helper</class>
|
53 |
+
</highstreet_hsapi>
|
54 |
+
</helpers>
|
55 |
+
<blocks>
|
56 |
+
<highstreet_hsapi>
|
57 |
+
<class>Highstreet_Hsapi_Block</class>
|
58 |
+
</highstreet_hsapi>
|
59 |
+
</blocks>
|
60 |
+
<resources>
|
61 |
+
<highstreet_hsapi_setup>
|
62 |
+
<setup>
|
63 |
+
<module>Highstreet_Hsapi</module>
|
64 |
+
</setup>
|
65 |
+
</highstreet_hsapi_setup>
|
66 |
+
</resources>
|
67 |
+
<events>
|
68 |
+
<sales_quote_merge_before>
|
69 |
+
<observers>
|
70 |
+
<highstreet_hsapi_merge_quote>
|
71 |
+
<type>singleton</type>
|
72 |
+
<class>Highstreet_Hsapi_Model_Observer</class>
|
73 |
+
<method>mergeQuote</method>
|
74 |
+
</highstreet_hsapi_merge_quote>
|
75 |
+
</observers>
|
76 |
+
</sales_quote_merge_before>
|
77 |
+
</events>
|
78 |
+
</global>
|
79 |
+
</config>
|
app/etc/modules/Highstreet_Api.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
|
3 |
+
<config>
|
4 |
+
<modules>
|
5 |
+
<Highstreet_Hsapi>
|
6 |
+
<active>true</active>
|
7 |
+
<codePool>local</codePool>
|
8 |
+
</Highstreet_Hsapi>
|
9 |
+
</modules>
|
10 |
+
</config>
|
app/etc/modules/Technooze_Timage.xml
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category Technooze/Modules/magento-how-tos
|
5 |
+
* @package Technooze_Timage
|
6 |
+
* @author Damodar Bashyal
|
7 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
8 |
+
*/
|
9 |
+
-->
|
10 |
+
<config>
|
11 |
+
<modules>
|
12 |
+
<Technooze_Timage>
|
13 |
+
<active>true</active>
|
14 |
+
<codePool>community</codePool>
|
15 |
+
</Technooze_Timage>
|
16 |
+
</modules>
|
17 |
+
</config>
|
app/locale/en_US/Highstreet_Hsapi.csv
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"Welcome", "Welcome"
|
2 |
+
"Billing address", "Billing address"
|
3 |
+
"Shipment", "Shipment"
|
4 |
+
"Payment", "Payment"
|
5 |
+
"Confirmation", "Confirmation"
|
6 |
+
"Log out", "Log out"
|
7 |
+
"Confirm and pay", "Confirm and pay"
|
8 |
+
"Your order is not final yet", "Your order is not final yet"
|
9 |
+
"You will continue to our secure payment page", "You will continue to our secure payment page"
|
10 |
+
"Hello!", "Hello!"
|
11 |
+
"Checkout as guest", "Checkout as guest"
|
12 |
+
"Log in", "Log in"
|
13 |
+
"hsapi_Register", "Register"
|
14 |
+
"Sign In", "Sign In"
|
15 |
+
"E-mail address", "E-mail address"
|
16 |
+
"ipad_Password", "Password"
|
17 |
+
"Forgot your password?", "Forgot your password?"
|
18 |
+
"Send", "Send"
|
19 |
+
"We have sent you an e-mail with which you can change your password.", "We have sent you an e-mail with which you can change your password."
|
20 |
+
"Create an account now", "Create an account now"
|
21 |
+
"and checkout faster next time", "and checkout faster next time"
|
22 |
+
"Please enter a valid e-mailaddress", "Please enter a valid e-mailaddress"
|
23 |
+
"Please enter a valid password", "Please enter a valid password"
|
24 |
+
"Repeat the password", "Repeat the password"
|
25 |
+
"First Name", "First Name"
|
26 |
+
"Last Name", "Last Name"
|
27 |
+
"Please enter a valid phone number.", "Please enter a valid phone number."
|
28 |
+
"Phone number", "Phone number"
|
29 |
+
"We ask for your phone number so that we can call you about your order if need be. We will never use your telephone number for other purposes.", "We ask for your phone number so that we can call you about your order if need be. We will never use your telephone number for other purposes."
|
30 |
+
"Street", "Street"
|
31 |
+
"House number", "House number"
|
32 |
+
"Zip code", "Zip code"
|
33 |
+
"City", "City"
|
34 |
+
"Something went wrong", "Something went wrong"
|
35 |
+
"Please try again", "Please try again"
|
36 |
+
"How do you want to pay for your order?", "How do you want to pay for your order?"
|
37 |
+
"Please check your order.", "Please check your order."
|
38 |
+
"Please check the order overview. If this is correct, you can place your order.", "Please check the order overview. If this is correct, you can place your order."
|
39 |
+
"How do you want to receive your order?", "How do you want to receive your order?"
|
40 |
+
"Invoice address / delivery address", "Invoice address / delivery address"
|
41 |
+
"Edit", "Edit"
|
42 |
+
"Delivery method", "Delivery method"
|
43 |
+
"Payment method", "Payment method"
|
44 |
+
"You can continue to the next step when you have entered all fields", "You can continue to the next step when you have entered all fields"
|
45 |
+
"There has been an unknown error. Please try again later again later.", "There has been an unknown error. Please try again later again later."
|
46 |
+
"Thanks for shopping at ", "Thanks for shopping at "
|
47 |
+
".<span class='hidden'>_ORDER_TEXT</span>", ".<span class='hidden'>_ORDER_TEXT</span>"
|
48 |
+
"When you tap 'Confirm and pay', you agree with ", "When you tap `Confirm and pay`, you agree with "
|
49 |
+
"the general terms", "the general terms"
|
50 |
+
" of ", " of "
|
51 |
+
"Ship to the same address", "Ship to the same address"
|
52 |
+
"Invoice address", "Invoice address"
|
53 |
+
"Delivery address", "Delivery address"
|
54 |
+
"Please make sure your passwords match.", "Please make sure your passwords match."
|
55 |
+
"Something went wrong while trying to get your address trough your zip code and house number. Please fill in your street and city manually.", "Er is iets fout gegaan met het ophalen van het adres via postcode en huisnummer. Vul het adres handmatig in."
|
56 |
+
"Street name is being retrieved", "Street name is being retrieved"
|
57 |
+
"City name is being retrieved", "City name is being retrieved"
|
58 |
+
|
59 |
+
"hsapi.index.couponTip", "Do you have a coupon code?<br />You can add your code on the<br />'payment' step."
|
60 |
+
|
61 |
+
"hsapi.addCouponAction.error.fatal", "An unexpected error has occurred, please try again later."
|
62 |
+
"hsapi.addCouponAction.error.invalid", "The coupon code you entered is invalid or has expired."
|
63 |
+
"hsapi.addCouponAction.error.length", "The coupon code you entered is too long, the maximum length is "
|
64 |
+
"hsapi.addCouponAction.success", "Kortingsbon '{coupon_code}' is succesvol toegepast. In je bestellijst kun je je korting bekijken."
|
65 |
+
"hsapi.addCouponAction.success.removed", "Kortingsbon '{coupon_code}' is succesvol verwijdert."
|
66 |
+
|
67 |
+
"hsapi.checkout.coupon.addTitle", "Add a <u>coupon code</u>"
|
68 |
+
"hsapi.checkout.coupon.form.title", "Here you can fill in your coupon code."
|
69 |
+
"hsapi.checkout.coupon.form.code", "Coupon code"
|
70 |
+
"hsapi.checkout.coupon.form.add", "Add"
|
71 |
+
"hsapi.checkout.coupon.form.remove", "Remove"
|
72 |
+
"hsapi.checkout.coupon.paymentTitle", "Choose one of the payment options"
|
73 |
+
|
74 |
+
"hsapi.checkout.payment.acceptAfterpayTermsText", "You have to accept the terms and conditions of AfterPay to use this payment method"
|
75 |
+
|
76 |
+
"hsapi.checkout.billing.error.email", "Please enter a valid e-mailaddress"
|
77 |
+
|
78 |
+
|
79 |
+
"There is already a customer registered using this email address. Please login using this email address or enter a different email address to register your account.", "The entered email address is already linked to an account. Please login instead or use a different email address for registration."
|
80 |
+
|
81 |
+
'"%s" is not a valid email address.', "hsapi.checkout.email.error"
|
82 |
+
'"%s" is not a valid hostname.', "hsapi.checkout.email.error"
|
83 |
+
'"%s" exceeds the allowed length.', "hsapi.checkout.email.error"
|
84 |
+
"'%value%' appears to be an IP address, but IP addresses are not allowed", "hsapi.checkout.email.error"
|
85 |
+
"'%value%' appears to be a DNS hostname but cannot match TLD against known list", "hsapi.checkout.email.error"
|
86 |
+
"'%value%' appears to be a DNS hostname but contains a dash in an invalid position", "hsapi.checkout.email.error"
|
87 |
+
"'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", "hsapi.checkout.email.error"
|
88 |
+
"'%value%' appears to be a DNS hostname but cannot extract TLD part", "hsapi.checkout.email.error"
|
89 |
+
"'%value%' does not appear to be a valid local network name", "hsapi.checkout.email.error"
|
90 |
+
"'%value%' appears to be a local network name but local network names are not allowed", "hsapi.checkout.email.error"
|
91 |
+
"'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", "hsapi.checkout.email.error"
|
92 |
+
|
93 |
+
|
app/locale/nl_NL/Highstreet_Hsapi.csv
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"Welcome", "Welkom"
|
2 |
+
"Billing address", "Factuuradres"
|
3 |
+
"Shipment", "Verzending"
|
4 |
+
"Payment", "Betaalwijze"
|
5 |
+
"Confirmation", "Bevestiging"
|
6 |
+
"Log out", "Log uit"
|
7 |
+
"Confirm and pay", "Bevestig en betaal"
|
8 |
+
"Your order is not final yet", "Je bestelling is nog niet definitief"
|
9 |
+
"You will continue to our secure payment page", "Je gaat door naar onze beveiligde betaalomgeving"
|
10 |
+
"Hello!", "Hallo!"
|
11 |
+
"Checkout as guest", "Reken af als gast"
|
12 |
+
"Log in", "Log in"
|
13 |
+
"hsapi_Register", "Registreer"
|
14 |
+
"Sign In", "Sign In"
|
15 |
+
"E-mail address", "E-mailadres"
|
16 |
+
"ipad_Password", "Wachtwoord"
|
17 |
+
"Forgot your password?", "Wachtwoord vergeten?"
|
18 |
+
"Send", "Verzenden"
|
19 |
+
"We have sent you an e-mail with which you can change your password.", "Er is een e-mail naar het door u opgegeven adres gestuurd waarmee u uw wachtwoord kunt veranderen."
|
20 |
+
"Create an account now", "Maak een account aan"
|
21 |
+
"and checkout faster next time", "en bestel de volgende keer makkelijker"
|
22 |
+
"Please enter a valid e-mailaddress", "Vul een geldig e-mail adres in"
|
23 |
+
"Please enter a valid password", "Vul een geldig wachtwoord in"
|
24 |
+
"Repeat the password", "Herhaal wachtwoord"
|
25 |
+
"First Name", "Voornaam"
|
26 |
+
"Last Name", "Achternaam"
|
27 |
+
"Please enter a valid phone number.", "Vul een geldig telefoonnummer in"
|
28 |
+
"Phone number", "Telefoonnummer"
|
29 |
+
"We ask for your phone number so that we can call you about your order if need be. We will never use your telephone number for other purposes.", "We vragen om een telefoonnummer zodat we je indien nodig kunnen bellen over de bestelling. We zullen je telefoonnummer nooit gebruiken voor andere doeleinden."
|
30 |
+
"Street", "Straat"
|
31 |
+
"House number", "Huisnummer"
|
32 |
+
"Zip code", "Postcode"
|
33 |
+
"City", "Plaats"
|
34 |
+
"Something went wrong", "Er is iets mis gegaan"
|
35 |
+
"Please try again", "Probeer het opnieuw"
|
36 |
+
"How do you want to pay for your order?", "Hoe wil je je bestelling<br />betalen?"
|
37 |
+
"Please check your order.", "Klopt jouw bestelling?"
|
38 |
+
"Please check the order overview. If this is correct, you can place your order.", "Hier zie je een overzicht van de bestelling. Als dit helemaal klopt kun je de bestelling plaatsen."
|
39 |
+
"How do you want to receive your order?", "Hoe wil je je bestelling<br />ontvangen?"
|
40 |
+
"Invoice address / delivery address", "Factuuradres/Bezorgadres"
|
41 |
+
"Edit", "Wijzig"
|
42 |
+
"Delivery method", "Verzendoptie"
|
43 |
+
"Payment method", "Betaalwijze"
|
44 |
+
"You can continue to the next step when you have entered all fields", "Je kunt pas naar de volgende stap als je alle velden volledig hebt ingevuld"
|
45 |
+
"There has been an unknown error. Please try again later again later.", "Er heeft zich een onbekende fout voorgedaan. Probeer het later nog eens."
|
46 |
+
"Thanks for shopping at ", "Leuk dat je bij "
|
47 |
+
".<span class='hidden'>_ORDER_TEXT</span>", " bestelt."
|
48 |
+
"When you tap 'Confirm and pay', you agree with ", "Als je op `Bevestig en betaal` tapt, ga je akkoord met "
|
49 |
+
"the general terms", "de algemene voorwaarden"
|
50 |
+
" of ", " van "
|
51 |
+
"Ship to the same address", "Bestelling verzenden naar hetzelfde adres"
|
52 |
+
"Invoice address", "Factuuradres"
|
53 |
+
"Delivery address", "Bezorgadres"
|
54 |
+
"Please make sure your passwords match.", "De ingevoerde wachtwoorden komen niet met elkaar overeen."
|
55 |
+
"Something went wrong while trying to get your address trough your zip code and house number. Please fill in your street and city manually.", "Er is iets fout gegaan met het ophalen van het adres via postcode en huisnummer. Vul het adres handmatig in."
|
56 |
+
"Street name is being retrieved", "Straatnaam wordt opgehaald"
|
57 |
+
"City name is being retrieved", "Plaatsnaam wordt opgehaald"
|
58 |
+
|
59 |
+
"hsapi.index.couponTip", "Heb je een tegoedbon?<br />Die kun je straks in de stap<br />'betaalwijze' invoeren."
|
60 |
+
|
61 |
+
"hsapi.addCouponAction.error.fatal", "Er heeft zich een onbekende fout voorgedaan, probleer het later nog eens."
|
62 |
+
"hsapi.addCouponAction.error.invalid", "De tegoedbon die je ingevoerd hebt is niet geldig."
|
63 |
+
"hsapi.addCouponAction.error.length", "De tegoedbon die je hebt ingevoerd is te lang, de maximale lengte is "
|
64 |
+
"hsapi.addCouponAction.success", "Tegoedbon '{coupon_code}' is succesvol toegepast. In je bestellijst kun je je korting bekijken."
|
65 |
+
"hsapi.addCouponAction.success.removed", "Tegoedbon '{coupon_code}' is succesvol verwijderd."
|
66 |
+
|
67 |
+
"hsapi.checkout.coupon.addTitle", "Voeg <u>tegoedbon</u> toe"
|
68 |
+
"hsapi.checkout.coupon.form.title", "Vul hier de code van je tegoedbon in."
|
69 |
+
"hsapi.checkout.coupon.form.code", "Tegoedbon"
|
70 |
+
"hsapi.checkout.coupon.form.add", "Voeg toe"
|
71 |
+
"hsapi.checkout.coupon.form.remove", "Verwijder"
|
72 |
+
"hsapi.checkout.coupon.paymentTitle", "Maak hier een keuze uit de volgende betaalopties"
|
73 |
+
|
74 |
+
"hsapi.checkout.payment.acceptAfterpayTermsText", "Je moet akkoord gaan met de betalingsvoorwaarden van AfterPay om gebruik te maken van deze betaalmethode"
|
75 |
+
|
76 |
+
"hsapi.checkout.billing.error.email", "Vul een geldig e-mailadres in"
|
77 |
+
|
78 |
+
|
79 |
+
"There is already a customer registered using this email address. Please login using this email address or enter a different email address to register your account.", "Het gebruikte e-mailadres is al gekoppeld aan een account. Log in met dit adres of gebruik een ander e-mailadres voor registratie."
|
80 |
+
|
81 |
+
'"%s" is not a valid email address.', "hsapi.checkout.email.error"
|
82 |
+
'"%s" is not a valid hostname.', "hsapi.checkout.email.error"
|
83 |
+
'"%s" exceeds the allowed length.', "hsapi.checkout.email.error"
|
84 |
+
"'%value%' appears to be an IP address, but IP addresses are not allowed", "hsapi.checkout.email.error"
|
85 |
+
"'%value%' appears to be a DNS hostname but cannot match TLD against known list", "hsapi.checkout.email.error"
|
86 |
+
"'%value%' appears to be a DNS hostname but contains a dash in an invalid position", "hsapi.checkout.email.error"
|
87 |
+
"'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", "hsapi.checkout.email.error"
|
88 |
+
"'%value%' appears to be a DNS hostname but cannot extract TLD part", "hsapi.checkout.email.error"
|
89 |
+
"'%value%' does not appear to be a valid local network name", "hsapi.checkout.email.error"
|
90 |
+
"'%value%' appears to be a local network name but local network names are not allowed", "hsapi.checkout.email.error"
|
91 |
+
"'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", "hsapi.checkout.email.error"
|
92 |
+
|
93 |
+
|
94 |
+
|
package.xml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Highstreet</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license>-</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Highstreet Magento Extension. This extension allows the Highstreet iPad app to connect to the store. </summary>
|
10 |
+
<description>The extension provides read-only access to the catalog (products and categories) by providing a simple API for the app. 
|
11 |
+
This extension does not modify or affect the Magento installation, nor does it change any catalog data.</description>
|
12 |
+
<notes>- First public release of the Highstreet Magento extension</notes>
|
13 |
+
<authors><author><name>Christian Apers</name><user>Christian</user><email>Christian@Touchwonders.com</email></author><author><name>Tim Wachter</name><user>Tim</user><email>Tim@Touchwonders.com</email></author></authors>
|
14 |
+
<date>2014-08-08</date>
|
15 |
+
<time>08:09:01</time>
|
16 |
+
<contents><target name="magecommunity"><dir name="Technooze"><dir name="Timage"><dir name="Block"><file name="Data.php" hash="02f8402df49abe64716e01746055330e"/></dir><dir name="Helper"><file name="Data.php" hash="4ade060d79bd29a91a524fce9e61e49b"/><file name="Data.php" hash="4ade060d79bd29a91a524fce9e61e49b"/></dir><dir name="etc"><file name="config.xml" hash="ff5675c31f16c03674ae87f19964a59d"/><file name="config.xml" hash="ff5675c31f16c03674ae87f19964a59d"/></dir></dir></dir></target><target name="magelocal"><dir name="Highstreet"><dir name="Hsapi"><dir name="Helper"><file name="Data.php" hash="94ba070797ec9925a331969b012be7f6"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><dir name="Model"><file name="Attributes.php" hash="6ad75fe439bfc6993ff741b2ae452150"/><file name="Categories.php" hash="79c3135fe7d99bf8f2cc1776bf792cb0"/><file name="Checkout.php" hash="b6c4606464818bf9cb4cceb766105c2e"/><file name="Images.php" hash="32d65360440199910c05b1e087c1cee2"/><file name="Observer.php" hash="3797806da488c928c0cbc543ce98763c"/><file name="Products.php" hash="24942419f4fdd676ad8ca8b462c30a03"/><file name="SearchSuggestions.php" hash="17e0a008e2f90c0f5f6c5f7c3f010c9c"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><dir name="controllers"><file name="IndexController.php" hash="79797b7b4fbc842a4c63dfaef03ac7f0"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><dir name="etc"><file name="Configuration.json" hash="d35d719b384223addf201cf847ce6963"/><file name="config.xml" hash="b4f33b6ea6e8f24e7bacd85a48763cd4"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><file name=".DS_Store" hash="bdce70b0d3d7ee6d49b036d8339f2acc"/></dir><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir></target><target name="mageetc"><dir name="modules"><file name="Highstreet_Api.xml" hash="97e586a7ef0a274d4f0fda883c646f31"/><file name="Technooze_Timage.xml" hash="bec7a12e3028d25b3a28c6eafe1878b4"/><file name="Highstreet_SmartAppBanner.xml" hash=""/></dir></target><target name="magelocale"><dir><dir name="en_US"><file name="Highstreet_Hsapi.csv" hash="1764bb5d414822ec79e1f39199f785b3"/></dir><dir name="nl_NL"><file name="Highstreet_Hsapi.csv" hash="4e3bab835cb6cd465bee52bebe393f67"/></dir></dir></target></contents>
|
17 |
+
<compatible/>
|
18 |
+
<dependencies><required><php><min>5.0.0.0</min><max>6.0.0.0</max></php><extension><name>gd</name><min>2.0</min><max>3.0</max></extension></required></dependencies>
|
19 |
+
</package>
|