@@ -35,7 +35,7 @@ discard block |
||
| 35 | 35 | * @access public |
| 36 | 36 | * @return string |
| 37 | 37 | */ |
| 38 | - static function encrypt ($pwd, $data, $ispwdHex = 0) |
|
| 38 | + static function encrypt($pwd, $data, $ispwdHex = 0) |
|
| 39 | 39 | { |
| 40 | 40 | if ($ispwdHex) |
| 41 | 41 | $pwd = @pack('H*', $pwd); // valid input, please! |
@@ -80,7 +80,7 @@ discard block |
||
| 80 | 80 | * @access public |
| 81 | 81 | * @return string |
| 82 | 82 | */ |
| 83 | - static function decrypt ($pwd, $data, $ispwdHex = 0) |
|
| 83 | + static function decrypt($pwd, $data, $ispwdHex = 0) |
|
| 84 | 84 | { |
| 85 | 85 | return self::encrypt($pwd, $data, $ispwdHex); |
| 86 | 86 | } |
@@ -37,8 +37,10 @@ |
||
| 37 | 37 | */ |
| 38 | 38 | static function encrypt ($pwd, $data, $ispwdHex = 0) |
| 39 | 39 | { |
| 40 | - if ($ispwdHex) |
|
| 41 | - $pwd = @pack('H*', $pwd); // valid input, please! |
|
| 40 | + if ($ispwdHex) { |
|
| 41 | + $pwd = @pack('H*', $pwd); |
|
| 42 | + } |
|
| 43 | + // valid input, please! |
|
| 42 | 44 | |
| 43 | 45 | $key[] = ''; |
| 44 | 46 | $box[] = ''; |
@@ -20,7 +20,7 @@ |
||
| 20 | 20 | { |
| 21 | 21 | if (Security::getCurrentUser()) { |
| 22 | 22 | return true; |
| 23 | - } else { |
|
| 23 | + }else { |
|
| 24 | 24 | return Security::permissionFailure($this, _t( |
| 25 | 25 | 'AccountPage.CANNOTCONFIRMLOGGEDIN', |
| 26 | 26 | 'Please login to view this page.' |
@@ -12,35 +12,35 @@ |
||
| 12 | 12 | */ |
| 13 | 13 | class OrderHistoryPageController extends \PageController |
| 14 | 14 | { |
| 15 | - /** |
|
| 16 | - * @var array |
|
| 17 | - */ |
|
| 18 | - private static $allowed_actions = array( |
|
| 19 | - 'index', |
|
| 20 | - ); |
|
| 15 | + /** |
|
| 16 | + * @var array |
|
| 17 | + */ |
|
| 18 | + private static $allowed_actions = array( |
|
| 19 | + 'index', |
|
| 20 | + ); |
|
| 21 | 21 | |
| 22 | - /** |
|
| 23 | - * @return bool|\SilverStripe\Control\HTTPResponse |
|
| 24 | - */ |
|
| 25 | - public function checkMember() |
|
| 26 | - { |
|
| 27 | - if (Security::getCurrentUser()) { |
|
| 28 | - return true; |
|
| 29 | - } else { |
|
| 30 | - return Security::permissionFailure($this, _t( |
|
| 31 | - 'AccountPage.CANNOTCONFIRMLOGGEDIN', |
|
| 32 | - 'Please login to view this page.' |
|
| 33 | - )); |
|
| 34 | - } |
|
| 35 | - } |
|
| 22 | + /** |
|
| 23 | + * @return bool|\SilverStripe\Control\HTTPResponse |
|
| 24 | + */ |
|
| 25 | + public function checkMember() |
|
| 26 | + { |
|
| 27 | + if (Security::getCurrentUser()) { |
|
| 28 | + return true; |
|
| 29 | + } else { |
|
| 30 | + return Security::permissionFailure($this, _t( |
|
| 31 | + 'AccountPage.CANNOTCONFIRMLOGGEDIN', |
|
| 32 | + 'Please login to view this page.' |
|
| 33 | + )); |
|
| 34 | + } |
|
| 35 | + } |
|
| 36 | 36 | |
| 37 | - /** |
|
| 38 | - * @return array |
|
| 39 | - */ |
|
| 40 | - public function Index() |
|
| 41 | - { |
|
| 42 | - $this->checkMember(); |
|
| 37 | + /** |
|
| 38 | + * @return array |
|
| 39 | + */ |
|
| 40 | + public function Index() |
|
| 41 | + { |
|
| 42 | + $this->checkMember(); |
|
| 43 | 43 | |
| 44 | - return array(); |
|
| 45 | - } |
|
| 44 | + return array(); |
|
| 45 | + } |
|
| 46 | 46 | } |
@@ -262,7 +262,7 @@ |
||
| 262 | 262 | if ($client) { |
| 263 | 263 | if ($category = $this->getCategory($data['code'])) { |
| 264 | 264 | $result = $client->patch($category, $data); |
| 265 | - } else { |
|
| 265 | + }else { |
|
| 266 | 266 | $result = $client->post($this->getItemCategoriesURL(), $data); |
| 267 | 267 | } |
| 268 | 268 | $errors = array_merge($errors, $client->getErrors($result)); |
@@ -9,300 +9,300 @@ |
||
| 9 | 9 | |
| 10 | 10 | class FoxyStripeClient |
| 11 | 11 | { |
| 12 | - /** |
|
| 13 | - * @var string |
|
| 14 | - */ |
|
| 15 | - private static $table_name = 'FS_FoxyStripeClient'; |
|
| 16 | - |
|
| 17 | - /** |
|
| 18 | - * @var |
|
| 19 | - */ |
|
| 20 | - private $client; |
|
| 21 | - |
|
| 22 | - /** |
|
| 23 | - * @var |
|
| 24 | - */ |
|
| 25 | - private $current_store; |
|
| 26 | - |
|
| 27 | - /** |
|
| 28 | - * @var |
|
| 29 | - */ |
|
| 30 | - private $item_categories_url; |
|
| 31 | - |
|
| 32 | - /** |
|
| 33 | - * @var |
|
| 34 | - */ |
|
| 35 | - private $item_categories; |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * FoxyStripeClient constructor. |
|
| 39 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 40 | - */ |
|
| 41 | - public function __construct() |
|
| 42 | - { |
|
| 43 | - $config = array( |
|
| 44 | - 'use_sandbox' => false, |
|
| 45 | - ); |
|
| 46 | - |
|
| 47 | - if ($setting = FoxyStripeSetting::current_foxystripe_setting()) { |
|
| 48 | - $config['client_id'] = $setting->client_id; |
|
| 49 | - $config['client_secret'] = $setting->client_secret; |
|
| 50 | - $config['refresh_token'] = $setting->refresh_token; |
|
| 51 | - $config['access_token'] = $setting->access_token; |
|
| 52 | - } |
|
| 53 | - |
|
| 54 | - $guzzle_config = array( |
|
| 55 | - 'defaults' => array( |
|
| 56 | - 'debug' => false, |
|
| 57 | - 'exceptions' => false, |
|
| 58 | - ), |
|
| 59 | - ); |
|
| 60 | - |
|
| 61 | - /* |
|
| 12 | + /** |
|
| 13 | + * @var string |
|
| 14 | + */ |
|
| 15 | + private static $table_name = 'FS_FoxyStripeClient'; |
|
| 16 | + |
|
| 17 | + /** |
|
| 18 | + * @var |
|
| 19 | + */ |
|
| 20 | + private $client; |
|
| 21 | + |
|
| 22 | + /** |
|
| 23 | + * @var |
|
| 24 | + */ |
|
| 25 | + private $current_store; |
|
| 26 | + |
|
| 27 | + /** |
|
| 28 | + * @var |
|
| 29 | + */ |
|
| 30 | + private $item_categories_url; |
|
| 31 | + |
|
| 32 | + /** |
|
| 33 | + * @var |
|
| 34 | + */ |
|
| 35 | + private $item_categories; |
|
| 36 | + |
|
| 37 | + /** |
|
| 38 | + * FoxyStripeClient constructor. |
|
| 39 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 40 | + */ |
|
| 41 | + public function __construct() |
|
| 42 | + { |
|
| 43 | + $config = array( |
|
| 44 | + 'use_sandbox' => false, |
|
| 45 | + ); |
|
| 46 | + |
|
| 47 | + if ($setting = FoxyStripeSetting::current_foxystripe_setting()) { |
|
| 48 | + $config['client_id'] = $setting->client_id; |
|
| 49 | + $config['client_secret'] = $setting->client_secret; |
|
| 50 | + $config['refresh_token'] = $setting->refresh_token; |
|
| 51 | + $config['access_token'] = $setting->access_token; |
|
| 52 | + } |
|
| 53 | + |
|
| 54 | + $guzzle_config = array( |
|
| 55 | + 'defaults' => array( |
|
| 56 | + 'debug' => false, |
|
| 57 | + 'exceptions' => false, |
|
| 58 | + ), |
|
| 59 | + ); |
|
| 60 | + |
|
| 61 | + /* |
|
| 62 | 62 | * Set up our Guzzle Client |
| 63 | 63 | */ |
| 64 | - $guzzle = new Client($guzzle_config); |
|
| 65 | - //CacheSubscriber::attach($guzzle); // todo add caching middleware guzzle-cache-middleware |
|
| 64 | + $guzzle = new Client($guzzle_config); |
|
| 65 | + //CacheSubscriber::attach($guzzle); // todo add caching middleware guzzle-cache-middleware |
|
| 66 | 66 | |
| 67 | - /* |
|
| 67 | + /* |
|
| 68 | 68 | * Get our FoxyClient |
| 69 | 69 | */ |
| 70 | - $fc = new FoxyClient($guzzle, $config); |
|
| 71 | - |
|
| 72 | - $this->setClient($fc); |
|
| 73 | - $this->setCurrentStore(); |
|
| 74 | - $this->setItemCategoriesURL(); |
|
| 75 | - $this->setItemCategories(); |
|
| 76 | - } |
|
| 77 | - |
|
| 78 | - /** |
|
| 79 | - * @return mixed |
|
| 80 | - */ |
|
| 81 | - public function getClient() |
|
| 82 | - { |
|
| 83 | - return $this->client; |
|
| 84 | - } |
|
| 85 | - |
|
| 86 | - /** |
|
| 87 | - * @param $client |
|
| 88 | - * |
|
| 89 | - * @return $this |
|
| 90 | - */ |
|
| 91 | - public function setClient($client) |
|
| 92 | - { |
|
| 93 | - $this->client = $client; |
|
| 94 | - |
|
| 95 | - return $this; |
|
| 96 | - } |
|
| 97 | - |
|
| 98 | - /** |
|
| 99 | - * @return bool |
|
| 100 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 101 | - */ |
|
| 102 | - public static function is_valid() |
|
| 103 | - { |
|
| 104 | - $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 105 | - return $config->EnableAPI && |
|
| 106 | - $config->client_id && |
|
| 107 | - $config->client_secret && |
|
| 108 | - $config->refresh_token && |
|
| 109 | - $config->access_token; |
|
| 110 | - } |
|
| 111 | - |
|
| 112 | - /** |
|
| 113 | - * @return mixed |
|
| 114 | - */ |
|
| 115 | - public function getCurrentStore() |
|
| 116 | - { |
|
| 117 | - return $this->current_store; |
|
| 118 | - } |
|
| 119 | - |
|
| 120 | - /** |
|
| 121 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 122 | - */ |
|
| 123 | - public function setCurrentStore() |
|
| 124 | - { |
|
| 125 | - $client = $this->getClient(); |
|
| 126 | - $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 127 | - |
|
| 128 | - $errors = array(); |
|
| 129 | - $data = array( |
|
| 130 | - 'store_domain' => $config->StoreName, |
|
| 131 | - ); |
|
| 132 | - |
|
| 133 | - if ($client && $result = $client->get()) { |
|
| 134 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 135 | - if ($reporting_uri = $client->getLink('fx:reporting')) { |
|
| 136 | - $errors = array_merge($errors, $client->getErrors($reporting_uri)); |
|
| 137 | - if ($result = $client->get($reporting_uri)) { |
|
| 138 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 139 | - if ($store_exists_uri = $client->getLink('fx:reporting_store_domain_exists')) { |
|
| 140 | - $errors = array_merge($errors, $client->getErrors($store_exists_uri)); |
|
| 141 | - if ($result = $client->get($store_exists_uri, $data)) { |
|
| 142 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 143 | - if ($store = $client->getLink('fx:store')) { |
|
| 144 | - $errors = array_merge($errors, $client->getErrors($store)); |
|
| 145 | - $this->current_store = $store; |
|
| 146 | - } |
|
| 147 | - } |
|
| 148 | - } |
|
| 149 | - } |
|
| 150 | - } |
|
| 151 | - if (count($errors)) { |
|
| 152 | - Injector::inst()->get(LoggerInterface::class)->error('setCurrentStore errors - '.json_encode($errors)); |
|
| 153 | - } |
|
| 154 | - } |
|
| 155 | - } |
|
| 156 | - |
|
| 157 | - /** |
|
| 158 | - * @param array $data |
|
| 159 | - * |
|
| 160 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 161 | - */ |
|
| 162 | - public function updateStore($data = []) |
|
| 163 | - { |
|
| 164 | - $client = $this->getClient(); |
|
| 165 | - $errors = []; |
|
| 166 | - |
|
| 167 | - $result = $client->patch($this->getCurrentStore(), $data); |
|
| 168 | - |
|
| 169 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 170 | - if (count($errors)) { |
|
| 171 | - Injector::inst()->get(LoggerInterface::class)->error('updateStore errors - '.json_encode($errors)); |
|
| 172 | - } |
|
| 173 | - } |
|
| 174 | - |
|
| 175 | - /** |
|
| 176 | - * @return mixed |
|
| 177 | - */ |
|
| 178 | - public function getItemCategoriesURL() |
|
| 179 | - { |
|
| 180 | - return $this->item_categories_url; |
|
| 181 | - } |
|
| 182 | - |
|
| 183 | - /** |
|
| 184 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 185 | - */ |
|
| 186 | - public function setItemCategoriesURL() |
|
| 187 | - { |
|
| 188 | - $client = $this->getClient(); |
|
| 189 | - $errors = []; |
|
| 190 | - |
|
| 191 | - if ($client) { |
|
| 192 | - $result = $client->get($this->getCurrentStore()); |
|
| 193 | - |
|
| 194 | - if (isset($result['_links']['fx:item_categories']['href'])) { |
|
| 195 | - $this->item_categories_url = $result['_links']['fx:item_categories']['href']; |
|
| 196 | - } |
|
| 197 | - |
|
| 198 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 199 | - if (count($errors)) { |
|
| 200 | - Injector::inst() |
|
| 201 | - ->get(LoggerInterface::class)->error('setItemCategoriesURL errors - '.json_encode($errors)); |
|
| 202 | - } |
|
| 203 | - } |
|
| 204 | - } |
|
| 205 | - |
|
| 206 | - /** |
|
| 207 | - * @return mixed |
|
| 208 | - */ |
|
| 209 | - public function getItemCategories() |
|
| 210 | - { |
|
| 211 | - return $this->item_categories; |
|
| 212 | - } |
|
| 213 | - |
|
| 214 | - /** |
|
| 215 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 216 | - */ |
|
| 217 | - public function setItemCategories() |
|
| 218 | - { |
|
| 219 | - $client = $this->getClient(); |
|
| 220 | - $errors = []; |
|
| 221 | - |
|
| 222 | - if ($client) { |
|
| 223 | - $result = $client->get($this->getItemCategoriesURL()); |
|
| 224 | - |
|
| 225 | - $this->item_categories = $result; |
|
| 226 | - |
|
| 227 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 228 | - if (count($errors)) { |
|
| 229 | - Injector::inst() |
|
| 230 | - ->get(LoggerInterface::class)->error('setItemCategories errors - '.json_encode($errors)); |
|
| 231 | - } |
|
| 232 | - } |
|
| 233 | - } |
|
| 234 | - |
|
| 235 | - /** |
|
| 236 | - * @param $code |
|
| 237 | - * |
|
| 238 | - * @return bool |
|
| 239 | - * |
|
| 240 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 241 | - */ |
|
| 242 | - public function getCategory($code) |
|
| 243 | - { |
|
| 244 | - if ($categoriesURL = $this->getItemCategoriesURL()) { |
|
| 245 | - $client = $this->getClient(); |
|
| 246 | - $errors = []; |
|
| 247 | - $data = [ |
|
| 248 | - 'code' => $code, |
|
| 249 | - ]; |
|
| 250 | - if ($result = $client->get($categoriesURL, $data)) { |
|
| 251 | - if (count($result['_embedded']['fx:item_categories']) > 0) { |
|
| 252 | - $category = $result['_embedded']['fx:item_categories'][0]['_links']['self']['href']; |
|
| 253 | - |
|
| 254 | - return $category; |
|
| 255 | - } |
|
| 256 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 257 | - if (count($errors)) { |
|
| 258 | - Injector::inst()->get(LoggerInterface::class)->error('getCategory errors - '.json_encode($errors)); |
|
| 259 | - } |
|
| 260 | - } |
|
| 261 | - } |
|
| 262 | - |
|
| 263 | - return false; |
|
| 264 | - } |
|
| 265 | - |
|
| 266 | - /** |
|
| 267 | - * @param array $data |
|
| 268 | - * |
|
| 269 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 270 | - */ |
|
| 271 | - public function putCategory($data = []) |
|
| 272 | - { |
|
| 273 | - $client = $this->getClient(); |
|
| 274 | - $errors = []; |
|
| 275 | - |
|
| 276 | - if ($client) { |
|
| 277 | - if ($category = $this->getCategory($data['code'])) { |
|
| 278 | - $result = $client->patch($category, $data); |
|
| 279 | - } else { |
|
| 280 | - $result = $client->post($this->getItemCategoriesURL(), $data); |
|
| 281 | - } |
|
| 282 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 283 | - if (count($errors)) { |
|
| 284 | - Injector::inst()->get(LoggerInterface::class)->error('putCategory errors - '.json_encode($errors)); |
|
| 285 | - } |
|
| 286 | - } |
|
| 287 | - } |
|
| 288 | - |
|
| 289 | - /** |
|
| 290 | - * @param array $data |
|
| 291 | - * |
|
| 292 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 293 | - */ |
|
| 294 | - public function deleteCategory($data = []) |
|
| 295 | - { |
|
| 296 | - $client = $this->getClient(); |
|
| 297 | - $errors = []; |
|
| 298 | - |
|
| 299 | - if ($category = $this->getCategory($data['code'])) { |
|
| 300 | - $result = $client->delete($category); |
|
| 301 | - |
|
| 302 | - $errors = array_merge($errors, $client->getErrors($result)); |
|
| 303 | - if (count($errors)) { |
|
| 304 | - Injector::inst()->get(LoggerInterface::class)->error('deleteCategory errors - '.json_encode($errors)); |
|
| 305 | - } |
|
| 306 | - } |
|
| 307 | - } |
|
| 70 | + $fc = new FoxyClient($guzzle, $config); |
|
| 71 | + |
|
| 72 | + $this->setClient($fc); |
|
| 73 | + $this->setCurrentStore(); |
|
| 74 | + $this->setItemCategoriesURL(); |
|
| 75 | + $this->setItemCategories(); |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + /** |
|
| 79 | + * @return mixed |
|
| 80 | + */ |
|
| 81 | + public function getClient() |
|
| 82 | + { |
|
| 83 | + return $this->client; |
|
| 84 | + } |
|
| 85 | + |
|
| 86 | + /** |
|
| 87 | + * @param $client |
|
| 88 | + * |
|
| 89 | + * @return $this |
|
| 90 | + */ |
|
| 91 | + public function setClient($client) |
|
| 92 | + { |
|
| 93 | + $this->client = $client; |
|
| 94 | + |
|
| 95 | + return $this; |
|
| 96 | + } |
|
| 97 | + |
|
| 98 | + /** |
|
| 99 | + * @return bool |
|
| 100 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 101 | + */ |
|
| 102 | + public static function is_valid() |
|
| 103 | + { |
|
| 104 | + $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 105 | + return $config->EnableAPI && |
|
| 106 | + $config->client_id && |
|
| 107 | + $config->client_secret && |
|
| 108 | + $config->refresh_token && |
|
| 109 | + $config->access_token; |
|
| 110 | + } |
|
| 111 | + |
|
| 112 | + /** |
|
| 113 | + * @return mixed |
|
| 114 | + */ |
|
| 115 | + public function getCurrentStore() |
|
| 116 | + { |
|
| 117 | + return $this->current_store; |
|
| 118 | + } |
|
| 119 | + |
|
| 120 | + /** |
|
| 121 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 122 | + */ |
|
| 123 | + public function setCurrentStore() |
|
| 124 | + { |
|
| 125 | + $client = $this->getClient(); |
|
| 126 | + $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 127 | + |
|
| 128 | + $errors = array(); |
|
| 129 | + $data = array( |
|
| 130 | + 'store_domain' => $config->StoreName, |
|
| 131 | + ); |
|
| 132 | + |
|
| 133 | + if ($client && $result = $client->get()) { |
|
| 134 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 135 | + if ($reporting_uri = $client->getLink('fx:reporting')) { |
|
| 136 | + $errors = array_merge($errors, $client->getErrors($reporting_uri)); |
|
| 137 | + if ($result = $client->get($reporting_uri)) { |
|
| 138 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 139 | + if ($store_exists_uri = $client->getLink('fx:reporting_store_domain_exists')) { |
|
| 140 | + $errors = array_merge($errors, $client->getErrors($store_exists_uri)); |
|
| 141 | + if ($result = $client->get($store_exists_uri, $data)) { |
|
| 142 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 143 | + if ($store = $client->getLink('fx:store')) { |
|
| 144 | + $errors = array_merge($errors, $client->getErrors($store)); |
|
| 145 | + $this->current_store = $store; |
|
| 146 | + } |
|
| 147 | + } |
|
| 148 | + } |
|
| 149 | + } |
|
| 150 | + } |
|
| 151 | + if (count($errors)) { |
|
| 152 | + Injector::inst()->get(LoggerInterface::class)->error('setCurrentStore errors - '.json_encode($errors)); |
|
| 153 | + } |
|
| 154 | + } |
|
| 155 | + } |
|
| 156 | + |
|
| 157 | + /** |
|
| 158 | + * @param array $data |
|
| 159 | + * |
|
| 160 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 161 | + */ |
|
| 162 | + public function updateStore($data = []) |
|
| 163 | + { |
|
| 164 | + $client = $this->getClient(); |
|
| 165 | + $errors = []; |
|
| 166 | + |
|
| 167 | + $result = $client->patch($this->getCurrentStore(), $data); |
|
| 168 | + |
|
| 169 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 170 | + if (count($errors)) { |
|
| 171 | + Injector::inst()->get(LoggerInterface::class)->error('updateStore errors - '.json_encode($errors)); |
|
| 172 | + } |
|
| 173 | + } |
|
| 174 | + |
|
| 175 | + /** |
|
| 176 | + * @return mixed |
|
| 177 | + */ |
|
| 178 | + public function getItemCategoriesURL() |
|
| 179 | + { |
|
| 180 | + return $this->item_categories_url; |
|
| 181 | + } |
|
| 182 | + |
|
| 183 | + /** |
|
| 184 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 185 | + */ |
|
| 186 | + public function setItemCategoriesURL() |
|
| 187 | + { |
|
| 188 | + $client = $this->getClient(); |
|
| 189 | + $errors = []; |
|
| 190 | + |
|
| 191 | + if ($client) { |
|
| 192 | + $result = $client->get($this->getCurrentStore()); |
|
| 193 | + |
|
| 194 | + if (isset($result['_links']['fx:item_categories']['href'])) { |
|
| 195 | + $this->item_categories_url = $result['_links']['fx:item_categories']['href']; |
|
| 196 | + } |
|
| 197 | + |
|
| 198 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 199 | + if (count($errors)) { |
|
| 200 | + Injector::inst() |
|
| 201 | + ->get(LoggerInterface::class)->error('setItemCategoriesURL errors - '.json_encode($errors)); |
|
| 202 | + } |
|
| 203 | + } |
|
| 204 | + } |
|
| 205 | + |
|
| 206 | + /** |
|
| 207 | + * @return mixed |
|
| 208 | + */ |
|
| 209 | + public function getItemCategories() |
|
| 210 | + { |
|
| 211 | + return $this->item_categories; |
|
| 212 | + } |
|
| 213 | + |
|
| 214 | + /** |
|
| 215 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 216 | + */ |
|
| 217 | + public function setItemCategories() |
|
| 218 | + { |
|
| 219 | + $client = $this->getClient(); |
|
| 220 | + $errors = []; |
|
| 221 | + |
|
| 222 | + if ($client) { |
|
| 223 | + $result = $client->get($this->getItemCategoriesURL()); |
|
| 224 | + |
|
| 225 | + $this->item_categories = $result; |
|
| 226 | + |
|
| 227 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 228 | + if (count($errors)) { |
|
| 229 | + Injector::inst() |
|
| 230 | + ->get(LoggerInterface::class)->error('setItemCategories errors - '.json_encode($errors)); |
|
| 231 | + } |
|
| 232 | + } |
|
| 233 | + } |
|
| 234 | + |
|
| 235 | + /** |
|
| 236 | + * @param $code |
|
| 237 | + * |
|
| 238 | + * @return bool |
|
| 239 | + * |
|
| 240 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 241 | + */ |
|
| 242 | + public function getCategory($code) |
|
| 243 | + { |
|
| 244 | + if ($categoriesURL = $this->getItemCategoriesURL()) { |
|
| 245 | + $client = $this->getClient(); |
|
| 246 | + $errors = []; |
|
| 247 | + $data = [ |
|
| 248 | + 'code' => $code, |
|
| 249 | + ]; |
|
| 250 | + if ($result = $client->get($categoriesURL, $data)) { |
|
| 251 | + if (count($result['_embedded']['fx:item_categories']) > 0) { |
|
| 252 | + $category = $result['_embedded']['fx:item_categories'][0]['_links']['self']['href']; |
|
| 253 | + |
|
| 254 | + return $category; |
|
| 255 | + } |
|
| 256 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 257 | + if (count($errors)) { |
|
| 258 | + Injector::inst()->get(LoggerInterface::class)->error('getCategory errors - '.json_encode($errors)); |
|
| 259 | + } |
|
| 260 | + } |
|
| 261 | + } |
|
| 262 | + |
|
| 263 | + return false; |
|
| 264 | + } |
|
| 265 | + |
|
| 266 | + /** |
|
| 267 | + * @param array $data |
|
| 268 | + * |
|
| 269 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 270 | + */ |
|
| 271 | + public function putCategory($data = []) |
|
| 272 | + { |
|
| 273 | + $client = $this->getClient(); |
|
| 274 | + $errors = []; |
|
| 275 | + |
|
| 276 | + if ($client) { |
|
| 277 | + if ($category = $this->getCategory($data['code'])) { |
|
| 278 | + $result = $client->patch($category, $data); |
|
| 279 | + } else { |
|
| 280 | + $result = $client->post($this->getItemCategoriesURL(), $data); |
|
| 281 | + } |
|
| 282 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 283 | + if (count($errors)) { |
|
| 284 | + Injector::inst()->get(LoggerInterface::class)->error('putCategory errors - '.json_encode($errors)); |
|
| 285 | + } |
|
| 286 | + } |
|
| 287 | + } |
|
| 288 | + |
|
| 289 | + /** |
|
| 290 | + * @param array $data |
|
| 291 | + * |
|
| 292 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 293 | + */ |
|
| 294 | + public function deleteCategory($data = []) |
|
| 295 | + { |
|
| 296 | + $client = $this->getClient(); |
|
| 297 | + $errors = []; |
|
| 298 | + |
|
| 299 | + if ($category = $this->getCategory($data['code'])) { |
|
| 300 | + $result = $client->delete($category); |
|
| 301 | + |
|
| 302 | + $errors = array_merge($errors, $client->getErrors($result)); |
|
| 303 | + if (count($errors)) { |
|
| 304 | + Injector::inst()->get(LoggerInterface::class)->error('deleteCategory errors - '.json_encode($errors)); |
|
| 305 | + } |
|
| 306 | + } |
|
| 307 | + } |
|
| 308 | 308 | } |
@@ -159,7 +159,7 @@ discard block |
||
| 159 | 159 | |
| 160 | 160 | if ($output) { |
| 161 | 161 | echo self::$cart_url.'?'.$qs; |
| 162 | - } else { |
|
| 162 | + }else { |
|
| 163 | 163 | return self::$cart_url.'?'.$qs; |
| 164 | 164 | } |
| 165 | 165 | } |
@@ -183,18 +183,18 @@ discard block |
||
| 183 | 183 | if ($option_value == '--OPEN--') { |
| 184 | 184 | $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
| 185 | 185 | $value = ($urlencode) ? urlencode($option_name).'||'.$hash.'||open' : $option_name.'||'.$hash.'||open'; |
| 186 | - } else { |
|
| 186 | + }else { |
|
| 187 | 187 | $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
| 188 | 188 | if ($method == 'name') { |
| 189 | 189 | $value = ($urlencode) ? urlencode($option_name).'||'.$hash : $option_name.'||'.$hash; |
| 190 | - } else { |
|
| 190 | + }else { |
|
| 191 | 191 | $value = ($urlencode) ? urlencode($option_value).'||'.$hash : $option_value.'||'.$hash; |
| 192 | 192 | } |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | 195 | if ($output) { |
| 196 | 196 | echo $value; |
| 197 | - } else { |
|
| 197 | + }else { |
|
| 198 | 198 | return $value; |
| 199 | 199 | } |
| 200 | 200 | } |
@@ -322,7 +322,7 @@ discard block |
||
| 322 | 322 | .preg_quote($value[2]).'\1%', '${1}' |
| 323 | 323 | .self::fc_hash_value($code, $name[2], $value[2], 'value', false) |
| 324 | 324 | .'$1', $input); |
| 325 | - } else { |
|
| 325 | + }else { |
|
| 326 | 326 | $input_signed = preg_replace('%([\'"])'.$prefix.preg_quote($name[2]) |
| 327 | 327 | .'\1%', '${1}'.$prefix |
| 328 | 328 | .self::fc_hash_value($code, $name[2], $value[2], 'name', false) |
@@ -21,12 +21,12 @@ discard block |
||
| 21 | 21 | */ |
| 22 | 22 | class FoxyCart_Helper |
| 23 | 23 | { |
| 24 | - /** |
|
| 25 | - * API Key (Secret). |
|
| 26 | - * |
|
| 27 | - * @var string |
|
| 28 | - **/ |
|
| 29 | - private static $secret; |
|
| 24 | + /** |
|
| 25 | + * API Key (Secret). |
|
| 26 | + * |
|
| 27 | + * @var string |
|
| 28 | + **/ |
|
| 29 | + private static $secret; |
|
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | 32 | * Cart URL. |
@@ -34,416 +34,416 @@ discard block |
||
| 34 | 34 | * @var string |
| 35 | 35 | * Notes: Could be 'https://yourdomain.foxycart.com/cart' or 'https://secure.yourdomain.com/cart' |
| 36 | 36 | **/ |
| 37 | - // protected static $cart_url = 'https://yourdomain.foxycart.com/cart'; |
|
| 38 | - protected static $cart_url; |
|
| 39 | - |
|
| 40 | - public static function setCartURL($storeName = null) |
|
| 41 | - { |
|
| 42 | - self::$cart_url = 'https://'.$storeName.'.faxycart.com/cart'; |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - public static function setSecret($secret = null) |
|
| 46 | - { |
|
| 47 | - self::$secret = $secret; |
|
| 48 | - } |
|
| 49 | - |
|
| 50 | - public function __construct() |
|
| 51 | - { |
|
| 52 | - self::setCartURL(FoxyCart::getFoxyCartStoreName()); |
|
| 53 | - self::setSecret(FoxyCart::getStoreKey()); |
|
| 54 | - } |
|
| 55 | - |
|
| 56 | - public static function getSecret() |
|
| 57 | - { |
|
| 58 | - return FoxyCart::getStoreKey(); |
|
| 59 | - } |
|
| 60 | - |
|
| 61 | - /** |
|
| 62 | - * Cart Excludes. |
|
| 63 | - * |
|
| 64 | - * Arrays of values and prefixes that should be ignored when signing links and forms. |
|
| 65 | - * |
|
| 66 | - * @var array |
|
| 67 | - */ |
|
| 68 | - protected static $cart_excludes = array( |
|
| 69 | - // Cart values |
|
| 70 | - 'cart', 'fcsid', 'empty', 'coupon', 'output', 'sub_token', 'redirect', 'callback', '_', |
|
| 71 | - // Checkout pre-population values |
|
| 72 | - 'customer_email', 'customer_first_name', 'customer_last_name', 'customer_address1', 'customer_address2', |
|
| 73 | - 'customer_city', 'customer_state', 'customer_postal_code', 'customer_country', 'customer_phone', |
|
| 74 | - 'customer_company', 'shipping_first_name', 'shipping_last_name', 'shipping_address1', 'shipping_address2', |
|
| 75 | - 'shipping_city', 'shipping_state', 'shipping_postal_code', 'shipping_country', 'shipping_phone', |
|
| 76 | - 'shipping_company', |
|
| 77 | - ); |
|
| 78 | - protected static $cart_excludes_prefixes = array( |
|
| 79 | - 'h:', 'x:', '__', |
|
| 80 | - ); |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * Debugging. |
|
| 84 | - * |
|
| 85 | - * Set to $debug to TRUE to enable debug logging. |
|
| 86 | - */ |
|
| 87 | - protected static $debug = false; |
|
| 88 | - protected static $log = array(); |
|
| 89 | - |
|
| 90 | - /** |
|
| 91 | - * "Link Method": Generate HMAC SHA256 for GET Query Strings. |
|
| 92 | - * |
|
| 93 | - * Notes: Can't parse_str because PHP doesn't support non-alphanumeric characters as array keys. |
|
| 94 | - * |
|
| 95 | - * @return string |
|
| 96 | - **/ |
|
| 97 | - public static function fc_hash_querystring($qs, $output = true) |
|
| 98 | - { |
|
| 99 | - self::$log[] = '<strong>Signing link</strong> with data: ' |
|
| 100 | - .htmlspecialchars(substr($qs, 0, 150)).'...'; |
|
| 101 | - $fail = self::$cart_url.'?'.$qs; |
|
| 102 | - |
|
| 103 | - // If the link appears to be hashed already, don't bother |
|
| 104 | - if (strpos($qs, '||')) { |
|
| 105 | - self::$log[] = '<strong>Link appears to be signed already</strong>: '.htmlspecialchars($code[0]); |
|
| 106 | - |
|
| 107 | - return $fail; |
|
| 108 | - } |
|
| 109 | - |
|
| 110 | - // Stick an ampersand on the beginning of the querystring to make matching the first element a little easier |
|
| 111 | - $qs = '&'.urldecode($qs); |
|
| 112 | - |
|
| 113 | - // Get all the prefixes, codes, and name=value pairs |
|
| 114 | - preg_match_all( |
|
| 115 | - '%(?P<amp>&(?:amp;)?)(?P<prefix>[a-z0-9]{1,3}:)?(?P<name>[^=]+)=(?P<value>[^&]+)%', |
|
| 116 | - $qs, |
|
| 117 | - $pairs, |
|
| 118 | - PREG_SET_ORDER |
|
| 119 | - ); |
|
| 120 | - self::$log[] = 'Found the following pairs to sign:<pre>'.htmlspecialchars(print_r($pairs, true)).'</pre>'; |
|
| 121 | - |
|
| 122 | - // Get all the "code" values, set the matches in $codes |
|
| 123 | - $codes = array(); |
|
| 124 | - foreach ($pairs as $pair) { |
|
| 125 | - if ($pair['name'] == 'code') { |
|
| 126 | - $codes[$pair['prefix']] = $pair['value']; |
|
| 127 | - } |
|
| 128 | - } |
|
| 129 | - if (!count($codes)) { |
|
| 130 | - self::$log[] = '<strong style="color:#600;">No code found</strong> for the above link.'; |
|
| 131 | - |
|
| 132 | - return $fail; |
|
| 133 | - } |
|
| 134 | - self::$log[] = '<strong style="color:orange;">CODES found:</strong> ' |
|
| 135 | - .htmlspecialchars(print_r($codes, true)); |
|
| 136 | - |
|
| 137 | - // Sign the name/value pairs |
|
| 138 | - foreach ($pairs as $pair) { |
|
| 139 | - // Skip the cart excludes |
|
| 140 | - if (in_array($pair['name'], self::$cart_excludes) |
|
| 141 | - || in_array($pair['prefix'], self::$cart_excludes_prefixes)) { |
|
| 142 | - self::$log[] = '<strong style="color:purple;">Skipping</strong> the reserved parameter or prefix "' |
|
| 143 | - .$pair['prefix'].$pair['name'].'" = '.$pair['value']; |
|
| 144 | - continue; |
|
| 145 | - } |
|
| 146 | - |
|
| 147 | - // Continue to sign the value and replace the name=value in the querystring with name=value||hash |
|
| 148 | - $value = self::fc_hash_value( |
|
| 149 | - $codes[$pair['prefix']], |
|
| 150 | - $pair['name'], |
|
| 151 | - $pair['value'], |
|
| 152 | - 'value', |
|
| 153 | - false, |
|
| 154 | - 'urlencode' |
|
| 155 | - ); |
|
| 156 | - $replacement = $pair['amp'].$pair['prefix'].urlencode($pair['name']).'='.$value; |
|
| 157 | - $qs = str_replace($pair[0], $replacement, $qs); |
|
| 158 | - self::$log[] = 'Signed <strong>'.$pair['name'].'</strong> = <strong>'.$pair['value'].'</strong> with ' |
|
| 159 | - .$replacement.'.<br />Replacing: '.$pair[0].'<br />With... '.$replacement; |
|
| 160 | - } |
|
| 161 | - $qs = ltrim($qs, '&'); // Get rid of that leading ampersand we added earlier |
|
| 162 | - |
|
| 163 | - if ($output) { |
|
| 164 | - echo self::$cart_url.'?'.$qs; |
|
| 165 | - } else { |
|
| 166 | - return self::$cart_url.'?'.$qs; |
|
| 167 | - } |
|
| 168 | - } |
|
| 169 | - |
|
| 170 | - /** |
|
| 171 | - * "Form Method": Generate HMAC SHA256 for form elements or individual <input />s. |
|
| 172 | - * |
|
| 173 | - * @return string |
|
| 174 | - **/ |
|
| 175 | - public static function fc_hash_value( |
|
| 176 | - $product_code, |
|
| 177 | - $option_name, |
|
| 178 | - $option_value = '', |
|
| 179 | - $method = 'name', |
|
| 180 | - $output = true, |
|
| 181 | - $urlencode = false |
|
| 182 | - ) { |
|
| 183 | - if (!$product_code || !$option_name) { |
|
| 184 | - return false; |
|
| 185 | - } |
|
| 186 | - if ($option_value == '--OPEN--') { |
|
| 187 | - $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
|
| 188 | - $value = ($urlencode) ? urlencode($option_name).'||'.$hash.'||open' : $option_name.'||'.$hash.'||open'; |
|
| 189 | - } else { |
|
| 190 | - $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
|
| 191 | - if ($method == 'name') { |
|
| 192 | - $value = ($urlencode) ? urlencode($option_name).'||'.$hash : $option_name.'||'.$hash; |
|
| 193 | - } else { |
|
| 194 | - $value = ($urlencode) ? urlencode($option_value).'||'.$hash : $option_value.'||'.$hash; |
|
| 195 | - } |
|
| 196 | - } |
|
| 197 | - |
|
| 198 | - if ($output) { |
|
| 199 | - echo $value; |
|
| 200 | - } else { |
|
| 201 | - return $value; |
|
| 202 | - } |
|
| 203 | - } |
|
| 204 | - |
|
| 205 | - /** |
|
| 206 | - * Raw HTML Signing: Sign all links and form elements in a block of HTML. |
|
| 207 | - * |
|
| 208 | - * Accepts a string of HTML and signs all links and forms. |
|
| 209 | - * Requires link 'href' and form 'action' attributes to use 'https' and not 'http'. |
|
| 210 | - * Requires a 'code' to be set in every form. |
|
| 211 | - * |
|
| 212 | - * @return string |
|
| 213 | - **/ |
|
| 214 | - public static function fc_hash_html($html) |
|
| 215 | - { |
|
| 216 | - // Initialize some counting |
|
| 217 | - $count['temp'] = 0; // temp counter |
|
| 218 | - $count['links'] = 0; |
|
| 219 | - $count['forms'] = 0; |
|
| 220 | - $count['inputs'] = 0; |
|
| 221 | - $count['lists'] = 0; |
|
| 222 | - $count['textareas'] = 0; |
|
| 223 | - |
|
| 224 | - // Find and sign all the links |
|
| 225 | - preg_match_all( |
|
| 226 | - '%<a .*?href=[\'"]'.preg_quote(self::$cart_url).'(?:\.php)?\?(.+?)[\'"].*?>%i', |
|
| 227 | - $html, |
|
| 228 | - $querystrings |
|
| 229 | - ); |
|
| 230 | - // print_r($querystrings); |
|
| 231 | - foreach ($querystrings[1] as $querystring) { |
|
| 232 | - // If it's already signed, skip it. |
|
| 233 | - if (preg_match('%&(?:amp;)?hash=%i', $querystring)) { |
|
| 234 | - continue; |
|
| 235 | - } |
|
| 236 | - $pattern = '%(href=[\'"])'.preg_quote(self::$cart_url, '%').'(?:\.php)?\?' |
|
| 237 | - .preg_quote($querystring, '%').'([\'"])%i'; |
|
| 238 | - $signed = self::fc_hash_querystring($querystring, false); |
|
| 239 | - $html = preg_replace($pattern, '$1'.$signed.'$2', $html, -1, $count['temp']); |
|
| 240 | - $count['links'] += $count['temp']; |
|
| 241 | - } |
|
| 242 | - unset($querystrings); |
|
| 243 | - |
|
| 244 | - // Find and sign all form values |
|
| 245 | - preg_match_all( |
|
| 246 | - '%<form [^>]*?action=[\'"]'.preg_quote(self::$cart_url).'?[\'"].*?>(.+?)</form>%is', |
|
| 247 | - $html, |
|
| 248 | - $forms |
|
| 249 | - ); |
|
| 250 | - foreach ($forms[1] as $form) { |
|
| 251 | - ++$count['forms']; |
|
| 252 | - self::$log[] = '<strong>Signing form</strong> with data: '.htmlspecialchars(substr( |
|
| 253 | - $form, |
|
| 254 | - 0, |
|
| 255 | - 150 |
|
| 256 | - )).'...'; |
|
| 257 | - |
|
| 258 | - // Store the original form so we can replace it when we're done |
|
| 259 | - $form_original = $form; |
|
| 260 | - |
|
| 261 | - // Check for the "code" input, set the matches in $codes |
|
| 262 | - if (!preg_match_all( |
|
| 263 | - '%<[^>]*?name=([\'"])([0-9]{1,3}:)?code\1[^>]*?>%i', |
|
| 264 | - $form, |
|
| 265 | - $codes, |
|
| 266 | - PREG_SET_ORDER |
|
| 267 | - )) { |
|
| 268 | - self::$log[] = '<strong style="color:#600;">No code found</strong> for the above form.'; |
|
| 269 | - continue; |
|
| 270 | - } |
|
| 271 | - // For each code found, sign the appropriate inputs |
|
| 272 | - foreach ($codes as $code) { |
|
| 273 | - // If the form appears to be hashed already, don't bother |
|
| 274 | - if (strpos($code[0], '||')) { |
|
| 275 | - self::$log[] = '<strong>Form appears to be signed already</strong>: '.htmlspecialchars($code[0]); |
|
| 276 | - continue; |
|
| 277 | - } |
|
| 278 | - // Get the code and the prefix |
|
| 279 | - $prefix = (isset($code[2])) ? $code[2] : ''; |
|
| 280 | - preg_match('%<[^>]*?value=([\'"])(.+?)\1[^>]*?>%i', $code[0], $code); |
|
| 281 | - $code = trim($code[2]); |
|
| 282 | - self::$log[] = '<strong>Prefix for '.htmlspecialchars($code).'</strong>: '.htmlspecialchars($prefix); |
|
| 283 | - if (!$code) { // If the code is empty, skip this form or specific prefixed elements |
|
| 284 | - continue; |
|
| 285 | - } |
|
| 286 | - |
|
| 287 | - // Sign all <input /> elements with matching prefix |
|
| 288 | - preg_match_all( |
|
| 289 | - '%<input [^>]*?name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(?:.+?)\1[^>]*>%i', |
|
| 290 | - $form, |
|
| 291 | - $inputs |
|
| 292 | - ); |
|
| 293 | - foreach ($inputs[0] as $input) { |
|
| 294 | - ++$count['inputs']; |
|
| 295 | - // Test to make sure both name and value attributes are found |
|
| 296 | - if (preg_match( |
|
| 297 | - '%name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1%i', |
|
| 298 | - $input, |
|
| 299 | - $name |
|
| 300 | - ) > 0) { |
|
| 301 | - preg_match('%value=([\'"])(.*?)\1%i', $input, $value); |
|
| 302 | - $value = (count($value) > 0) ? $value : array('', '', ''); |
|
| 303 | - preg_match('%type=([\'"])(.*?)\1%i', $input, $type); |
|
| 304 | - $type = (count($type) > 0) ? $type : array('', '', ''); |
|
| 305 | - // Skip the cart excludes |
|
| 306 | - if (in_array( |
|
| 307 | - $prefix.$name[2], |
|
| 308 | - self::$cart_excludes |
|
| 309 | - ) || in_array(substr( |
|
| 310 | - $prefix.$name[2], |
|
| 311 | - 0, |
|
| 312 | - 2 |
|
| 313 | - ), self::$cart_excludes_prefixes)) { |
|
| 314 | - self::$log[] = '<strong style="color:purple;">Skipping</strong> |
|
| 37 | + // protected static $cart_url = 'https://yourdomain.foxycart.com/cart'; |
|
| 38 | + protected static $cart_url; |
|
| 39 | + |
|
| 40 | + public static function setCartURL($storeName = null) |
|
| 41 | + { |
|
| 42 | + self::$cart_url = 'https://'.$storeName.'.faxycart.com/cart'; |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + public static function setSecret($secret = null) |
|
| 46 | + { |
|
| 47 | + self::$secret = $secret; |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + public function __construct() |
|
| 51 | + { |
|
| 52 | + self::setCartURL(FoxyCart::getFoxyCartStoreName()); |
|
| 53 | + self::setSecret(FoxyCart::getStoreKey()); |
|
| 54 | + } |
|
| 55 | + |
|
| 56 | + public static function getSecret() |
|
| 57 | + { |
|
| 58 | + return FoxyCart::getStoreKey(); |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * Cart Excludes. |
|
| 63 | + * |
|
| 64 | + * Arrays of values and prefixes that should be ignored when signing links and forms. |
|
| 65 | + * |
|
| 66 | + * @var array |
|
| 67 | + */ |
|
| 68 | + protected static $cart_excludes = array( |
|
| 69 | + // Cart values |
|
| 70 | + 'cart', 'fcsid', 'empty', 'coupon', 'output', 'sub_token', 'redirect', 'callback', '_', |
|
| 71 | + // Checkout pre-population values |
|
| 72 | + 'customer_email', 'customer_first_name', 'customer_last_name', 'customer_address1', 'customer_address2', |
|
| 73 | + 'customer_city', 'customer_state', 'customer_postal_code', 'customer_country', 'customer_phone', |
|
| 74 | + 'customer_company', 'shipping_first_name', 'shipping_last_name', 'shipping_address1', 'shipping_address2', |
|
| 75 | + 'shipping_city', 'shipping_state', 'shipping_postal_code', 'shipping_country', 'shipping_phone', |
|
| 76 | + 'shipping_company', |
|
| 77 | + ); |
|
| 78 | + protected static $cart_excludes_prefixes = array( |
|
| 79 | + 'h:', 'x:', '__', |
|
| 80 | + ); |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * Debugging. |
|
| 84 | + * |
|
| 85 | + * Set to $debug to TRUE to enable debug logging. |
|
| 86 | + */ |
|
| 87 | + protected static $debug = false; |
|
| 88 | + protected static $log = array(); |
|
| 89 | + |
|
| 90 | + /** |
|
| 91 | + * "Link Method": Generate HMAC SHA256 for GET Query Strings. |
|
| 92 | + * |
|
| 93 | + * Notes: Can't parse_str because PHP doesn't support non-alphanumeric characters as array keys. |
|
| 94 | + * |
|
| 95 | + * @return string |
|
| 96 | + **/ |
|
| 97 | + public static function fc_hash_querystring($qs, $output = true) |
|
| 98 | + { |
|
| 99 | + self::$log[] = '<strong>Signing link</strong> with data: ' |
|
| 100 | + .htmlspecialchars(substr($qs, 0, 150)).'...'; |
|
| 101 | + $fail = self::$cart_url.'?'.$qs; |
|
| 102 | + |
|
| 103 | + // If the link appears to be hashed already, don't bother |
|
| 104 | + if (strpos($qs, '||')) { |
|
| 105 | + self::$log[] = '<strong>Link appears to be signed already</strong>: '.htmlspecialchars($code[0]); |
|
| 106 | + |
|
| 107 | + return $fail; |
|
| 108 | + } |
|
| 109 | + |
|
| 110 | + // Stick an ampersand on the beginning of the querystring to make matching the first element a little easier |
|
| 111 | + $qs = '&'.urldecode($qs); |
|
| 112 | + |
|
| 113 | + // Get all the prefixes, codes, and name=value pairs |
|
| 114 | + preg_match_all( |
|
| 115 | + '%(?P<amp>&(?:amp;)?)(?P<prefix>[a-z0-9]{1,3}:)?(?P<name>[^=]+)=(?P<value>[^&]+)%', |
|
| 116 | + $qs, |
|
| 117 | + $pairs, |
|
| 118 | + PREG_SET_ORDER |
|
| 119 | + ); |
|
| 120 | + self::$log[] = 'Found the following pairs to sign:<pre>'.htmlspecialchars(print_r($pairs, true)).'</pre>'; |
|
| 121 | + |
|
| 122 | + // Get all the "code" values, set the matches in $codes |
|
| 123 | + $codes = array(); |
|
| 124 | + foreach ($pairs as $pair) { |
|
| 125 | + if ($pair['name'] == 'code') { |
|
| 126 | + $codes[$pair['prefix']] = $pair['value']; |
|
| 127 | + } |
|
| 128 | + } |
|
| 129 | + if (!count($codes)) { |
|
| 130 | + self::$log[] = '<strong style="color:#600;">No code found</strong> for the above link.'; |
|
| 131 | + |
|
| 132 | + return $fail; |
|
| 133 | + } |
|
| 134 | + self::$log[] = '<strong style="color:orange;">CODES found:</strong> ' |
|
| 135 | + .htmlspecialchars(print_r($codes, true)); |
|
| 136 | + |
|
| 137 | + // Sign the name/value pairs |
|
| 138 | + foreach ($pairs as $pair) { |
|
| 139 | + // Skip the cart excludes |
|
| 140 | + if (in_array($pair['name'], self::$cart_excludes) |
|
| 141 | + || in_array($pair['prefix'], self::$cart_excludes_prefixes)) { |
|
| 142 | + self::$log[] = '<strong style="color:purple;">Skipping</strong> the reserved parameter or prefix "' |
|
| 143 | + .$pair['prefix'].$pair['name'].'" = '.$pair['value']; |
|
| 144 | + continue; |
|
| 145 | + } |
|
| 146 | + |
|
| 147 | + // Continue to sign the value and replace the name=value in the querystring with name=value||hash |
|
| 148 | + $value = self::fc_hash_value( |
|
| 149 | + $codes[$pair['prefix']], |
|
| 150 | + $pair['name'], |
|
| 151 | + $pair['value'], |
|
| 152 | + 'value', |
|
| 153 | + false, |
|
| 154 | + 'urlencode' |
|
| 155 | + ); |
|
| 156 | + $replacement = $pair['amp'].$pair['prefix'].urlencode($pair['name']).'='.$value; |
|
| 157 | + $qs = str_replace($pair[0], $replacement, $qs); |
|
| 158 | + self::$log[] = 'Signed <strong>'.$pair['name'].'</strong> = <strong>'.$pair['value'].'</strong> with ' |
|
| 159 | + .$replacement.'.<br />Replacing: '.$pair[0].'<br />With... '.$replacement; |
|
| 160 | + } |
|
| 161 | + $qs = ltrim($qs, '&'); // Get rid of that leading ampersand we added earlier |
|
| 162 | + |
|
| 163 | + if ($output) { |
|
| 164 | + echo self::$cart_url.'?'.$qs; |
|
| 165 | + } else { |
|
| 166 | + return self::$cart_url.'?'.$qs; |
|
| 167 | + } |
|
| 168 | + } |
|
| 169 | + |
|
| 170 | + /** |
|
| 171 | + * "Form Method": Generate HMAC SHA256 for form elements or individual <input />s. |
|
| 172 | + * |
|
| 173 | + * @return string |
|
| 174 | + **/ |
|
| 175 | + public static function fc_hash_value( |
|
| 176 | + $product_code, |
|
| 177 | + $option_name, |
|
| 178 | + $option_value = '', |
|
| 179 | + $method = 'name', |
|
| 180 | + $output = true, |
|
| 181 | + $urlencode = false |
|
| 182 | + ) { |
|
| 183 | + if (!$product_code || !$option_name) { |
|
| 184 | + return false; |
|
| 185 | + } |
|
| 186 | + if ($option_value == '--OPEN--') { |
|
| 187 | + $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
|
| 188 | + $value = ($urlencode) ? urlencode($option_name).'||'.$hash.'||open' : $option_name.'||'.$hash.'||open'; |
|
| 189 | + } else { |
|
| 190 | + $hash = hash_hmac('sha256', $product_code.$option_name.$option_value, self::getSecret()); |
|
| 191 | + if ($method == 'name') { |
|
| 192 | + $value = ($urlencode) ? urlencode($option_name).'||'.$hash : $option_name.'||'.$hash; |
|
| 193 | + } else { |
|
| 194 | + $value = ($urlencode) ? urlencode($option_value).'||'.$hash : $option_value.'||'.$hash; |
|
| 195 | + } |
|
| 196 | + } |
|
| 197 | + |
|
| 198 | + if ($output) { |
|
| 199 | + echo $value; |
|
| 200 | + } else { |
|
| 201 | + return $value; |
|
| 202 | + } |
|
| 203 | + } |
|
| 204 | + |
|
| 205 | + /** |
|
| 206 | + * Raw HTML Signing: Sign all links and form elements in a block of HTML. |
|
| 207 | + * |
|
| 208 | + * Accepts a string of HTML and signs all links and forms. |
|
| 209 | + * Requires link 'href' and form 'action' attributes to use 'https' and not 'http'. |
|
| 210 | + * Requires a 'code' to be set in every form. |
|
| 211 | + * |
|
| 212 | + * @return string |
|
| 213 | + **/ |
|
| 214 | + public static function fc_hash_html($html) |
|
| 215 | + { |
|
| 216 | + // Initialize some counting |
|
| 217 | + $count['temp'] = 0; // temp counter |
|
| 218 | + $count['links'] = 0; |
|
| 219 | + $count['forms'] = 0; |
|
| 220 | + $count['inputs'] = 0; |
|
| 221 | + $count['lists'] = 0; |
|
| 222 | + $count['textareas'] = 0; |
|
| 223 | + |
|
| 224 | + // Find and sign all the links |
|
| 225 | + preg_match_all( |
|
| 226 | + '%<a .*?href=[\'"]'.preg_quote(self::$cart_url).'(?:\.php)?\?(.+?)[\'"].*?>%i', |
|
| 227 | + $html, |
|
| 228 | + $querystrings |
|
| 229 | + ); |
|
| 230 | + // print_r($querystrings); |
|
| 231 | + foreach ($querystrings[1] as $querystring) { |
|
| 232 | + // If it's already signed, skip it. |
|
| 233 | + if (preg_match('%&(?:amp;)?hash=%i', $querystring)) { |
|
| 234 | + continue; |
|
| 235 | + } |
|
| 236 | + $pattern = '%(href=[\'"])'.preg_quote(self::$cart_url, '%').'(?:\.php)?\?' |
|
| 237 | + .preg_quote($querystring, '%').'([\'"])%i'; |
|
| 238 | + $signed = self::fc_hash_querystring($querystring, false); |
|
| 239 | + $html = preg_replace($pattern, '$1'.$signed.'$2', $html, -1, $count['temp']); |
|
| 240 | + $count['links'] += $count['temp']; |
|
| 241 | + } |
|
| 242 | + unset($querystrings); |
|
| 243 | + |
|
| 244 | + // Find and sign all form values |
|
| 245 | + preg_match_all( |
|
| 246 | + '%<form [^>]*?action=[\'"]'.preg_quote(self::$cart_url).'?[\'"].*?>(.+?)</form>%is', |
|
| 247 | + $html, |
|
| 248 | + $forms |
|
| 249 | + ); |
|
| 250 | + foreach ($forms[1] as $form) { |
|
| 251 | + ++$count['forms']; |
|
| 252 | + self::$log[] = '<strong>Signing form</strong> with data: '.htmlspecialchars(substr( |
|
| 253 | + $form, |
|
| 254 | + 0, |
|
| 255 | + 150 |
|
| 256 | + )).'...'; |
|
| 257 | + |
|
| 258 | + // Store the original form so we can replace it when we're done |
|
| 259 | + $form_original = $form; |
|
| 260 | + |
|
| 261 | + // Check for the "code" input, set the matches in $codes |
|
| 262 | + if (!preg_match_all( |
|
| 263 | + '%<[^>]*?name=([\'"])([0-9]{1,3}:)?code\1[^>]*?>%i', |
|
| 264 | + $form, |
|
| 265 | + $codes, |
|
| 266 | + PREG_SET_ORDER |
|
| 267 | + )) { |
|
| 268 | + self::$log[] = '<strong style="color:#600;">No code found</strong> for the above form.'; |
|
| 269 | + continue; |
|
| 270 | + } |
|
| 271 | + // For each code found, sign the appropriate inputs |
|
| 272 | + foreach ($codes as $code) { |
|
| 273 | + // If the form appears to be hashed already, don't bother |
|
| 274 | + if (strpos($code[0], '||')) { |
|
| 275 | + self::$log[] = '<strong>Form appears to be signed already</strong>: '.htmlspecialchars($code[0]); |
|
| 276 | + continue; |
|
| 277 | + } |
|
| 278 | + // Get the code and the prefix |
|
| 279 | + $prefix = (isset($code[2])) ? $code[2] : ''; |
|
| 280 | + preg_match('%<[^>]*?value=([\'"])(.+?)\1[^>]*?>%i', $code[0], $code); |
|
| 281 | + $code = trim($code[2]); |
|
| 282 | + self::$log[] = '<strong>Prefix for '.htmlspecialchars($code).'</strong>: '.htmlspecialchars($prefix); |
|
| 283 | + if (!$code) { // If the code is empty, skip this form or specific prefixed elements |
|
| 284 | + continue; |
|
| 285 | + } |
|
| 286 | + |
|
| 287 | + // Sign all <input /> elements with matching prefix |
|
| 288 | + preg_match_all( |
|
| 289 | + '%<input [^>]*?name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(?:.+?)\1[^>]*>%i', |
|
| 290 | + $form, |
|
| 291 | + $inputs |
|
| 292 | + ); |
|
| 293 | + foreach ($inputs[0] as $input) { |
|
| 294 | + ++$count['inputs']; |
|
| 295 | + // Test to make sure both name and value attributes are found |
|
| 296 | + if (preg_match( |
|
| 297 | + '%name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1%i', |
|
| 298 | + $input, |
|
| 299 | + $name |
|
| 300 | + ) > 0) { |
|
| 301 | + preg_match('%value=([\'"])(.*?)\1%i', $input, $value); |
|
| 302 | + $value = (count($value) > 0) ? $value : array('', '', ''); |
|
| 303 | + preg_match('%type=([\'"])(.*?)\1%i', $input, $type); |
|
| 304 | + $type = (count($type) > 0) ? $type : array('', '', ''); |
|
| 305 | + // Skip the cart excludes |
|
| 306 | + if (in_array( |
|
| 307 | + $prefix.$name[2], |
|
| 308 | + self::$cart_excludes |
|
| 309 | + ) || in_array(substr( |
|
| 310 | + $prefix.$name[2], |
|
| 311 | + 0, |
|
| 312 | + 2 |
|
| 313 | + ), self::$cart_excludes_prefixes)) { |
|
| 314 | + self::$log[] = '<strong style="color:purple;">Skipping</strong> |
|
| 315 | 315 | the reserved parameter or prefix "'.$prefix.$name[2].'" = '.$value[2]; |
| 316 | - continue; |
|
| 317 | - } |
|
| 318 | - self::$log[] = '<strong>INPUT['.$type[2].']:</strong> Name: <strong>' |
|
| 319 | - .$prefix.htmlspecialchars(preg_quote($name[2])).'</strong>'; |
|
| 320 | - self::$log[] = '<strong>Replacement Pattern:</strong> ([\'"])' |
|
| 321 | - .$prefix.preg_quote($name[2]).'\1'; |
|
| 322 | - $value[2] = ($value[2] == '') ? '--OPEN--' : $value[2]; |
|
| 323 | - if ($type[2] == 'radio') { |
|
| 324 | - $input_signed = preg_replace('%([\'"])' |
|
| 325 | - .preg_quote($value[2]).'\1%', '${1}' |
|
| 326 | - .self::fc_hash_value($code, $name[2], $value[2], 'value', false) |
|
| 327 | - .'$1', $input); |
|
| 328 | - } else { |
|
| 329 | - $input_signed = preg_replace('%([\'"])'.$prefix.preg_quote($name[2]) |
|
| 330 | - .'\1%', '${1}'.$prefix |
|
| 331 | - .self::fc_hash_value($code, $name[2], $value[2], 'name', false) |
|
| 332 | - .'$1', $input); |
|
| 333 | - } |
|
| 334 | - self::$log[] = '<strong>INPUT:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 335 | - '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$name[2]). |
|
| 336 | - '</strong> :: Value: <strong>'.htmlspecialchars($value[2]). |
|
| 337 | - '</strong><br />Initial input: '.htmlspecialchars($input). |
|
| 338 | - '<br />Signed: <span style="color:#060;">'.htmlspecialchars($input_signed).'</span>'; |
|
| 339 | - $form = str_replace($input, $input_signed, $form); |
|
| 340 | - } |
|
| 341 | - } |
|
| 342 | - self::$log[] = '<strong>FORM after INPUTS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 343 | - |
|
| 344 | - // Sign all <option /> elements |
|
| 345 | - preg_match_all( |
|
| 346 | - '%<select [^>]*name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1[^>]*>(.+?)</select>%is', |
|
| 347 | - $form, |
|
| 348 | - $lists, |
|
| 349 | - PREG_SET_ORDER |
|
| 350 | - ); |
|
| 351 | - foreach ($lists as $list) { |
|
| 352 | - ++$count['lists']; |
|
| 353 | - preg_match_all( |
|
| 354 | - '%<option [^>]*value=([\'"])(.+?)\1[^>]*>(?:.*?)</option>%i', |
|
| 355 | - $list[0], |
|
| 356 | - $options, |
|
| 357 | - PREG_SET_ORDER |
|
| 358 | - ); |
|
| 359 | - self::$log[] = '<strong>Options:</strong> <pre>'.htmlspecialchars(print_r($options, true)) |
|
| 360 | - .'</pre>'; |
|
| 361 | - unset($form_part_signed); |
|
| 362 | - foreach ($options as $option) { |
|
| 363 | - if (!isset($form_part_signed)) { |
|
| 364 | - $form_part_signed = $list[0]; |
|
| 365 | - } |
|
| 366 | - $option_signed = preg_replace( |
|
| 367 | - '%'.preg_quote($option[1]).preg_quote($option[2]).preg_quote($option[1]).'%', |
|
| 368 | - $option[1].self::fc_hash_value( |
|
| 369 | - $code, |
|
| 370 | - $list[2], |
|
| 371 | - $option[2], |
|
| 372 | - 'value', |
|
| 373 | - false |
|
| 374 | - ).$option[1], |
|
| 375 | - $option[0] |
|
| 376 | - ); |
|
| 377 | - $form_part_signed = str_replace($option[0], $option_signed, $form_part_signed); |
|
| 378 | - self::$log[] = '<strong>OPTION:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 379 | - '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$list[2]). |
|
| 380 | - '</strong> :: Value: <strong>'.htmlspecialchars($option[2]). |
|
| 381 | - '</strong><br />Initial option: '.htmlspecialchars($option[0]). |
|
| 382 | - '<br />Signed: <span style="color:#060;">'.htmlspecialchars($option_signed).'</span>'; |
|
| 383 | - } |
|
| 384 | - $form = str_replace($list[0], $form_part_signed, $form); |
|
| 385 | - } |
|
| 386 | - self::$log[] = '<strong>FORM after OPTIONS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 387 | - |
|
| 388 | - // Sign all <textarea /> elements |
|
| 389 | - preg_match_all( |
|
| 390 | - '%<textarea [^>]*name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1[^>]*>(.*?)</textarea>%is', |
|
| 391 | - $form, |
|
| 392 | - $textareas, |
|
| 393 | - PREG_SET_ORDER |
|
| 394 | - ); |
|
| 395 | - // echo "\n\nTextareas: ".print_r($textareas, true); |
|
| 396 | - foreach ($textareas as $textarea) { |
|
| 397 | - ++$count['textareas']; |
|
| 398 | - // Tackle implied "--OPEN--" first, if textarea is empty |
|
| 399 | - $textarea[3] = ($textarea[3] == '') ? '--OPEN--' : $textarea[3]; |
|
| 400 | - $textarea_signed = preg_replace( |
|
| 401 | - '%([\'"])'.preg_quote($prefix.$textarea[2]).'\1%', |
|
| 402 | - '$1'.self::fc_hash_value( |
|
| 403 | - $code, |
|
| 404 | - $textarea[2], |
|
| 405 | - $textarea[3], |
|
| 406 | - 'name', |
|
| 407 | - false |
|
| 408 | - ).'$1', |
|
| 409 | - $textarea[0] |
|
| 410 | - ); |
|
| 411 | - $form = str_replace($textarea[0], $textarea_signed, $form); |
|
| 412 | - self::$log[] = '<strong>TEXTAREA:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 413 | - '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$textarea[2]). |
|
| 414 | - '</strong> :: Value: <strong>'.htmlspecialchars($textarea[3]). |
|
| 415 | - '</strong><br />Initial textarea: '.htmlspecialchars($textarea[0]). |
|
| 416 | - '<br />Signed: <span style="color:#060;">'.htmlspecialchars($textarea_signed).'</span>'; |
|
| 417 | - } |
|
| 418 | - self::$log[] = '<strong>FORM after TEXTAREAS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 419 | - |
|
| 420 | - // Exclude all <button> elements |
|
| 421 | - $form = preg_replace( |
|
| 422 | - '%<button ([^>]*)name=([\'"])(.*?)\1([^>]*>.*?</button>)%i', |
|
| 423 | - '<button $1name=$2x:$3$4', |
|
| 424 | - $form |
|
| 425 | - ); |
|
| 426 | - } |
|
| 427 | - // Replace the entire form |
|
| 428 | - self::$log[] = '<strong>FORM after ALL:</strong> <pre>'.htmlspecialchars($form).'</pre>' |
|
| 429 | - .'replacing <pre>'.htmlspecialchars($form_original).'</pre>'; |
|
| 430 | - $html = str_replace($form_original, $form, $html); |
|
| 431 | - self::$log[] = '<strong>FORM end</strong><hr />'; |
|
| 432 | - } |
|
| 433 | - |
|
| 434 | - // Return the signed output |
|
| 435 | - $output = ''; |
|
| 436 | - if (self::$debug) { |
|
| 437 | - self::$log['Summary'] = $count['links'].' links signed. '.$count['forms'].' forms signed. ' |
|
| 438 | - .$count['inputs'].' inputs signed. '.$count['lists'].' lists signed. '.$count['textareas'] |
|
| 439 | - .' textareas signed.'; |
|
| 440 | - $output .= '<h3>FoxyCart HMAC Debugging:</h3><ul>'; |
|
| 441 | - foreach (self::$log as $name => $value) { |
|
| 442 | - $output .= '<li><strong>'.$name.':</strong> '.$value.'</li>'; |
|
| 443 | - } |
|
| 444 | - $output .= '</ul><hr />'; |
|
| 445 | - } |
|
| 446 | - |
|
| 447 | - return $output.$html; |
|
| 448 | - } |
|
| 316 | + continue; |
|
| 317 | + } |
|
| 318 | + self::$log[] = '<strong>INPUT['.$type[2].']:</strong> Name: <strong>' |
|
| 319 | + .$prefix.htmlspecialchars(preg_quote($name[2])).'</strong>'; |
|
| 320 | + self::$log[] = '<strong>Replacement Pattern:</strong> ([\'"])' |
|
| 321 | + .$prefix.preg_quote($name[2]).'\1'; |
|
| 322 | + $value[2] = ($value[2] == '') ? '--OPEN--' : $value[2]; |
|
| 323 | + if ($type[2] == 'radio') { |
|
| 324 | + $input_signed = preg_replace('%([\'"])' |
|
| 325 | + .preg_quote($value[2]).'\1%', '${1}' |
|
| 326 | + .self::fc_hash_value($code, $name[2], $value[2], 'value', false) |
|
| 327 | + .'$1', $input); |
|
| 328 | + } else { |
|
| 329 | + $input_signed = preg_replace('%([\'"])'.$prefix.preg_quote($name[2]) |
|
| 330 | + .'\1%', '${1}'.$prefix |
|
| 331 | + .self::fc_hash_value($code, $name[2], $value[2], 'name', false) |
|
| 332 | + .'$1', $input); |
|
| 333 | + } |
|
| 334 | + self::$log[] = '<strong>INPUT:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 335 | + '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$name[2]). |
|
| 336 | + '</strong> :: Value: <strong>'.htmlspecialchars($value[2]). |
|
| 337 | + '</strong><br />Initial input: '.htmlspecialchars($input). |
|
| 338 | + '<br />Signed: <span style="color:#060;">'.htmlspecialchars($input_signed).'</span>'; |
|
| 339 | + $form = str_replace($input, $input_signed, $form); |
|
| 340 | + } |
|
| 341 | + } |
|
| 342 | + self::$log[] = '<strong>FORM after INPUTS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 343 | + |
|
| 344 | + // Sign all <option /> elements |
|
| 345 | + preg_match_all( |
|
| 346 | + '%<select [^>]*name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1[^>]*>(.+?)</select>%is', |
|
| 347 | + $form, |
|
| 348 | + $lists, |
|
| 349 | + PREG_SET_ORDER |
|
| 350 | + ); |
|
| 351 | + foreach ($lists as $list) { |
|
| 352 | + ++$count['lists']; |
|
| 353 | + preg_match_all( |
|
| 354 | + '%<option [^>]*value=([\'"])(.+?)\1[^>]*>(?:.*?)</option>%i', |
|
| 355 | + $list[0], |
|
| 356 | + $options, |
|
| 357 | + PREG_SET_ORDER |
|
| 358 | + ); |
|
| 359 | + self::$log[] = '<strong>Options:</strong> <pre>'.htmlspecialchars(print_r($options, true)) |
|
| 360 | + .'</pre>'; |
|
| 361 | + unset($form_part_signed); |
|
| 362 | + foreach ($options as $option) { |
|
| 363 | + if (!isset($form_part_signed)) { |
|
| 364 | + $form_part_signed = $list[0]; |
|
| 365 | + } |
|
| 366 | + $option_signed = preg_replace( |
|
| 367 | + '%'.preg_quote($option[1]).preg_quote($option[2]).preg_quote($option[1]).'%', |
|
| 368 | + $option[1].self::fc_hash_value( |
|
| 369 | + $code, |
|
| 370 | + $list[2], |
|
| 371 | + $option[2], |
|
| 372 | + 'value', |
|
| 373 | + false |
|
| 374 | + ).$option[1], |
|
| 375 | + $option[0] |
|
| 376 | + ); |
|
| 377 | + $form_part_signed = str_replace($option[0], $option_signed, $form_part_signed); |
|
| 378 | + self::$log[] = '<strong>OPTION:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 379 | + '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$list[2]). |
|
| 380 | + '</strong> :: Value: <strong>'.htmlspecialchars($option[2]). |
|
| 381 | + '</strong><br />Initial option: '.htmlspecialchars($option[0]). |
|
| 382 | + '<br />Signed: <span style="color:#060;">'.htmlspecialchars($option_signed).'</span>'; |
|
| 383 | + } |
|
| 384 | + $form = str_replace($list[0], $form_part_signed, $form); |
|
| 385 | + } |
|
| 386 | + self::$log[] = '<strong>FORM after OPTIONS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 387 | + |
|
| 388 | + // Sign all <textarea /> elements |
|
| 389 | + preg_match_all( |
|
| 390 | + '%<textarea [^>]*name=([\'"])'.preg_quote($prefix).'(?![0-9]{1,3})(.+?)\1[^>]*>(.*?)</textarea>%is', |
|
| 391 | + $form, |
|
| 392 | + $textareas, |
|
| 393 | + PREG_SET_ORDER |
|
| 394 | + ); |
|
| 395 | + // echo "\n\nTextareas: ".print_r($textareas, true); |
|
| 396 | + foreach ($textareas as $textarea) { |
|
| 397 | + ++$count['textareas']; |
|
| 398 | + // Tackle implied "--OPEN--" first, if textarea is empty |
|
| 399 | + $textarea[3] = ($textarea[3] == '') ? '--OPEN--' : $textarea[3]; |
|
| 400 | + $textarea_signed = preg_replace( |
|
| 401 | + '%([\'"])'.preg_quote($prefix.$textarea[2]).'\1%', |
|
| 402 | + '$1'.self::fc_hash_value( |
|
| 403 | + $code, |
|
| 404 | + $textarea[2], |
|
| 405 | + $textarea[3], |
|
| 406 | + 'name', |
|
| 407 | + false |
|
| 408 | + ).'$1', |
|
| 409 | + $textarea[0] |
|
| 410 | + ); |
|
| 411 | + $form = str_replace($textarea[0], $textarea_signed, $form); |
|
| 412 | + self::$log[] = '<strong>TEXTAREA:</strong> Code: <strong>'.htmlspecialchars($prefix.$code). |
|
| 413 | + '</strong> :: Name: <strong>'.htmlspecialchars($prefix.$textarea[2]). |
|
| 414 | + '</strong> :: Value: <strong>'.htmlspecialchars($textarea[3]). |
|
| 415 | + '</strong><br />Initial textarea: '.htmlspecialchars($textarea[0]). |
|
| 416 | + '<br />Signed: <span style="color:#060;">'.htmlspecialchars($textarea_signed).'</span>'; |
|
| 417 | + } |
|
| 418 | + self::$log[] = '<strong>FORM after TEXTAREAS:</strong> <pre>'.htmlspecialchars($form).'</pre>'; |
|
| 419 | + |
|
| 420 | + // Exclude all <button> elements |
|
| 421 | + $form = preg_replace( |
|
| 422 | + '%<button ([^>]*)name=([\'"])(.*?)\1([^>]*>.*?</button>)%i', |
|
| 423 | + '<button $1name=$2x:$3$4', |
|
| 424 | + $form |
|
| 425 | + ); |
|
| 426 | + } |
|
| 427 | + // Replace the entire form |
|
| 428 | + self::$log[] = '<strong>FORM after ALL:</strong> <pre>'.htmlspecialchars($form).'</pre>' |
|
| 429 | + .'replacing <pre>'.htmlspecialchars($form_original).'</pre>'; |
|
| 430 | + $html = str_replace($form_original, $form, $html); |
|
| 431 | + self::$log[] = '<strong>FORM end</strong><hr />'; |
|
| 432 | + } |
|
| 433 | + |
|
| 434 | + // Return the signed output |
|
| 435 | + $output = ''; |
|
| 436 | + if (self::$debug) { |
|
| 437 | + self::$log['Summary'] = $count['links'].' links signed. '.$count['forms'].' forms signed. ' |
|
| 438 | + .$count['inputs'].' inputs signed. '.$count['lists'].' lists signed. '.$count['textareas'] |
|
| 439 | + .' textareas signed.'; |
|
| 440 | + $output .= '<h3>FoxyCart HMAC Debugging:</h3><ul>'; |
|
| 441 | + foreach (self::$log as $name => $value) { |
|
| 442 | + $output .= '<li><strong>'.$name.':</strong> '.$value.'</li>'; |
|
| 443 | + } |
|
| 444 | + $output .= '</ul><hr />'; |
|
| 445 | + } |
|
| 446 | + |
|
| 447 | + return $output.$html; |
|
| 448 | + } |
|
| 449 | 449 | } |
@@ -88,7 +88,7 @@ discard block |
||
| 88 | 88 | // Retrieve validator, if one has been setup (e.g. via data extensions). |
| 89 | 89 | if ($config->hasMethod('getCMSValidator')) { |
| 90 | 90 | $validator = $config->getCMSValidator(); |
| 91 | - } else { |
|
| 91 | + }else { |
|
| 92 | 92 | $validator = null; |
| 93 | 93 | } |
| 94 | 94 | |
@@ -101,13 +101,13 @@ discard block |
||
| 101 | 101 | $actions, |
| 102 | 102 | $validator |
| 103 | 103 | )->setHTMLID('Form_EditForm'); |
| 104 | - $form->setValidationResponseCallback(function (ValidationResult $errors) use ($negotiator, $form) { |
|
| 104 | + $form->setValidationResponseCallback(function(ValidationResult $errors) use ($negotiator, $form) { |
|
| 105 | 105 | $request = $this->getRequest(); |
| 106 | 106 | if ($request->isAjax() && $negotiator) { |
| 107 | 107 | $result = $form->forTemplate(); |
| 108 | 108 | |
| 109 | 109 | return $negotiator->respond($request, array( |
| 110 | - 'CurrentForm' => function () use ($result) { |
|
| 110 | + 'CurrentForm' => function() use ($result) { |
|
| 111 | 111 | return $result; |
| 112 | 112 | }, |
| 113 | 113 | )); |
@@ -18,163 +18,163 @@ |
||
| 18 | 18 | |
| 19 | 19 | class FoxyStripeAdmin extends LeftAndMain |
| 20 | 20 | { |
| 21 | - /** |
|
| 22 | - * @var string |
|
| 23 | - */ |
|
| 24 | - private static $url_segment = 'foxystripe'; |
|
| 25 | - |
|
| 26 | - /** |
|
| 27 | - * @var string |
|
| 28 | - */ |
|
| 29 | - private static $url_rule = '/$Action/$ID/$OtherID'; |
|
| 30 | - |
|
| 31 | - /** |
|
| 32 | - * @var int |
|
| 33 | - */ |
|
| 34 | - private static $menu_priority = 4; |
|
| 35 | - |
|
| 36 | - /** |
|
| 37 | - * @var string |
|
| 38 | - */ |
|
| 39 | - private static $menu_title = 'FoxyStripe'; |
|
| 40 | - |
|
| 41 | - /** |
|
| 42 | - * @var string |
|
| 43 | - */ |
|
| 44 | - private static $menu_icon_class = 'font-icon-cog'; |
|
| 45 | - |
|
| 46 | - /** |
|
| 47 | - * @var string |
|
| 48 | - */ |
|
| 49 | - private static $tree_class = FoxyStripeSetting::class; |
|
| 50 | - |
|
| 51 | - /** |
|
| 52 | - * @var array |
|
| 53 | - */ |
|
| 54 | - private static $required_permission_codes = ['EDIT_GLOBAL_PERMISSION']; |
|
| 55 | - |
|
| 56 | - /** |
|
| 57 | - * Initialises the {@link FoxyStripeSetting} controller. |
|
| 58 | - */ |
|
| 59 | - public function init() |
|
| 60 | - { |
|
| 61 | - parent::init(); |
|
| 62 | - |
|
| 63 | - Requirements::javascript('silverstripe/cms: client/dist/js/bundle.js'); |
|
| 64 | - } |
|
| 65 | - |
|
| 66 | - /** |
|
| 67 | - * @param null $id |
|
| 68 | - * @param null $fields |
|
| 69 | - * |
|
| 70 | - * @return $this|Form |
|
| 71 | - */ |
|
| 72 | - public function getEditForm($id = null, $fields = null) |
|
| 73 | - { |
|
| 74 | - $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 75 | - $fields = $config->getCMSFields(); |
|
| 76 | - |
|
| 77 | - // Tell the CMS what URL the preview should show |
|
| 78 | - $home = Director::absoluteBaseURL(); |
|
| 79 | - $fields->push(new HiddenField('PreviewURL', 'Preview URL', $home)); |
|
| 80 | - |
|
| 81 | - // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load |
|
| 82 | - $fields->push($navField = new LiteralField( |
|
| 83 | - 'SilverStripeNavigator', |
|
| 84 | - $this->getSilverStripeNavigator() |
|
| 85 | - )); |
|
| 86 | - $navField->setAllowHTML(true); |
|
| 87 | - |
|
| 88 | - // Retrieve validator, if one has been setup (e.g. via data extensions). |
|
| 89 | - if ($config->hasMethod('getCMSValidator')) { |
|
| 90 | - $validator = $config->getCMSValidator(); |
|
| 91 | - } else { |
|
| 92 | - $validator = null; |
|
| 93 | - } |
|
| 94 | - |
|
| 95 | - $actions = $config->getCMSActions(); |
|
| 96 | - $negotiator = $this->getResponseNegotiator(); |
|
| 97 | - $form = Form::create( |
|
| 98 | - $this, |
|
| 99 | - 'EditForm', |
|
| 100 | - $fields, |
|
| 101 | - $actions, |
|
| 102 | - $validator |
|
| 103 | - )->setHTMLID('Form_EditForm'); |
|
| 104 | - $form->setValidationResponseCallback(function (ValidationResult $errors) use ($negotiator, $form) { |
|
| 105 | - $request = $this->getRequest(); |
|
| 106 | - if ($request->isAjax() && $negotiator) { |
|
| 107 | - $result = $form->forTemplate(); |
|
| 108 | - |
|
| 109 | - return $negotiator->respond($request, array( |
|
| 110 | - 'CurrentForm' => function () use ($result) { |
|
| 111 | - return $result; |
|
| 112 | - }, |
|
| 113 | - )); |
|
| 114 | - } |
|
| 115 | - return null; |
|
| 116 | - }); |
|
| 117 | - $form->addExtraClass('flexbox-area-grow fill-height cms-content cms-edit-form'); |
|
| 118 | - $form->setAttribute('data-pjax-fragment', 'CurrentForm'); |
|
| 119 | - |
|
| 120 | - if ($form->Fields()->hasTabSet()) { |
|
| 121 | - $form->Fields()->findOrMakeTab('Root')->setTemplate('SilverStripe\\Forms\\CMSTabSet'); |
|
| 122 | - } |
|
| 123 | - $form->setHTMLID('Form_EditForm'); |
|
| 124 | - $form->loadDataFrom($config); |
|
| 125 | - $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); |
|
| 126 | - |
|
| 127 | - // Use <button> to allow full jQuery UI styling |
|
| 128 | - $actions = $actions->dataFields(); |
|
| 129 | - if ($actions) { |
|
| 130 | - /** @var FormAction $action */ |
|
| 131 | - foreach ($actions as $action) { |
|
| 132 | - $action->setUseButtonTag(true); |
|
| 133 | - } |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - $this->extend('updateEditForm', $form); |
|
| 137 | - |
|
| 138 | - return $form; |
|
| 139 | - } |
|
| 140 | - |
|
| 141 | - /** |
|
| 142 | - * Save the current sites {@link FoxyStripeSetting} into the database. |
|
| 143 | - * |
|
| 144 | - * @param $data |
|
| 145 | - * @param $form |
|
| 146 | - * |
|
| 147 | - * @return \SilverStripe\Control\HTTPResponse |
|
| 148 | - * @throws \SilverStripe\Control\HTTPResponse_Exception |
|
| 149 | - */ |
|
| 150 | - public function save_foxystripe_setting($data, $form) |
|
| 151 | - { |
|
| 152 | - $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 153 | - $form->saveInto($config); |
|
| 154 | - try { |
|
| 155 | - $config->write(); |
|
| 156 | - } catch (ValidationException $ex) { |
|
| 157 | - $form->sessionMessage($ex->getResult()->message(), 'bad'); |
|
| 158 | - |
|
| 159 | - return $this->getResponseNegotiator()->respond($this->request); |
|
| 160 | - } |
|
| 161 | - $this->response->addHeader('X-Status', rawurlencode(_t('SilverStripe\\Admin\\LeftAndMain.SAVEDUP', 'Saved.'))); |
|
| 162 | - |
|
| 163 | - return $form->forTemplate(); |
|
| 164 | - } |
|
| 165 | - |
|
| 166 | - /** |
|
| 167 | - * @param bool $unlinked |
|
| 168 | - * |
|
| 169 | - * @return ArrayList |
|
| 170 | - */ |
|
| 171 | - public function Breadcrumbs($unlinked = false) |
|
| 172 | - { |
|
| 173 | - return new ArrayList(array( |
|
| 174 | - new ArrayData(array( |
|
| 175 | - 'Title' => static::menu_title(), |
|
| 176 | - 'Link' => $this->Link(), |
|
| 177 | - )), |
|
| 178 | - )); |
|
| 179 | - } |
|
| 21 | + /** |
|
| 22 | + * @var string |
|
| 23 | + */ |
|
| 24 | + private static $url_segment = 'foxystripe'; |
|
| 25 | + |
|
| 26 | + /** |
|
| 27 | + * @var string |
|
| 28 | + */ |
|
| 29 | + private static $url_rule = '/$Action/$ID/$OtherID'; |
|
| 30 | + |
|
| 31 | + /** |
|
| 32 | + * @var int |
|
| 33 | + */ |
|
| 34 | + private static $menu_priority = 4; |
|
| 35 | + |
|
| 36 | + /** |
|
| 37 | + * @var string |
|
| 38 | + */ |
|
| 39 | + private static $menu_title = 'FoxyStripe'; |
|
| 40 | + |
|
| 41 | + /** |
|
| 42 | + * @var string |
|
| 43 | + */ |
|
| 44 | + private static $menu_icon_class = 'font-icon-cog'; |
|
| 45 | + |
|
| 46 | + /** |
|
| 47 | + * @var string |
|
| 48 | + */ |
|
| 49 | + private static $tree_class = FoxyStripeSetting::class; |
|
| 50 | + |
|
| 51 | + /** |
|
| 52 | + * @var array |
|
| 53 | + */ |
|
| 54 | + private static $required_permission_codes = ['EDIT_GLOBAL_PERMISSION']; |
|
| 55 | + |
|
| 56 | + /** |
|
| 57 | + * Initialises the {@link FoxyStripeSetting} controller. |
|
| 58 | + */ |
|
| 59 | + public function init() |
|
| 60 | + { |
|
| 61 | + parent::init(); |
|
| 62 | + |
|
| 63 | + Requirements::javascript('silverstripe/cms: client/dist/js/bundle.js'); |
|
| 64 | + } |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * @param null $id |
|
| 68 | + * @param null $fields |
|
| 69 | + * |
|
| 70 | + * @return $this|Form |
|
| 71 | + */ |
|
| 72 | + public function getEditForm($id = null, $fields = null) |
|
| 73 | + { |
|
| 74 | + $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 75 | + $fields = $config->getCMSFields(); |
|
| 76 | + |
|
| 77 | + // Tell the CMS what URL the preview should show |
|
| 78 | + $home = Director::absoluteBaseURL(); |
|
| 79 | + $fields->push(new HiddenField('PreviewURL', 'Preview URL', $home)); |
|
| 80 | + |
|
| 81 | + // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load |
|
| 82 | + $fields->push($navField = new LiteralField( |
|
| 83 | + 'SilverStripeNavigator', |
|
| 84 | + $this->getSilverStripeNavigator() |
|
| 85 | + )); |
|
| 86 | + $navField->setAllowHTML(true); |
|
| 87 | + |
|
| 88 | + // Retrieve validator, if one has been setup (e.g. via data extensions). |
|
| 89 | + if ($config->hasMethod('getCMSValidator')) { |
|
| 90 | + $validator = $config->getCMSValidator(); |
|
| 91 | + } else { |
|
| 92 | + $validator = null; |
|
| 93 | + } |
|
| 94 | + |
|
| 95 | + $actions = $config->getCMSActions(); |
|
| 96 | + $negotiator = $this->getResponseNegotiator(); |
|
| 97 | + $form = Form::create( |
|
| 98 | + $this, |
|
| 99 | + 'EditForm', |
|
| 100 | + $fields, |
|
| 101 | + $actions, |
|
| 102 | + $validator |
|
| 103 | + )->setHTMLID('Form_EditForm'); |
|
| 104 | + $form->setValidationResponseCallback(function (ValidationResult $errors) use ($negotiator, $form) { |
|
| 105 | + $request = $this->getRequest(); |
|
| 106 | + if ($request->isAjax() && $negotiator) { |
|
| 107 | + $result = $form->forTemplate(); |
|
| 108 | + |
|
| 109 | + return $negotiator->respond($request, array( |
|
| 110 | + 'CurrentForm' => function () use ($result) { |
|
| 111 | + return $result; |
|
| 112 | + }, |
|
| 113 | + )); |
|
| 114 | + } |
|
| 115 | + return null; |
|
| 116 | + }); |
|
| 117 | + $form->addExtraClass('flexbox-area-grow fill-height cms-content cms-edit-form'); |
|
| 118 | + $form->setAttribute('data-pjax-fragment', 'CurrentForm'); |
|
| 119 | + |
|
| 120 | + if ($form->Fields()->hasTabSet()) { |
|
| 121 | + $form->Fields()->findOrMakeTab('Root')->setTemplate('SilverStripe\\Forms\\CMSTabSet'); |
|
| 122 | + } |
|
| 123 | + $form->setHTMLID('Form_EditForm'); |
|
| 124 | + $form->loadDataFrom($config); |
|
| 125 | + $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); |
|
| 126 | + |
|
| 127 | + // Use <button> to allow full jQuery UI styling |
|
| 128 | + $actions = $actions->dataFields(); |
|
| 129 | + if ($actions) { |
|
| 130 | + /** @var FormAction $action */ |
|
| 131 | + foreach ($actions as $action) { |
|
| 132 | + $action->setUseButtonTag(true); |
|
| 133 | + } |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + $this->extend('updateEditForm', $form); |
|
| 137 | + |
|
| 138 | + return $form; |
|
| 139 | + } |
|
| 140 | + |
|
| 141 | + /** |
|
| 142 | + * Save the current sites {@link FoxyStripeSetting} into the database. |
|
| 143 | + * |
|
| 144 | + * @param $data |
|
| 145 | + * @param $form |
|
| 146 | + * |
|
| 147 | + * @return \SilverStripe\Control\HTTPResponse |
|
| 148 | + * @throws \SilverStripe\Control\HTTPResponse_Exception |
|
| 149 | + */ |
|
| 150 | + public function save_foxystripe_setting($data, $form) |
|
| 151 | + { |
|
| 152 | + $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 153 | + $form->saveInto($config); |
|
| 154 | + try { |
|
| 155 | + $config->write(); |
|
| 156 | + } catch (ValidationException $ex) { |
|
| 157 | + $form->sessionMessage($ex->getResult()->message(), 'bad'); |
|
| 158 | + |
|
| 159 | + return $this->getResponseNegotiator()->respond($this->request); |
|
| 160 | + } |
|
| 161 | + $this->response->addHeader('X-Status', rawurlencode(_t('SilverStripe\\Admin\\LeftAndMain.SAVEDUP', 'Saved.'))); |
|
| 162 | + |
|
| 163 | + return $form->forTemplate(); |
|
| 164 | + } |
|
| 165 | + |
|
| 166 | + /** |
|
| 167 | + * @param bool $unlinked |
|
| 168 | + * |
|
| 169 | + * @return ArrayList |
|
| 170 | + */ |
|
| 171 | + public function Breadcrumbs($unlinked = false) |
|
| 172 | + { |
|
| 173 | + return new ArrayList(array( |
|
| 174 | + new ArrayData(array( |
|
| 175 | + 'Title' => static::menu_title(), |
|
| 176 | + 'Link' => $this->Link(), |
|
| 177 | + )), |
|
| 178 | + )); |
|
| 179 | + } |
|
| 180 | 180 | } |
@@ -211,7 +211,7 @@ discard block |
||
| 211 | 211 | $this->parseOrderDetails($response); |
| 212 | 212 | |
| 213 | 213 | return true; |
| 214 | - } else { |
|
| 214 | + }else { |
|
| 215 | 215 | return false; |
| 216 | 216 | } |
| 217 | 217 | } |
@@ -223,14 +223,14 @@ discard block |
||
| 223 | 223 | { |
| 224 | 224 | foreach ($response->transactions->transaction as $transaction) { |
| 225 | 225 | // Record transaction data from FoxyCart Datafeed: |
| 226 | - $this->Store_ID = (int) $transaction->store_id; |
|
| 227 | - $this->TransactionDate = (string) $transaction->transaction_date; |
|
| 228 | - $this->ProductTotal = (float) $transaction->product_total; |
|
| 229 | - $this->TaxTotal = (float) $transaction->tax_total; |
|
| 230 | - $this->ShippingTotal = (float) $transaction->shipping_total; |
|
| 231 | - $this->OrderTotal = (float) $transaction->order_total; |
|
| 232 | - $this->ReceiptURL = (string) $transaction->receipt_url; |
|
| 233 | - $this->OrderStatus = (string) $transaction->status; |
|
| 226 | + $this->Store_ID = (int)$transaction->store_id; |
|
| 227 | + $this->TransactionDate = (string)$transaction->transaction_date; |
|
| 228 | + $this->ProductTotal = (float)$transaction->product_total; |
|
| 229 | + $this->TaxTotal = (float)$transaction->tax_total; |
|
| 230 | + $this->ShippingTotal = (float)$transaction->shipping_total; |
|
| 231 | + $this->OrderTotal = (float)$transaction->order_total; |
|
| 232 | + $this->ReceiptURL = (string)$transaction->receipt_url; |
|
| 233 | + $this->OrderStatus = (string)$transaction->status; |
|
| 234 | 234 | |
| 235 | 235 | $this->extend('handleOrderInfo', $order, $response); |
| 236 | 236 | } |
@@ -249,18 +249,18 @@ discard block |
||
| 249 | 249 | if (Member::get()->filter('Email', $transaction->customer_email)->First()) { |
| 250 | 250 | $customer = Member::get()->filter('Email', $transaction->customer_email)->First(); |
| 251 | 251 | // if new customer, create account with data from FoxyCart |
| 252 | - } else { |
|
| 252 | + }else { |
|
| 253 | 253 | // set PasswordEncryption to 'none' so imported, encrypted password is not encrypted again |
| 254 | 254 | Config::modify()->set(Security::class, 'password_encryption_algorithm', 'none'); |
| 255 | 255 | |
| 256 | 256 | // create new Member, set password info from FoxyCart |
| 257 | 257 | $customer = Member::create(); |
| 258 | - $customer->Customer_ID = (int) $transaction->customer_id; |
|
| 259 | - $customer->FirstName = (string) $transaction->customer_first_name; |
|
| 260 | - $customer->Surname = (string) $transaction->customer_last_name; |
|
| 261 | - $customer->Email = (string) $transaction->customer_email; |
|
| 262 | - $customer->Password = (string) $transaction->customer_password; |
|
| 263 | - $customer->Salt = (string) $transaction->customer_password_salt; |
|
| 258 | + $customer->Customer_ID = (int)$transaction->customer_id; |
|
| 259 | + $customer->FirstName = (string)$transaction->customer_first_name; |
|
| 260 | + $customer->Surname = (string)$transaction->customer_last_name; |
|
| 261 | + $customer->Email = (string)$transaction->customer_email; |
|
| 262 | + $customer->Password = (string)$transaction->customer_password; |
|
| 263 | + $customer->Salt = (string)$transaction->customer_password_salt; |
|
| 264 | 264 | $customer->PasswordEncryption = 'none'; |
| 265 | 265 | |
| 266 | 266 | // record member record |
@@ -297,11 +297,11 @@ discard block |
||
| 297 | 297 | foreach ($transaction->transaction_details->transaction_detail as $detail) { |
| 298 | 298 | $OrderDetail = OrderDetail::create(); |
| 299 | 299 | |
| 300 | - $OrderDetail->Quantity = (int) $detail->product_quantity; |
|
| 301 | - $OrderDetail->ProductName = (string) $detail->product_name; |
|
| 302 | - $OrderDetail->ProductCode = (string) $detail->product_code; |
|
| 303 | - $OrderDetail->ProductImage = (string) $detail->image; |
|
| 304 | - $OrderDetail->ProductCategory = (string) $detail->category_code; |
|
| 300 | + $OrderDetail->Quantity = (int)$detail->product_quantity; |
|
| 301 | + $OrderDetail->ProductName = (string)$detail->product_name; |
|
| 302 | + $OrderDetail->ProductCode = (string)$detail->product_code; |
|
| 303 | + $OrderDetail->ProductImage = (string)$detail->image; |
|
| 304 | + $OrderDetail->ProductCategory = (string)$detail->category_code; |
|
| 305 | 305 | $priceModifier = 0; |
| 306 | 306 | |
| 307 | 307 | // parse OrderOptions |
@@ -309,14 +309,14 @@ discard block |
||
| 309 | 309 | // Find product via product_id custom variable |
| 310 | 310 | if ($option->product_option_name == 'product_id') { |
| 311 | 311 | // if product is found, set relation to OrderDetail |
| 312 | - $OrderProduct = ProductPage::get()->byID((int) $option->product_option_value); |
|
| 312 | + $OrderProduct = ProductPage::get()->byID((int)$option->product_option_value); |
|
| 313 | 313 | if ($OrderProduct) { |
| 314 | 314 | $OrderDetail->ProductID = $OrderProduct->ID; |
| 315 | 315 | } |
| 316 | - } else { |
|
| 316 | + }else { |
|
| 317 | 317 | $OrderOption = OrderOption::create(); |
| 318 | - $OrderOption->Name = (string) $option->product_option_name; |
|
| 319 | - $OrderOption->Value = (string) $option->product_option_value; |
|
| 318 | + $OrderOption->Name = (string)$option->product_option_name; |
|
| 319 | + $OrderOption->Value = (string)$option->product_option_value; |
|
| 320 | 320 | $OrderOption->write(); |
| 321 | 321 | $OrderDetail->OrderOptions()->add($OrderOption); |
| 322 | 322 | |
@@ -324,7 +324,7 @@ discard block |
||
| 324 | 324 | } |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | - $OrderDetail->Price = (float) $detail->product_price + (float) $priceModifier; |
|
| 327 | + $OrderDetail->Price = (float)$detail->product_price + (float)$priceModifier; |
|
| 328 | 328 | |
| 329 | 329 | // extend OrderDetail parsing, allowing for recording custom fields from FoxyCart |
| 330 | 330 | $this->extend('handleOrderItem', $order, $response, $OrderDetail); |
@@ -33,361 +33,361 @@ |
||
| 33 | 33 | */ |
| 34 | 34 | class Order extends DataObject implements PermissionProvider |
| 35 | 35 | { |
| 36 | - /** |
|
| 37 | - * @var array |
|
| 38 | - */ |
|
| 39 | - private static $db = array( |
|
| 40 | - 'Order_ID' => 'Int', |
|
| 41 | - 'TransactionDate' => 'DBDatetime', |
|
| 42 | - 'ProductTotal' => 'Currency', |
|
| 43 | - 'TaxTotal' => 'Currency', |
|
| 44 | - 'ShippingTotal' => 'Currency', |
|
| 45 | - 'OrderTotal' => 'Currency', |
|
| 46 | - 'ReceiptURL' => 'Varchar(255)', |
|
| 47 | - 'OrderStatus' => 'Varchar(255)', |
|
| 48 | - 'Response' => 'Text', |
|
| 49 | - ); |
|
| 50 | - |
|
| 51 | - /** |
|
| 52 | - * @var array |
|
| 53 | - */ |
|
| 54 | - private static $has_one = array( |
|
| 55 | - 'Member' => Member::class, |
|
| 56 | - ); |
|
| 57 | - |
|
| 58 | - /** |
|
| 59 | - * @var array |
|
| 60 | - */ |
|
| 61 | - private static $has_many = array( |
|
| 62 | - 'Details' => OrderDetail::class, |
|
| 63 | - ); |
|
| 64 | - |
|
| 65 | - /** |
|
| 66 | - * @var string |
|
| 67 | - */ |
|
| 68 | - private static $singular_name = 'Order'; |
|
| 69 | - |
|
| 70 | - /** |
|
| 71 | - * @var string |
|
| 72 | - */ |
|
| 73 | - private static $plural_name = 'Orders'; |
|
| 74 | - |
|
| 75 | - /** |
|
| 76 | - * @var string |
|
| 77 | - */ |
|
| 78 | - private static $description = 'Orders from FoxyCart Datafeed'; |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * @var string |
|
| 82 | - */ |
|
| 83 | - private static $default_sort = 'TransactionDate DESC, ID DESC'; |
|
| 84 | - |
|
| 85 | - /** |
|
| 86 | - * @var array |
|
| 87 | - */ |
|
| 88 | - private static $summary_fields = array( |
|
| 89 | - 'Order_ID', |
|
| 90 | - 'TransactionDate.Nice', |
|
| 91 | - 'Member.Name', |
|
| 92 | - 'ProductTotal.Nice', |
|
| 93 | - 'ShippingTotal.Nice', |
|
| 94 | - 'TaxTotal.Nice', |
|
| 95 | - 'OrderTotal.Nice', |
|
| 96 | - 'ReceiptLink', |
|
| 97 | - ); |
|
| 98 | - |
|
| 99 | - /** |
|
| 100 | - * @var array |
|
| 101 | - */ |
|
| 102 | - private static $searchable_fields = array( |
|
| 103 | - 'Order_ID', |
|
| 104 | - 'TransactionDate' => array( |
|
| 105 | - 'field' => DateField::class, |
|
| 106 | - 'filter' => 'PartialMatchFilter', |
|
| 107 | - ), |
|
| 108 | - 'Member.ID', |
|
| 109 | - 'OrderTotal', |
|
| 110 | - 'Details.ProductID', |
|
| 111 | - ); |
|
| 112 | - |
|
| 113 | - /** |
|
| 114 | - * @var array |
|
| 115 | - */ |
|
| 116 | - private static $casting = array( |
|
| 117 | - 'ReceiptLink' => 'HTMLVarchar', |
|
| 118 | - ); |
|
| 119 | - |
|
| 120 | - /** |
|
| 121 | - * @var array |
|
| 122 | - */ |
|
| 123 | - private static $indexes = array( |
|
| 124 | - 'Order_ID' => true, // make unique |
|
| 125 | - ); |
|
| 126 | - |
|
| 127 | - /** |
|
| 128 | - * @var string |
|
| 129 | - */ |
|
| 130 | - private static $table_name = 'Order'; |
|
| 131 | - |
|
| 132 | - /** |
|
| 133 | - * @param bool $includerelations |
|
| 134 | - * |
|
| 135 | - * @return array|string |
|
| 136 | - */ |
|
| 137 | - public function fieldLabels($includerelations = true) |
|
| 138 | - { |
|
| 139 | - $labels = parent::fieldLabels(); |
|
| 140 | - |
|
| 141 | - $labels['Order_ID'] = _t('Order.Order_ID', 'Order ID#'); |
|
| 142 | - $labels['TransactionDate'] = _t('Order.TransactionDate', 'Date'); |
|
| 143 | - $labels['TransactionDate.NiceUS'] = _t('Order.TransactionDate', 'Date'); |
|
| 144 | - $labels['Member.Name'] = _t('Order.MemberName', 'Customer'); |
|
| 145 | - $labels['Member.ID'] = _t('Order.MemberName', 'Customer'); |
|
| 146 | - $labels['ProductTotal.Nice'] = _t('Order.ProductTotal', 'Sub Total'); |
|
| 147 | - $labels['TaxTotal.Nice'] = _t('Order.TaxTotal', 'Tax'); |
|
| 148 | - $labels['ShippingTotal.Nice'] = _t('Order.ShippingTotal', 'Shipping'); |
|
| 149 | - $labels['OrderTotal'] = _t('Order.OrderTotal', 'Total'); |
|
| 150 | - $labels['OrderTotal.Nice'] = _t('Order.OrderTotal', 'Total'); |
|
| 151 | - $labels['ReceiptLink'] = _t('Order.ReceiptLink', 'Invoice'); |
|
| 152 | - $labels['Details.ProductID'] = _t('Order.Details.ProductID', 'Product'); |
|
| 153 | - |
|
| 154 | - return $labels; |
|
| 155 | - } |
|
| 156 | - |
|
| 157 | - /** |
|
| 158 | - * @return mixed |
|
| 159 | - */ |
|
| 160 | - public function ReceiptLink() |
|
| 161 | - { |
|
| 162 | - return $this->getReceiptLink(); |
|
| 163 | - } |
|
| 164 | - |
|
| 165 | - /** |
|
| 166 | - * @return mixed |
|
| 167 | - */ |
|
| 168 | - public function getReceiptLink() |
|
| 169 | - { |
|
| 170 | - $obj = DBHTMLVarchar::create(); |
|
| 171 | - $obj->setValue( |
|
| 172 | - '<a href="'.$this->ReceiptURL.'" target="_blank" class="cms-panel-link action external-link">view</a>' |
|
| 173 | - ); |
|
| 174 | - |
|
| 175 | - return $obj; |
|
| 176 | - } |
|
| 177 | - |
|
| 178 | - /** |
|
| 179 | - * @return bool|string |
|
| 180 | - */ |
|
| 181 | - public function getDecryptedResponse() |
|
| 182 | - { |
|
| 183 | - $decrypted = urldecode($this->Response); |
|
| 184 | - if (FoxyCart::getStoreKey()) { |
|
| 185 | - return \rc4crypt::decrypt(FoxyCart::getStoreKey(), $decrypted); |
|
| 186 | - } |
|
| 187 | - return false; |
|
| 188 | - } |
|
| 189 | - |
|
| 190 | - /** |
|
| 191 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 192 | - */ |
|
| 193 | - public function onBeforeWrite() |
|
| 194 | - { |
|
| 195 | - $this->parseOrder(); |
|
| 196 | - parent::onBeforeWrite(); |
|
| 197 | - } |
|
| 198 | - |
|
| 199 | - /** |
|
| 200 | - * @return bool |
|
| 201 | - * |
|
| 202 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 203 | - */ |
|
| 204 | - public function parseOrder() |
|
| 205 | - { |
|
| 206 | - if ($this->getDecryptedResponse()) { |
|
| 207 | - $response = new \SimpleXMLElement($this->getDecryptedResponse()); |
|
| 208 | - |
|
| 209 | - $this->parseOrderInfo($response); |
|
| 210 | - $this->parseOrderCustomer($response); |
|
| 211 | - $this->parseOrderDetails($response); |
|
| 212 | - |
|
| 213 | - return true; |
|
| 214 | - } else { |
|
| 215 | - return false; |
|
| 216 | - } |
|
| 217 | - } |
|
| 218 | - |
|
| 219 | - /** |
|
| 220 | - * @param $response |
|
| 221 | - */ |
|
| 222 | - public function parseOrderInfo($response) |
|
| 223 | - { |
|
| 224 | - foreach ($response->transactions->transaction as $transaction) { |
|
| 225 | - // Record transaction data from FoxyCart Datafeed: |
|
| 226 | - $this->Store_ID = (int) $transaction->store_id; |
|
| 227 | - $this->TransactionDate = (string) $transaction->transaction_date; |
|
| 228 | - $this->ProductTotal = (float) $transaction->product_total; |
|
| 229 | - $this->TaxTotal = (float) $transaction->tax_total; |
|
| 230 | - $this->ShippingTotal = (float) $transaction->shipping_total; |
|
| 231 | - $this->OrderTotal = (float) $transaction->order_total; |
|
| 232 | - $this->ReceiptURL = (string) $transaction->receipt_url; |
|
| 233 | - $this->OrderStatus = (string) $transaction->status; |
|
| 234 | - |
|
| 235 | - $this->extend('handleOrderInfo', $order, $response); |
|
| 236 | - } |
|
| 237 | - } |
|
| 238 | - |
|
| 239 | - /** |
|
| 240 | - * @param $response |
|
| 241 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 242 | - */ |
|
| 243 | - public function parseOrderCustomer($response) |
|
| 244 | - { |
|
| 245 | - foreach ($response->transactions->transaction as $transaction) { |
|
| 246 | - // if not a guest transaction in FoxyCart |
|
| 247 | - if (isset($transaction->customer_email) && $transaction->is_anonymous == 0) { |
|
| 248 | - // if Customer is existing member, associate with current order |
|
| 249 | - if (Member::get()->filter('Email', $transaction->customer_email)->First()) { |
|
| 250 | - $customer = Member::get()->filter('Email', $transaction->customer_email)->First(); |
|
| 251 | - // if new customer, create account with data from FoxyCart |
|
| 252 | - } else { |
|
| 253 | - // set PasswordEncryption to 'none' so imported, encrypted password is not encrypted again |
|
| 254 | - Config::modify()->set(Security::class, 'password_encryption_algorithm', 'none'); |
|
| 255 | - |
|
| 256 | - // create new Member, set password info from FoxyCart |
|
| 257 | - $customer = Member::create(); |
|
| 258 | - $customer->Customer_ID = (int) $transaction->customer_id; |
|
| 259 | - $customer->FirstName = (string) $transaction->customer_first_name; |
|
| 260 | - $customer->Surname = (string) $transaction->customer_last_name; |
|
| 261 | - $customer->Email = (string) $transaction->customer_email; |
|
| 262 | - $customer->Password = (string) $transaction->customer_password; |
|
| 263 | - $customer->Salt = (string) $transaction->customer_password_salt; |
|
| 264 | - $customer->PasswordEncryption = 'none'; |
|
| 265 | - |
|
| 266 | - // record member record |
|
| 267 | - $customer->write(); |
|
| 268 | - } |
|
| 269 | - |
|
| 270 | - // set Order MemberID |
|
| 271 | - $this->MemberID = $customer->ID; |
|
| 272 | - |
|
| 273 | - $this->extend('handleOrderCustomer', $order, $response, $customer); |
|
| 274 | - } |
|
| 275 | - } |
|
| 276 | - } |
|
| 277 | - |
|
| 278 | - /** |
|
| 279 | - * @param $response |
|
| 280 | - * |
|
| 281 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 282 | - */ |
|
| 283 | - public function parseOrderDetails($response) |
|
| 284 | - { |
|
| 285 | - |
|
| 286 | - // remove previous OrderDetails and OrderOptions so we don't end up with duplicates |
|
| 287 | - foreach ($this->Details() as $detail) { |
|
| 288 | - /** @var OrderOption $orderOption */ |
|
| 289 | - foreach ($detail->OrderOptions() as $orderOption) { |
|
| 290 | - $orderOption->delete(); |
|
| 291 | - } |
|
| 292 | - $detail->delete(); |
|
| 293 | - } |
|
| 294 | - |
|
| 295 | - foreach ($response->transactions->transaction as $transaction) { |
|
| 296 | - // Associate ProductPages, Options, Quantity with Order |
|
| 297 | - foreach ($transaction->transaction_details->transaction_detail as $detail) { |
|
| 298 | - $OrderDetail = OrderDetail::create(); |
|
| 299 | - |
|
| 300 | - $OrderDetail->Quantity = (int) $detail->product_quantity; |
|
| 301 | - $OrderDetail->ProductName = (string) $detail->product_name; |
|
| 302 | - $OrderDetail->ProductCode = (string) $detail->product_code; |
|
| 303 | - $OrderDetail->ProductImage = (string) $detail->image; |
|
| 304 | - $OrderDetail->ProductCategory = (string) $detail->category_code; |
|
| 305 | - $priceModifier = 0; |
|
| 306 | - |
|
| 307 | - // parse OrderOptions |
|
| 308 | - foreach ($detail->transaction_detail_options->transaction_detail_option as $option) { |
|
| 309 | - // Find product via product_id custom variable |
|
| 310 | - if ($option->product_option_name == 'product_id') { |
|
| 311 | - // if product is found, set relation to OrderDetail |
|
| 312 | - $OrderProduct = ProductPage::get()->byID((int) $option->product_option_value); |
|
| 313 | - if ($OrderProduct) { |
|
| 314 | - $OrderDetail->ProductID = $OrderProduct->ID; |
|
| 315 | - } |
|
| 316 | - } else { |
|
| 317 | - $OrderOption = OrderOption::create(); |
|
| 318 | - $OrderOption->Name = (string) $option->product_option_name; |
|
| 319 | - $OrderOption->Value = (string) $option->product_option_value; |
|
| 320 | - $OrderOption->write(); |
|
| 321 | - $OrderDetail->OrderOptions()->add($OrderOption); |
|
| 322 | - |
|
| 323 | - $priceModifier += $option->price_mod; |
|
| 324 | - } |
|
| 325 | - } |
|
| 326 | - |
|
| 327 | - $OrderDetail->Price = (float) $detail->product_price + (float) $priceModifier; |
|
| 328 | - |
|
| 329 | - // extend OrderDetail parsing, allowing for recording custom fields from FoxyCart |
|
| 330 | - $this->extend('handleOrderItem', $order, $response, $OrderDetail); |
|
| 331 | - |
|
| 332 | - // write |
|
| 333 | - $OrderDetail->write(); |
|
| 334 | - |
|
| 335 | - // associate with this order |
|
| 336 | - $this->Details()->add($OrderDetail); |
|
| 337 | - } |
|
| 338 | - } |
|
| 339 | - } |
|
| 340 | - |
|
| 341 | - /** |
|
| 342 | - * @param bool $member |
|
| 343 | - * |
|
| 344 | - * @return bool|int |
|
| 345 | - */ |
|
| 346 | - public function canView($member = null) |
|
| 347 | - { |
|
| 348 | - return Permission::check('Product_ORDERS', 'any', $member); |
|
| 349 | - } |
|
| 350 | - |
|
| 351 | - /** |
|
| 352 | - * @param null $member |
|
| 353 | - * |
|
| 354 | - * @return bool |
|
| 355 | - */ |
|
| 356 | - public function canEdit($member = null) |
|
| 357 | - { |
|
| 358 | - return false; |
|
| 359 | - //return Permission::check('Product_ORDERS', 'any', $member); |
|
| 360 | - } |
|
| 361 | - |
|
| 362 | - /** |
|
| 363 | - * @param null $member |
|
| 364 | - * |
|
| 365 | - * @return bool |
|
| 366 | - */ |
|
| 367 | - public function canDelete($member = null) |
|
| 368 | - { |
|
| 369 | - return false; |
|
| 370 | - //return Permission::check('Product_ORDERS', 'any', $member); |
|
| 371 | - } |
|
| 372 | - |
|
| 373 | - /** |
|
| 374 | - * @param null $member |
|
| 375 | - * @param array $context |
|
| 376 | - * |
|
| 377 | - * @return bool |
|
| 378 | - */ |
|
| 379 | - public function canCreate($member = null, $context = []) |
|
| 380 | - { |
|
| 381 | - return false; |
|
| 382 | - } |
|
| 383 | - |
|
| 384 | - /** |
|
| 385 | - * @return array |
|
| 386 | - */ |
|
| 387 | - public function providePermissions() |
|
| 388 | - { |
|
| 389 | - return array( |
|
| 390 | - 'Product_ORDERS' => 'Allow user to manage Orders and related objects', |
|
| 391 | - ); |
|
| 392 | - } |
|
| 36 | + /** |
|
| 37 | + * @var array |
|
| 38 | + */ |
|
| 39 | + private static $db = array( |
|
| 40 | + 'Order_ID' => 'Int', |
|
| 41 | + 'TransactionDate' => 'DBDatetime', |
|
| 42 | + 'ProductTotal' => 'Currency', |
|
| 43 | + 'TaxTotal' => 'Currency', |
|
| 44 | + 'ShippingTotal' => 'Currency', |
|
| 45 | + 'OrderTotal' => 'Currency', |
|
| 46 | + 'ReceiptURL' => 'Varchar(255)', |
|
| 47 | + 'OrderStatus' => 'Varchar(255)', |
|
| 48 | + 'Response' => 'Text', |
|
| 49 | + ); |
|
| 50 | + |
|
| 51 | + /** |
|
| 52 | + * @var array |
|
| 53 | + */ |
|
| 54 | + private static $has_one = array( |
|
| 55 | + 'Member' => Member::class, |
|
| 56 | + ); |
|
| 57 | + |
|
| 58 | + /** |
|
| 59 | + * @var array |
|
| 60 | + */ |
|
| 61 | + private static $has_many = array( |
|
| 62 | + 'Details' => OrderDetail::class, |
|
| 63 | + ); |
|
| 64 | + |
|
| 65 | + /** |
|
| 66 | + * @var string |
|
| 67 | + */ |
|
| 68 | + private static $singular_name = 'Order'; |
|
| 69 | + |
|
| 70 | + /** |
|
| 71 | + * @var string |
|
| 72 | + */ |
|
| 73 | + private static $plural_name = 'Orders'; |
|
| 74 | + |
|
| 75 | + /** |
|
| 76 | + * @var string |
|
| 77 | + */ |
|
| 78 | + private static $description = 'Orders from FoxyCart Datafeed'; |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * @var string |
|
| 82 | + */ |
|
| 83 | + private static $default_sort = 'TransactionDate DESC, ID DESC'; |
|
| 84 | + |
|
| 85 | + /** |
|
| 86 | + * @var array |
|
| 87 | + */ |
|
| 88 | + private static $summary_fields = array( |
|
| 89 | + 'Order_ID', |
|
| 90 | + 'TransactionDate.Nice', |
|
| 91 | + 'Member.Name', |
|
| 92 | + 'ProductTotal.Nice', |
|
| 93 | + 'ShippingTotal.Nice', |
|
| 94 | + 'TaxTotal.Nice', |
|
| 95 | + 'OrderTotal.Nice', |
|
| 96 | + 'ReceiptLink', |
|
| 97 | + ); |
|
| 98 | + |
|
| 99 | + /** |
|
| 100 | + * @var array |
|
| 101 | + */ |
|
| 102 | + private static $searchable_fields = array( |
|
| 103 | + 'Order_ID', |
|
| 104 | + 'TransactionDate' => array( |
|
| 105 | + 'field' => DateField::class, |
|
| 106 | + 'filter' => 'PartialMatchFilter', |
|
| 107 | + ), |
|
| 108 | + 'Member.ID', |
|
| 109 | + 'OrderTotal', |
|
| 110 | + 'Details.ProductID', |
|
| 111 | + ); |
|
| 112 | + |
|
| 113 | + /** |
|
| 114 | + * @var array |
|
| 115 | + */ |
|
| 116 | + private static $casting = array( |
|
| 117 | + 'ReceiptLink' => 'HTMLVarchar', |
|
| 118 | + ); |
|
| 119 | + |
|
| 120 | + /** |
|
| 121 | + * @var array |
|
| 122 | + */ |
|
| 123 | + private static $indexes = array( |
|
| 124 | + 'Order_ID' => true, // make unique |
|
| 125 | + ); |
|
| 126 | + |
|
| 127 | + /** |
|
| 128 | + * @var string |
|
| 129 | + */ |
|
| 130 | + private static $table_name = 'Order'; |
|
| 131 | + |
|
| 132 | + /** |
|
| 133 | + * @param bool $includerelations |
|
| 134 | + * |
|
| 135 | + * @return array|string |
|
| 136 | + */ |
|
| 137 | + public function fieldLabels($includerelations = true) |
|
| 138 | + { |
|
| 139 | + $labels = parent::fieldLabels(); |
|
| 140 | + |
|
| 141 | + $labels['Order_ID'] = _t('Order.Order_ID', 'Order ID#'); |
|
| 142 | + $labels['TransactionDate'] = _t('Order.TransactionDate', 'Date'); |
|
| 143 | + $labels['TransactionDate.NiceUS'] = _t('Order.TransactionDate', 'Date'); |
|
| 144 | + $labels['Member.Name'] = _t('Order.MemberName', 'Customer'); |
|
| 145 | + $labels['Member.ID'] = _t('Order.MemberName', 'Customer'); |
|
| 146 | + $labels['ProductTotal.Nice'] = _t('Order.ProductTotal', 'Sub Total'); |
|
| 147 | + $labels['TaxTotal.Nice'] = _t('Order.TaxTotal', 'Tax'); |
|
| 148 | + $labels['ShippingTotal.Nice'] = _t('Order.ShippingTotal', 'Shipping'); |
|
| 149 | + $labels['OrderTotal'] = _t('Order.OrderTotal', 'Total'); |
|
| 150 | + $labels['OrderTotal.Nice'] = _t('Order.OrderTotal', 'Total'); |
|
| 151 | + $labels['ReceiptLink'] = _t('Order.ReceiptLink', 'Invoice'); |
|
| 152 | + $labels['Details.ProductID'] = _t('Order.Details.ProductID', 'Product'); |
|
| 153 | + |
|
| 154 | + return $labels; |
|
| 155 | + } |
|
| 156 | + |
|
| 157 | + /** |
|
| 158 | + * @return mixed |
|
| 159 | + */ |
|
| 160 | + public function ReceiptLink() |
|
| 161 | + { |
|
| 162 | + return $this->getReceiptLink(); |
|
| 163 | + } |
|
| 164 | + |
|
| 165 | + /** |
|
| 166 | + * @return mixed |
|
| 167 | + */ |
|
| 168 | + public function getReceiptLink() |
|
| 169 | + { |
|
| 170 | + $obj = DBHTMLVarchar::create(); |
|
| 171 | + $obj->setValue( |
|
| 172 | + '<a href="'.$this->ReceiptURL.'" target="_blank" class="cms-panel-link action external-link">view</a>' |
|
| 173 | + ); |
|
| 174 | + |
|
| 175 | + return $obj; |
|
| 176 | + } |
|
| 177 | + |
|
| 178 | + /** |
|
| 179 | + * @return bool|string |
|
| 180 | + */ |
|
| 181 | + public function getDecryptedResponse() |
|
| 182 | + { |
|
| 183 | + $decrypted = urldecode($this->Response); |
|
| 184 | + if (FoxyCart::getStoreKey()) { |
|
| 185 | + return \rc4crypt::decrypt(FoxyCart::getStoreKey(), $decrypted); |
|
| 186 | + } |
|
| 187 | + return false; |
|
| 188 | + } |
|
| 189 | + |
|
| 190 | + /** |
|
| 191 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 192 | + */ |
|
| 193 | + public function onBeforeWrite() |
|
| 194 | + { |
|
| 195 | + $this->parseOrder(); |
|
| 196 | + parent::onBeforeWrite(); |
|
| 197 | + } |
|
| 198 | + |
|
| 199 | + /** |
|
| 200 | + * @return bool |
|
| 201 | + * |
|
| 202 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 203 | + */ |
|
| 204 | + public function parseOrder() |
|
| 205 | + { |
|
| 206 | + if ($this->getDecryptedResponse()) { |
|
| 207 | + $response = new \SimpleXMLElement($this->getDecryptedResponse()); |
|
| 208 | + |
|
| 209 | + $this->parseOrderInfo($response); |
|
| 210 | + $this->parseOrderCustomer($response); |
|
| 211 | + $this->parseOrderDetails($response); |
|
| 212 | + |
|
| 213 | + return true; |
|
| 214 | + } else { |
|
| 215 | + return false; |
|
| 216 | + } |
|
| 217 | + } |
|
| 218 | + |
|
| 219 | + /** |
|
| 220 | + * @param $response |
|
| 221 | + */ |
|
| 222 | + public function parseOrderInfo($response) |
|
| 223 | + { |
|
| 224 | + foreach ($response->transactions->transaction as $transaction) { |
|
| 225 | + // Record transaction data from FoxyCart Datafeed: |
|
| 226 | + $this->Store_ID = (int) $transaction->store_id; |
|
| 227 | + $this->TransactionDate = (string) $transaction->transaction_date; |
|
| 228 | + $this->ProductTotal = (float) $transaction->product_total; |
|
| 229 | + $this->TaxTotal = (float) $transaction->tax_total; |
|
| 230 | + $this->ShippingTotal = (float) $transaction->shipping_total; |
|
| 231 | + $this->OrderTotal = (float) $transaction->order_total; |
|
| 232 | + $this->ReceiptURL = (string) $transaction->receipt_url; |
|
| 233 | + $this->OrderStatus = (string) $transaction->status; |
|
| 234 | + |
|
| 235 | + $this->extend('handleOrderInfo', $order, $response); |
|
| 236 | + } |
|
| 237 | + } |
|
| 238 | + |
|
| 239 | + /** |
|
| 240 | + * @param $response |
|
| 241 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 242 | + */ |
|
| 243 | + public function parseOrderCustomer($response) |
|
| 244 | + { |
|
| 245 | + foreach ($response->transactions->transaction as $transaction) { |
|
| 246 | + // if not a guest transaction in FoxyCart |
|
| 247 | + if (isset($transaction->customer_email) && $transaction->is_anonymous == 0) { |
|
| 248 | + // if Customer is existing member, associate with current order |
|
| 249 | + if (Member::get()->filter('Email', $transaction->customer_email)->First()) { |
|
| 250 | + $customer = Member::get()->filter('Email', $transaction->customer_email)->First(); |
|
| 251 | + // if new customer, create account with data from FoxyCart |
|
| 252 | + } else { |
|
| 253 | + // set PasswordEncryption to 'none' so imported, encrypted password is not encrypted again |
|
| 254 | + Config::modify()->set(Security::class, 'password_encryption_algorithm', 'none'); |
|
| 255 | + |
|
| 256 | + // create new Member, set password info from FoxyCart |
|
| 257 | + $customer = Member::create(); |
|
| 258 | + $customer->Customer_ID = (int) $transaction->customer_id; |
|
| 259 | + $customer->FirstName = (string) $transaction->customer_first_name; |
|
| 260 | + $customer->Surname = (string) $transaction->customer_last_name; |
|
| 261 | + $customer->Email = (string) $transaction->customer_email; |
|
| 262 | + $customer->Password = (string) $transaction->customer_password; |
|
| 263 | + $customer->Salt = (string) $transaction->customer_password_salt; |
|
| 264 | + $customer->PasswordEncryption = 'none'; |
|
| 265 | + |
|
| 266 | + // record member record |
|
| 267 | + $customer->write(); |
|
| 268 | + } |
|
| 269 | + |
|
| 270 | + // set Order MemberID |
|
| 271 | + $this->MemberID = $customer->ID; |
|
| 272 | + |
|
| 273 | + $this->extend('handleOrderCustomer', $order, $response, $customer); |
|
| 274 | + } |
|
| 275 | + } |
|
| 276 | + } |
|
| 277 | + |
|
| 278 | + /** |
|
| 279 | + * @param $response |
|
| 280 | + * |
|
| 281 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 282 | + */ |
|
| 283 | + public function parseOrderDetails($response) |
|
| 284 | + { |
|
| 285 | + |
|
| 286 | + // remove previous OrderDetails and OrderOptions so we don't end up with duplicates |
|
| 287 | + foreach ($this->Details() as $detail) { |
|
| 288 | + /** @var OrderOption $orderOption */ |
|
| 289 | + foreach ($detail->OrderOptions() as $orderOption) { |
|
| 290 | + $orderOption->delete(); |
|
| 291 | + } |
|
| 292 | + $detail->delete(); |
|
| 293 | + } |
|
| 294 | + |
|
| 295 | + foreach ($response->transactions->transaction as $transaction) { |
|
| 296 | + // Associate ProductPages, Options, Quantity with Order |
|
| 297 | + foreach ($transaction->transaction_details->transaction_detail as $detail) { |
|
| 298 | + $OrderDetail = OrderDetail::create(); |
|
| 299 | + |
|
| 300 | + $OrderDetail->Quantity = (int) $detail->product_quantity; |
|
| 301 | + $OrderDetail->ProductName = (string) $detail->product_name; |
|
| 302 | + $OrderDetail->ProductCode = (string) $detail->product_code; |
|
| 303 | + $OrderDetail->ProductImage = (string) $detail->image; |
|
| 304 | + $OrderDetail->ProductCategory = (string) $detail->category_code; |
|
| 305 | + $priceModifier = 0; |
|
| 306 | + |
|
| 307 | + // parse OrderOptions |
|
| 308 | + foreach ($detail->transaction_detail_options->transaction_detail_option as $option) { |
|
| 309 | + // Find product via product_id custom variable |
|
| 310 | + if ($option->product_option_name == 'product_id') { |
|
| 311 | + // if product is found, set relation to OrderDetail |
|
| 312 | + $OrderProduct = ProductPage::get()->byID((int) $option->product_option_value); |
|
| 313 | + if ($OrderProduct) { |
|
| 314 | + $OrderDetail->ProductID = $OrderProduct->ID; |
|
| 315 | + } |
|
| 316 | + } else { |
|
| 317 | + $OrderOption = OrderOption::create(); |
|
| 318 | + $OrderOption->Name = (string) $option->product_option_name; |
|
| 319 | + $OrderOption->Value = (string) $option->product_option_value; |
|
| 320 | + $OrderOption->write(); |
|
| 321 | + $OrderDetail->OrderOptions()->add($OrderOption); |
|
| 322 | + |
|
| 323 | + $priceModifier += $option->price_mod; |
|
| 324 | + } |
|
| 325 | + } |
|
| 326 | + |
|
| 327 | + $OrderDetail->Price = (float) $detail->product_price + (float) $priceModifier; |
|
| 328 | + |
|
| 329 | + // extend OrderDetail parsing, allowing for recording custom fields from FoxyCart |
|
| 330 | + $this->extend('handleOrderItem', $order, $response, $OrderDetail); |
|
| 331 | + |
|
| 332 | + // write |
|
| 333 | + $OrderDetail->write(); |
|
| 334 | + |
|
| 335 | + // associate with this order |
|
| 336 | + $this->Details()->add($OrderDetail); |
|
| 337 | + } |
|
| 338 | + } |
|
| 339 | + } |
|
| 340 | + |
|
| 341 | + /** |
|
| 342 | + * @param bool $member |
|
| 343 | + * |
|
| 344 | + * @return bool|int |
|
| 345 | + */ |
|
| 346 | + public function canView($member = null) |
|
| 347 | + { |
|
| 348 | + return Permission::check('Product_ORDERS', 'any', $member); |
|
| 349 | + } |
|
| 350 | + |
|
| 351 | + /** |
|
| 352 | + * @param null $member |
|
| 353 | + * |
|
| 354 | + * @return bool |
|
| 355 | + */ |
|
| 356 | + public function canEdit($member = null) |
|
| 357 | + { |
|
| 358 | + return false; |
|
| 359 | + //return Permission::check('Product_ORDERS', 'any', $member); |
|
| 360 | + } |
|
| 361 | + |
|
| 362 | + /** |
|
| 363 | + * @param null $member |
|
| 364 | + * |
|
| 365 | + * @return bool |
|
| 366 | + */ |
|
| 367 | + public function canDelete($member = null) |
|
| 368 | + { |
|
| 369 | + return false; |
|
| 370 | + //return Permission::check('Product_ORDERS', 'any', $member); |
|
| 371 | + } |
|
| 372 | + |
|
| 373 | + /** |
|
| 374 | + * @param null $member |
|
| 375 | + * @param array $context |
|
| 376 | + * |
|
| 377 | + * @return bool |
|
| 378 | + */ |
|
| 379 | + public function canCreate($member = null, $context = []) |
|
| 380 | + { |
|
| 381 | + return false; |
|
| 382 | + } |
|
| 383 | + |
|
| 384 | + /** |
|
| 385 | + * @return array |
|
| 386 | + */ |
|
| 387 | + public function providePermissions() |
|
| 388 | + { |
|
| 389 | + return array( |
|
| 390 | + 'Product_ORDERS' => 'Allow user to manage Orders and related objects', |
|
| 391 | + ); |
|
| 392 | + } |
|
| 393 | 393 | } |
@@ -332,7 +332,7 @@ discard block |
||
| 332 | 332 | FormAction::create('save_foxystripe_setting', _t('FoxyStripeSetting.SAVE', 'Save')) |
| 333 | 333 | ->addExtraClass('btn-primary font-icon-save') |
| 334 | 334 | ); |
| 335 | - } else { |
|
| 335 | + }else { |
|
| 336 | 336 | $actions = FieldList::create(); |
| 337 | 337 | } |
| 338 | 338 | $this->extend('updateCMSActions', $actions); |
@@ -360,7 +360,7 @@ discard block |
||
| 360 | 360 | } |
| 361 | 361 | $config->StoreKey = $key; |
| 362 | 362 | $config->write(); |
| 363 | - DB::alteration_message('Created FoxyCart Store Key ' . $key, 'created'); |
|
| 363 | + DB::alteration_message('Created FoxyCart Store Key '.$key, 'created'); |
|
| 364 | 364 | } |
| 365 | 365 | } |
| 366 | 366 | |
@@ -462,7 +462,7 @@ discard block |
||
| 462 | 462 | */ |
| 463 | 463 | private static function getSSOLink() |
| 464 | 464 | { |
| 465 | - return Director::absoluteBaseURL() . 'foxystripe/sso/'; |
|
| 465 | + return Director::absoluteBaseURL().'foxystripe/sso/'; |
|
| 466 | 466 | } |
| 467 | 467 | |
| 468 | 468 | /** |
@@ -470,7 +470,7 @@ discard block |
||
| 470 | 470 | */ |
| 471 | 471 | private static function getDataFeedLink() |
| 472 | 472 | { |
| 473 | - return Director::absoluteBaseURL() . 'foxystripe/'; |
|
| 473 | + return Director::absoluteBaseURL().'foxystripe/'; |
|
| 474 | 474 | } |
| 475 | 475 | |
| 476 | 476 | /** |
@@ -62,236 +62,236 @@ discard block |
||
| 62 | 62 | */ |
| 63 | 63 | class FoxyStripeSetting extends DataObject implements PermissionProvider, TemplateGlobalProvider |
| 64 | 64 | { |
| 65 | - /** |
|
| 66 | - * @var string |
|
| 67 | - */ |
|
| 68 | - private static $singular_name = 'FoxyStripe Setting'; |
|
| 69 | - /** |
|
| 70 | - * @var string |
|
| 71 | - */ |
|
| 72 | - private static $plural_name = 'FoxyStripe Settings'; |
|
| 73 | - /** |
|
| 74 | - * @var string |
|
| 75 | - */ |
|
| 76 | - private static $description = 'Update the settings for your store'; |
|
| 77 | - |
|
| 78 | - /** |
|
| 79 | - * @var array |
|
| 80 | - */ |
|
| 81 | - private static $db = [ |
|
| 82 | - 'StoreTitle' => 'Varchar(255)', |
|
| 83 | - 'StoreName' => 'Varchar(255)', |
|
| 84 | - 'CustomSSL' => 'Boolean', |
|
| 85 | - 'RemoteDomain' => 'Varchar(255)', |
|
| 86 | - 'StoreURL' => 'Varchar(255)', |
|
| 87 | - 'ReceiptURL' => 'Varchar(255)', |
|
| 88 | - 'StoreEmail' => 'Varchar(255)', |
|
| 89 | - 'FromEmail' => 'Varchar(255)', |
|
| 90 | - 'StorePostalCode' => 'Varchar(10)', |
|
| 91 | - 'StoreCountry' => 'Varchar(100)', |
|
| 92 | - 'StoreRegion' => 'Varchar(100)', |
|
| 93 | - 'StoreLocaleCode' => 'Varchar(10)', |
|
| 94 | - 'StoreLogoURL' => 'Varchar(255)', |
|
| 95 | - 'CheckoutType' => 'Varchar(50)', |
|
| 96 | - 'BccEmail' => 'Boolean', |
|
| 97 | - 'UseWebhook' => 'Boolean', |
|
| 98 | - 'StoreKey' => 'Varchar(60)', |
|
| 99 | - 'CartValidation' => 'Boolean', |
|
| 100 | - 'UseSingleSignOn' => 'Boolean', |
|
| 101 | - 'AllowMultiship' => 'Boolean', |
|
| 102 | - 'StoreTimezone' => 'Varchar(100)', |
|
| 103 | - 'MultiGroup' => 'Boolean', |
|
| 104 | - 'ProductLimit' => 'Int', |
|
| 105 | - 'MaxQuantity' => 'Int', |
|
| 106 | - 'EnableAPI' => 'Boolean', |
|
| 107 | - 'client_id' => 'Varchar(255)', |
|
| 108 | - 'client_secret' => 'Varchar(255)', |
|
| 109 | - 'access_token' => 'Varchar(255)', |
|
| 110 | - 'refresh_token' => 'Varchar(255)', |
|
| 111 | - 'EnableSidecart' => 'Boolean', |
|
| 112 | - ]; |
|
| 113 | - |
|
| 114 | - // Set Default values |
|
| 115 | - private static $defaults = [ |
|
| 116 | - 'ProductLimit' => 10, |
|
| 117 | - 'EnableSidecart' => 1, |
|
| 118 | - ]; |
|
| 119 | - |
|
| 120 | - /** |
|
| 121 | - * @var string |
|
| 122 | - */ |
|
| 123 | - private static $table_name = 'FoxyStripeSetting'; |
|
| 124 | - |
|
| 125 | - /** |
|
| 126 | - * Default permission to check for 'LoggedInUsers' to create or edit pages. |
|
| 127 | - * |
|
| 128 | - * @var array |
|
| 129 | - * @config |
|
| 130 | - */ |
|
| 131 | - private static $required_permission = ['CMS_ACCESS_CMSMain', 'CMS_ACCESS_LeftAndMain']; |
|
| 132 | - |
|
| 133 | - /** |
|
| 134 | - * @return FieldList |
|
| 135 | - */ |
|
| 136 | - public function getCMSFields() |
|
| 137 | - { |
|
| 138 | - $fields = FieldList::create( |
|
| 139 | - TabSet::create( |
|
| 140 | - 'Root', |
|
| 141 | - $tabMain = Tab::create( |
|
| 142 | - 'Main' |
|
| 143 | - ) |
|
| 144 | - ), |
|
| 145 | - HiddenField::create('ID') |
|
| 146 | - ); |
|
| 147 | - $tabMain->setTitle('Settings'); |
|
| 148 | - |
|
| 149 | - // settings tab |
|
| 150 | - $fields->addFieldsToTab('Root.Main', [ |
|
| 151 | - // Store Details |
|
| 152 | - HeaderField::create('StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), 3), |
|
| 153 | - LiteralField::create('DetailsIntro', _t( |
|
| 154 | - 'FoxyStripeSiteConfig.DetailsIntro', |
|
| 155 | - '<p>Maps to data in your |
|
| 65 | + /** |
|
| 66 | + * @var string |
|
| 67 | + */ |
|
| 68 | + private static $singular_name = 'FoxyStripe Setting'; |
|
| 69 | + /** |
|
| 70 | + * @var string |
|
| 71 | + */ |
|
| 72 | + private static $plural_name = 'FoxyStripe Settings'; |
|
| 73 | + /** |
|
| 74 | + * @var string |
|
| 75 | + */ |
|
| 76 | + private static $description = 'Update the settings for your store'; |
|
| 77 | + |
|
| 78 | + /** |
|
| 79 | + * @var array |
|
| 80 | + */ |
|
| 81 | + private static $db = [ |
|
| 82 | + 'StoreTitle' => 'Varchar(255)', |
|
| 83 | + 'StoreName' => 'Varchar(255)', |
|
| 84 | + 'CustomSSL' => 'Boolean', |
|
| 85 | + 'RemoteDomain' => 'Varchar(255)', |
|
| 86 | + 'StoreURL' => 'Varchar(255)', |
|
| 87 | + 'ReceiptURL' => 'Varchar(255)', |
|
| 88 | + 'StoreEmail' => 'Varchar(255)', |
|
| 89 | + 'FromEmail' => 'Varchar(255)', |
|
| 90 | + 'StorePostalCode' => 'Varchar(10)', |
|
| 91 | + 'StoreCountry' => 'Varchar(100)', |
|
| 92 | + 'StoreRegion' => 'Varchar(100)', |
|
| 93 | + 'StoreLocaleCode' => 'Varchar(10)', |
|
| 94 | + 'StoreLogoURL' => 'Varchar(255)', |
|
| 95 | + 'CheckoutType' => 'Varchar(50)', |
|
| 96 | + 'BccEmail' => 'Boolean', |
|
| 97 | + 'UseWebhook' => 'Boolean', |
|
| 98 | + 'StoreKey' => 'Varchar(60)', |
|
| 99 | + 'CartValidation' => 'Boolean', |
|
| 100 | + 'UseSingleSignOn' => 'Boolean', |
|
| 101 | + 'AllowMultiship' => 'Boolean', |
|
| 102 | + 'StoreTimezone' => 'Varchar(100)', |
|
| 103 | + 'MultiGroup' => 'Boolean', |
|
| 104 | + 'ProductLimit' => 'Int', |
|
| 105 | + 'MaxQuantity' => 'Int', |
|
| 106 | + 'EnableAPI' => 'Boolean', |
|
| 107 | + 'client_id' => 'Varchar(255)', |
|
| 108 | + 'client_secret' => 'Varchar(255)', |
|
| 109 | + 'access_token' => 'Varchar(255)', |
|
| 110 | + 'refresh_token' => 'Varchar(255)', |
|
| 111 | + 'EnableSidecart' => 'Boolean', |
|
| 112 | + ]; |
|
| 113 | + |
|
| 114 | + // Set Default values |
|
| 115 | + private static $defaults = [ |
|
| 116 | + 'ProductLimit' => 10, |
|
| 117 | + 'EnableSidecart' => 1, |
|
| 118 | + ]; |
|
| 119 | + |
|
| 120 | + /** |
|
| 121 | + * @var string |
|
| 122 | + */ |
|
| 123 | + private static $table_name = 'FoxyStripeSetting'; |
|
| 124 | + |
|
| 125 | + /** |
|
| 126 | + * Default permission to check for 'LoggedInUsers' to create or edit pages. |
|
| 127 | + * |
|
| 128 | + * @var array |
|
| 129 | + * @config |
|
| 130 | + */ |
|
| 131 | + private static $required_permission = ['CMS_ACCESS_CMSMain', 'CMS_ACCESS_LeftAndMain']; |
|
| 132 | + |
|
| 133 | + /** |
|
| 134 | + * @return FieldList |
|
| 135 | + */ |
|
| 136 | + public function getCMSFields() |
|
| 137 | + { |
|
| 138 | + $fields = FieldList::create( |
|
| 139 | + TabSet::create( |
|
| 140 | + 'Root', |
|
| 141 | + $tabMain = Tab::create( |
|
| 142 | + 'Main' |
|
| 143 | + ) |
|
| 144 | + ), |
|
| 145 | + HiddenField::create('ID') |
|
| 146 | + ); |
|
| 147 | + $tabMain->setTitle('Settings'); |
|
| 148 | + |
|
| 149 | + // settings tab |
|
| 150 | + $fields->addFieldsToTab('Root.Main', [ |
|
| 151 | + // Store Details |
|
| 152 | + HeaderField::create('StoreDetails', _t('FoxyStripeSiteConfig.StoreDetails', 'Store Settings'), 3), |
|
| 153 | + LiteralField::create('DetailsIntro', _t( |
|
| 154 | + 'FoxyStripeSiteConfig.DetailsIntro', |
|
| 155 | + '<p>Maps to data in your |
|
| 156 | 156 | <a href="https://admin.foxycart.com/admin.php?ThisAction=EditStore" target="_blank"> |
| 157 | 157 | FoxyCart store settings |
| 158 | 158 | </a>.' |
| 159 | - )), |
|
| 160 | - TextField::create('StoreTitle') |
|
| 161 | - ->setTitle(_t('FoxyStripeSiteConfig.StoreTitle', 'Store Name')) |
|
| 162 | - ->setDescription(_t( |
|
| 163 | - 'FoxyStripeSiteConfig.StoreTitleDescription', |
|
| 164 | - 'The name of your store as you\'d like it displayed to your customers' |
|
| 165 | - )), |
|
| 166 | - CheckboxField::create('CustomSSL', 'Use custom SSL'), |
|
| 167 | - TextField::create('RemoteDomain') |
|
| 168 | - ->setTitle(_t('FoxyStripeSiteConfig.RemoteDomain', 'Store Remote Domain')) |
|
| 169 | - ->setDescription(_t( |
|
| 170 | - 'FoxyStripeSiteConfig.RemoteDomainDescription', |
|
| 171 | - 'custom subdomain for FoxyCart' |
|
| 172 | - )) |
|
| 173 | - ->displayIf('CustomSSL')->isChecked()->end(), |
|
| 174 | - TextField::create('StoreName') |
|
| 175 | - ->setTitle(_t('FoxyStripeSiteConfig.StoreName', 'Store Domain')) |
|
| 176 | - ->setDescription(_t( |
|
| 177 | - 'FoxyStripeSiteConfig.StoreNameDescription', |
|
| 178 | - 'This is a unique FoxyCart subdomain for your cart, checkout, and receipt' |
|
| 179 | - )) |
|
| 180 | - ->hideIf('CustomSSL')->isChecked()->end(), |
|
| 181 | - TextField::create('StoreURL') |
|
| 182 | - ->setTitle(_t('FoxyStripeSiteConfig.StoreURL', 'Store URL')) |
|
| 183 | - ->setDescription(_t( |
|
| 184 | - 'FoxyStripeSiteConfig.StoreURLDescription', |
|
| 185 | - 'The URL of your online store' |
|
| 186 | - )), |
|
| 187 | - TextField::create('ReceiptURL') |
|
| 188 | - ->setTitle(_t('FoxyStripeSiteConfig.ReceiptURL', 'Receipt URL')) |
|
| 189 | - ->setDescription(_t( |
|
| 190 | - 'FoxyStripeSiteConfig.ReceiptURLDescription', |
|
| 191 | - 'By default, FoxyCart sends customers back to the page referrer after completing a purchase. |
|
| 159 | + )), |
|
| 160 | + TextField::create('StoreTitle') |
|
| 161 | + ->setTitle(_t('FoxyStripeSiteConfig.StoreTitle', 'Store Name')) |
|
| 162 | + ->setDescription(_t( |
|
| 163 | + 'FoxyStripeSiteConfig.StoreTitleDescription', |
|
| 164 | + 'The name of your store as you\'d like it displayed to your customers' |
|
| 165 | + )), |
|
| 166 | + CheckboxField::create('CustomSSL', 'Use custom SSL'), |
|
| 167 | + TextField::create('RemoteDomain') |
|
| 168 | + ->setTitle(_t('FoxyStripeSiteConfig.RemoteDomain', 'Store Remote Domain')) |
|
| 169 | + ->setDescription(_t( |
|
| 170 | + 'FoxyStripeSiteConfig.RemoteDomainDescription', |
|
| 171 | + 'custom subdomain for FoxyCart' |
|
| 172 | + )) |
|
| 173 | + ->displayIf('CustomSSL')->isChecked()->end(), |
|
| 174 | + TextField::create('StoreName') |
|
| 175 | + ->setTitle(_t('FoxyStripeSiteConfig.StoreName', 'Store Domain')) |
|
| 176 | + ->setDescription(_t( |
|
| 177 | + 'FoxyStripeSiteConfig.StoreNameDescription', |
|
| 178 | + 'This is a unique FoxyCart subdomain for your cart, checkout, and receipt' |
|
| 179 | + )) |
|
| 180 | + ->hideIf('CustomSSL')->isChecked()->end(), |
|
| 181 | + TextField::create('StoreURL') |
|
| 182 | + ->setTitle(_t('FoxyStripeSiteConfig.StoreURL', 'Store URL')) |
|
| 183 | + ->setDescription(_t( |
|
| 184 | + 'FoxyStripeSiteConfig.StoreURLDescription', |
|
| 185 | + 'The URL of your online store' |
|
| 186 | + )), |
|
| 187 | + TextField::create('ReceiptURL') |
|
| 188 | + ->setTitle(_t('FoxyStripeSiteConfig.ReceiptURL', 'Receipt URL')) |
|
| 189 | + ->setDescription(_t( |
|
| 190 | + 'FoxyStripeSiteConfig.ReceiptURLDescription', |
|
| 191 | + 'By default, FoxyCart sends customers back to the page referrer after completing a purchase. |
|
| 192 | 192 | Instead, you can set a specific URL here.' |
| 193 | - )), |
|
| 194 | - TextField::create('StoreEmail') |
|
| 195 | - ->setTitle(_t('FoxyStripeSiteConfig.StoreEmail', 'Store Email')) |
|
| 196 | - ->setDescription(_t( |
|
| 197 | - 'FoxyStripeSiteConfig.StoreEmailDescription', |
|
| 198 | - 'This is the email address of your store. By default, this will be the from address for your |
|
| 193 | + )), |
|
| 194 | + TextField::create('StoreEmail') |
|
| 195 | + ->setTitle(_t('FoxyStripeSiteConfig.StoreEmail', 'Store Email')) |
|
| 196 | + ->setDescription(_t( |
|
| 197 | + 'FoxyStripeSiteConfig.StoreEmailDescription', |
|
| 198 | + 'This is the email address of your store. By default, this will be the from address for your |
|
| 199 | 199 | store receipts. ' |
| 200 | - )), |
|
| 201 | - TextField::create('FromEmail') |
|
| 202 | - ->setTitle(_t('FoxyStripeSiteConfig.FromEmail', 'From Email')) |
|
| 203 | - ->setDescription(_t( |
|
| 204 | - 'FoxyStripeSiteConfig.FromEmailDescription', |
|
| 205 | - 'Used for when you want to specify a different from email than your store\'s email address' |
|
| 206 | - )), |
|
| 207 | - TextField::create('StorePostalCode', 'Postal Code'), |
|
| 208 | - CountryDropdownField::create('StoreCountry', 'Country'), |
|
| 209 | - TextField::create('StoreRegion', 'State/Region'), |
|
| 210 | - TextField::create('StoreLocaleCode', 'Locale Code') |
|
| 211 | - ->setDescription('example: en_US'), |
|
| 212 | - TextField::create('StoreTimezone', 'Store timezone'), |
|
| 213 | - TextField::create('StoreLogoURL', 'Logo URL') |
|
| 214 | - ->setAttribute('placeholder', 'http://'), |
|
| 215 | - ]); |
|
| 216 | - |
|
| 217 | - $fields->addFieldsToTab('Root.Advanced', [ |
|
| 218 | - HeaderField::create('AdvanceHeader', _t( |
|
| 219 | - 'FoxyStripeSiteConfig.AdvancedHeader', |
|
| 220 | - 'Advanced Settings' |
|
| 221 | - ), 3), |
|
| 222 | - LiteralField::create('AdvancedIntro', _t( |
|
| 223 | - 'FoxyStripeSiteConfig.AdvancedIntro', |
|
| 224 | - '<p>Maps to data in your |
|
| 200 | + )), |
|
| 201 | + TextField::create('FromEmail') |
|
| 202 | + ->setTitle(_t('FoxyStripeSiteConfig.FromEmail', 'From Email')) |
|
| 203 | + ->setDescription(_t( |
|
| 204 | + 'FoxyStripeSiteConfig.FromEmailDescription', |
|
| 205 | + 'Used for when you want to specify a different from email than your store\'s email address' |
|
| 206 | + )), |
|
| 207 | + TextField::create('StorePostalCode', 'Postal Code'), |
|
| 208 | + CountryDropdownField::create('StoreCountry', 'Country'), |
|
| 209 | + TextField::create('StoreRegion', 'State/Region'), |
|
| 210 | + TextField::create('StoreLocaleCode', 'Locale Code') |
|
| 211 | + ->setDescription('example: en_US'), |
|
| 212 | + TextField::create('StoreTimezone', 'Store timezone'), |
|
| 213 | + TextField::create('StoreLogoURL', 'Logo URL') |
|
| 214 | + ->setAttribute('placeholder', 'http://'), |
|
| 215 | + ]); |
|
| 216 | + |
|
| 217 | + $fields->addFieldsToTab('Root.Advanced', [ |
|
| 218 | + HeaderField::create('AdvanceHeader', _t( |
|
| 219 | + 'FoxyStripeSiteConfig.AdvancedHeader', |
|
| 220 | + 'Advanced Settings' |
|
| 221 | + ), 3), |
|
| 222 | + LiteralField::create('AdvancedIntro', _t( |
|
| 223 | + 'FoxyStripeSiteConfig.AdvancedIntro', |
|
| 224 | + '<p>Maps to data in your |
|
| 225 | 225 | <a href="https://admin.foxycart.com/admin.php?ThisAction=EditAdvancedFeatures" target="_blank"> |
| 226 | 226 | FoxyCart advanced store settings |
| 227 | 227 | </a>.</p>' |
| 228 | - )), |
|
| 229 | - DropdownField::create('CheckoutType', 'Checkout Type', $this->getCheckoutTypes()), |
|
| 230 | - CheckboxField::create('BccEmail', 'BCC Admin Email') |
|
| 231 | - ->setDescription('bcc all receipts to store\'s email address'), |
|
| 232 | - CheckboxField::create('UseWebhook', 'Use Webhook') |
|
| 233 | - ->setDescription('record order history in CMS, allows customers to view their order history'), |
|
| 234 | - ReadonlyField::create('WebhookURL', 'Webhook URL', self::getDataFeedLink()), |
|
| 235 | - ReadonlyField::create('StoreKey', 'Webhook Key', self::getDataFeedLink()), |
|
| 236 | - CheckboxField::create('CartValidation', 'Use cart validation'), |
|
| 237 | - CheckboxField::create('UseSingleSignOn', 'Use single sign on') |
|
| 238 | - ->setDescription('Sync user accounts between FoxyCart and your website'), |
|
| 239 | - ReadonlyField::create('SingleSignOnURL', 'Single sign on URL', self::getSSOLink()), |
|
| 240 | - CheckboxField::create('AllowMultiship', 'Allow multiple shipments per order'), |
|
| 241 | - ]); |
|
| 242 | - |
|
| 243 | - // configuration warning |
|
| 244 | - if (FoxyCart::store_name_warning() !== null) { |
|
| 245 | - $fields->insertBefore(LiteralField::create( |
|
| 246 | - 'StoreSubDomainHeaderWarning', |
|
| 247 | - _t( |
|
| 248 | - 'FoxyStripeSiteConfig.StoreSubDomainHeadingWarning', |
|
| 249 | - '<p class="message error">Store Domain must be entered below |
|
| 228 | + )), |
|
| 229 | + DropdownField::create('CheckoutType', 'Checkout Type', $this->getCheckoutTypes()), |
|
| 230 | + CheckboxField::create('BccEmail', 'BCC Admin Email') |
|
| 231 | + ->setDescription('bcc all receipts to store\'s email address'), |
|
| 232 | + CheckboxField::create('UseWebhook', 'Use Webhook') |
|
| 233 | + ->setDescription('record order history in CMS, allows customers to view their order history'), |
|
| 234 | + ReadonlyField::create('WebhookURL', 'Webhook URL', self::getDataFeedLink()), |
|
| 235 | + ReadonlyField::create('StoreKey', 'Webhook Key', self::getDataFeedLink()), |
|
| 236 | + CheckboxField::create('CartValidation', 'Use cart validation'), |
|
| 237 | + CheckboxField::create('UseSingleSignOn', 'Use single sign on') |
|
| 238 | + ->setDescription('Sync user accounts between FoxyCart and your website'), |
|
| 239 | + ReadonlyField::create('SingleSignOnURL', 'Single sign on URL', self::getSSOLink()), |
|
| 240 | + CheckboxField::create('AllowMultiship', 'Allow multiple shipments per order'), |
|
| 241 | + ]); |
|
| 242 | + |
|
| 243 | + // configuration warning |
|
| 244 | + if (FoxyCart::store_name_warning() !== null) { |
|
| 245 | + $fields->insertBefore(LiteralField::create( |
|
| 246 | + 'StoreSubDomainHeaderWarning', |
|
| 247 | + _t( |
|
| 248 | + 'FoxyStripeSiteConfig.StoreSubDomainHeadingWarning', |
|
| 249 | + '<p class="message error">Store Domain must be entered below |
|
| 250 | 250 | </a></p>' |
| 251 | - ) |
|
| 252 | - ), 'StoreDetails'); |
|
| 253 | - } |
|
| 254 | - |
|
| 255 | - // products tab |
|
| 256 | - $fields->addFieldsToTab('Root.Products', [ |
|
| 257 | - HeaderField::create('ProductHeader', _t( |
|
| 258 | - 'FoxyStripeSiteConfig.ProductHeader', |
|
| 259 | - 'Products' |
|
| 260 | - ), 3), |
|
| 261 | - CheckboxField::create('MultiGroup') |
|
| 262 | - ->setTitle(_t('FoxyStripeSiteConfig.MultiGroup', 'Multiple Groups')) |
|
| 263 | - ->setDescription(_t( |
|
| 264 | - 'FoxyStripeSiteConfig.MultiGroupDescription', |
|
| 265 | - 'Allows products to be shown in multiple Product Groups' |
|
| 266 | - )), |
|
| 267 | - HeaderField::create('ProductGroupHD', _t( |
|
| 268 | - 'FoxyStripeSiteConfig.ProductGroupHD', |
|
| 269 | - 'Product Groups' |
|
| 270 | - ), 3), |
|
| 271 | - NumericField::create('ProductLimit') |
|
| 272 | - ->setTitle(_t('FoxyStripeSiteConfig.ProductLimit', 'Products per Page')) |
|
| 273 | - ->setDescription(_t( |
|
| 274 | - 'FoxyStripeSiteConfig.ProductLimitDescription', |
|
| 275 | - 'Number of Products to show per page on a Product Group' |
|
| 276 | - )), |
|
| 277 | - HeaderField::create('ProductQuantityHD', _t( |
|
| 278 | - 'FoxyStripeSiteConfig.ProductQuantityHD', |
|
| 279 | - 'Product Form Max Quantity' |
|
| 280 | - ), 3), |
|
| 281 | - NumericField::create('MaxQuantity') |
|
| 282 | - ->setTitle(_t('FoxyStripeSiteConfig.MaxQuantity', 'Max Quantity')) |
|
| 283 | - ->setDescription(_t( |
|
| 284 | - 'FoxyStripeSiteConfig.MaxQuantityDescription', |
|
| 285 | - 'Sets max quantity for product form dropdown (add to cart form - default 10)' |
|
| 286 | - )), |
|
| 287 | - ]); |
|
| 288 | - |
|
| 289 | - // categories tab |
|
| 290 | - $fields->addFieldsToTab('Root.Categories', [ |
|
| 291 | - HeaderField::create('CategoryHD', _t('FoxyStripeSiteConfig.CategoryHD', 'FoxyStripe Categories'), 3), |
|
| 292 | - LiteralField::create('CategoryDescrip', _t( |
|
| 293 | - 'FoxyStripeSiteConfig.CategoryDescrip', |
|
| 294 | - '<p>FoxyCart Categories offer a way to give products additional behaviors that cannot be |
|
| 251 | + ) |
|
| 252 | + ), 'StoreDetails'); |
|
| 253 | + } |
|
| 254 | + |
|
| 255 | + // products tab |
|
| 256 | + $fields->addFieldsToTab('Root.Products', [ |
|
| 257 | + HeaderField::create('ProductHeader', _t( |
|
| 258 | + 'FoxyStripeSiteConfig.ProductHeader', |
|
| 259 | + 'Products' |
|
| 260 | + ), 3), |
|
| 261 | + CheckboxField::create('MultiGroup') |
|
| 262 | + ->setTitle(_t('FoxyStripeSiteConfig.MultiGroup', 'Multiple Groups')) |
|
| 263 | + ->setDescription(_t( |
|
| 264 | + 'FoxyStripeSiteConfig.MultiGroupDescription', |
|
| 265 | + 'Allows products to be shown in multiple Product Groups' |
|
| 266 | + )), |
|
| 267 | + HeaderField::create('ProductGroupHD', _t( |
|
| 268 | + 'FoxyStripeSiteConfig.ProductGroupHD', |
|
| 269 | + 'Product Groups' |
|
| 270 | + ), 3), |
|
| 271 | + NumericField::create('ProductLimit') |
|
| 272 | + ->setTitle(_t('FoxyStripeSiteConfig.ProductLimit', 'Products per Page')) |
|
| 273 | + ->setDescription(_t( |
|
| 274 | + 'FoxyStripeSiteConfig.ProductLimitDescription', |
|
| 275 | + 'Number of Products to show per page on a Product Group' |
|
| 276 | + )), |
|
| 277 | + HeaderField::create('ProductQuantityHD', _t( |
|
| 278 | + 'FoxyStripeSiteConfig.ProductQuantityHD', |
|
| 279 | + 'Product Form Max Quantity' |
|
| 280 | + ), 3), |
|
| 281 | + NumericField::create('MaxQuantity') |
|
| 282 | + ->setTitle(_t('FoxyStripeSiteConfig.MaxQuantity', 'Max Quantity')) |
|
| 283 | + ->setDescription(_t( |
|
| 284 | + 'FoxyStripeSiteConfig.MaxQuantityDescription', |
|
| 285 | + 'Sets max quantity for product form dropdown (add to cart form - default 10)' |
|
| 286 | + )), |
|
| 287 | + ]); |
|
| 288 | + |
|
| 289 | + // categories tab |
|
| 290 | + $fields->addFieldsToTab('Root.Categories', [ |
|
| 291 | + HeaderField::create('CategoryHD', _t('FoxyStripeSiteConfig.CategoryHD', 'FoxyStripe Categories'), 3), |
|
| 292 | + LiteralField::create('CategoryDescrip', _t( |
|
| 293 | + 'FoxyStripeSiteConfig.CategoryDescrip', |
|
| 294 | + '<p>FoxyCart Categories offer a way to give products additional behaviors that cannot be |
|
| 295 | 295 | accomplished by product options alone, including category specific coupon codes, |
| 296 | 296 | shipping and handling fees, and email receipts. |
| 297 | 297 | <a href="https://wiki.foxycart.com/v/2.0/categories" target="_blank"> |
@@ -300,262 +300,262 @@ discard block |
||
| 300 | 300 | <p>Categories you\'ve created in FoxyStripe must also be created in your |
| 301 | 301 | <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" |
| 302 | 302 | target="_blank">FoxyCart Categories</a> admin panel.</p>' |
| 303 | - )), |
|
| 304 | - GridField::create( |
|
| 305 | - 'ProductCategory', |
|
| 306 | - _t('FoxyStripeSiteConfig.ProductCategory', 'FoxyCart Categories'), |
|
| 307 | - ProductCategory::get(), |
|
| 308 | - GridFieldConfig_RecordEditor::create() |
|
| 309 | - ), |
|
| 310 | - ]); |
|
| 311 | - |
|
| 312 | - // option groups tab |
|
| 313 | - $fields->addFieldsToTab('Root.Groups', [ |
|
| 314 | - HeaderField::create('OptionGroupsHead', _t('FoxyStripeSiteConfig', 'Product Option Groups'), 3), |
|
| 315 | - LiteralField::create('OptionGroupsDescrip', _t( |
|
| 316 | - 'FoxyStripeSiteConfig.OptionGroupsDescrip', |
|
| 317 | - '<p>Product Option Groups allow you to name a set of product options.</p>' |
|
| 318 | - )), |
|
| 319 | - GridField::create( |
|
| 320 | - 'OptionGroup', |
|
| 321 | - _t('FoxyStripeSiteConfig.OptionGroup', 'Product Option Groups'), |
|
| 322 | - OptionGroup::get(), |
|
| 323 | - GridFieldConfig_RecordEditor::create() |
|
| 324 | - ), |
|
| 325 | - ]); |
|
| 326 | - |
|
| 327 | - // api tab |
|
| 328 | - if (Permission::check('ADMIN')) { |
|
| 329 | - $fields->addFieldsToTab('Root.API', [ |
|
| 330 | - HeaderField::create('APIHD', 'FoxyCart API Settings', 3), |
|
| 331 | - CheckboxField::create('EnableAPI', 'Enable FoxyCart API'), |
|
| 332 | - TextField::create('client_id', 'FoxyCart Client ID'), |
|
| 333 | - TextField::create('client_secret', 'FoxyCart Client Secret'), |
|
| 334 | - TextField::create('access_token', 'FoxyCart Access Token'), |
|
| 335 | - TextField::create('refresh_token', 'FoxyCart Refresh Token'), |
|
| 336 | - ]); |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - $fields->addFieldsToTab('Root.Template', [ |
|
| 340 | - HeaderField::create('TemplateHD', _t('FoxyStripeSiteConfig.TemplateHD', 'Template Options'), 3), |
|
| 341 | - CheckboxField::create('EnableSidecart') |
|
| 342 | - ->setDescription('Turns on the Sidebar cart. Uncheck to use the full page cart.'), |
|
| 343 | - ]); |
|
| 344 | - |
|
| 345 | - $this->extend('updateCMSFields', $fields); |
|
| 346 | - |
|
| 347 | - return $fields; |
|
| 348 | - } |
|
| 349 | - |
|
| 350 | - /** |
|
| 351 | - * @return FieldList |
|
| 352 | - */ |
|
| 353 | - public function getCMSActions() |
|
| 354 | - { |
|
| 355 | - if (Permission::check('ADMIN') || Permission::check('EDIT_FOXYSTRIPE_SETTING')) { |
|
| 356 | - $actions = new FieldList( |
|
| 357 | - FormAction::create('save_foxystripe_setting', _t('FoxyStripeSetting.SAVE', 'Save')) |
|
| 358 | - ->addExtraClass('btn-primary font-icon-save') |
|
| 359 | - ); |
|
| 360 | - } else { |
|
| 361 | - $actions = FieldList::create(); |
|
| 362 | - } |
|
| 363 | - $this->extend('updateCMSActions', $actions); |
|
| 364 | - |
|
| 365 | - return $actions; |
|
| 366 | - } |
|
| 367 | - |
|
| 368 | - /** |
|
| 369 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 370 | - */ |
|
| 371 | - public function requireDefaultRecords() |
|
| 372 | - { |
|
| 373 | - parent::requireDefaultRecords(); |
|
| 374 | - $config = self::current_foxystripe_setting(); |
|
| 375 | - |
|
| 376 | - if (!$config) { |
|
| 377 | - self::make_foxystripe_setting(); |
|
| 378 | - DB::alteration_message('Added default FoxyStripe Setting', 'created'); |
|
| 379 | - } |
|
| 380 | - |
|
| 381 | - if (!$config->StoreKey) { |
|
| 382 | - $key = FoxyCart::setStoreKey(); |
|
| 383 | - while (!ctype_alnum($key)) { |
|
| 384 | - $key = FoxyCart::setStoreKey(); |
|
| 385 | - } |
|
| 386 | - $config->StoreKey = $key; |
|
| 387 | - $config->write(); |
|
| 388 | - DB::alteration_message('Created FoxyCart Store Key ' . $key, 'created'); |
|
| 389 | - } |
|
| 390 | - } |
|
| 391 | - |
|
| 392 | - /** |
|
| 393 | - * @return string |
|
| 394 | - */ |
|
| 395 | - public function CMSEditLink() |
|
| 396 | - { |
|
| 397 | - return FoxyStripeAdmin::singleton()->Link(); |
|
| 398 | - } |
|
| 399 | - |
|
| 400 | - /** |
|
| 401 | - * @param null $member |
|
| 402 | - * |
|
| 403 | - * @return bool|int|null |
|
| 404 | - */ |
|
| 405 | - public function canEdit($member = null) |
|
| 406 | - { |
|
| 407 | - if (!$member) { |
|
| 408 | - $member = Security::getCurrentUser(); |
|
| 409 | - } |
|
| 410 | - |
|
| 411 | - $extended = $this->extendedCan('canEdit', $member); |
|
| 412 | - if ($extended !== null) { |
|
| 413 | - return $extended; |
|
| 414 | - } |
|
| 415 | - |
|
| 416 | - return Permission::checkMember($member, 'EDIT_FOXYSTRIPE_SETTING'); |
|
| 417 | - } |
|
| 418 | - |
|
| 419 | - /** |
|
| 420 | - * @return array |
|
| 421 | - */ |
|
| 422 | - public function providePermissions() |
|
| 423 | - { |
|
| 424 | - return [ |
|
| 425 | - 'EDIT_FOXYSTRIPE_SETTING' => [ |
|
| 426 | - 'name' => _t( |
|
| 427 | - 'FoxyStripeSetting.EDIT_FOXYSTRIPE_SETTING', |
|
| 428 | - 'Manage FoxyStripe settings' |
|
| 429 | - ), |
|
| 430 | - 'category' => _t( |
|
| 431 | - 'Permissions.PERMISSIONS_FOXYSTRIPE_SETTING', |
|
| 432 | - 'FoxyStripe' |
|
| 433 | - ), |
|
| 434 | - 'help' => _t( |
|
| 435 | - 'FoxyStripeSetting.EDIT_PERMISSION_FOXYSTRIPE_SETTING', |
|
| 436 | - 'Ability to edit the settings of a FoxyStripe Store.' |
|
| 437 | - ), |
|
| 438 | - 'sort' => 400, |
|
| 439 | - ], |
|
| 440 | - ]; |
|
| 441 | - } |
|
| 442 | - |
|
| 443 | - /** |
|
| 444 | - * Get the current sites {@link GlobalSiteSetting}, and creates a new one |
|
| 445 | - * through {@link make_global_config()} if none is found. |
|
| 446 | - * |
|
| 447 | - * @return FoxyStripeSetting|DataObject |
|
| 448 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 449 | - */ |
|
| 450 | - public static function current_foxystripe_setting() |
|
| 451 | - { |
|
| 452 | - if ($config = self::get()->first()) { |
|
| 453 | - return $config; |
|
| 454 | - } |
|
| 455 | - |
|
| 456 | - return self::make_foxystripe_setting(); |
|
| 457 | - } |
|
| 458 | - |
|
| 459 | - /** |
|
| 460 | - * Create {@link GlobalSiteSetting} with defaults from language file. |
|
| 461 | - * |
|
| 462 | - * @return static |
|
| 463 | - */ |
|
| 464 | - public static function make_foxystripe_setting() |
|
| 465 | - { |
|
| 466 | - $config = self::create(); |
|
| 467 | - try { |
|
| 468 | - $config->write(); |
|
| 469 | - } catch (ValidationException $e) { |
|
| 470 | - } |
|
| 471 | - |
|
| 472 | - return $config; |
|
| 473 | - } |
|
| 474 | - |
|
| 475 | - /** |
|
| 476 | - * Add $GlobalConfig to all SSViewers. |
|
| 477 | - */ |
|
| 478 | - public static function get_template_global_variables() |
|
| 479 | - { |
|
| 480 | - return [ |
|
| 481 | - 'FoxyStripe' => 'current_foxystripe_setting', |
|
| 482 | - ]; |
|
| 483 | - } |
|
| 484 | - |
|
| 485 | - /** |
|
| 486 | - * @return string |
|
| 487 | - */ |
|
| 488 | - private static function getSSOLink() |
|
| 489 | - { |
|
| 490 | - return Director::absoluteBaseURL() . 'foxystripe/sso/'; |
|
| 491 | - } |
|
| 492 | - |
|
| 493 | - /** |
|
| 494 | - * @return string |
|
| 495 | - */ |
|
| 496 | - private static function getDataFeedLink() |
|
| 497 | - { |
|
| 498 | - return Director::absoluteBaseURL() . 'foxystripe/'; |
|
| 499 | - } |
|
| 500 | - |
|
| 501 | - /** |
|
| 502 | - * @return array |
|
| 503 | - */ |
|
| 504 | - public function getCheckoutTypes() |
|
| 505 | - { |
|
| 506 | - return [ |
|
| 507 | - 'default_account' => 'Allow guest and customer accounts, default to account', |
|
| 508 | - 'default_guest' => 'Allow guest and customer accounts, default to guest', |
|
| 509 | - 'account_only' => 'Allow customer accounts only', |
|
| 510 | - 'guest_only' => 'Allow guests only', |
|
| 511 | - ]; |
|
| 512 | - } |
|
| 513 | - |
|
| 514 | - /** |
|
| 515 | - * @return array |
|
| 516 | - */ |
|
| 517 | - public function getDataMap() |
|
| 518 | - { |
|
| 519 | - return [ |
|
| 520 | - 'store_name' => $this->StoreTitle, |
|
| 521 | - 'store_domain' => $this->StoreName, |
|
| 522 | - 'store_url' => $this->StoreURL, |
|
| 523 | - 'receipt_continue_url' => $this->ReceiptURL, |
|
| 524 | - 'store_email' => $this->StoreEmail, |
|
| 525 | - 'from_email' => $this->FromEmail, |
|
| 526 | - 'postal_code' => $this->StorePostalCode, |
|
| 527 | - 'country' => $this->StoreCountry, |
|
| 528 | - 'region' => $this->StoreRegion, |
|
| 529 | - 'locale_code' => $this->StoreLocaleCode, |
|
| 530 | - 'logo_url' => $this->StoreLogoURL, |
|
| 531 | - 'checkout_type' => $this->CheckoutType, |
|
| 532 | - 'bcc_on_receipt_email' => $this->BccEmail, |
|
| 533 | - 'use_webhook' => $this->UseWebhook, |
|
| 534 | - 'webhook_url' => $this->getDataFeedLink(), |
|
| 535 | - 'webhook_key' => $this->StoreKey, |
|
| 536 | - 'use_cart_validation' => $this->CartValidation, |
|
| 537 | - 'use_single_sign_on' => $this->UseSingleSignOn, |
|
| 538 | - 'single_sign_on_url' => $this->getSSOLink(), |
|
| 539 | - 'customer_password_hash_type' => 'sha1_salted_suffix', |
|
| 540 | - 'customer_password_hash_config' => 40, |
|
| 541 | - 'features_multiship' => $this->AllowMultiship, |
|
| 542 | - //'timezone' => $this->StoreTimezone, |
|
| 543 | - ]; |
|
| 544 | - } |
|
| 545 | - |
|
| 546 | - /** |
|
| 547 | - * if StoreTitle is empty, grab values from FoxyCart. |
|
| 548 | - * |
|
| 549 | - * example of 2 way sync for future reference |
|
| 550 | - * |
|
| 551 | - * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 552 | - */ |
|
| 553 | - public function onBeforeWrite() |
|
| 554 | - { |
|
| 555 | - parent::onBeforeWrite(); |
|
| 556 | - |
|
| 557 | - if ($this->ID && !$this->StoreTitle && $this->access_token) { |
|
| 558 | - /* |
|
| 303 | + )), |
|
| 304 | + GridField::create( |
|
| 305 | + 'ProductCategory', |
|
| 306 | + _t('FoxyStripeSiteConfig.ProductCategory', 'FoxyCart Categories'), |
|
| 307 | + ProductCategory::get(), |
|
| 308 | + GridFieldConfig_RecordEditor::create() |
|
| 309 | + ), |
|
| 310 | + ]); |
|
| 311 | + |
|
| 312 | + // option groups tab |
|
| 313 | + $fields->addFieldsToTab('Root.Groups', [ |
|
| 314 | + HeaderField::create('OptionGroupsHead', _t('FoxyStripeSiteConfig', 'Product Option Groups'), 3), |
|
| 315 | + LiteralField::create('OptionGroupsDescrip', _t( |
|
| 316 | + 'FoxyStripeSiteConfig.OptionGroupsDescrip', |
|
| 317 | + '<p>Product Option Groups allow you to name a set of product options.</p>' |
|
| 318 | + )), |
|
| 319 | + GridField::create( |
|
| 320 | + 'OptionGroup', |
|
| 321 | + _t('FoxyStripeSiteConfig.OptionGroup', 'Product Option Groups'), |
|
| 322 | + OptionGroup::get(), |
|
| 323 | + GridFieldConfig_RecordEditor::create() |
|
| 324 | + ), |
|
| 325 | + ]); |
|
| 326 | + |
|
| 327 | + // api tab |
|
| 328 | + if (Permission::check('ADMIN')) { |
|
| 329 | + $fields->addFieldsToTab('Root.API', [ |
|
| 330 | + HeaderField::create('APIHD', 'FoxyCart API Settings', 3), |
|
| 331 | + CheckboxField::create('EnableAPI', 'Enable FoxyCart API'), |
|
| 332 | + TextField::create('client_id', 'FoxyCart Client ID'), |
|
| 333 | + TextField::create('client_secret', 'FoxyCart Client Secret'), |
|
| 334 | + TextField::create('access_token', 'FoxyCart Access Token'), |
|
| 335 | + TextField::create('refresh_token', 'FoxyCart Refresh Token'), |
|
| 336 | + ]); |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + $fields->addFieldsToTab('Root.Template', [ |
|
| 340 | + HeaderField::create('TemplateHD', _t('FoxyStripeSiteConfig.TemplateHD', 'Template Options'), 3), |
|
| 341 | + CheckboxField::create('EnableSidecart') |
|
| 342 | + ->setDescription('Turns on the Sidebar cart. Uncheck to use the full page cart.'), |
|
| 343 | + ]); |
|
| 344 | + |
|
| 345 | + $this->extend('updateCMSFields', $fields); |
|
| 346 | + |
|
| 347 | + return $fields; |
|
| 348 | + } |
|
| 349 | + |
|
| 350 | + /** |
|
| 351 | + * @return FieldList |
|
| 352 | + */ |
|
| 353 | + public function getCMSActions() |
|
| 354 | + { |
|
| 355 | + if (Permission::check('ADMIN') || Permission::check('EDIT_FOXYSTRIPE_SETTING')) { |
|
| 356 | + $actions = new FieldList( |
|
| 357 | + FormAction::create('save_foxystripe_setting', _t('FoxyStripeSetting.SAVE', 'Save')) |
|
| 358 | + ->addExtraClass('btn-primary font-icon-save') |
|
| 359 | + ); |
|
| 360 | + } else { |
|
| 361 | + $actions = FieldList::create(); |
|
| 362 | + } |
|
| 363 | + $this->extend('updateCMSActions', $actions); |
|
| 364 | + |
|
| 365 | + return $actions; |
|
| 366 | + } |
|
| 367 | + |
|
| 368 | + /** |
|
| 369 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 370 | + */ |
|
| 371 | + public function requireDefaultRecords() |
|
| 372 | + { |
|
| 373 | + parent::requireDefaultRecords(); |
|
| 374 | + $config = self::current_foxystripe_setting(); |
|
| 375 | + |
|
| 376 | + if (!$config) { |
|
| 377 | + self::make_foxystripe_setting(); |
|
| 378 | + DB::alteration_message('Added default FoxyStripe Setting', 'created'); |
|
| 379 | + } |
|
| 380 | + |
|
| 381 | + if (!$config->StoreKey) { |
|
| 382 | + $key = FoxyCart::setStoreKey(); |
|
| 383 | + while (!ctype_alnum($key)) { |
|
| 384 | + $key = FoxyCart::setStoreKey(); |
|
| 385 | + } |
|
| 386 | + $config->StoreKey = $key; |
|
| 387 | + $config->write(); |
|
| 388 | + DB::alteration_message('Created FoxyCart Store Key ' . $key, 'created'); |
|
| 389 | + } |
|
| 390 | + } |
|
| 391 | + |
|
| 392 | + /** |
|
| 393 | + * @return string |
|
| 394 | + */ |
|
| 395 | + public function CMSEditLink() |
|
| 396 | + { |
|
| 397 | + return FoxyStripeAdmin::singleton()->Link(); |
|
| 398 | + } |
|
| 399 | + |
|
| 400 | + /** |
|
| 401 | + * @param null $member |
|
| 402 | + * |
|
| 403 | + * @return bool|int|null |
|
| 404 | + */ |
|
| 405 | + public function canEdit($member = null) |
|
| 406 | + { |
|
| 407 | + if (!$member) { |
|
| 408 | + $member = Security::getCurrentUser(); |
|
| 409 | + } |
|
| 410 | + |
|
| 411 | + $extended = $this->extendedCan('canEdit', $member); |
|
| 412 | + if ($extended !== null) { |
|
| 413 | + return $extended; |
|
| 414 | + } |
|
| 415 | + |
|
| 416 | + return Permission::checkMember($member, 'EDIT_FOXYSTRIPE_SETTING'); |
|
| 417 | + } |
|
| 418 | + |
|
| 419 | + /** |
|
| 420 | + * @return array |
|
| 421 | + */ |
|
| 422 | + public function providePermissions() |
|
| 423 | + { |
|
| 424 | + return [ |
|
| 425 | + 'EDIT_FOXYSTRIPE_SETTING' => [ |
|
| 426 | + 'name' => _t( |
|
| 427 | + 'FoxyStripeSetting.EDIT_FOXYSTRIPE_SETTING', |
|
| 428 | + 'Manage FoxyStripe settings' |
|
| 429 | + ), |
|
| 430 | + 'category' => _t( |
|
| 431 | + 'Permissions.PERMISSIONS_FOXYSTRIPE_SETTING', |
|
| 432 | + 'FoxyStripe' |
|
| 433 | + ), |
|
| 434 | + 'help' => _t( |
|
| 435 | + 'FoxyStripeSetting.EDIT_PERMISSION_FOXYSTRIPE_SETTING', |
|
| 436 | + 'Ability to edit the settings of a FoxyStripe Store.' |
|
| 437 | + ), |
|
| 438 | + 'sort' => 400, |
|
| 439 | + ], |
|
| 440 | + ]; |
|
| 441 | + } |
|
| 442 | + |
|
| 443 | + /** |
|
| 444 | + * Get the current sites {@link GlobalSiteSetting}, and creates a new one |
|
| 445 | + * through {@link make_global_config()} if none is found. |
|
| 446 | + * |
|
| 447 | + * @return FoxyStripeSetting|DataObject |
|
| 448 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 449 | + */ |
|
| 450 | + public static function current_foxystripe_setting() |
|
| 451 | + { |
|
| 452 | + if ($config = self::get()->first()) { |
|
| 453 | + return $config; |
|
| 454 | + } |
|
| 455 | + |
|
| 456 | + return self::make_foxystripe_setting(); |
|
| 457 | + } |
|
| 458 | + |
|
| 459 | + /** |
|
| 460 | + * Create {@link GlobalSiteSetting} with defaults from language file. |
|
| 461 | + * |
|
| 462 | + * @return static |
|
| 463 | + */ |
|
| 464 | + public static function make_foxystripe_setting() |
|
| 465 | + { |
|
| 466 | + $config = self::create(); |
|
| 467 | + try { |
|
| 468 | + $config->write(); |
|
| 469 | + } catch (ValidationException $e) { |
|
| 470 | + } |
|
| 471 | + |
|
| 472 | + return $config; |
|
| 473 | + } |
|
| 474 | + |
|
| 475 | + /** |
|
| 476 | + * Add $GlobalConfig to all SSViewers. |
|
| 477 | + */ |
|
| 478 | + public static function get_template_global_variables() |
|
| 479 | + { |
|
| 480 | + return [ |
|
| 481 | + 'FoxyStripe' => 'current_foxystripe_setting', |
|
| 482 | + ]; |
|
| 483 | + } |
|
| 484 | + |
|
| 485 | + /** |
|
| 486 | + * @return string |
|
| 487 | + */ |
|
| 488 | + private static function getSSOLink() |
|
| 489 | + { |
|
| 490 | + return Director::absoluteBaseURL() . 'foxystripe/sso/'; |
|
| 491 | + } |
|
| 492 | + |
|
| 493 | + /** |
|
| 494 | + * @return string |
|
| 495 | + */ |
|
| 496 | + private static function getDataFeedLink() |
|
| 497 | + { |
|
| 498 | + return Director::absoluteBaseURL() . 'foxystripe/'; |
|
| 499 | + } |
|
| 500 | + |
|
| 501 | + /** |
|
| 502 | + * @return array |
|
| 503 | + */ |
|
| 504 | + public function getCheckoutTypes() |
|
| 505 | + { |
|
| 506 | + return [ |
|
| 507 | + 'default_account' => 'Allow guest and customer accounts, default to account', |
|
| 508 | + 'default_guest' => 'Allow guest and customer accounts, default to guest', |
|
| 509 | + 'account_only' => 'Allow customer accounts only', |
|
| 510 | + 'guest_only' => 'Allow guests only', |
|
| 511 | + ]; |
|
| 512 | + } |
|
| 513 | + |
|
| 514 | + /** |
|
| 515 | + * @return array |
|
| 516 | + */ |
|
| 517 | + public function getDataMap() |
|
| 518 | + { |
|
| 519 | + return [ |
|
| 520 | + 'store_name' => $this->StoreTitle, |
|
| 521 | + 'store_domain' => $this->StoreName, |
|
| 522 | + 'store_url' => $this->StoreURL, |
|
| 523 | + 'receipt_continue_url' => $this->ReceiptURL, |
|
| 524 | + 'store_email' => $this->StoreEmail, |
|
| 525 | + 'from_email' => $this->FromEmail, |
|
| 526 | + 'postal_code' => $this->StorePostalCode, |
|
| 527 | + 'country' => $this->StoreCountry, |
|
| 528 | + 'region' => $this->StoreRegion, |
|
| 529 | + 'locale_code' => $this->StoreLocaleCode, |
|
| 530 | + 'logo_url' => $this->StoreLogoURL, |
|
| 531 | + 'checkout_type' => $this->CheckoutType, |
|
| 532 | + 'bcc_on_receipt_email' => $this->BccEmail, |
|
| 533 | + 'use_webhook' => $this->UseWebhook, |
|
| 534 | + 'webhook_url' => $this->getDataFeedLink(), |
|
| 535 | + 'webhook_key' => $this->StoreKey, |
|
| 536 | + 'use_cart_validation' => $this->CartValidation, |
|
| 537 | + 'use_single_sign_on' => $this->UseSingleSignOn, |
|
| 538 | + 'single_sign_on_url' => $this->getSSOLink(), |
|
| 539 | + 'customer_password_hash_type' => 'sha1_salted_suffix', |
|
| 540 | + 'customer_password_hash_config' => 40, |
|
| 541 | + 'features_multiship' => $this->AllowMultiship, |
|
| 542 | + //'timezone' => $this->StoreTimezone, |
|
| 543 | + ]; |
|
| 544 | + } |
|
| 545 | + |
|
| 546 | + /** |
|
| 547 | + * if StoreTitle is empty, grab values from FoxyCart. |
|
| 548 | + * |
|
| 549 | + * example of 2 way sync for future reference |
|
| 550 | + * |
|
| 551 | + * @throws \Psr\Container\NotFoundExceptionInterface |
|
| 552 | + */ |
|
| 553 | + public function onBeforeWrite() |
|
| 554 | + { |
|
| 555 | + parent::onBeforeWrite(); |
|
| 556 | + |
|
| 557 | + if ($this->ID && !$this->StoreTitle && $this->access_token) { |
|
| 558 | + /* |
|
| 559 | 559 | if ($fc = new FoxyStripeClient()) { |
| 560 | 560 | $client = $fc->getClient(); |
| 561 | 561 | $errors = []; |
@@ -570,20 +570,20 @@ discard block |
||
| 570 | 570 | } |
| 571 | 571 | } |
| 572 | 572 | */ |
| 573 | - } |
|
| 574 | - } |
|
| 575 | - |
|
| 576 | - /** |
|
| 577 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 578 | - */ |
|
| 579 | - public function onAfterWrite() |
|
| 580 | - { |
|
| 581 | - parent::onAfterWrite(); |
|
| 582 | - |
|
| 583 | - if (FoxyStripeClient::is_valid() && $this->isChanged()) { |
|
| 584 | - if ($fc = new FoxyStripeClient()) { |
|
| 585 | - $fc->updateStore($this->getDataMap()); |
|
| 586 | - } |
|
| 587 | - } |
|
| 588 | - } |
|
| 573 | + } |
|
| 574 | + } |
|
| 575 | + |
|
| 576 | + /** |
|
| 577 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 578 | + */ |
|
| 579 | + public function onAfterWrite() |
|
| 580 | + { |
|
| 581 | + parent::onAfterWrite(); |
|
| 582 | + |
|
| 583 | + if (FoxyStripeClient::is_valid() && $this->isChanged()) { |
|
| 584 | + if ($fc = new FoxyStripeClient()) { |
|
| 585 | + $fc->updateStore($this->getDataMap()); |
|
| 586 | + } |
|
| 587 | + } |
|
| 588 | + } |
|
| 589 | 589 | } |
@@ -18,7 +18,7 @@ |
||
| 18 | 18 | |
| 19 | 19 | if ($config->EnableSidecart) { |
| 20 | 20 | Requirements::javascript( |
| 21 | - "https://cdn.foxycart.com/" . FoxyCart::getFoxyCartStoreName() . "/loader.js", |
|
| 21 | + "https://cdn.foxycart.com/".FoxyCart::getFoxyCartStoreName()."/loader.js", |
|
| 22 | 22 | [ |
| 23 | 23 | "async" => true, |
| 24 | 24 | "defer" => true, |
@@ -9,21 +9,21 @@ |
||
| 9 | 9 | |
| 10 | 10 | class FoxyStripePageExtension extends Extension |
| 11 | 11 | { |
| 12 | - /** |
|
| 13 | - * @throws \SilverStripe\ORM\ValidationException |
|
| 14 | - */ |
|
| 15 | - public function onAfterInit() |
|
| 16 | - { |
|
| 17 | - $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 12 | + /** |
|
| 13 | + * @throws \SilverStripe\ORM\ValidationException |
|
| 14 | + */ |
|
| 15 | + public function onAfterInit() |
|
| 16 | + { |
|
| 17 | + $config = FoxyStripeSetting::current_foxystripe_setting(); |
|
| 18 | 18 | |
| 19 | - if ($config->EnableSidecart) { |
|
| 20 | - Requirements::javascript( |
|
| 21 | - "https://cdn.foxycart.com/" . FoxyCart::getFoxyCartStoreName() . "/loader.js", |
|
| 22 | - [ |
|
| 23 | - "async" => true, |
|
| 24 | - "defer" => true, |
|
| 25 | - ] |
|
| 26 | - ); |
|
| 27 | - } |
|
| 28 | - } |
|
| 19 | + if ($config->EnableSidecart) { |
|
| 20 | + Requirements::javascript( |
|
| 21 | + "https://cdn.foxycart.com/" . FoxyCart::getFoxyCartStoreName() . "/loader.js", |
|
| 22 | + [ |
|
| 23 | + "async" => true, |
|
| 24 | + "defer" => true, |
|
| 25 | + ] |
|
| 26 | + ); |
|
| 27 | + } |
|
| 28 | + } |
|
| 29 | 29 | } |
@@ -226,9 +226,9 @@ discard block |
||
| 226 | 226 | */ |
| 227 | 227 | public function getCMSFields() |
| 228 | 228 | { |
| 229 | - $this->beforeUpdateCMSFields(function (FieldList $fields) { |
|
| 229 | + $this->beforeUpdateCMSFields(function(FieldList $fields) { |
|
| 230 | 230 | // Cateogry Dropdown field w/ add new |
| 231 | - $source = function () { |
|
| 231 | + $source = function() { |
|
| 232 | 232 | return ProductCategory::get()->map()->toArray(); |
| 233 | 233 | }; |
| 234 | 234 | $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source()) |
@@ -368,7 +368,7 @@ discard block |
||
| 368 | 368 | $product = self::get()->byID($this->ID); |
| 369 | 369 | if (isset($product->ParentID)) { |
| 370 | 370 | $origParent = $product->ParentID; |
| 371 | - } else { |
|
| 371 | + }else { |
|
| 372 | 372 | $origParent = null; |
| 373 | 373 | } |
| 374 | 374 | $currentParent = $this->ParentID; |
@@ -448,8 +448,7 @@ discard block |
||
| 448 | 448 | $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName; |
| 449 | 449 | |
| 450 | 450 | return (FoxyStripeSetting::current_foxystripe_setting()->CartValidation) |
| 451 | - ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) : |
|
| 452 | - $optionValue; |
|
| 451 | + ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) : $optionValue; |
|
| 453 | 452 | } |
| 454 | 453 | |
| 455 | 454 | /** |
@@ -56,189 +56,189 @@ discard block |
||
| 56 | 56 | */ |
| 57 | 57 | class ProductPage extends \Page implements PermissionProvider |
| 58 | 58 | { |
| 59 | - /** |
|
| 60 | - * @var string |
|
| 61 | - */ |
|
| 62 | - private static $default_parent = ProductHolder::class; |
|
| 63 | - |
|
| 64 | - /** |
|
| 65 | - * @var bool |
|
| 66 | - */ |
|
| 67 | - private static $can_be_root = false; |
|
| 68 | - |
|
| 69 | - /** |
|
| 70 | - * @var array |
|
| 71 | - */ |
|
| 72 | - private static $db = [ |
|
| 73 | - 'Price' => 'Currency', |
|
| 74 | - 'Weight' => 'Decimal', |
|
| 75 | - 'Code' => 'Varchar(100)', |
|
| 76 | - 'ReceiptTitle' => 'HTMLVarchar(255)', |
|
| 77 | - 'Available' => 'Boolean', |
|
| 78 | - ]; |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * @var array |
|
| 82 | - */ |
|
| 83 | - private static $has_one = [ |
|
| 84 | - 'Category' => ProductCategory::class, |
|
| 85 | - ]; |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * @var array |
|
| 89 | - */ |
|
| 90 | - private static $has_many = [ |
|
| 91 | - 'ProductOptions' => OptionItem::class, |
|
| 92 | - 'OrderDetails' => OrderDetail::class, |
|
| 93 | - ]; |
|
| 94 | - |
|
| 95 | - /** |
|
| 96 | - * @var array |
|
| 97 | - */ |
|
| 98 | - private static $many_many = [ |
|
| 99 | - 'Images' => Image::class, |
|
| 100 | - ]; |
|
| 101 | - |
|
| 102 | - /** |
|
| 103 | - * @var array |
|
| 104 | - */ |
|
| 105 | - private static $many_many_extraFields = [ |
|
| 106 | - 'Images' => [ |
|
| 107 | - 'SortOrder' => 'Int', |
|
| 108 | - ], |
|
| 109 | - ]; |
|
| 110 | - |
|
| 111 | - /** |
|
| 112 | - * @var array |
|
| 113 | - */ |
|
| 114 | - private static $owns = [ |
|
| 115 | - 'Images', |
|
| 116 | - ]; |
|
| 117 | - |
|
| 118 | - /** |
|
| 119 | - * @var array |
|
| 120 | - */ |
|
| 121 | - private static $belongs_many_many = [ |
|
| 122 | - 'ProductHolders' => ProductHolder::class, |
|
| 123 | - ]; |
|
| 124 | - |
|
| 125 | - /** |
|
| 126 | - * @var string |
|
| 127 | - */ |
|
| 128 | - private static $singular_name = 'Product'; |
|
| 129 | - |
|
| 130 | - /** |
|
| 131 | - * @var string |
|
| 132 | - */ |
|
| 133 | - private static $plural_name = 'Products'; |
|
| 134 | - |
|
| 135 | - /** |
|
| 136 | - * @var string |
|
| 137 | - */ |
|
| 138 | - private static $description = 'A product that can be added to the shopping cart'; |
|
| 139 | - |
|
| 140 | - /** |
|
| 141 | - * @var array |
|
| 142 | - */ |
|
| 143 | - private static $indexes = [ |
|
| 144 | - 'Code' => [ |
|
| 145 | - 'type' => 'unique', |
|
| 146 | - 'columns' => ['Code'], |
|
| 147 | - ], |
|
| 148 | - ]; |
|
| 149 | - |
|
| 150 | - /** |
|
| 151 | - * @var array |
|
| 152 | - */ |
|
| 153 | - private static $defaults = [ |
|
| 154 | - 'ShowInMenus' => false, |
|
| 155 | - 'Available' => true, |
|
| 156 | - 'Weight' => '0.0', |
|
| 157 | - ]; |
|
| 158 | - |
|
| 159 | - /** |
|
| 160 | - * @var array |
|
| 161 | - */ |
|
| 162 | - private static $summary_fields = [ |
|
| 163 | - 'Image.CMSThumbnail', |
|
| 164 | - 'Title', |
|
| 165 | - 'Code', |
|
| 166 | - 'Price.Nice', |
|
| 167 | - 'Category.Title', |
|
| 168 | - ]; |
|
| 169 | - |
|
| 170 | - /** |
|
| 171 | - * @var array |
|
| 172 | - */ |
|
| 173 | - private static $searchable_fields = [ |
|
| 174 | - 'Title', |
|
| 175 | - 'Code', |
|
| 176 | - 'Available', |
|
| 177 | - 'Category.ID', |
|
| 178 | - ]; |
|
| 179 | - |
|
| 180 | - /** |
|
| 181 | - * @var string |
|
| 182 | - */ |
|
| 183 | - private static $table_name = 'ProductPage'; |
|
| 184 | - |
|
| 185 | - /** |
|
| 186 | - * Construct a new ProductPage. |
|
| 187 | - * |
|
| 188 | - * @param array|null $record Used internally for rehydrating an object from database content. |
|
| 189 | - * Bypasses setters on this class, and hence should not be used |
|
| 190 | - * for populating data on new records. |
|
| 191 | - * @param boolean $isSingleton This this to true if this is a singleton() object, a stub for calling methods. |
|
| 192 | - * Singletons don't have their defaults set. |
|
| 193 | - * @param array $queryParams List of DataQuery params necessary to lazy load, or load related objects. |
|
| 194 | - */ |
|
| 195 | - public function __construct($record = null, $isSingleton = false, $queryParams = []) |
|
| 196 | - { |
|
| 197 | - parent::__construct($record, $isSingleton, $queryParams); |
|
| 198 | - |
|
| 199 | - if (Controller::has_curr()) { |
|
| 200 | - if (Controller::curr() instanceof ContentController) { |
|
| 201 | - Requirements::javascript('dynamic/foxystripe: javascript/quantity.js'); |
|
| 202 | - Requirements::css('dynamic/foxystripe: client/dist/css/quantityfield.css'); |
|
| 203 | - } |
|
| 204 | - } |
|
| 205 | - } |
|
| 206 | - |
|
| 207 | - /** |
|
| 208 | - * @param bool $includerelations |
|
| 209 | - * |
|
| 210 | - * @return array |
|
| 211 | - */ |
|
| 212 | - public function fieldLabels($includerelations = true) |
|
| 213 | - { |
|
| 214 | - $labels = parent::fieldLabels(); |
|
| 215 | - |
|
| 216 | - $labels['Title'] = _t('ProductPage.TitleLabel', 'Name'); |
|
| 217 | - $labels['Code'] = _t('ProductPage.CodeLabel', 'Code'); |
|
| 218 | - $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price'); |
|
| 219 | - $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available'); |
|
| 220 | - $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category'); |
|
| 221 | - $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category'); |
|
| 222 | - $labels['Image.CMSThumbnail'] = _t('ProductPage.ImageLabel', 'Image'); |
|
| 223 | - |
|
| 224 | - return $labels; |
|
| 225 | - } |
|
| 226 | - |
|
| 227 | - /** |
|
| 228 | - * @return \SilverStripe\Forms\FieldList |
|
| 229 | - */ |
|
| 230 | - public function getCMSFields() |
|
| 231 | - { |
|
| 232 | - $this->beforeUpdateCMSFields(function (FieldList $fields) { |
|
| 233 | - // Cateogry Dropdown field w/ add new |
|
| 234 | - $source = function () { |
|
| 235 | - return ProductCategory::get()->map()->toArray(); |
|
| 236 | - }; |
|
| 237 | - $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source()) |
|
| 238 | - ->setEmptyString('') |
|
| 239 | - ->setDescription(_t( |
|
| 240 | - 'ProductPage.CategoryDescription', |
|
| 241 | - 'Required, must also exist in |
|
| 59 | + /** |
|
| 60 | + * @var string |
|
| 61 | + */ |
|
| 62 | + private static $default_parent = ProductHolder::class; |
|
| 63 | + |
|
| 64 | + /** |
|
| 65 | + * @var bool |
|
| 66 | + */ |
|
| 67 | + private static $can_be_root = false; |
|
| 68 | + |
|
| 69 | + /** |
|
| 70 | + * @var array |
|
| 71 | + */ |
|
| 72 | + private static $db = [ |
|
| 73 | + 'Price' => 'Currency', |
|
| 74 | + 'Weight' => 'Decimal', |
|
| 75 | + 'Code' => 'Varchar(100)', |
|
| 76 | + 'ReceiptTitle' => 'HTMLVarchar(255)', |
|
| 77 | + 'Available' => 'Boolean', |
|
| 78 | + ]; |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * @var array |
|
| 82 | + */ |
|
| 83 | + private static $has_one = [ |
|
| 84 | + 'Category' => ProductCategory::class, |
|
| 85 | + ]; |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * @var array |
|
| 89 | + */ |
|
| 90 | + private static $has_many = [ |
|
| 91 | + 'ProductOptions' => OptionItem::class, |
|
| 92 | + 'OrderDetails' => OrderDetail::class, |
|
| 93 | + ]; |
|
| 94 | + |
|
| 95 | + /** |
|
| 96 | + * @var array |
|
| 97 | + */ |
|
| 98 | + private static $many_many = [ |
|
| 99 | + 'Images' => Image::class, |
|
| 100 | + ]; |
|
| 101 | + |
|
| 102 | + /** |
|
| 103 | + * @var array |
|
| 104 | + */ |
|
| 105 | + private static $many_many_extraFields = [ |
|
| 106 | + 'Images' => [ |
|
| 107 | + 'SortOrder' => 'Int', |
|
| 108 | + ], |
|
| 109 | + ]; |
|
| 110 | + |
|
| 111 | + /** |
|
| 112 | + * @var array |
|
| 113 | + */ |
|
| 114 | + private static $owns = [ |
|
| 115 | + 'Images', |
|
| 116 | + ]; |
|
| 117 | + |
|
| 118 | + /** |
|
| 119 | + * @var array |
|
| 120 | + */ |
|
| 121 | + private static $belongs_many_many = [ |
|
| 122 | + 'ProductHolders' => ProductHolder::class, |
|
| 123 | + ]; |
|
| 124 | + |
|
| 125 | + /** |
|
| 126 | + * @var string |
|
| 127 | + */ |
|
| 128 | + private static $singular_name = 'Product'; |
|
| 129 | + |
|
| 130 | + /** |
|
| 131 | + * @var string |
|
| 132 | + */ |
|
| 133 | + private static $plural_name = 'Products'; |
|
| 134 | + |
|
| 135 | + /** |
|
| 136 | + * @var string |
|
| 137 | + */ |
|
| 138 | + private static $description = 'A product that can be added to the shopping cart'; |
|
| 139 | + |
|
| 140 | + /** |
|
| 141 | + * @var array |
|
| 142 | + */ |
|
| 143 | + private static $indexes = [ |
|
| 144 | + 'Code' => [ |
|
| 145 | + 'type' => 'unique', |
|
| 146 | + 'columns' => ['Code'], |
|
| 147 | + ], |
|
| 148 | + ]; |
|
| 149 | + |
|
| 150 | + /** |
|
| 151 | + * @var array |
|
| 152 | + */ |
|
| 153 | + private static $defaults = [ |
|
| 154 | + 'ShowInMenus' => false, |
|
| 155 | + 'Available' => true, |
|
| 156 | + 'Weight' => '0.0', |
|
| 157 | + ]; |
|
| 158 | + |
|
| 159 | + /** |
|
| 160 | + * @var array |
|
| 161 | + */ |
|
| 162 | + private static $summary_fields = [ |
|
| 163 | + 'Image.CMSThumbnail', |
|
| 164 | + 'Title', |
|
| 165 | + 'Code', |
|
| 166 | + 'Price.Nice', |
|
| 167 | + 'Category.Title', |
|
| 168 | + ]; |
|
| 169 | + |
|
| 170 | + /** |
|
| 171 | + * @var array |
|
| 172 | + */ |
|
| 173 | + private static $searchable_fields = [ |
|
| 174 | + 'Title', |
|
| 175 | + 'Code', |
|
| 176 | + 'Available', |
|
| 177 | + 'Category.ID', |
|
| 178 | + ]; |
|
| 179 | + |
|
| 180 | + /** |
|
| 181 | + * @var string |
|
| 182 | + */ |
|
| 183 | + private static $table_name = 'ProductPage'; |
|
| 184 | + |
|
| 185 | + /** |
|
| 186 | + * Construct a new ProductPage. |
|
| 187 | + * |
|
| 188 | + * @param array|null $record Used internally for rehydrating an object from database content. |
|
| 189 | + * Bypasses setters on this class, and hence should not be used |
|
| 190 | + * for populating data on new records. |
|
| 191 | + * @param boolean $isSingleton This this to true if this is a singleton() object, a stub for calling methods. |
|
| 192 | + * Singletons don't have their defaults set. |
|
| 193 | + * @param array $queryParams List of DataQuery params necessary to lazy load, or load related objects. |
|
| 194 | + */ |
|
| 195 | + public function __construct($record = null, $isSingleton = false, $queryParams = []) |
|
| 196 | + { |
|
| 197 | + parent::__construct($record, $isSingleton, $queryParams); |
|
| 198 | + |
|
| 199 | + if (Controller::has_curr()) { |
|
| 200 | + if (Controller::curr() instanceof ContentController) { |
|
| 201 | + Requirements::javascript('dynamic/foxystripe: javascript/quantity.js'); |
|
| 202 | + Requirements::css('dynamic/foxystripe: client/dist/css/quantityfield.css'); |
|
| 203 | + } |
|
| 204 | + } |
|
| 205 | + } |
|
| 206 | + |
|
| 207 | + /** |
|
| 208 | + * @param bool $includerelations |
|
| 209 | + * |
|
| 210 | + * @return array |
|
| 211 | + */ |
|
| 212 | + public function fieldLabels($includerelations = true) |
|
| 213 | + { |
|
| 214 | + $labels = parent::fieldLabels(); |
|
| 215 | + |
|
| 216 | + $labels['Title'] = _t('ProductPage.TitleLabel', 'Name'); |
|
| 217 | + $labels['Code'] = _t('ProductPage.CodeLabel', 'Code'); |
|
| 218 | + $labels['Price.Nice'] = _t('ProductPage.PriceLabel', 'Price'); |
|
| 219 | + $labels['Available.Nice'] = _t('ProductPage.AvailableLabel', 'Available'); |
|
| 220 | + $labels['Category.ID'] = _t('ProductPage.IDLabel', 'Category'); |
|
| 221 | + $labels['Category.Title'] = _t('ProductPage.CategoryTitleLabel', 'Category'); |
|
| 222 | + $labels['Image.CMSThumbnail'] = _t('ProductPage.ImageLabel', 'Image'); |
|
| 223 | + |
|
| 224 | + return $labels; |
|
| 225 | + } |
|
| 226 | + |
|
| 227 | + /** |
|
| 228 | + * @return \SilverStripe\Forms\FieldList |
|
| 229 | + */ |
|
| 230 | + public function getCMSFields() |
|
| 231 | + { |
|
| 232 | + $this->beforeUpdateCMSFields(function (FieldList $fields) { |
|
| 233 | + // Cateogry Dropdown field w/ add new |
|
| 234 | + $source = function () { |
|
| 235 | + return ProductCategory::get()->map()->toArray(); |
|
| 236 | + }; |
|
| 237 | + $catField = DropdownField::create('CategoryID', _t('ProductPage.Category', 'FoxyCart Category'), $source()) |
|
| 238 | + ->setEmptyString('') |
|
| 239 | + ->setDescription(_t( |
|
| 240 | + 'ProductPage.CategoryDescription', |
|
| 241 | + 'Required, must also exist in |
|
| 242 | 242 | <a href="https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories" target="_blank"> |
| 243 | 243 | FoxyCart Categories |
| 244 | 244 | </a>. |
@@ -246,119 +246,119 @@ discard block |
||
| 246 | 246 | <a href="admin/settings"> |
| 247 | 247 | Settings > FoxyStripe > Categories |
| 248 | 248 | </a>' |
| 249 | - )); |
|
| 250 | - if (class_exists('QuickAddNewExtension')) { |
|
| 251 | - $catField->useAddNew('ProductCategory', $source); |
|
| 252 | - } |
|
| 253 | - |
|
| 254 | - $fields->addFieldsToTab( |
|
| 255 | - 'Root.Main', |
|
| 256 | - [ |
|
| 257 | - TextField::create('Code') |
|
| 258 | - ->setTitle(_t('ProductPage.Code', 'Product Code')) |
|
| 259 | - ->setDescription(_t( |
|
| 260 | - 'ProductPage.CodeDescription', |
|
| 261 | - 'Required, must be unique. Product identifier used by FoxyCart in transactions' |
|
| 262 | - )), |
|
| 263 | - CurrencyField::create('Price') |
|
| 264 | - ->setTitle(_t('ProductPage.Price', 'Price')) |
|
| 265 | - ->setDescription(_t( |
|
| 266 | - 'ProductPage.PriceDescription', |
|
| 267 | - 'Base price for this product. Can be modified using Product Options' |
|
| 268 | - )), |
|
| 269 | - NumericField::create('Weight') |
|
| 270 | - ->setTitle(_t('ProductPage.Weight', 'Weight')) |
|
| 271 | - ->setDescription(_t( |
|
| 272 | - 'ProductPage.WeightDescription', |
|
| 273 | - 'Base weight for this product in lbs. Can be modified using Product Options' |
|
| 274 | - )) |
|
| 275 | - ->setScale(2), |
|
| 276 | - $catField, |
|
| 277 | - ], |
|
| 278 | - 'Content' |
|
| 279 | - ); |
|
| 280 | - |
|
| 281 | - // Product Options field |
|
| 282 | - $config = GridFieldConfig_RelationEditor::create(); |
|
| 283 | - $config->addComponent(new GridFieldOrderableRows('SortOrder')); |
|
| 284 | - $products = $this->ProductOptions()->sort('SortOrder'); |
|
| 285 | - $config->removeComponentsByType(GridFieldAddExistingAutocompleter::class); |
|
| 286 | - $prodOptField = GridField::create( |
|
| 287 | - 'ProductOptions', |
|
| 288 | - _t('ProductPage.ProductOptions', 'Options'), |
|
| 289 | - $products, |
|
| 290 | - $config |
|
| 291 | - ); |
|
| 292 | - |
|
| 293 | - // Details tab |
|
| 294 | - $fields->addFieldsToTab('Root.Details', [ |
|
| 295 | - CheckboxField::create('Available') |
|
| 296 | - ->setTitle(_t('ProductPage.Available', 'Available for purchase')) |
|
| 297 | - ->setDescription(_t( |
|
| 298 | - 'ProductPage.AvailableDescription', |
|
| 299 | - 'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"' |
|
| 300 | - )), |
|
| 301 | - TextField::create('ReceiptTitle') |
|
| 302 | - ->setTitle(_t('ProductPage.ReceiptTitle', 'Product Title for Receipt')) |
|
| 303 | - ->setDescription(_t( |
|
| 304 | - 'ProductPage.ReceiptTitleDescription', |
|
| 305 | - 'Optional' |
|
| 306 | - )), |
|
| 307 | - ]); |
|
| 308 | - |
|
| 309 | - // Options Tab |
|
| 310 | - $fields->addFieldsToTab('Root.Options', [ |
|
| 311 | - $prodOptField |
|
| 312 | - ->setDescription(_t( |
|
| 313 | - 'Page.OptionsDescrip', |
|
| 314 | - '<p>Product Options allow products to be customized by attributes such as size or color. |
|
| 249 | + )); |
|
| 250 | + if (class_exists('QuickAddNewExtension')) { |
|
| 251 | + $catField->useAddNew('ProductCategory', $source); |
|
| 252 | + } |
|
| 253 | + |
|
| 254 | + $fields->addFieldsToTab( |
|
| 255 | + 'Root.Main', |
|
| 256 | + [ |
|
| 257 | + TextField::create('Code') |
|
| 258 | + ->setTitle(_t('ProductPage.Code', 'Product Code')) |
|
| 259 | + ->setDescription(_t( |
|
| 260 | + 'ProductPage.CodeDescription', |
|
| 261 | + 'Required, must be unique. Product identifier used by FoxyCart in transactions' |
|
| 262 | + )), |
|
| 263 | + CurrencyField::create('Price') |
|
| 264 | + ->setTitle(_t('ProductPage.Price', 'Price')) |
|
| 265 | + ->setDescription(_t( |
|
| 266 | + 'ProductPage.PriceDescription', |
|
| 267 | + 'Base price for this product. Can be modified using Product Options' |
|
| 268 | + )), |
|
| 269 | + NumericField::create('Weight') |
|
| 270 | + ->setTitle(_t('ProductPage.Weight', 'Weight')) |
|
| 271 | + ->setDescription(_t( |
|
| 272 | + 'ProductPage.WeightDescription', |
|
| 273 | + 'Base weight for this product in lbs. Can be modified using Product Options' |
|
| 274 | + )) |
|
| 275 | + ->setScale(2), |
|
| 276 | + $catField, |
|
| 277 | + ], |
|
| 278 | + 'Content' |
|
| 279 | + ); |
|
| 280 | + |
|
| 281 | + // Product Options field |
|
| 282 | + $config = GridFieldConfig_RelationEditor::create(); |
|
| 283 | + $config->addComponent(new GridFieldOrderableRows('SortOrder')); |
|
| 284 | + $products = $this->ProductOptions()->sort('SortOrder'); |
|
| 285 | + $config->removeComponentsByType(GridFieldAddExistingAutocompleter::class); |
|
| 286 | + $prodOptField = GridField::create( |
|
| 287 | + 'ProductOptions', |
|
| 288 | + _t('ProductPage.ProductOptions', 'Options'), |
|
| 289 | + $products, |
|
| 290 | + $config |
|
| 291 | + ); |
|
| 292 | + |
|
| 293 | + // Details tab |
|
| 294 | + $fields->addFieldsToTab('Root.Details', [ |
|
| 295 | + CheckboxField::create('Available') |
|
| 296 | + ->setTitle(_t('ProductPage.Available', 'Available for purchase')) |
|
| 297 | + ->setDescription(_t( |
|
| 298 | + 'ProductPage.AvailableDescription', |
|
| 299 | + 'If unchecked, will remove "Add to Cart" form and instead display "Currently unavailable"' |
|
| 300 | + )), |
|
| 301 | + TextField::create('ReceiptTitle') |
|
| 302 | + ->setTitle(_t('ProductPage.ReceiptTitle', 'Product Title for Receipt')) |
|
| 303 | + ->setDescription(_t( |
|
| 304 | + 'ProductPage.ReceiptTitleDescription', |
|
| 305 | + 'Optional' |
|
| 306 | + )), |
|
| 307 | + ]); |
|
| 308 | + |
|
| 309 | + // Options Tab |
|
| 310 | + $fields->addFieldsToTab('Root.Options', [ |
|
| 311 | + $prodOptField |
|
| 312 | + ->setDescription(_t( |
|
| 313 | + 'Page.OptionsDescrip', |
|
| 314 | + '<p>Product Options allow products to be customized by attributes such as size or color. |
|
| 315 | 315 | Options can also modify the product\'s price, weight or code.<br></p>' |
| 316 | - )), |
|
| 317 | - ]); |
|
| 318 | - |
|
| 319 | - // Images tab |
|
| 320 | - $images = SortableUploadField::create('Images') |
|
| 321 | - ->setSortColumn('SortOrder') |
|
| 322 | - ->setIsMultiUpload(true) |
|
| 323 | - ->setAllowedFileCategories('image') |
|
| 324 | - ->setFolderName('Uploads/Products/Images'); |
|
| 325 | - |
|
| 326 | - $fields->addFieldsToTab('Root.Images', [ |
|
| 327 | - $images, |
|
| 328 | - ]); |
|
| 329 | - |
|
| 330 | - if (FoxyCart::store_name_warning() !== null) { |
|
| 331 | - $fields->addFieldToTab('Root.Main', LiteralField::create('StoreSubDomainHeaderWarning', _t( |
|
| 332 | - 'ProductPage.StoreSubDomainHeaderWarning', |
|
| 333 | - '<p class="message error">Store sub-domain must be entered in the |
|
| 316 | + )), |
|
| 317 | + ]); |
|
| 318 | + |
|
| 319 | + // Images tab |
|
| 320 | + $images = SortableUploadField::create('Images') |
|
| 321 | + ->setSortColumn('SortOrder') |
|
| 322 | + ->setIsMultiUpload(true) |
|
| 323 | + ->setAllowedFileCategories('image') |
|
| 324 | + ->setFolderName('Uploads/Products/Images'); |
|
| 325 | + |
|
| 326 | + $fields->addFieldsToTab('Root.Images', [ |
|
| 327 | + $images, |
|
| 328 | + ]); |
|
| 329 | + |
|
| 330 | + if (FoxyCart::store_name_warning() !== null) { |
|
| 331 | + $fields->addFieldToTab('Root.Main', LiteralField::create('StoreSubDomainHeaderWarning', _t( |
|
| 332 | + 'ProductPage.StoreSubDomainHeaderWarning', |
|
| 333 | + '<p class="message error">Store sub-domain must be entered in the |
|
| 334 | 334 | <a href="/admin/settings/">site settings</a></p>' |
| 335 | - )), 'Title'); |
|
| 336 | - } |
|
| 337 | - }); |
|
| 338 | - |
|
| 339 | - return parent::getCMSFields(); |
|
| 340 | - } |
|
| 341 | - |
|
| 342 | - /** |
|
| 343 | - * @return RequiredFields |
|
| 344 | - */ |
|
| 345 | - public function getCMSValidator() |
|
| 346 | - { |
|
| 347 | - return new RequiredFields(['CategoryID', 'Price', 'Weight', 'Code']); |
|
| 348 | - } |
|
| 349 | - |
|
| 350 | - /** |
|
| 351 | - * @return \SilverStripe\ORM\ValidationResult |
|
| 352 | - */ |
|
| 353 | - public function validate() |
|
| 354 | - { |
|
| 355 | - $result = parent::validate(); |
|
| 356 | - |
|
| 357 | - if (ProductPage::get()->filter('Code', $this->Code)->exclude('ID', $this->ID)->first()) { |
|
| 358 | - $result->addError('Code must be unique for each product.'); |
|
| 359 | - } |
|
| 360 | - |
|
| 361 | - /*if($this->ID>0){ |
|
| 335 | + )), 'Title'); |
|
| 336 | + } |
|
| 337 | + }); |
|
| 338 | + |
|
| 339 | + return parent::getCMSFields(); |
|
| 340 | + } |
|
| 341 | + |
|
| 342 | + /** |
|
| 343 | + * @return RequiredFields |
|
| 344 | + */ |
|
| 345 | + public function getCMSValidator() |
|
| 346 | + { |
|
| 347 | + return new RequiredFields(['CategoryID', 'Price', 'Weight', 'Code']); |
|
| 348 | + } |
|
| 349 | + |
|
| 350 | + /** |
|
| 351 | + * @return \SilverStripe\ORM\ValidationResult |
|
| 352 | + */ |
|
| 353 | + public function validate() |
|
| 354 | + { |
|
| 355 | + $result = parent::validate(); |
|
| 356 | + |
|
| 357 | + if (ProductPage::get()->filter('Code', $this->Code)->exclude('ID', $this->ID)->first()) { |
|
| 358 | + $result->addError('Code must be unique for each product.'); |
|
| 359 | + } |
|
| 360 | + |
|
| 361 | + /*if($this->ID>0){ |
|
| 362 | 362 | if ($this->Price <= 0) { |
| 363 | 363 | $result->addError('Price must be a positive value'); |
| 364 | 364 | } |
@@ -370,173 +370,173 @@ discard block |
||
| 370 | 370 | } |
| 371 | 371 | }*/ |
| 372 | 372 | |
| 373 | - return $result; |
|
| 374 | - } |
|
| 375 | - |
|
| 376 | - /** |
|
| 377 | - * @return \SilverStripe\ORM\ManyManyList |
|
| 378 | - */ |
|
| 379 | - public function getSortedImages() |
|
| 380 | - { |
|
| 381 | - return $this->Images()->Sort('SortOrder'); |
|
| 382 | - } |
|
| 383 | - |
|
| 384 | - /** |
|
| 385 | - * @return \SilverStripe\ORM\ManyManyList |
|
| 386 | - */ |
|
| 387 | - public function SortedImages() |
|
| 388 | - { |
|
| 389 | - return $this->getSortedImages(); |
|
| 390 | - } |
|
| 391 | - |
|
| 392 | - /** |
|
| 393 | - * @return Image|bool |
|
| 394 | - */ |
|
| 395 | - public function getImage() |
|
| 396 | - { |
|
| 397 | - if ($this->getSortedImages()->count() > 0) { |
|
| 398 | - return $this->getSortedImages()->first(); |
|
| 399 | - } |
|
| 400 | - |
|
| 401 | - return false; |
|
| 402 | - } |
|
| 403 | - |
|
| 404 | - /** |
|
| 405 | - * @return Image|bool |
|
| 406 | - */ |
|
| 407 | - public function Image() |
|
| 408 | - { |
|
| 409 | - return $this->getImage(); |
|
| 410 | - } |
|
| 411 | - |
|
| 412 | - /** |
|
| 413 | - * @throws \Exception |
|
| 414 | - */ |
|
| 415 | - public function onBeforeWrite() |
|
| 416 | - { |
|
| 417 | - parent::onBeforeWrite(); |
|
| 418 | - if (!$this->CategoryID) { |
|
| 419 | - $default = ProductCategory::get()->filter(['Code' => 'DEFAULT'])->first(); |
|
| 420 | - $this->CategoryID = $default->ID; |
|
| 421 | - } |
|
| 422 | - |
|
| 423 | - //update many_many lists when multi-group is on |
|
| 424 | - if (FoxyStripeSetting::current_foxystripe_setting()->MultiGroup) { |
|
| 425 | - $holders = $this->ProductHolders(); |
|
| 426 | - $product = self::get()->byID($this->ID); |
|
| 427 | - if (isset($product->ParentID)) { |
|
| 428 | - $origParent = $product->ParentID; |
|
| 429 | - } else { |
|
| 430 | - $origParent = null; |
|
| 431 | - } |
|
| 432 | - $currentParent = $this->ParentID; |
|
| 433 | - if ($origParent != $currentParent) { |
|
| 434 | - if ($holders->find('ID', $origParent)) { |
|
| 435 | - $holders->removeByID($origParent); |
|
| 436 | - } |
|
| 437 | - } |
|
| 438 | - $holders->add($currentParent); |
|
| 439 | - } |
|
| 440 | - |
|
| 441 | - $this->Title = trim($this->Title); |
|
| 442 | - $this->Code = trim($this->Code); |
|
| 443 | - $this->ReceiptTitle = trim($this->ReceiptTitle); |
|
| 444 | - } |
|
| 445 | - |
|
| 446 | - public function onAfterWrite() |
|
| 447 | - { |
|
| 448 | - parent::onAfterWrite(); |
|
| 449 | - } |
|
| 450 | - |
|
| 451 | - public function onBeforeDelete() |
|
| 452 | - { |
|
| 453 | - if ($this->Status != 'Published') { |
|
| 454 | - if ($this->ProductOptions()) { |
|
| 455 | - $options = $this->getComponents('ProductOptions'); |
|
| 456 | - foreach ($options as $option) { |
|
| 457 | - $option->delete(); |
|
| 458 | - } |
|
| 459 | - } |
|
| 460 | - } |
|
| 461 | - parent::onBeforeDelete(); |
|
| 462 | - } |
|
| 463 | - |
|
| 464 | - /** |
|
| 465 | - * @param null $productCode |
|
| 466 | - * @param null $optionName |
|
| 467 | - * @param null $optionValue |
|
| 468 | - * @param string $method |
|
| 469 | - * @param bool $output |
|
| 470 | - * @param bool $urlEncode |
|
| 471 | - * |
|
| 472 | - * @return null|string |
|
| 473 | - */ |
|
| 474 | - public static function getGeneratedValue( |
|
| 475 | - $productCode = null, |
|
| 476 | - $optionName = null, |
|
| 477 | - $optionValue = null, |
|
| 478 | - $method = 'name', |
|
| 479 | - $output = false, |
|
| 480 | - $urlEncode = false |
|
| 481 | - ) { |
|
| 482 | - $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName; |
|
| 483 | - |
|
| 484 | - return (FoxyStripeSetting::current_foxystripe_setting()->CartValidation) |
|
| 485 | - ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) : |
|
| 486 | - $optionValue; |
|
| 487 | - } |
|
| 488 | - |
|
| 489 | - /** |
|
| 490 | - * @param Member $member |
|
| 491 | - * |
|
| 492 | - * @return bool |
|
| 493 | - */ |
|
| 494 | - public function canEdit($member = null) |
|
| 495 | - { |
|
| 496 | - return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 497 | - } |
|
| 498 | - |
|
| 499 | - public function canDelete($member = null) |
|
| 500 | - { |
|
| 501 | - return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 502 | - } |
|
| 503 | - |
|
| 504 | - public function canCreate($member = null, $context = []) |
|
| 505 | - { |
|
| 506 | - return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 507 | - } |
|
| 508 | - |
|
| 509 | - public function canPublish($member = null) |
|
| 510 | - { |
|
| 511 | - return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 512 | - } |
|
| 513 | - |
|
| 514 | - public function providePermissions() |
|
| 515 | - { |
|
| 516 | - return [ |
|
| 517 | - 'Product_CANCRUD' => 'Allow user to manage Products and related objects', |
|
| 518 | - ]; |
|
| 519 | - } |
|
| 520 | - |
|
| 521 | - /** |
|
| 522 | - * @return bool |
|
| 523 | - */ |
|
| 524 | - public function getIsAvailable() |
|
| 525 | - { |
|
| 526 | - if (!$this->Available) { |
|
| 527 | - return false; |
|
| 528 | - } |
|
| 529 | - |
|
| 530 | - if (!$this->ProductOptions()->exists()) { |
|
| 531 | - return true; |
|
| 532 | - } |
|
| 533 | - |
|
| 534 | - foreach ($this->ProductOptions() as $option) { |
|
| 535 | - if ($option->Available) { |
|
| 536 | - return true; |
|
| 537 | - } |
|
| 538 | - } |
|
| 539 | - |
|
| 540 | - return false; |
|
| 541 | - } |
|
| 373 | + return $result; |
|
| 374 | + } |
|
| 375 | + |
|
| 376 | + /** |
|
| 377 | + * @return \SilverStripe\ORM\ManyManyList |
|
| 378 | + */ |
|
| 379 | + public function getSortedImages() |
|
| 380 | + { |
|
| 381 | + return $this->Images()->Sort('SortOrder'); |
|
| 382 | + } |
|
| 383 | + |
|
| 384 | + /** |
|
| 385 | + * @return \SilverStripe\ORM\ManyManyList |
|
| 386 | + */ |
|
| 387 | + public function SortedImages() |
|
| 388 | + { |
|
| 389 | + return $this->getSortedImages(); |
|
| 390 | + } |
|
| 391 | + |
|
| 392 | + /** |
|
| 393 | + * @return Image|bool |
|
| 394 | + */ |
|
| 395 | + public function getImage() |
|
| 396 | + { |
|
| 397 | + if ($this->getSortedImages()->count() > 0) { |
|
| 398 | + return $this->getSortedImages()->first(); |
|
| 399 | + } |
|
| 400 | + |
|
| 401 | + return false; |
|
| 402 | + } |
|
| 403 | + |
|
| 404 | + /** |
|
| 405 | + * @return Image|bool |
|
| 406 | + */ |
|
| 407 | + public function Image() |
|
| 408 | + { |
|
| 409 | + return $this->getImage(); |
|
| 410 | + } |
|
| 411 | + |
|
| 412 | + /** |
|
| 413 | + * @throws \Exception |
|
| 414 | + */ |
|
| 415 | + public function onBeforeWrite() |
|
| 416 | + { |
|
| 417 | + parent::onBeforeWrite(); |
|
| 418 | + if (!$this->CategoryID) { |
|
| 419 | + $default = ProductCategory::get()->filter(['Code' => 'DEFAULT'])->first(); |
|
| 420 | + $this->CategoryID = $default->ID; |
|
| 421 | + } |
|
| 422 | + |
|
| 423 | + //update many_many lists when multi-group is on |
|
| 424 | + if (FoxyStripeSetting::current_foxystripe_setting()->MultiGroup) { |
|
| 425 | + $holders = $this->ProductHolders(); |
|
| 426 | + $product = self::get()->byID($this->ID); |
|
| 427 | + if (isset($product->ParentID)) { |
|
| 428 | + $origParent = $product->ParentID; |
|
| 429 | + } else { |
|
| 430 | + $origParent = null; |
|
| 431 | + } |
|
| 432 | + $currentParent = $this->ParentID; |
|
| 433 | + if ($origParent != $currentParent) { |
|
| 434 | + if ($holders->find('ID', $origParent)) { |
|
| 435 | + $holders->removeByID($origParent); |
|
| 436 | + } |
|
| 437 | + } |
|
| 438 | + $holders->add($currentParent); |
|
| 439 | + } |
|
| 440 | + |
|
| 441 | + $this->Title = trim($this->Title); |
|
| 442 | + $this->Code = trim($this->Code); |
|
| 443 | + $this->ReceiptTitle = trim($this->ReceiptTitle); |
|
| 444 | + } |
|
| 445 | + |
|
| 446 | + public function onAfterWrite() |
|
| 447 | + { |
|
| 448 | + parent::onAfterWrite(); |
|
| 449 | + } |
|
| 450 | + |
|
| 451 | + public function onBeforeDelete() |
|
| 452 | + { |
|
| 453 | + if ($this->Status != 'Published') { |
|
| 454 | + if ($this->ProductOptions()) { |
|
| 455 | + $options = $this->getComponents('ProductOptions'); |
|
| 456 | + foreach ($options as $option) { |
|
| 457 | + $option->delete(); |
|
| 458 | + } |
|
| 459 | + } |
|
| 460 | + } |
|
| 461 | + parent::onBeforeDelete(); |
|
| 462 | + } |
|
| 463 | + |
|
| 464 | + /** |
|
| 465 | + * @param null $productCode |
|
| 466 | + * @param null $optionName |
|
| 467 | + * @param null $optionValue |
|
| 468 | + * @param string $method |
|
| 469 | + * @param bool $output |
|
| 470 | + * @param bool $urlEncode |
|
| 471 | + * |
|
| 472 | + * @return null|string |
|
| 473 | + */ |
|
| 474 | + public static function getGeneratedValue( |
|
| 475 | + $productCode = null, |
|
| 476 | + $optionName = null, |
|
| 477 | + $optionValue = null, |
|
| 478 | + $method = 'name', |
|
| 479 | + $output = false, |
|
| 480 | + $urlEncode = false |
|
| 481 | + ) { |
|
| 482 | + $optionName = ($optionName !== null) ? preg_replace('/\s/', '_', $optionName) : $optionName; |
|
| 483 | + |
|
| 484 | + return (FoxyStripeSetting::current_foxystripe_setting()->CartValidation) |
|
| 485 | + ? \FoxyCart_Helper::fc_hash_value($productCode, $optionName, $optionValue, $method, $output, $urlEncode) : |
|
| 486 | + $optionValue; |
|
| 487 | + } |
|
| 488 | + |
|
| 489 | + /** |
|
| 490 | + * @param Member $member |
|
| 491 | + * |
|
| 492 | + * @return bool |
|
| 493 | + */ |
|
| 494 | + public function canEdit($member = null) |
|
| 495 | + { |
|
| 496 | + return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 497 | + } |
|
| 498 | + |
|
| 499 | + public function canDelete($member = null) |
|
| 500 | + { |
|
| 501 | + return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 502 | + } |
|
| 503 | + |
|
| 504 | + public function canCreate($member = null, $context = []) |
|
| 505 | + { |
|
| 506 | + return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 507 | + } |
|
| 508 | + |
|
| 509 | + public function canPublish($member = null) |
|
| 510 | + { |
|
| 511 | + return Permission::check('Product_CANCRUD', 'any', $member); |
|
| 512 | + } |
|
| 513 | + |
|
| 514 | + public function providePermissions() |
|
| 515 | + { |
|
| 516 | + return [ |
|
| 517 | + 'Product_CANCRUD' => 'Allow user to manage Products and related objects', |
|
| 518 | + ]; |
|
| 519 | + } |
|
| 520 | + |
|
| 521 | + /** |
|
| 522 | + * @return bool |
|
| 523 | + */ |
|
| 524 | + public function getIsAvailable() |
|
| 525 | + { |
|
| 526 | + if (!$this->Available) { |
|
| 527 | + return false; |
|
| 528 | + } |
|
| 529 | + |
|
| 530 | + if (!$this->ProductOptions()->exists()) { |
|
| 531 | + return true; |
|
| 532 | + } |
|
| 533 | + |
|
| 534 | + foreach ($this->ProductOptions() as $option) { |
|
| 535 | + if ($option->Available) { |
|
| 536 | + return true; |
|
| 537 | + } |
|
| 538 | + } |
|
| 539 | + |
|
| 540 | + return false; |
|
| 541 | + } |
|
| 542 | 542 | } |