├── .gitignore ├── .htaccess ├── README.md ├── classes ├── class.exchange_1c.catalog_import.php └── class.exchange_1c.manager.php ├── index.php ├── module ├── module.1c_exchange.php ├── module.1c_exchange.tpl.php └── tpl │ ├── config.tpl.php │ ├── footer.tpl.php │ ├── header.tpl.php │ ├── page_attributes.tpl.php │ └── page_options.tpl.php ├── plugin └── index.html ├── temp └── index.html └── tool ├── attributes.php ├── category.php └── product.php /.gitignore: -------------------------------------------------------------------------------- 1 | Описание 2 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | AuthType Basic 2 | AuthName "Please input login and password!" 3 | require valid-user 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 1c_exchange 2 | =========== 3 | 4 | синхронизация товаров 1С и MODx используя стандартную обработку Обмен с WEB-сайтом встроенную в 1С Торговля и склад 10.3 5 | 6 |
Содержимое копируется в паку manager/1c_exchange
9 |Устанавливается модуль 1c_exchange с кодом
10 |
11 | include_once(MODX_BASE_PATH.'manager/1c_exchange/module/module.1c_exchange.php');
12 |
13 | После установки появится окно с настройками модуля.
14 | -------------------------------------------------------------------------------- /classes/class.exchange_1c.catalog_import.php: -------------------------------------------------------------------------------- 1 | modx = $modx; 9 | $this->config = $config; 10 | } 11 | /** 12 | * modeCheckauth 13 | * @ 14 | */ 15 | function modeCheckauth() { 16 | // Проверяем включен или нет модуль 17 | if (!$this->config['status']) { 18 | echo "failure\n"; 19 | echo "1c module OFF"; 20 | exit; 21 | } 22 | // Разрешен ли IP 23 | if ($this->config['allow_ip'] != '') { 24 | $ip = $_SERVER['REMOTE_ADDR']; 25 | $allow_ips = explode("\r\n", $this->config['allow_ip']); 26 | if (!in_array($ip, $allow_ips)) { 27 | echo "failure\n"; 28 | echo "IP is not allowed"; 29 | exit; 30 | } 31 | } 32 | echo "success\n"; 33 | echo session_name() ."\n"; 34 | echo session_id() ."\n"; 35 | } 36 | /* 37 | * modeInit 38 | * @ 39 | */ 40 | function modeInit() { 41 | $tmp_files = glob($this->config['dir_temp'] .'*.*'); 42 | if (is_array($tmp_files)) { 43 | foreach ($tmp_files as $v) { 44 | unlink($v); 45 | } 46 | } 47 | $limit = 100000 * 1024; 48 | echo "zip=no\n"; 49 | echo "file_limit=". $limit ."\n"; 50 | } 51 | /* 52 | * modeFile 53 | * @ 54 | */ 55 | function modeFile() { 56 | $filename = basename($_REQUEST['filename']); 57 | $DATA = file_get_contents("php://input"); 58 | if ($DATA !== false) { 59 | if ($fp = fopen($this->config['dir_temp'] . $filename, "wb")) { 60 | $result = fwrite($fp, $DATA); 61 | if ($result === strlen($DATA)) { 62 | echo "success\n"; 63 | chmod($this->config['dir_temp'], 0777); 64 | } else { 65 | echo "failure\n"; 66 | } 67 | } else { 68 | echo "failure\n"; 69 | echo "Can not open file: " . $this->config['dir_temp'] . $filename . "\n"; 70 | } 71 | } else { 72 | echo "failure\n"; 73 | echo "No data file\n"; 74 | } 75 | } 76 | /** 77 | * modeImport 78 | * @ 79 | */ 80 | function modeImport() { 81 | $filename = basename($_REQUEST['filename']); 82 | if (isset($filename) && $this->config['status']) { 83 | $importFile = $this->config['dir_temp'] . $filename; 84 | } else { 85 | echo "failure\n"; 86 | echo "ERROR 10: No file name variable"; 87 | return 0; 88 | } 89 | if ($filename == 'import.xml') { 90 | $this->parseImport($importFile); 91 | echo "success\n"; 92 | } elseif ($filename == 'offers.xml') { 93 | $this->parseOffers($importFile); 94 | echo "success\n"; 95 | } else { 96 | echo "failure\n"; 97 | echo $filename; 98 | } 99 | $this->clearVars(); 100 | return; 101 | } 102 | /** 103 | * Удаляем все неиспользуемые параметры товаров снятых с производства 104 | * @ 105 | */ 106 | function clearVars(){ 107 | // Удалим все TV параметры не спользуемые в шаблоне для товаров снятых с производства 108 | if($this->config['clear_tvs'] && $this->config['product_prodution_tpl_id'] && $this->config['prodution_catalog_id']) { 109 | $tv_p_res = $this->query("SELECT tmplvarid FROM " . $this->modx->getFullTableName('site_tmplvar_templates') . " WHERE templateid = " . $this->config['product_tpl_id']); 110 | while($tv = mysql_fetch_array($tv_p_res)) { 111 | $tv_product[] = $tv[0]; 112 | } 113 | $tv_p_p_res = $this->query("SELECT tmplvarid FROM " . $this->modx->getFullTableName('site_tmplvar_templates') . " WHERE templateid = " . $this->config['product_prodution_tpl_id']); 114 | while($tv = mysql_fetch_array($tv_p_p_res)) { 115 | $tv_product_prodution[] = $tv[0]; 116 | } 117 | $this->query("DELETE FROM " . $this->config['tbl_catalog_tv'] . " 118 | WHERE contentid IN (" . implode(',',$this->modx->getChildIds($this->config['prodution_catalog_id'])) . ") 119 | AND tmplvarid IN (" . implode(",", array_diff($tv_product,$tv_product_prodution)) . ")"); 120 | } 121 | // Полная очистка кэша 122 | $this->modx->clearCache(); 123 | include_once MODX_BASE_PATH . 'manager/processors/cache_sync.class.processor.php'; 124 | $sync = new synccache(); 125 | $sync->setCachepath(MODX_BASE_PATH . "assets/cache/"); 126 | $sync->setReport(false); 127 | $sync->emptyCache(); 128 | } 129 | /** 130 | * Парсит товары и категории 131 | * @ 132 | */ 133 | function parseImport($importFile) { 134 | $xml = simplexml_load_file($importFile); 135 | $data = array(); 136 | // Группы 137 | if ($xml->Классификатор->Группы) { 138 | $this->model('tool/category'); 139 | $this->tool_category->getCategory($xml->Классификатор->Группы->Группа, $this->config['catalog_id']); 140 | $this->tool_category->cleanCategories(); 141 | } 142 | // Свойства 143 | /* if ($xml->Классификатор->Свойства) { 144 | $this->model('tool/attributes'); 145 | $this->tool_attributes->insertAttribute($xml->Классификатор->Свойства->Свойство); 146 | }*/ 147 | // Товары 148 | if ($xml->Каталог->Товары->Товар) { 149 | foreach ($xml->Каталог->Товары->Товар as $product) { 150 | $uuid = explode('#', (string) $product->Ид); 151 | $data['1c_id'] = $uuid[0]; 152 | $data['model'] = $product->Артикул ? (string) $product->Артикул : ''; 153 | $data['sku'] = $data['model']; 154 | $data['name'] = $product->Наименование ? (string) trim($product->Наименование) : ''; 155 | if ($product->Группы) { 156 | $data['category_1c_id'] = (string) $product->Группы->Ид; 157 | } 158 | if ($product->Описание) { 159 | $data['description'] = (string) $product->Описание; 160 | } 161 | if ($product->Статус) { 162 | $data['status'] = (string) $product->Статус; 163 | } 164 | // Свойства продукта 165 | /* if ($product->ЗначенияСвойств) { 166 | foreach ($product->ЗначенияСвойств->ЗначенияСвойства as $property) { 167 | if (isset(static::$PROPERTIES[(string) $property->Ид]['name'])) { 168 | $attribute = static::$PROPERTIES[(string) $property->Ид]; 169 | if (isset($attribute['values'][(string) $property->Значение])) { 170 | $attribute_value = str_replace("'", "'", (string) $attribute['values'][(string) $property->Значение]); 171 | } else if ((string) $property->Значение != '') { 172 | $attribute_value = str_replace("'", "'", (string) $property->Значение); 173 | } else { 174 | continue; 175 | } 176 | switch ($attribute['name']) { 177 | case 'Производитель': 178 | $manufacturer_name = $attribute_value; 179 | $manufacturer_id = $this->getValue("SELECT id FROM " . $this->config['tbl_catalog'] . " WHERE pagetitle = '" . $manufacturer_name . "'"); 180 | if (!$manufacturer_id) { 181 | $data_manufacturer = array( 182 | 'type' => 'document', 183 | 'parent' => $this->config['brands_catalog_id'], 184 | 'pagetitle' => $manufacturer_name, 185 | 'longtitle' => $manufacturer_name, 186 | 'alias' => $this->translit($manufacturer_name), 187 | 'template' => $this->config['brand_tpl_id'], 188 | 'hidemenu' => 1, 189 | 'published' => 1, 190 | 'deleted' => 0, 191 | 'createdon' => $this->config['currentdate'], 192 | 'editedon' => $this->config['currentdate'] 193 | ); 194 | $manufacturer_id = $this->insert($data_manufacturer, $this->config['tbl_catalog']); 195 | } 196 | $data['manufacturer_name'] = $manufacturer_name; 197 | $data['manufacturer_id'] = $manufacturer_id; 198 | break; 199 | default: 200 | $attribute_value = explode(", ", $attribute_value); 201 | $data['product_attribute'][] = array( 202 | 'attribute_id' => $attribute['id'], 203 | 'product_attribute_description' => $attribute_value 204 | ); 205 | } 206 | } 207 | } 208 | }*/ 209 | // Реквизиты продукта 210 | if ($product->ЗначенияРеквизитов) { 211 | foreach ($product->ЗначенияРеквизитов->ЗначениеРеквизита as $requisite) { 212 | switch ($requisite->Наименование) { 213 | case 'ОписаниеВФорматеHTML': 214 | $data['description'] = $requisite->Значение ? (string) $requisite->Значение : ''; 215 | break; 216 | case 'Код': 217 | $data['uid'] = (string) $requisite->Значение; 218 | break; 219 | case 'Полное наименование': 220 | $data['fullname'] = $requisite->Значение ? (string) trim(str_replace($product->Наименование, '' , $requisite->Значение)) : ''; 221 | break; 222 | } 223 | } 224 | } 225 | $this->setProduct($data); 226 | unset($data); 227 | } 228 | } 229 | if ($this->config['delete_products']) { 230 | if ($this->config['moved_deleted_product_to_trash']) 231 | $parent_trash = ", parent = '" . $this->config['trash_catalog_id'] . "'"; 232 | $this->query("UPDATE " . $this->config['tbl_catalog'] . " SET deleted = '1' " . $parent_trash . " WHERE parent IN (" . implode(",", $this->UPDATE_CATEGORIES) . ") AND editedon != " . $this->config['currentdate'] . ""); 233 | } 234 | unset($xml, $this->UPDATE_CATEGORIES); 235 | } 236 | /** 237 | * Функция работы с продуктом 238 | * 239 | * @param array 240 | */ 241 | private function setProduct($product) { 242 | if (!$product) 243 | return; 244 | //Проверяем есть ли такой товар в БД 245 | $product_id = ''; 246 | // по коду 247 | if (!$product_id && $this->config['uid']) { 248 | $product_id = $this->getValue('SELECT id FROM ' . $this->config['tbl_catalog'] . ' 249 | WHERE ' . $this->config['uid'] . ' = "' . (string) $product['uid'] . '" OR '.$this->config['xml_id'].' = "'.(string) $product['1c_id'].'" AND isfolder = 0'); 250 | } 251 | // по имени 252 | if (!$product_id) { 253 | $title = $this->escape(trim((string) $product['name'])); 254 | $title_trim = str_replace(' ', '', $title); 255 | $product_id = $this->getValue('SELECT id FROM ' . $this->config['tbl_catalog'] . ' WHERE 256 | `pagetitle` = "' . $title . '" OR 257 | `alias` = "' . $this->translit($title) . '" OR 258 | `pagetitle` = "' . $title_trim . '" OR 259 | `alias` = "' . $this->translit($title_trim) . '"'); 260 | } 261 | $data = $this->initProduct($product); 262 | $this->model('tool/product'); 263 | if ($product_id) { 264 | if ($this->config['update_products']) { 265 | $this->tool_product->editProduct($product_id, $data); 266 | } 267 | 268 | } else { 269 | if ($this->config['add_products']) { 270 | $product_id = $this->tool_product->addProduct($data); 271 | } 272 | } 273 | } 274 | /** 275 | * Обновляет массив с информацией о продукте 276 | * 277 | * @param array новые данные 278 | * @param array обновляемые данные 279 | * @return array 280 | */ 281 | private function initProduct($product, $data = array()) { 282 | $result = array( 283 | $this->config['xml_id'] => $product['1c_id'], 284 | 'model' => (isset($product['model'])) ? $product['model'] : (isset($data['model']) ? $data['model'] : ''), 285 | 'sku' => (isset($product['sku'])) ? $product['sku'] : (isset($data['sku']) ? $data['sku'] : ''), 286 | 'uid' => (isset($product['uid'])) ? $product['uid'] : (isset($data['uid']) ? $data['uid'] : ''), 287 | 'manufacturer_id' => (isset($product['manufacturer_id'])) ? $product['manufacturer_id'] : (isset($data['manufacturer_id']) ? $data['manufacturer_id'] : 0), 288 | 'manufacturer_name' => (isset($product['manufacturer_name'])) ? $product['manufacturer_name'] : (isset($data['manufacturer_name']) ? $data['manufacturer_name'] : ''), 289 | 'createdon' => $this->config['currentdate'], 290 | 'product_attribute' => (isset($product['product_attribute'])) ? $product['product_attribute'] : (isset($data['product_attribute']) ? $data['product_attribute'] : array()) 291 | ); 292 | $result['product_description'] = array( 293 | 'name' => isset($product['name']) ? $product['name'] : (isset($data['product_description']['name']) ? $data['product_description']['name'] : ''), 294 | 'fullname' => isset($product['fullname']) ? $product['fullname'] : (isset($data['product_description']['fullname']) ? $data['product_description']['fullname'] : ''), 295 | 'description' => isset($product['description']) ? "" . htmlentities(strip_tags(preg_replace('|\s+|', ' ', $product['description'])), ENT_QUOTES, "UTF-8") . "
" : (isset($data['product_description']['description']) ? $data['product_description']['description'] : '') 296 | ); 297 | if (isset($product['category_1c_id']) && isset(static::$CATEGORIES[$product['category_1c_id']])) { 298 | $result['product_category'] = (int) static::$CATEGORIES[$product['category_1c_id']]; 299 | } else { 300 | $result['product_category'] = $data['product_category'] ? $data['product_category'] : 0; 301 | } 302 | if ($product['category_1c_id'] && static::$CATEGORIES_PRODUTION[$product['category_1c_id']] && $this->config['product_prodution_tpl_id']) { 303 | $result['template'] = $this->config['product_prodution_tpl_id']; 304 | } else { 305 | $result['template'] = $this->config['product_tpl_id']; 306 | } 307 | $this->UPDATE_CATEGORIES[$result['product_category']] = $result['product_category']; 308 | return $result; 309 | } 310 | /** 311 | * Парсит цены и количество 312 | * 313 | * @param string наименование типа цены 314 | */ 315 | public function parseOffers($importFile) { 316 | $xml = simplexml_load_file($importFile); 317 | $data = array(); 318 | $price_types = array(); 319 | if ($xml->ПакетПредложений->ТипыЦен->ТипЦены) { 320 | foreach ($xml->ПакетПредложений->ТипыЦен->ТипЦены as $type) { 321 | $price_types[(string) $type->Ид] = (string) $type->Наименование; 322 | } 323 | } 324 | if ($xml->ПакетПредложений->Предложения->Предложение) { 325 | foreach ($xml->ПакетПредложений->Предложения->Предложение as $offer) { 326 | //UUID без номера после # 327 | $uuid = explode("#", $offer->Ид); 328 | $data['1c_id'] = $uuid[0]; 329 | $data['product_id'] = $this->getValue('SELECT id FROM ' . $this->config['tbl_catalog'] . ' WHERE '.$this->config['xml_id'].'="'.$this->escape($data['1c_id']).'" AND isfolder = 0'); 330 | //Цена за единицу 331 | if ($offer->Цены) { 332 | // найдём валюту закупочной цены 333 | if (!empty($this->config['price_currency']) && $offer->Цены->Цена->ИдТипаЦены) { 334 | foreach ($offer->Цены->Цена as $price) { 335 | if ($price_types[(string) $price->ИдТипаЦены] == $this->config['price_currency']) { 336 | $data['currency'] = (string) $price->Валюта; 337 | } 338 | } 339 | } 340 | // Первая цена по умолчанию - $config_price_type_main 341 | if (!$this->config['price_type']) { 342 | $data['price'] = (float) $offer->Цены->Цена->ЦенаЗаЕдиницу; 343 | } else { 344 | if ($offer->Цены->Цена->ИдТипаЦены) { 345 | foreach ($offer->Цены->Цена as $price) { 346 | if ($price_types[(string) $price->ИдТипаЦены] == $this->config['price_type']) { 347 | $data['price'] = (float) sprintf("%0.2f", ($price->ЦенаЗаЕдиницу / $this->config[$data['currency']])); 348 | } 349 | } 350 | } 351 | } 352 | // Вторая цена и тд - $discount_price_type 353 | if (!empty($this->config['price_additional_type']) && $offer->Цены->Цена->ИдТипаЦены && $this->config['price_additional']) { 354 | foreach ($offer->Цены->Цена as $price) { 355 | $key = $price_types[(string) $price->ИдТипаЦены]; 356 | if (isset($this->config['price_additional_type'][$key])) { 357 | $value = array( 358 | 'id' => (string) $price->ИдТипаЦены, 359 | 'type' => $key, 360 | 'position' => $this->config['price_additional_type'][$key]['position'], 361 | 'price' => (float) sprintf("%0.0f", ($price->ЦенаЗаЕдиницу / $this->config[$data['currency']])) 362 | ); 363 | $data['price_additional'][] = $value; 364 | unset($value); 365 | } 366 | } 367 | } 368 | //Количество 369 | $data['quantity'] = isset($offer->Количество) ? (int) $offer->Количество : 0; 370 | //Характеристики 371 | /*if ($offer->ХарактеристикиТовара && $this->config['add_options']) { 372 | $product_option_value_data = array(); 373 | $product_option_data = array(); 374 | $count = count($offer->ХарактеристикиТовара->ХарактеристикаТовара); 375 | foreach ($offer->ХарактеристикиТовара->ХарактеристикаТовара as $i => $opt) { 376 | $name_1c = $this->escape((string) $opt->Наименование); 377 | $value_1c = $this->escape((string) $opt->Значение); 378 | if (!empty($name_1c) && !empty($value_1c)) { 379 | $product_option_value_data[] = array( 380 | 'product_option_value_id' => $uuid[0], 381 | 'option_value_id' => $uuid[1], 382 | 'quantity' => isset($data['quantity']) ? (int) $data['quantity'] : 0, 383 | 'price' => isset($data['price']) ? (int) $data['price'] : 0, 384 | 'value' => $value_1c 385 | ); 386 | $product_option_data = array( 387 | 'option_id' => $uuid[1], 388 | 'product_option_id' => $uuid[0], 389 | 'name' => (string) $name_1c, 390 | 'type' => 'select', 391 | 'required' => 1, 392 | 'product_option_value' => $product_option_value_data 393 | ); 394 | } 395 | } 396 | $this->setOption($product_option_data); 397 | }*/ 398 | } 399 | if ($this->config['update_prices']) { 400 | $this->setPrice($data); 401 | } 402 | unset($data); 403 | } 404 | } 405 | } 406 | /** 407 | * Установка характеристик 408 | * 409 | */ 410 | /* private function setOption($data) { 411 | $option_id = $this->getValue("SELECT id FROM " . $this->config['tbl_opt'] . " WHERE option_id = '" . $data['option_id'] . "'"); 412 | $product_option_value = $data['product_option_value']; 413 | unset($data['product_option_value']); 414 | if ($option_id) { 415 | $this->update($data, $this->config['tbl_opt'], "id = " . $option_id); 416 | $this->setOptionValue($option_id, $product_option_value); 417 | } else { 418 | $option_id = $this->insert($data, $this->config['tbl_opt']); 419 | $this->setOptionValue($option_id, $product_option_value); 420 | } 421 | }*/ 422 | /** 423 | * Установка значения характеристики 424 | * 425 | */ 426 | /* private function setOptionValue($option_id, $values) { 427 | foreach ($values as $val) { 428 | $value_id = $this->getValue("SELECT id FROM " . $this->config['tbl_opt_val'] . " WHERE value = '" . $val['value'] . "' AND option_value_id = '" . $val['option_value_id'] . "'"); 429 | if ($value_id) { 430 | $this->update($val, $this->config['tbl_opt_val'], "id = " . $value_id); 431 | } else { 432 | $this->insert($val, $this->config['tbl_opt_val']); 433 | } 434 | } 435 | }*/ 436 | /** 437 | * Установка цены 438 | * 439 | */ 440 | private function setPrice($data) { 441 | if ($data['1c_id']) { 442 | $price_id = $this->getValue('SELECT id FROM ' . $this->config['tbl_catalog_tv'] . ' WHERE tmplvarid = "' . $this->config['price_id'] . '" AND contentid = "' . $data['product_id'] . '"'); 443 | $currency_id = $this->getValue('SELECT id FROM ' . $this->config['tbl_catalog_tv'] . ' WHERE tmplvarid = "' . $this->config['currency_id'] . '" AND contentid = "' . $data['product_id'] . '"'); 444 | if ($price_id) { 445 | $this->update(array( 446 | 'value' => $data['price'] 447 | ), $this->config['tbl_catalog_tv'], "id = " . $price_id); 448 | } else { 449 | $this->insert(array( 450 | 'tmplvarid' => $this->config['price_id'], 451 | 'contentid' => $data['product_id'], 452 | 'value' => $data['price'] 453 | ), $this->config['tbl_catalog_tv']); 454 | } 455 | if ($currency_id && $data['currency'] != 'руб') { 456 | $this->update(array( 457 | 'value' => $data['currency'] 458 | ), $this->config['tbl_catalog_tv'], "id = " . $currency_id); 459 | } elseif (!$currency_id && $data['currency'] != 'руб') { 460 | $this->insert(array( 461 | 'tmplvarid' => $this->config['currency_id'], 462 | 'contentid' => $data['product_id'], 463 | 'value' => $data['currency'] 464 | ), $this->config['tbl_catalog_tv']); 465 | } elseif ($currency_id && $data['currency'] == 'руб') { 466 | $this->query("DELETE FROM " . $this->config['tbl_catalog_tv'] . " WHERE id = " . $currency_id); 467 | } 468 | } 469 | } 470 | protected function query($SQL) { 471 | return $this->modx->db->query($SQL); 472 | } 473 | protected function update($array, $table, $where = '') { 474 | return $this->modx->db->update($array, $table, $where); 475 | } 476 | protected function insert($array, $table) { 477 | $this->modx->db->insert($array, $table); 478 | return $this->modx->db->getInsertId(); 479 | } 480 | protected function getValue($SQL) { 481 | return $this->modx->db->getValue($this->modx->db->query($SQL)); 482 | } 483 | protected function escape($escape) { 484 | return $this->modx->db->escape($escape); 485 | } 486 | /** 487 | * Подгружаем классы по шаблону 488 | * @ $this->model('tool/product'); 489 | * @ $this->tool_product-> ..... 490 | */ 491 | function model($model) { 492 | $file = MODX_BASE_PATH . MGR_DIR . '/1c_exchange/' . $model . '.php'; 493 | $class = 'Modx' . preg_replace('/[^a-zA-Z0-9]/', '', $model); 494 | if (file_exists($file)) { 495 | include_once($file); 496 | $obj = str_replace('/', '_', $model); 497 | $this->$obj = new $class($this->modx, $this->config); 498 | } else { 499 | trigger_error('Error: Could not load model ' . $file . '!'); 500 | exit(); 501 | } 502 | } 503 | function SaveLog($data) { 504 | $tbl_manager_log = $this->modx->getFullTableName('manager_log'); 505 | $fields['timestamp'] = time(); 506 | $fields['internalKey'] = $this->modx->db->escape($data['internalKey']); 507 | $fields['username'] = $this->modx->db->escape($data['username']); 508 | $fields['action'] = $data['action']; 509 | $fields['itemid'] = $data['itemId']; 510 | $fields['itemname'] = $this->modx->db->escape($data['itemName']); 511 | $fields['message'] = $this->modx->db->escape($data['msg']); 512 | $this->insert($fields,$tbl_manager_log); 513 | } 514 | /** 515 | * транслит из русского 516 | * 517 | */ 518 | function translit($text) { 519 | $ru = explode('-', "А-а-Б-б-В-в-Ґ-ґ-Г-г-Д-д-Е-е-Ё-ё-Є-є-Ж-ж-З-з-И-и-І-і-Ї-ї-Й-й-К-к-Л-л-М-м-Н-н-О-о-П-п-Р-р-С-с-Т-т-У-у-Ф-ф-Х-х-Ц-ц-Ч-ч-Ш-ш-Щ-щ-Ъ-ъ-Ы-ы-Ь-ь-Э-э-Ю-ю-Я-я"); 520 | $en = explode('-', "A-a-B-b-V-v-G-g-G-g-D-d-E-e-YO-yo-E-e-ZH-zh-Z-z-I-i-I-i-I-i-Y-y-K-k-L-l-M-m-N-n-O-o-P-p-R-r-S-s-T-t-U-u-F-f-H-h-TS-ts-CH-ch-SH-sh-SCH-sch---Y-y---E-e-YU-yu-YA-ya"); 521 | $text = str_replace($ru, $en, $text); 522 | $text = preg_replace("/[\s]+/ui", '-', $text); 523 | $text = strtolower(preg_replace("/[^0-9a-zа-я\-]+/ui", '', $text)); 524 | $id = $this->getValue("SELECT id FROM " . $this->config['tbl_catalog'] . " WHERE alias='" . $text . "' LIMIT 1"); 525 | if ($id) { 526 | $text = $text . "-" . $id; 527 | } 528 | return $text; 529 | } 530 | } 531 | ?> 532 | -------------------------------------------------------------------------------- /classes/class.exchange_1c.manager.php: -------------------------------------------------------------------------------- 1 | modx = $modx; 5 | $this->dbname = $modx->db->config['dbase']; 6 | $this->mod_tbl_config = $modx->db->config['table_prefix'] . "exchange1c_manager_config"; // таблица конфигурации модуля 7 | $this->mod_tbl_catalog = $modx->getFullTableName('site_content'); // таблица с документами/ресурсами 8 | $this->mod_tbl_catalog_tv = $modx->getFullTableName('site_tmplvar_contentvalues'); // таблица с ТВ параметрами 9 | $this->mod_tbl_attr_group = $modx->getFullTableName('exchange1c_product_attributes_group'); // таблица с категориями свойств 10 | $this->mod_tbl_attr = $modx->getFullTableName('exchange1c_product_attributes'); // таблица свойств 11 | $this->mod_tbl_opt = $modx->getFullTableName('exchange1c_product_options'); // таблица с характеристиками 12 | $this->mod_tbl_opt_val = $modx->getFullTableName('exchange1c_product_options_values'); // таблица со значениями характеристик 13 | $this->mod_dir_temp = MODX_BASE_PATH . MGR_DIR . '/1c_exchange/temp/'; // Временная папка для обмена выгрузкой/загрузкой 14 | $this->mod_price_additional = ''; // true | false - Включить дополнительные цены товара 15 | $this->mod_price_additional_type = serialize(array('Мелкий опт' => array('position' => 1),'Крупный опт' => array('position' => 2))); // Дополнительные цены товара 16 | $this->xml_id = 'xml_id'; // название колонки в таблице $this->mod_tbl_catalog с уникальным идентификатором 1С 17 | } 18 | 19 | 20 | function modInstall() { 21 | $sql = array(); 22 | // добавим колонку в таблицу $this->mod_tbl_catalog для уникального идентификатора 1С 23 | $sql[] = "ALTER TABLE $this->mod_tbl_catalog ADD COLUMN $this->xml_id varchar (255)"; 24 | 25 | // создаём таблицы для свойств номенклатуры 26 | $sql[] = "CREATE TABLE IF NOT EXISTS $this->mod_tbl_attr_group (`id` int(11) NOT NULL auto_increment,`name` varchar(255) NOT NULL, `attr_values` TEXT, `visible` INT(1), `attr_index` INT(11), `attr_group_id` varchar(255) NOT NULL, PRIMARY KEY (`id`));"; 27 | $sql[] = "CREATE TABLE IF NOT EXISTS $this->mod_tbl_attr (`id` int(20) NOT NULL auto_increment,`product_id` varchar(255) NOT NULL, `attribute_id` varchar(255) NOT NULL, `text` TEXT, PRIMARY KEY (`id`));"; 28 | 29 | // создаём таблицы для характеристик номенклатуры 30 | $sql[] = "CREATE TABLE IF NOT EXISTS $this->mod_tbl_opt (`id` int(20) NOT NULL auto_increment,`option_id` varchar(255) NOT NULL, `product_option_id` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `type` varchar(255) NOT NULL, `required` INT(1), `position` INT(11) NOT NULL, PRIMARY KEY (`id`));"; 31 | $sql[] = "CREATE TABLE IF NOT EXISTS $this->mod_tbl_opt_val (`id` int(20) NOT NULL auto_increment,`product_option_value_id` varchar(255) NOT NULL,`option_value_id` varchar(255) NOT NULL, `quantity` varchar(255) NOT NULL, `price` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, `position` INT(11) NOT NULL, PRIMARY KEY (`id`));"; 32 | 33 | // создаём таблицу с конфигурацией модуля 34 | $sql[] = "CREATE TABLE IF NOT EXISTS `$this->mod_tbl_config` (`id` INT(11) NOT NULL AUTO_INCREMENT, `setting` VARCHAR(255), `value` TEXT, PRIMARY KEY (`id`));"; 35 | 36 | // заполняем конфигурацию модуля 37 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_version', '$this->mod_cur_version');"; // версия модуля 38 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_user', 'user');"; // пользователь 39 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_pass', 'pass');"; // пароль 40 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_status', '1');"; // статус, включить/выключить модуль загрузки 41 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_allow_ip', '');"; // разрешённые IP 42 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_price_id', '4');"; // id тв-параметра цены 43 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_currency_id', '3');"; // id тв-параметра валюты 44 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_catalog_id', '3');"; // id каталога товаров 45 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_brands_catalog_id', '');"; // id раздела производители 46 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_brand_tpl_id', '');"; // id шаблона производителя 47 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_brand_tv_id', '');"; // id тв-параметра производителя 48 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_category_podcat_tpl_id', '7');"; // id шаблона подкатегории товаров 49 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_category_tpl_id', '7');"; // id шаблона, непосредственно самой категории с товарами 50 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_product_tpl_id', '8');"; // id шаблона товара 51 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_trash_catalog_id', '179');"; // id раздела корзины, в которую переносятся товары при удалении 52 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_prodution_catalog_id', '');"; // id раздела товаров снятых с производства 53 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_product_prodution_tpl_id', '');"; // id шаблона для товаров снятых с производства 54 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_add_products', '1');"; // добавлять товары 55 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_update_products', '1');"; // обновлять товары 56 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_update_description_product', '');"; // обновлять описания товаров 57 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_delete_products', '');"; // удалять товары 58 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_moved_deleted_product_to_trash', '');"; // переносить удалённые товары в корзину 59 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_add_categories', '1');"; // добавлять категории товаров 60 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_update_categories', '1');"; // обновлять категории товаров 61 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_delete_categories', '1');"; // удалять категории товаров 62 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_moved_deleted_category_to_trash', '');"; // переносить удалённые категории товаров в корзину 63 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_update_prices', '1');"; // обновлять цены 64 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_add_options', '');"; // добавлять характеристики 65 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_clear_tvs', '');"; // удалять неиспользуемые тв-параметры товаро снятых с производства 66 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_xml_id', '$this->xml_id');"; // название колонки в таблице $this->mod_tbl_catalog с уникальным идентификатором 1С 67 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_uid', 'description');"; // поле в таблице $this->mod_tbl_catalog по которому будут синхронизироваться товары, в 1С это Код товара 68 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_price_type', 'Розничная');"; // название розничной цены 69 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_price_currency', 'Закупочная');"; // название закупочной цены, используется только для получения валюты товара 70 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_price_additional', '$this->mod_price_additional');"; // включить дополнительные цены товара 71 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_price_additional_type', '$this->mod_price_additional_type');"; // сериализованный массив с дополнительными ценами товаров 72 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_dir_temp', '$this->mod_dir_temp');"; // папка синхронизации с временными файлами 1С 73 | // добавляем в таблицу конфигурации полные названия таблиц 74 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_catalog', '$this->mod_tbl_catalog');"; // таблица с документами/ресурсами 75 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_catalog_tv', '$this->mod_tbl_catalog_tv');"; // таблица с ТВ параметрами 76 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_attr_group', '$this->mod_tbl_attr_group');"; // таблица с категориями свойств 77 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_attr', '$this->mod_tbl_attr');"; // таблица свойст 78 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_opt', '$this->mod_tbl_opt');"; // таблица с характеристиками 79 | $sql[] = "INSERT INTO `$this->mod_tbl_config` VALUES (NULL, 'conf_tbl_opt_val', '$this->mod_tbl_opt_val');"; // таблица со значениями характеристик 80 | 81 | foreach ($sql as $line) { 82 | $this->modx->db->query($line); 83 | } 84 | 85 | } 86 | 87 | /** 88 | * Получаем полную конфигурацию модуля 89 | * 90 | * @return array 91 | */ 92 | function getModConfig() { 93 | $output = array(); 94 | if (mysql_num_rows(mysql_query("SHOW TABLES FROM $this->dbname LIKE '$this->mod_tbl_config'")) > 0) { 95 | $config_query = $this->modx->db->select("*", $this->mod_tbl_config); 96 | while ($config = mysql_fetch_array($config_query)) { 97 | $output[$config[1]] = $config[2]; 98 | } 99 | } 100 | return $output; 101 | } 102 | 103 | /** 104 | * Сохраняет конфигурацию модуля 105 | * 106 | * @param array $data 107 | */ 108 | function saveConfig($data) { 109 | $config = array( 110 | 'conf_user' => array("value" => $this->modx->db->escape($data['user'])), 111 | 'conf_pass' => array("value" => $this->modx->db->escape($data['pass'])), 112 | 'conf_status' => array("value" => $data['status']), 113 | 'conf_allow_ip' => array("value" => $this->modx->db->escape($data['allow_ip'])), 114 | 'conf_price_id' => array("value" => $this->modx->db->escape($data['price_id'])), 115 | 'conf_currency_id' => array("value" => $this->modx->db->escape($data['currency_id'])), 116 | 'conf_catalog_id' => array("value" => $this->modx->db->escape($data['catalog_id'])), 117 | 'conf_brands_catalog_id' => array("value" => $this->modx->db->escape($data['brands_catalog_id'])), 118 | 'conf_brand_tpl_id' => array("value" => $this->modx->db->escape($data['brand_tpl_id'])), 119 | 'conf_brand_tv_id' => array("value" => $this->modx->db->escape($data['brand_tv_id'])), 120 | 'conf_category_podcat_tpl_id' => array("value" => $this->modx->db->escape($data['category_podcat_tpl_id'])), 121 | 'conf_category_tpl_id' => array("value" => $this->modx->db->escape($data['category_tpl_id'])), 122 | 'conf_product_tpl_id' => array("value" => $this->modx->db->escape($data['product_tpl_id'])), 123 | 'conf_trash_catalog_id' => array("value" => $this->modx->db->escape($data['trash_catalog_id'])), 124 | 'conf_prodution_catalog_id' => array("value" => $this->modx->db->escape($data['prodution_catalog_id'])), 125 | 'conf_product_prodution_tpl_id' => array("value" => $this->modx->db->escape($data['product_prodution_tpl_id'])), 126 | 'conf_add_products' => array("value" => $data['add_products']), 127 | 'conf_update_products' => array("value" => $data['update_products']), 128 | 'conf_update_description_product' => array("value" => $data['update_description_product']), 129 | 'conf_delete_products' => array("value" => $data['delete_products']), 130 | 'conf_moved_deleted_product_to_trash' => array("value" => $data['moved_deleted_product_to_trash']), 131 | 'conf_add_categories' => array("value" => $data['add_categories']), 132 | 'conf_update_categories' => array("value" => $data['update_categories']), 133 | 'conf_delete_categories' => array("value" => $data['delete_categories']), 134 | 'conf_moved_deleted_category_to_trash' => array("value" => $data['moved_deleted_category_to_trash']), 135 | 'conf_update_prices' => array("value" => $data['update_prices']), 136 | 'conf_add_options' => array("value" => $data['add_options']), 137 | 'conf_clear_tvs' => array("value" => $data['clear_tvs']), 138 | 'conf_uid' => $data['uid'] ? array("value" => $this->modx->db->escape($data['uid'])) : array("value" => "link_attributes"), 139 | 'conf_price_type' => $data['price_type'] ? array("value" => $this->modx->db->escape($data['price_type'])) : array("value" => "Розничная"), 140 | 'conf_price_currency' => $data['price_currency'] ? array("value" => $this->modx->db->escape($data['price_currency'])) : array("value" => "Закупочная") 141 | ); 142 | 143 | foreach ($config as $key => $value) { 144 | $query = $this->modx->db->update($value, $this->mod_tbl_config, "setting = '$key'"); 145 | } 146 | } 147 | 148 | /** 149 | * Удаляет все данные модуля из БД 150 | */ 151 | function modUninstall() { 152 | $sql = array(); 153 | $sql[] = "ALTER TABLE $this->mod_tbl_catalog DROP COLUMN $this->xml_id"; 154 | $sql[] = "DROP TABLE IF EXISTS $this->mod_tbl_config"; 155 | $sql[] = "DROP TABLE IF EXISTS $this->mod_tbl_attr_group"; 156 | $sql[] = "DROP TABLE IF EXISTS $this->mod_tbl_attr"; 157 | $sql[] = "DROP TABLE IF EXISTS $this->mod_tbl_opt"; 158 | $sql[] = "DROP TABLE IF EXISTS $this->mod_tbl_opt_val"; 159 | 160 | foreach ($sql as $line) { 161 | $this->modx->db->query($line); 162 | } 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | db->connect(); 5 | if (empty($modx->config)) { 6 | $modx->getSettings(); 7 | } 8 | // Загружаем конфигурацию 9 | $config = array(); 10 | if (mysql_num_rows(mysql_query("SHOW TABLES FROM " . $modx->db->config['dbase'] . " LIKE '" . $modx->db->config['table_prefix'] . "exchange1c_manager_config'")) > 0) { 11 | $config_query = $modx->db->select("*", $modx->getFullTableName('exchange1c_manager_config')); 12 | while ($conf = mysql_fetch_array($config_query)) { 13 | if ($conf[1] == 'price_additional_type') { 14 | $conf[2] = unserialize($conf[2]); 15 | } 16 | $config[str_replace("conf_", "", $conf[1])] = $conf[2]; 17 | } 18 | } 19 | 20 | $user = $config['user']; 21 | $pass = $config['pass']; 22 | 23 | if (!isset($_SERVER['PHP_AUTH_USER']) or $_SERVER['PHP_AUTH_USER']!==$user or $_SERVER['PHP_AUTH_PW']!==$pass) { 24 | 25 | header('WWW-Authenticate: Basic realm="Auth"'); 26 | header('HTTP/1.0 401 Unauthorized'); 27 | exit("Sorry, Access Denied"); 28 | 29 | } else { 30 | 31 | // добавляем в конфиг что не хватило 32 | $config['currentdate'] = time() + $modx->config['server_offset_time']; // текущая дата 33 | $config['USD'] = $modx->getConfig('USD') ? $modx->getConfig('USD') : 1; // курс доллара 34 | $config['EUR'] = $modx->getConfig('EUR') ? $modx->getConfig('EUR') : 1; // курс евро 35 | $config['руб'] = $modx->getConfig('RUB') ? $modx->getConfig('RUB') : 1; // курс рубля 36 | 37 | // разбираем POST запросы 38 | if (isset($_REQUEST['mode']) && $_REQUEST['type'] == 'catalog') { 39 | require_once(MODX_BASE_PATH . MGR_DIR . "/1c_exchange/classes/class.exchange_1c.catalog_import.php"); 40 | $ModxExchange1c = new ModxExchange1c($modx, $config); 41 | switch ($_REQUEST['mode']) { 42 | case 'checkauth': 43 | $ModxExchange1c->modeCheckauth(); 44 | break; 45 | case 'init': 46 | $ModxExchange1c->modeInit(); 47 | break; 48 | case 'file': 49 | $ModxExchange1c->modeFile(); 50 | break; 51 | case 'import': 52 | $ModxExchange1c->modeImport(); 53 | break; 54 | default: 55 | echo "success\n"; 56 | } 57 | } else { 58 | echo "failure\n"; 59 | exit; 60 | } 61 | } 62 | ?> 63 | -------------------------------------------------------------------------------- /module/module.1c_exchange.php: -------------------------------------------------------------------------------- 1 | config['manager_theme']; 4 | $mod_page = "index.php?a=112&id=" . $_GET['id']; 5 | $cur_version = '0.1'; 6 | 7 | define("EXCHANGE1C_PATH", "../manager/1c_exchange/"); 8 | 9 | require_once EXCHANGE1C_PATH . "classes/class.exchange_1c.manager.php"; 10 | 11 | $exchange1c = new EX1Cmanager($modx); 12 | $exchange1c->mod_cur_version = $cur_version; 13 | 14 | //Настройки модуля 15 | $tmp_config = $exchange1c->getModConfig(); 16 | extract($tmp_config); 17 | 18 | $installed = isset($conf_version) ? 1 : 0; 19 | 20 | $action = !empty($_GET['action']) ? $_GET['action'] : (!empty($_POST['action']) ? $_POST['action'] : ''); 21 | switch ($action) { 22 | 23 | //Установка модуля 24 | case 'install': 25 | $exchange1c->modInstall(); 26 | $modx->sendRedirect($mod_page, 0, "REDIRECT_HEADER"); 27 | break; 28 | 29 | //Удаление модуля 30 | case "uninstall": 31 | if (!$modx->hasPermission('save_document')) { 32 | global $e; 33 | $e->setError(3); 34 | $e->dumpError(); 35 | exit; 36 | } 37 | $exchange1c->modUninstall(); 38 | $modx->sendRedirect($mod_page, 0, "REDIRECT_HEADER"); 39 | break; 40 | 41 | //Сохранение конфигурации 42 | case "save_config": 43 | if (!$modx->hasPermission('save_document')) { 44 | global $e; 45 | $e->setError(3); 46 | $e->dumpError(); 47 | exit; 48 | } 49 | $exchange1c->saveConfig($_POST); 50 | $modx->sendRedirect($mod_page, 0, "REDIRECT_HEADER"); 51 | break; 52 | 53 | 54 | // страница свойств номенклатуры 55 | case "load_attributes": 56 | include "tpl/header.tpl.php"; 57 | include "tpl/page_attributes.tpl.php"; 58 | include "tpl/footer.tpl.php"; 59 | break; 60 | 61 | // страница характеристик номенклатуры 62 | case "load_options": 63 | include "tpl/header.tpl.php"; 64 | include "tpl/page_options.tpl.php"; 65 | include "tpl/footer.tpl.php"; 66 | break; 67 | 68 | //Страница модуля 69 | default: 70 | include "tpl/header.tpl.php"; 71 | 72 | if ($installed == 0) { 73 | echo '
21 | 22 | 23 | Пользователь 24 | 25 | Пароль 26 | 27 | Разрешённые IP (каждый с новой строки) 28 | |
29 |
32 | |
35 | ID TV-параметра цены 36 | 37 | ID TV-параметра валюты 38 | 39 | ID каталога товаров 40 | 41 | 47 | 48 | 49 | ID шаблона категории c подкатегориями товаров 50 | 51 | ID шаблона категории товаров 52 | 53 | ID шаблона товара 54 | 55 | ID папки корзины 56 | 57 | |
61 |
64 | |
69 | 70 | 73 | 74 | 77 | 78 | 81 | |
82 |
85 | |
90 | 91 | 94 | 95 | 98 | 99 | 102 | 103 | 106 | |
107 |
110 | |
115 | 116 | 117 | |
125 |
128 | |
131 | Поле в таблице "site_content" по которому будут синхронизироваться товары, в 1С это Код товара 132 | 133 | Основная цена товара (Розничная) 134 | 135 | Название цены из которой берётся валюта товара (Закупочная) |
136 |