У клиента есть база в 1С и есть сайт, который создавался мной. Клиент торгует одеждой, соответственно, у товара могут быть разные размеры и цвета - стоимость меняется по желанию. Времени на переделку 1с пока нет, а выгружать надо было в субботу-воскресенье.
1С была построоена таким образом, что все товары хранились одним списком, отличались только названиями и свойствами
Блуза женская Satin Б-122-1145 / Черная, 44 размер Блуза женская Satin Б-122-1145 / Синяя, 44 размер
Хранить такую информацию в базе и фильтровать неудобно. Было принято решение перейти на торговые предложения с выделением основного товара и выделения модификаций.
Блуза женская Satin Б-122-1145 - Основное
Торговое предложение
Блуза женская Satin Б-122-1145
Цвет Черная
Размер 44
Блуза женская Satin Б-122-1145 Цвет Синяя Размер 44
Свойства хранятся в справочнике, чтобы не было повторений и ошибок в наполнении.
Следовательно, нам выгружали два файла
offers.xml import.xml
В одном хранятся свойства, в другом цены, соответственно.
Файлы XML могут храниться любого размера, соответственно, поэтому был использован XMLReader
<?php
class xml2assoc2
{
function __construct($xml,$tag,$log_name)
{
$this->log_name = $log_name;
$this->need_lock_export = false; //поставить true когда необходимо что бы был 1 экспорт за 1 раз
$this->all_node_count = 0;
$this->firm_list = array();
$this->node_count = 0;
$this->node_name = $tag; //нод перебора заказов
$this->export_type = 2; //тип выгрузки 1 для 1с файла 2 для 2с файла
$this->xml_file = $xml;
if (!file_exists($this->xml_file)) die ('File '.$this->xml_file.' not exists');
$this->create_XML_reader();
$this->current_xml_array = array();
if (!$this->check_lock())
die('Выгрузка уже производится');
$this->calculate_all_node_count();
if ($this->all_node_count==0) die('Экспорт невозможен - количество нодов равно 0');
}
public function calculate_all_node_count()
{
$this->xml_count_reader = new XMLReader();
$this->xml_count_reader->open($this->xml_file);
while($this->xml_count_reader->read())
{
switch ($this->xml_count_reader->nodeType)
{
case XMLReader::END_ELEMENT:
break;
case XMLReader::ELEMENT:
$name = $this->xml_count_reader->name;
if ($name == $this->node_name)
{
$this->all_node_count++;
}
break;
case XMLReader::TEXT:
case XMLReader::CDAT A:
}
}
$this->xml_count_reader->close();
}
//получение данных о ноде
public function node_data()
{
return $this->current_xml_array;
}
public function return_firm_statistic()
{
return $this->firm_list;
}
//закрываем ХМЛ потоковый
public function close_xml()
{
$this->xml->close();
$this->delete_lock();
$this->save_firm_export_to_file(100);
}
///создание потокового чтения ХИЛ
private function create_XML_reader()
{
$this->xml = new XMLReader();
$this->xml->open($this->xml_file);
}
//Устанавливает тип экспорта - смотри инициализацию класса
public function set_export_type($type)
{
if ($type!=1)
$this->export_type = 2;
else
$this->export_type = 1;
}
///считываем заказы поэлементно
private function read_orders()
{
while($this->xml->read())
{
switch ($this->xml->nodeType)
{
case XMLReader::ELEMENT:
$name = $this->xml->name;
//echo $name.'<br>';
if ($name ==$this->node_name)
{
return $this->get_order_node();
}
break;
case XMLReader::TEXT:
case XMLReader::CDAT A:
}
}
}
///функция инициализации и считывания поэлементно заказов
public function get_next_order()
{
$data = $this->read_orders();
//print_r($data);
$this->current_xml_array = array();
if (is_array($data))
{
$this->current_xml_array = $data['data'];
$this->node_count++;
$this->save_firm_export_to_file();
return $this->current_xml_array;
}
$this->close_xml();
return false;
}
///статистика
public function get_statistic()
{
return 'Количество нодов:'.$this->node_count.'<br/>Количество использованной оперативной памяти:'.memory_get_usage(true).' байт</br>';
}
///Считываем сам нод заказа
private function get_order_node()
{
$prefix ='_c';
$assoc = null;
while($this->xml->read())
{
switch ($this->xml->nodeType) {
case XMLReader::END_ELEMENT: return array('type'=>$prefix,'data'=>$assoc);
case XMLReader::ELEMENT:
$name = rus2translit_utf($this->xml->name);
$have_atr = $this->xml->hasAttributes;
if ($this->xml->isEmptyElement)
{
$assoc[$name]['_v']='';
}
else
{
$val = $this->get_order_node();
if (isset($assoc[$name]))
{
///если индекс 0 есть то не нужно переделывать массив
if (!isset($assoc[$name][0]))
{
$val_temp = $assoc[$name];
$assoc[$name] = array();
$assoc[$name][0] = $val_temp;
}
$id = sizeof($assoc[$name]);
if ($have_atr) $el = & $assoc[$name][$id]['_a'];
$assoc[$name][$id][$val['type']] = $val['data'];
}
else
{
if ($have_atr) $el = &$assoc[$name]['_a'];
$assoc[$name][$val['type']] = $val['data'];
}
}
if($have_atr)
{
///$el =& $assoc[$name]['_a'];
while($this->xml->moveToNextAttribute())
$el[rus2translit_utf($this->xml->name)] = $this->xml->value;
}
break;
case XMLReader::TEXT:
case XMLReader::CDAT A:
$prefix = '_v';
$assoc .= $this->xml->value;
}
}
$val = array('type'=>$prefix,'data'=>$assoc);
return $val;
}
private function lock_export()
{
file_put_contents('lock.dat',time()+180);
}
public function delete_lock()
{
if (file_exists('lock.dat')) unlink('lock.dat');
file_put_contents('lock.dat',time()-5);
}
private function check_lock()
{
if ($this->need_lock_export == false) return true;
if (file_exists('lock.dat'))
{
/// die('Идет экспорт');
$time = @file_get_contents('lock.dat');
if (is_numeric(@$time))
{
if (time()<$time)
{
return false;
}
}
}
$this->lock_export();
return true;
}
private function save_firm_export_to_file($procent='')
{
if (@$handle = fopen('procent_status.txt', 'w+'))
{
if ($procent==='') $procent = intval(100*$this->node_count/$this->all_node_count);
fwrite($handle, $this->log_name.": ".$procent.'%');
fclose($handle);
}
}
public function draw_info()
{
return print_r($this->current_xml_array,true).'<hr>';
}
}
if (!function_exists("rus2translit_utf"))
{
function rus2translit_utf($string) {
$converter = array(
'а' => 'a', 'б' => 'b', 'в' => 'v',
'г' => 'g', 'д' => 'd', 'е' => 'e',
'ё' => 'e', 'ж' => 'zh', 'з' => 'z',
'и' => 'i', 'й' => 'y', 'к' => 'k',
'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r',
'с' => 's', 'т' => 't', 'у' => 'u',
'ф' => 'f', 'х' => 'h', 'ц' => 'c',
'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sch',
'ь' => '\'', 'ы' => 'y', 'ъ' => '\'',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
'А' => 'A', 'Б' => 'B', 'В' => 'V',
'Г' => 'G', 'Д' => 'D', 'Е' => 'E',
'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z',
'И' => 'I', 'Й' => 'Y', 'К' => 'K',
'Л' => 'L', 'М' => 'M', 'Н' => 'N',
'О' => 'O', 'П' => 'P', 'Р' => 'R',
'С' => 'S', 'Т' => 'T', 'У' => 'U',
'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C',
'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sch',
'Ь' => '\'', 'Ы' => 'Y', 'Ъ' => '\'',
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
' ' => '_', '"'=> '',
);
return strtr($string, $converter);
}
}
?>
В классе мы можем видеть сколько памяти потребляет скрипт ( он был оптимизирован под использование не больше 5 МБ памяти на 100 МБ XML )
И сам обработчик:
<?php
//header('Content-type: text/html; charset=UTF-8');
include_once "import_market.php";
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule("iblock");
CModule::IncludeModule("catalog");
$groups = array();
$xml2assoc2 = new xml2assoc2("import.xml",convert_utf('Группа'),'Экспорт названий категорий');
$xml2assoc2->set_export_type(2);
while ($data = $xml2assoc2->get_next_order())
{
//считываем данные по категориям
foreach ($data['Gruppy']['_c']['Gruppa'] as $id=>$val)
{
$groups[$val['_c']['Id']['_v']] = $val['_c']['Naimenovanie']['_v'];
}
}
//считываем данные данные по товарам - соотношение айди и группы
$goods_data = array();
$xml2assoc2 = new xml2assoc2("import.xml",convert_utf('Товар'),'Экспорт данных товаров по категориям');
$xml2assoc2->set_export_type(2);
while ($data = $xml2assoc2->get_next_order())
{
$goods_data[$data['Id']['_v']] = array('Artikul'=>$data['Artikul']['_v'],'Gruppy'=>$data['Gruppy']['_c']['Id']['_v']);
}
//print_r($goods_data);die();
function convert_1251($str)
{
return iconv('utf-8','windows-1251', $str);
}
function convert_utf($str)
{
return iconv('windows-1251','utf-8', $str);
}
//обработка нодов
$xml2assoc2 = new xml2assoc2("offers.xml",convert_utf('Предложение'),'Экспорт цен');
$xml2assoc2->set_export_type(2);
while ($data = $xml2assoc2->get_next_order())
{
//тут обработка должна быть нода
$full_name = $data['Naimenovanie']['_v'];
$cost = $data['Ceny']['_c']['Cena']['0']['_c']['CenaZaEdinicu']['_v'];
//получаем размер и цвет
$slesh_pos = strrpos($full_name,'/');
$name = convert_1251(trim(mb_substr($full_name,0,$slesh_pos)));
$item_data = explode(',',trim(mb_substr($full_name,$slesh_pos+1)));
$color = convert_1251(trim(@$item_data[0]));
$size = trim(intval(@$item_data[1]));
$group_id = $goods_data[$data['Id']['_v']]['Gruppy'];
$group_name = convert_1251($groups[$goods_data[$data['Id']['_v']]['Gruppy']]);
/*
echo 'Название:'.$name."<br>";
echo 'Цена:'.$cost."<br>";
echo 'Цвет:'.$color."<br>";
echo 'Размер:'.$size."<br>";
echo 'Группа (ID):'.$group_id."<br>";
echo 'Группа (название):'.$group_name."<br>";
echo '<hr>';
*/
/* РАЗДЕЛ */
$arFilterSection = Array('IBLOCK_ID'=>'3', 'GLOBAL_ACTIVE'=>'Y', 'NAME'=>$group_name);
$db_list_section = CIBlockSection::GetList(Array(), $arFilterSection, true);
while($ar_result_section = $db_list_section->GetNext())
{
$GROUP_ID=$ar_result_section['ID'];
}
if(!$GROUP_ID):
$bs = new CIBlockSection;
$arFields = Array(
"ACTIVE" => "Y",
"IBLOCK_ID" => "3",
"NAME" => $group_name,
"CODE" => rus2translit($group_name)
);
$GROUP_ID = $bs->Add($arFields);
endif;
/* РАЗДЕЛ */
/* ЦВЕТ */
echo 'Цвет:'.$color."<br>";
$arSelectColor = Array("ID");
$arFilterColor = Array("IBLOCK_ID"=>"5", "ACTIVE_DATE"=>"Y", "ACTIVE"=>"Y", "NAME"=>$color);
$resColor = CIBlockElement::GetList(Array(), $arFilterColor, false, Array("nPageColor"=>1), $arSelectColor);
while($obColor = $resColor->GetNextElement())
{
$arFieldsColor = $obColor->GetFields();
$COLOR_ID=$arFieldsColor["ID"];
}
if (!$COLOR_ID):
$el_color = new CIBlockElement;
$arLoadProductArrayColor = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => false, // элемент лежит в корне раздела
"IBLOCK_ID" => 5,
"NAME" => $color,
"ACTIVE" => "Y" // активен
);
$COLOR_ID = $el_color->Add($arLoadProductArrayColor);
endif;
/* ЦВЕТ */
/* РАЗМЕР */
echo 'Размер:'.$size."<br>";
$arSelectSize = Array("ID");
$arFilterSize = Array("IBLOCK_ID"=>"6", "ACTIVE_DATE"=>"Y", "ACTIVE"=>"Y", "NAME"=>$size);
$resSize = CIBlockElement::GetList(Array(), $arFilterSize, false, Array("nPageSize"=>1), $arSelectSize);
while($obSize = $resSize->GetNextElement())
{
$arFieldsSize = $obSize->GetFields();
$SIZE_ID=$arFieldsSize["ID"];
}
if (!$SIZE_ID):
$el_size = new CIBlockElement;
$arLoadProductArraysize = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => false, // элемент лежит в корне раздела
"IBLOCK_ID" => 6,
"NAME" => $size,
"ACTIVE" => "Y" // активен
);
$SIZE_ID = $el_size->Add($arLoadProductArraysize);
endif;
/* РАЗМЕР */
/* ТОВАР */
$arSelectElement = Array("ID", "NAME", "DATE_ACTIVE_FROM");
$arFilterElement = Array("IBLOCK_ID"=>"3", "ACTIVE_DATE"=>"Y", "ACTIVE"=>"Y", "NAME"=>$name);
$res_element = CIBlockElement::GetList(Array(), $arFilterElement, false, Array("nPageSize"=>50), $arSelectElement);
while($ob_element = $res_element->GetNextElement())
{
$arFieldsElement = $ob_element->GetFields();
$ELEMENT_ID=$arFieldsElement["ID"];
}
if (!$ELEMENT_ID):
$el_element = new CIBlockElement;
$arLoadProductArrayElement = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => $GROUP_ID, // элемент лежит в корне раздела
"IBLOCK_ID" => 3,
"NAME" => $name,
"ACTIVE" => "Y", // активен
);
$ELEMENT_ID = $el_element->Add($arLoadProductArrayElement);
$el_element_offer = new CIBlockElement;
$PROP = array();
$PROP[13] = $COLOR_ID; // COLOR
$PROP[14] = $SIZE_ID; // SIZE
$arLoadProductArrayElementOffer = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => false, // элемент лежит в корне раздела
"IBLOCK_ID" => 7,
"NAME" => $name,
"PROPERTY_VALUES"=> $PROP,
"ACTIVE" => "Y" // активен
);
$ELEMENT_ID_OFFER = $el_element_offer->Add($arLoadProductArrayElementOffer);
$arFieldsPrice = Array(
"PRODUCT_ID" => $ELEMENT_ID_OFFER,
"CATALOG_GROUP_ID" => "1",
"PRICE" => $cost,
"CURRENCY" => "RUB"
);
CPrice::Add($arFieldsPrice);
CIBlockElement::SetPropertyValues($ELEMENT_ID_OFFER, "7", $ELEMENT_ID, "CML2_LINK");
else:
$el_element = new CIBlockElement;
$PROP = array();
$PROP[13] = $COLOR_ID; // COLOR
$PROP[14] = $SIZE_ID; // SIZE
$arLoadProductArrayElement = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => false, // элемент лежит в корне раздела
"IBLOCK_ID" => 7,
"NAME" => $name,
"PROPERTY_VALUES"=> $PROP,
"ACTIVE" => "Y" // активен
);
$ELEMENT_ID_OFFER = $el_element->Add($arLoadProductArrayElement);
CIBlockElement::SetPropertyValues($ELEMENT_ID_OFFER, "7", $ELEMENT_ID, "CML2_LINK");
$arFieldsPrice = Array(
"PRODUCT_ID" => $ELEMENT_ID_OFFER,
"CATALOG_GROUP_ID" => "1",
"PRICE" => $cost,
"CURRENCY" => "RUB"
);
CPrice::Add($arFieldsPrice);
unset($el_element);
unset($PROP);
endif;
echo 'ТОВАР:'.$ELEMENT_ID."<br>";
/* ТОВАР */
unset($GROUP_ID);
unset($SIZE_ID);
unset($COLOR_ID);
unset($ELEMENT_ID);
unset($ELEMENT_ID_OFFER);
//ОБРАБОТКА ДОЛЖНА БЫТЬ ТУТ
}
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");
?>
Таким образом у нас заполняются справочники, создаются разделы, товары в них заносятся и привязываются торг предложения.
Сорри, забыл упомянуть: у клиента стоит 1С 7,7. Обновлять и тд - отказывается. Предпочитает только вести настройку 1с с нуля. Этим занимаются его 1с программисты. Поэтому и пришлось развести такой зоопарк, т.к. штатных обработчиков нет в 7.7. + она очень сильно кастомизирована была.
Данный скрипт проверяет на заполнение поле email, так же проверяет правильность заполнения. Если пользователь заполнил всё верно, то div меняется на "Вы подписаны", "На почту выслано сообщение".
$('input.email_send').click(function(e){
e.preventDefault();
var email = $('#email_text').val();
var adr_pattern=/[0-9a-z_]+@[0-9a-z_]+\.[a-z]{2,5}/i;
if(!adr_pattern.test(email)){
$('#email_error').css('display','block');
return false;
}else{
$.ajax({
type:"POST",
url:"/",
dat a:{"ajaxsubscriptionaddemail":email},
dataType:"html",
success:function(msg){
$('#sub_id,span.email').remove();
$('div.subscription h5').text('Вы подписаны.').after('<p>На почту выслано письмо для активации</p>');
}
});
}
});
Обработчик
В обработчике представлена форма в <div></div>. Код добавления подписки в HTML формате срабатывает только при получении POST. Аякс происходит с перезагрузкой файла, в котором лежит данный код ("/include/subscription.php").
Алексей, я уверен вы с благими намерениями выложили эти 2 куска кода. Но если вы решали техническую проблему, то где комментарии? А если это готовое решение, то как его применить?
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».