Существует проблема с выгрузкой заказов с 2 разных сайтов.
Если сайты являются копиями друг друга, т.е. сначала был сделан сайт 1, затем скопирован и развернут с базой, и на его основе с незначительными доработками был сделан сайт 2.
Для 1 сайта уже была подключены импорты заказов из Битрикс, и импорт номенклатуры в Битрикс.
Для второго сайта сделали идентичные обмены, также путем копирования обменов, и изменения параметров отбора и древа групп в обмене товарами, и без изменений обмена заказами, кроме url адреса.
При включении на автомате обоих импортов заказов происходит проблема дублирования заказа. Со 2 сайта приходит заказ, и полностью удаляет документы старого заказа в 1С, полученного с первого сайта. При сравнении и проверке заказов выяснилось, что заказы с идентичными ID.
Самый быстрый - меняем стартовое значение поля ID
Оно int(11), значит у нас есть в запасе от (-2147483648 до 2147483647)
Для первого сайта оставляем всё как есть.
Для второго: ALTER TABLE `b_sale_order` AUTO_INCREMENT = 100000000;
Для третьего: ALTER TABLE `b_sale_order` AUTO_INCREMENT = 200000000;
Для пользователя - задействуем нумератор заказов, что бы не боялся больших цифр.
Пишет нам один заказчик, что сайт начал долго открываться.
Заходим - действительно, ~17 секунд отдаётся контент.
Начали анализировать ситуацию, в одном из включаемых файлов видим это:
sleep(15); - команда которая говорит серверу - подожди просто 15 секунд, потом делай свои дела дальше.
Это даже не смешно, "случайно" такую команду не напишешь, за 15 лет разработки я применил эту команду только 1 раз, и то, в сервисном скрипте, который по крону делает что то.
Так что это 100% диверсия. И те разработчики, если такое сделали, не известно, на что ещё способны. Как минимум 2 бэкдора уже нашёл.
Продолжение этой проблемы. Когда менеджер работает одновременно в админке и в 1С, и когда в 1С выключена загрузка отгрузок и оплат - Битрикс убирает из заказа эти данные. Возвращаем информацию в заказ, и список заказов.
<?php
// local/php_interface/init.php
// Добавляем информацию внутри заказа
\Bitrix\Main\EventManager::getInstance()->addEventHandler('sale', 'onSaleAdminOrderInfoBlockShow', ['DivasoftFixSyncOrderInfo', 'onSaleAdminOrderInfoBlockShow']);
// Заполняем колонки в списке заказов
\Bitrix\Main\EventManager::getInstance()->addEventHandler("main", "OnAdminListDisplay", ['DivasoftFixSyncOrderInfo', 'onAdminListDisplay']);
\Bitrix\Main\EventManager::getInstance()->addEventHandler("main", "OnAdminSubListDisplay", ['DivasoftFixSyncOrderInfo', 'onAdminListDisplay']);
class DivasoftFixSyncOrderInfo {
static function getSystemDeliveryNameByOrderD7($order) {
$shipmentCollection = $order->getShipmentCollection();
$shipmenName = "Не выбрана";
$systemShipmentItemCollection = $shipmentCollection->getSystemShipment()->getShipmentItemCollection();
foreach ($shipmentCollection as $obShipment) {
if ($obShipment->isSystem()) {
$arShipment = $obShipment->getFields()->getValues();
$shipmenName = $arShipment['DELIVERY_NAME'];
}
}
return $shipmenName;
}
static function getSystemPaymentNameByOrderD7($order) {
// getSystemPayment такого метода нет, запросим информацию по тому что есть
$paySystemService = \Bitrix\Sale\PaySystem\Manager::getObjectById($order->getField('PAY_SYSTEM_ID'));
$payName = $paySystemService->getField("NAME");
return $payName;
}
function onSaleAdminOrderInfoBlockShow(\Bitrix\Main\Event $event) {
$order = $event->getParameter("ORDER");
$shipmenName = self::getSystemDeliveryNameByOrderD7($order);
$payName = self::getSystemPaymentNameByOrderD7($order);
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::SUCCESS, array(
array('TITLE' => 'Доставка:', 'VALUE' => $shipmenName, 'ID' => 'dvs_system_shipment'),
array('TITLE' => 'Оплата:', 'VALUE' => $payName, 'ID' => 'dvs_system_payment'),
), 'sale'
);
}
function onAdminListDisplay(&$list) {
if ($list->table_id == "tbl_sale_order") {
foreach ($list->aRows as &$row) {
foreach ($row->aFields as $key => &$val) {
$order = false;
if ($key == "DELIVERY") {
if (!$val['view']['value']) {
if (!$order) {
$order = \Bitrix\Sale\Order::load($row->arRes['ID']);
}
$val['view']['value'] = self::getSystemDeliveryNameByOrderD7($order);
}
}
if ($key == "PAY_SYSTEM") {
if (!$val['view']['value']) {
if (!$order) {
$order = \Bitrix\Sale\Order::load($row->arRes['ID']);
}
$val['view']['value'] = self::getSystemPaymentNameByOrderD7($order);
}
}
}
}
}
}
}
?>
Каждый фронтенд-разработчик в своей практике сталкивался с элементами дизайна, которые ни в верстке, ни в стилях, ни в js не предусматривались. Откуда они взялись? Отладчик – верный помощник любого фронтендера, как на зло, так же ничем помочь не может, он просто ничего не показывает.
Все просто – это стандартные псевдоклассы, встроенные по умолчанию во внутренние стили браузера. Например, как в случаи со стилем outline, который необходимо отменять в самом начале работы, если конечно дизайн вашего сайта не подразумевает голубую подсветку форм.
Часто появляющимися псевдоэлементами может похвалиться Google Chrome, впрочем, другим движкам на webkit так же ничего не мешает отличиться.
Надо методично стилизовать все внутренние стили браузера.
Например, довольно часто встречается баг фича с input, когда на input с типом search появляется «синий крестик». На самом деле это кнопка, которая чистит ввод поиска пользователя. Кнопка может и полезная, но практика показывает, что с точки зрения дизайна сайта она совершенно не приемлема и не вписывается в общую концепцию. Убирается эта кнопка по средствам следующей конструкции:
input[type=search]{ -webkit-appearance: none;}
Еще одним интересным примером является настройка placeholder все в том же input. Помимо стандартного: цвета шрифта и бекграунда формы, выявилась интересная особенность ее отображения внешнего вида все в том же Google Chrome. Суть проблемы заключалась в том, что слово, заложенное в placeholder на темном бекграунде так же оставалось темным. Несмотря на значение color: #fff для input, ничего не менялось. Решение представлено ниже. Обратите внимание на двойное двоеточие. Если оно будет одинарным, то правило не сработает:
Поэтому, если в процессе верстки вдруг появляется что-то, что разработчиком не предусматривалось, не стоит паниковать! В первую очередь стоит проверить, а не портят ли картину встроенные псевдоклассы браузера.
Очень часто нужно сделать генерацию пароля, который пользователь должен вводить при входе, или генерировать код капчи. Но мы не задумываемся - как распознавать символы который похожи друг на друга? Например I и l - это i и L, O и 0 - Буква и цифра. А если используется шрифт, где буквы и цифры практически одинаковые, то всё становится очень сложно.
Делаем алфавит только по символам, которые нельзя трактовать двояко:
Сложно найти в этом огромном списке актуальную версию сборки. Теперь с помощью небольшого парсера получаем свежую дату и название файла для скачивания.
Есть несколько способов подключения и инициализации рекапч, но самый удобный это тот, который занимает мало строчек кода, и максимально эффективен.
В init.php добавляем код, инициализирующий рекапчу. Код добавляется структурно после подключения всех стилей и скриптов, что исключает ошибку раннего старта рекапчи. Код добавляется именно через addString(), а не через addScript():
Тем самым не зная точно сколько рекапч будет на странице, мы можем работать с ними по идентификатору дива (в данном случае это recaptchaUID), в котором эта капча инициализировалась по классу g-recaptcha.
Нам понадобится рутованный аппарат. Редактируем файл /system/etc/mixer_path.xml
Находим что нибудь связанное с MIC1 / MIC2 / MIC3 и значениями On. Меняем на Off, перезагружаем. Если всё нормально то телефон включится. Если нет - откатываем изменения(через рекавери).
У каждого производителя этот файл уникальный, но принцип одинаковый.
Так же в этом файле можно увеличить громкость динамиков, и чувствительность/усиление микрофона.
ID покупателя (так называемый FUSER_ID) уникальный для посетителя, открывшего сайт. Он у него живет в куках, даже если он еще не делал ничего. Сейчас поясню, для чего он нужен.
В продукте реализован механизм, который позволяет работать с корзиной не авторизованным пользователям. Чтобы этот механизм работал, корзина привязывается не к ID пользователя сайта, а к FUSER_ID - идентификатор пользователя магазина, который записывается в куки. Опишу несколько ситуаций:
Ситуация первая:
Вы не авторизованный пользователь, кладёте товар в корзину - создаётся новый FUSER_ID, пусть это FUSER_X, который записывается в базу и в куки.
Затем вы авторизуетесь под аккаунтом пользователя A. Если к идентификатору пользователя А не привязан никакой FUSER_ID, то он опять же создаётся, привязывается к идентификатору пользователя А (записывается в базу) и пишется в куки, путь это будет FUSER_Y. В это же время все товары не авторизованного пользователя переносятся в корзину авторизованного пользователя.
Товары покупателя FUSER_X ---> Товары покупателя FUSER_Y.
Соответственно, теперь к FUSER_X не будет привязано ни одного товара и FUSER_X удаляется из базы.
Ситуация вторая:
Вы авторизованный пользователь А, вашей корзине есть товары, которые привязаны к FUSER_Y.
Вы решили разлогиниться.
В этот момент Вы становитесь не авторизованным пользователем и FUSER_ID из куков удаляется и пишется НОВЫЙ, корзина пуста, т.к. именно по FUSER_ID осуществляется выборка товаров в корзине.
Ситуация третья:
Вы авторизованный пользователь А, вашей корзине есть товары, которые привязаны к FUSER_Y.
Вы не собираетесь разлогиниваться, но получается так, что закончилось время жизни сессии - вы становитесь не авторизованным пользователем. Из куков не удаляется FUSER_ID, он остаётся таким же равным FUSER_Y, т.е. получается, что вы не авторизованный пользователь с FUSER_ID пользователя А, поэтому в корзине присутствуют товары пользователя А.
Это нормальная ситуация. Согласитесь, пользователю будет не очень приятно, если он набрал 50 товаров в корзину, время сессии закончилось и его товары из корзины пропали.
За этот же компьютер садится другой пользователь, который авторизуется под аккаунтом пользователя В, идентификатор пользователя магазина FUSER_Z. И тут возникает "первая ситуация", перенос товаров от FUSER_Y к FUSER_Z.
В итоге, если пользователь А, авторизуется снова (на другом компьютере или браузере), то его корзина будет пуста.
Т.е. пользователь B "приобрёл" корзину пользователя А.
Если пользователь А и пользователь B, работают за разными компьютерами, то ситуации переноса корзины от пользователя А к пользователю B никогда не произойдёт, соответственно проблему у покупателей быть не должно.
Это неизбежная логика стандартного механизма корзины.
p.s. FUSER_ID это ID покупателя, но НЕ ID профиля покупателя, это разные сущности.
И волшебный ответ для того, что бы аккаунт прошёл валидацию "your account is temporarily disabled. business verification please contact support to resolve"
Hello!
What types of emails will you be sending - transactional or marketing?
transactional + marketing
Register info, Order info, Promo mail.
Where do you source your database of email addresses?
CMS 1C-Bitrix (divasoft.ru)
Are all of your email addresses double-opt in?
I do not quite understand, but the mail has.
What is your expected monthly volume of messages?
100-1000, we just start online-store
Have you read our Email Best Practices document?
Yes!
Can you please give us the URL that your users use to sign up for your email as well as a link to your Terms of Service?
In development, link to register page = https://divasoft.ru/login/?register=yes&backurl=%2F
p.s. этот сервис скрывает ip адрес сервера отправителя
Дальше в Админ-панели, в настройках Валюты->Языковые настройки (/bitrix/admin/currency_edit.php?lang=ru&ID=RUB)
Строка формата для вывода валюты: # руб.
Разделитель тысяч при выводе: Другое значение  
Дальше меняем длину одного столбца в SQL таблице:
ALTER TABLE `b_catalog_currency_lang`
CHANGE `THOUSANDS_SEP` `THOUSANDS_SEP` varchar(10) COLLATE 'utf8_unicode_ci' NULL DEFAULT ' ' AFTER `DEC_POINT`;
И устанавливаем нужное значение разделителя вручную (т.к. в админке ограничение на 5 символов при вводе):
UPDATE `b_catalog_currency_lang` SET `THOUSANDS_SEP` = ' '
WHERE `CURRENCY` = 'RUB' AND `LID` = 'ru';
Солнечное утро пятницы не предвещало ничего плохого, когда раздался звонок от клиента: «Долго открывается сайт». «Слишком много пользователей», — первым делом решили мы, потому что такое уже случалось. Да и хостер не отреагировал на резкое увеличение трафика, так что причин для беспокойства пока ещё не было. Полезли в админку, чтобы в очередной раз прибавить мощностей, но от представших нашему взору графиков потеряли дар речи.
Ответ мог быть только один — DDoS. И тут неожиданно очнулся Rusonyx и отключил к чёрту наш сайт. Не, ну а что? Конечно, мы написали в техподдержку и спустя полтора часа получили пространный ответ:
На Ваш сервер зафиксирован сильный поток входящего трафика, IP адрес заблокирован. Вам нужно: 1. Обратиться к компании, предоставляющей услуги фильтрации траффика (Qurator например). 2. Купить новый IP адрес. 3. Сообщить нам информацию, которую Вам предоставили (Qurator например), далее мы сделаем все самостоятельно.
Сказано, сделано. Покупаем IP-адрес всё у того же Rusonyx. Благоразумно отказываемся от предложенного Qurator, ибо есть сервисы куда дешевле и надёжнее, к ним и обращаемся. И всю полученную информацию скидываем обратно хостеру. Ждём. И, внезапно, обнаруживаем, что свежекупленный IP тоже попал под DDoS. «КАК?!» — спрашиваем у хостера, — «...» Покупаем ещё один IP и снова ждём. Ждём. Ждём. Тут стоит упомянуть, что у русоникса две линии техподдержки: круглосуточная для простых обращений и инженерная (не работающая по выходным, да) для вот таких проблем. А меж тем пятница стремительно проходит.
Изрядно переживаем, потому что клиент теряет прибыль, а мы — нервные клетки. Мандража добавляет отсутствие доступа к панели управления и невозможность снять свежие бекапы сайта. Снова и снова бомбардируем техподдержку хостера, как наступает он — вечер пятницы, злоклятое время для всех админов. На этом, видимо, рабочий день инженеров русоникса заканчивается и они со спокойной совестью уходят домой. Напоминаю, вся информация для защиты у них есть уже несколько часов, а сайт всё ещё DDoS'ят. С сожалением понимаем, что не можем ничего сделать до понедельника. В нервном ожидании проводим и выходные и, наконец, получаем в воскресенье наши бэкапы. И первое, что делаем — уходим к другому хостеру.
Итого
Мы скрыли сайт системой фильтрации трафика на уровне DNS.
Отказались от услуг недобросовестного, а точнее бессовестного русоникса.
Защитили исходящие сообщения от почтового сервиса сайта через сторонний SMTP-сервис.
Вышли из-под DDoS.
Дополнительно узнали, что у клиента есть серьёзно настроенные конкуренты.
...
Profit!
Ах да, чуть не забыла самое интересное, вместе с недоступностью сайта клиента просто катастрофически выросли посещения на наш сайт ;)
P.S.: Обратили внимание, что в посте не названы сервисы и ресурсы, которые мы использовали? Конечно это сделано нарочно, для обеспечения безопасности. Впрочем, все они легко гуглятся, если вас интересует эта тема.
Знаете, что случается, когда человеку становится лень? Правильно. Он придумывает способ (иногда новаторский и гениальный) облегчить свою работу. Поэтому у нас сразу две хорошие новости.
Во-первых, я решила в своём напряжённом и невероятно плотном графике выделить место для регулярных публикаций. А это значит, что блог Дивасофт снова будет вестись и пополняться интересными материалами. Но, увы, времени на оповещение об этом соцсетей не нашлось.
Поэтому, во-вторых, мы стали использовать удобный, но пока несовершенный (не хватает нам выгрузки в гугл+, но её уже делают) модуль CrossTopus. Помимо прочих плюшек, у ребят отличная техподдержка, с которой мы легко нашли общий язык и даже подружились. Но это уже совсем другая история.
Ах, да. Ещё у нас обновлены иконки соцсетей, как там говорят в таких случаях? Подписывайтесь, ставьте лайки, ждите свежих новостей =)
Как и всякая хорошая вещь, блог «Дивасофт» начинался с идеи. Чужой. Где-то на просторах интернета мы подсмотрели дизайн с широкими картинками и узким текстом. Отталкиваясь от него, приступили к созданию своего варианта. Долго, очень долго мы вымеряли шаблоны. Придумывали, где разметить дату и подпись, использовать ли теги, как обойтись с картинками, что делать с разделением по страницам. И вот, спустя чуть ли не полгода, блог «Дивасофт» запущен и работает.
И он красивый. Да, вот так вот нескромно с нашей стороны это заявлять, но посудите сами. Чего только стоит исходный код страницы, залюбоваться можно. Разметка всех и вся сделана по стандартам HTML5. Вы только посмотрите на структуру каждого поста!
<article>
<header>
<h2><a href="">Открытие блога</a></h2>
<span><time datetime="2014-05-16T12:00:00+04:00">16 Мая 2014</time>,
<em>Ashe Gentle</em></span>
</header>
<p>Как и всякая хорошая вещь, блог «Дивасофт» начинался с идеи. Чужой. Где-то на просторах интернета мы подсмотрели дизайн с широкими картинками и узким текстом. Отталкиваясь от него, приступили к созданию своего варианта. Долго, очень долго мы вымеряли шаблоны. Придумывали, где разметить дату и подпись, использовать ли теги, как обойтись с картинками, что делать с разделением по страницам. И вот, спустя чуть ли не полгода, блог «Дивасофт» запущен и работает.</p>
<h3>Подзаголовок</h3>
<p>И он красивый. Да, вот так вот нескромно с нашей стороны это заявлять, но посудите сами. Чего только стоит исходный код страницы, залюбоваться можно. Разметка всех и вся сделана по стандартам HTML5. Вы только посмотрите на структуру каждого поста!</p>
<footer>
<em><a href="#">Бекэнд</a>, <a href="#">Bitrix</a></em>
</footer>
</article>
Тут тебе и <article>, и <header>, и <footer>, и <time> и всё-всё-всё на свете. А как замечательно оформлены у нас цитаты:
<blockquote cite="http://divasoft.ru/blog/">
<p>А как замечательно оформлены у нас цитаты</p>
</blockquote>
Отдельно стоит упомянуть типографику. Вы обратили внимание, что мы используем верные кавычки, принятые в русском языке — «ёлочки»? И, конечно, длинные тире вместо дефисов и минусов, которые, между прочим, не так просто поставить. Приходится использовать либо цифровые коды, либо специальные символы html.
А ещё мы точно продумали расположение изображений. Их может быть четыре рядом, три, два или одно на весь блок записи. И при всём этом отступы между ними будут равными. Пришлось повозиться с полпикселями, появляющимися в разных браузерах. Но и эту проблему мы решили, использовав float: right; для крайнего правого изображения.
Кстати, о полпикселях. Это происходит потому, что мы используем собственную процентную сетку. Которая тоже была разработана путём долгих и кровавых споров. У нас вообще никогда без них не обходится. Сейчас, например, воюем за или против переносов слов.
Всё вышесказанное относилось к вёрстке, но и с натягом вышло не так просто. Изначально планировалось использовать стандартный компонент битрикс — блог. Но когда уже всё было готово и мы приступили к тестированию, возникли непредвиденные проблемы. Оказалось, что начиная с 12 версии, разработчики битрикса запретили использование HTML-редактора в блогах. Наверное, это связано с безопасностью. И наверное, важно. Но нам абсолютно не подходит. Так реализация проекта застопорилась на неопределённое время, пока мы искали пути обхода. Как вариант рассматривали использование другой площадки — wordpress, например. Заточенный именно для блогов, он мог бы стать решением всех проблем. Но оказалось нецелесообразным разбивать единую систему. Поэтому мы сделали блог на инфоблоках.
И увидел Бог всё, что Он создал, и вот, хорошо весьма. И был вечер, и было утро...
Возможно, потом у нас будут комментарии и подписка, и конечно «новое видение» основного сайта. Пока это всё в проекте и в необозримом будущем. Но уже сейчас вы можете читать о жизни компании, её проблемах, решениях, разработках, проектах и о многом другом. Присоединяйтесь!