[{"data":1,"prerenderedAt":1625},["ShallowReactive",2],{"navigation_docs":3,"-modules-insync-portal-check":238,"-modules-insync-portal-check-surround":1622},[4,45,60],{"title":5,"description":6,"icon":7,"path":8,"stem":9,"children":10},"Методология",null,"ruler","\u002Fmethodology","1.methodology",[11,15,20,25,30,35,40],{"title":12,"path":8,"stem":13,"description":14},"bxshef: методология и проверка навыков","1.methodology\u002Findex","Как писать навыки ИИ-агентов для Битрикса и как проверять, что им можно верить",{"title":16,"path":17,"stem":18,"description":19},"Стандарт навыка","\u002Fmethodology\u002Fstandard","1.methodology\u002F1.standard","11 правил, каждое из провала на стенде",{"title":21,"path":22,"stem":23,"description":24},"Методология проверки","\u002Fmethodology\u002Fmethod","1.methodology\u002F2.method","lint → eval → стенд; что измерено",{"title":26,"path":27,"stem":28,"description":29},"bxshef — CLI","\u002Fmethodology\u002Fbxshef","1.methodology\u002F3.bxshef","lint, eval, feedback",{"title":31,"path":32,"stem":33,"description":34},"GitHub Action","\u002Fmethodology\u002Faction","1.methodology\u002F4.action","тот же lint + eval в любом репозитории навыков",{"title":36,"path":37,"stem":38,"description":39},"Заготовка репозитория","\u002Fmethodology\u002Ftemplate","1.methodology\u002F5.template","с чего начать автору модуля",{"title":41,"path":42,"stem":43,"description":44},"Приёмник отзывов","\u002Fmethodology\u002Ffeedback","1.methodology\u002F6.feedback","куда уходят отзывы ИИ-агентов",{"title":46,"description":6,"icon":47,"path":48,"stem":49,"children":50},"Навыки","sparkles","\u002Fskills","2.skills",[51,55],{"title":52,"path":48,"stem":53,"description":54},"Навыки shef.*","2.skills\u002Findex","npx skills add bx-shef\u002Fskills",{"title":56,"path":57,"stem":58,"description":59},"shef-feedback","\u002Fskills\u002Fshef-feedback","2.skills\u002F1.shef-feedback","Отправить отзыв о навыке shef-* или навыке команды. Брать ВСЕГДА, когда просят оставить или отправить отзыв о навыке — даже если сам навык в диалоге не виден, —",{"title":61,"description":6,"icon":62,"path":63,"stem":64,"children":65},"Модули shef.*","package","\u002Fmodules","3.modules",[66,69,131,179],{"title":61,"path":63,"stem":67,"description":68},"3.modules\u002Findex","Что за чем ставить",{"title":70,"description":6,"path":71,"stem":72,"children":73},"shef.options","\u002Fmodules\u002Foptions","3.modules\u002F1.options\u002Findex",[74,76,81,86,91,96,101,106,110,114,119,123,127],{"title":70,"path":71,"stem":72,"description":75},"фундамент: настройки, трейты, компоненты",{"title":77,"path":78,"stem":79,"description":80},"[`\\Shef\\Options\\Installator`] Installer","\u002Fmodules\u002Foptions\u002Finstaller","3.modules\u002F1.options\u002F1.installer","Для облегчения установок.",{"title":82,"path":83,"stem":84,"description":85},"Сборка, CI и релиз","\u002Fmodules\u002Foptions\u002Fbuild-and-install","3.modules\u002F1.options\u002F10.build-and-install","Раскладка репозитория — в module-structure.md, процесс —\nв CONTRIBUTING.md, установка глазами пользователя —\nв README.md.",{"title":87,"path":88,"stem":89,"description":90},"Раскладка репозитория","\u002Fmodules\u002Foptions\u002Fmodule-structure","3.modules\u002F1.options\u002F11.module-structure","Файл про устройство репозитория. Опорные точки модуля — в CLAUDE.md,\nпроцесс — в CONTRIBUTING.md, сборка — в\nbuild-and-install.md.",{"title":92,"path":93,"stem":94,"description":95},"Проверка на портале","\u002Fmodules\u002Foptions\u002Fportal-check","3.modules\u002F1.options\u002F12.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, кеш,\nраскладка файлов, поведение при обновлении. Проверять это приходится руками —\nи лучше по списку, потому что забытый шаг находит не разработчик, а клиент.",{"title":97,"path":98,"stem":99,"description":100},"[`\\Shef\\Options\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Foptions\u002Foptions","3.modules\u002F1.options\u002F2.options","Поддерживает следующие типы:",{"title":102,"path":103,"stem":104,"description":105},"Работа с пользователями","\u002Fmodules\u002Foptions\u002Fsecurity","3.modules\u002F1.options\u002F3.security","",{"title":107,"path":108,"stem":109,"description":105},"[`\\Shef\\Options\\Main\\Utils`] Утилиты","\u002Fmodules\u002Foptions\u002Futils","3.modules\u002F1.options\u002F4.utils",{"title":111,"path":112,"stem":113,"description":105},"[`\\Shef\\Options\\Components`] Работа с компонентами","\u002Fmodules\u002Foptions\u002Fcomponents","3.modules\u002F1.options\u002F5.components",{"title":115,"path":116,"stem":117,"description":118},"[`\\Shef\\Options\\Options`] Паттерны","\u002Fmodules\u002Foptions\u002Fpattern","3.modules\u002F1.options\u002F6.pattern","Запускаемые примеры: singleton.php,\nconfig.php, smartstd.php —\nкак их гонять, написано в examples\u002FREADME.md.",{"title":120,"path":121,"stem":122,"description":105},"[`\\Shef\\Options\\Tests`] Тестирование","\u002Fmodules\u002Foptions\u002Ftests","3.modules\u002F1.options\u002F7.tests",{"title":124,"path":125,"stem":126,"description":105},"[`\\Shef\\Options\\TraitList`] Набор трейтов","\u002Fmodules\u002Foptions\u002Ftraitlist","3.modules\u002F1.options\u002F8.traitlist",{"title":128,"path":129,"stem":130,"description":105},"Правила для ИИ-агентов в этом репозитории","\u002Fmodules\u002Foptions\u002Fagent-rules","3.modules\u002F1.options\u002F9.agent-rules",{"title":132,"description":6,"path":133,"stem":134,"children":135},"shef.problems","\u002Fmodules\u002Fproblems","3.modules\u002F2.problems\u002Findex",[136,138,143,147,152,157,161,166,169,172,175],{"title":132,"path":133,"stem":134,"description":137},"логи, журнал событий, учёт проблем",{"title":139,"path":140,"stem":141,"description":142},"[`\\Shef\\Problems\\Integration`] События и меню","\u002Fmodules\u002Fproblems\u002Fevents","3.modules\u002F2.problems\u002F1.events","Что модуль регистрирует в ядре при установке. Список — в .settings.php, ключ\ninstallEvents; что каждый обработчик существует, сверяет\ntests\u002Fsettings_test.php.",{"title":144,"path":145,"stem":146,"description":105},"Безопасность логов","\u002Fmodules\u002Fproblems\u002Fsecurity","3.modules\u002F2.problems\u002F10.security",{"title":148,"path":149,"stem":150,"description":151},"Быстрая отладка: `_pr`, `_log`, `_log1`","\u002Fmodules\u002Fproblems\u002Fdeffunctions","3.modules\u002F2.problems\u002F2.deffunctions","Функции объявляет def-functions.php, подключается он из include.php.",{"title":153,"path":154,"stem":155,"description":156},"Уровни логирования","\u002Fmodules\u002Fproblems\u002Floglevel","3.modules\u002F2.problems\u002F3.loglevel","Уровни — стандарт PSR-3, в Monolog это \\Monolog\\Level. Ниже — когда какой брать.",{"title":158,"path":159,"stem":160,"description":105},"[`\\Shef\\Problems\\Integration\\Monolog`] Monolog","\u002Fmodules\u002Fproblems\u002Fmonolog","3.modules\u002F2.problems\u002F4.monolog",{"title":162,"path":163,"stem":164,"description":165},"Ротация логов","\u002Fmodules\u002Fproblems\u002Flogrotate","3.modules\u002F2.problems\u002F5.logrotate","Логи модуля лежат в каталоге логов — по умолчанию на уровень выше корня сайта,\nдля BitrixVM \u002Fhome\u002Fbitrix\u002Fsh_log\u002F*.log, — и сами не чистятся. Ротацию делает\nlogrotate — системная утилита, а не Monolog: Monolog тоже умеет\n(RotatingFileHandler), но тогда за файлами следит каждый PHP-процесс, а не\nодна служба.",{"title":128,"path":167,"stem":168,"description":105},"\u002Fmodules\u002Fproblems\u002Fagent-rules","3.modules\u002F2.problems\u002F6.agent-rules",{"title":82,"path":170,"stem":171,"description":85},"\u002Fmodules\u002Fproblems\u002Fbuild-and-install","3.modules\u002F2.problems\u002F7.build-and-install",{"title":87,"path":173,"stem":174,"description":90},"\u002Fmodules\u002Fproblems\u002Fmodule-structure","3.modules\u002F2.problems\u002F8.module-structure",{"title":92,"path":176,"stem":177,"description":178},"\u002Fmodules\u002Fproblems\u002Fportal-check","3.modules\u002F2.problems\u002F9.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, меню,\nраскладка файлов, журнал событий, поведение при обновлении. Проверять это\nприходится руками — и лучше по списку, потому что забытый шаг находит не\nразработчик, а клиент.",{"title":180,"description":6,"path":181,"stem":182,"children":183},"shef.insync","\u002Fmodules\u002Finsync","3.modules\u002F3.insync\u002Findex",[184,186,191,194,198,203,208,213,218,222,227,232,235],{"title":180,"path":181,"stem":182,"description":185},"агенты, импорт, API-клиенты, модели",{"title":187,"path":188,"stem":189,"description":190},"[`\\Shef\\InSync\\Agents`] Агенты","\u002Fmodules\u002Finsync\u002Fagents","3.modules\u002F3.insync\u002F1.agents","Агент импорта — наследник \\Shef\\InSync\\Agents\\AAgent. Описание агента для\nb_agent — \\Shef\\InSync\\Agents\\Entity, установку и управление берёт на себя\n\\Shef\\InSync\\Agents\\Manager.",{"title":87,"path":192,"stem":193,"description":90},"\u002Fmodules\u002Finsync\u002Fmodule-structure","3.modules\u002F3.insync\u002F10.module-structure",{"title":92,"path":195,"stem":196,"description":197},"\u002Fmodules\u002Finsync\u002Fportal-check","3.modules\u002F3.insync\u002F11.portal-check","Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое\nменю, раскладка компонентов, агенты, таблица импорта, поведение при\nобновлении. Проверять это приходится руками — и лучше по списку, потому что\nзабытый шаг находит не разработчик, а клиент.",{"title":199,"path":200,"stem":201,"description":202},"Безопасность","\u002Fmodules\u002Finsync\u002Fsecurity","3.modules\u002F3.insync\u002F12.security","Модуль даёт другим модулям заготовки для синхронизаций, и самые опасные места\nу него общие с ними: кто может запускать агенты и импорт, что ложится в каталоги\nимпорта, что уходит в SQL и в лог. Ниже — что держит модуль и что остаётся\nпроекту.",{"title":204,"path":205,"stem":206,"description":207},"[`\\Shef\\InSync\\Sync`] Импорт","\u002Fmodules\u002Finsync\u002Fimport","3.modules\u002F3.insync\u002F2.import","Импорт идёт в два шага через таблицу импорта \\Shef\\InSync\\Sync\\Model\\SyncTable\n(shef_insync_model):",{"title":209,"path":210,"stem":211,"description":212},"[`\\Shef\\InSync\\Api`] API","\u002Fmodules\u002Finsync\u002Fapi","3.modules\u002F3.insync\u002F3.api","Обращение к внешнему API по HTTP — наследник \\Shef\\InSync\\Api\\AConnector.",{"title":214,"path":215,"stem":216,"description":217},"[`\\Shef\\InSync\\TraitList\\Xml`] Парсинг XML","\u002Fmodules\u002Finsync\u002Fxml","3.modules\u002F3.insync\u002F4.xml","Разбор XML сделан через SbWereWolf\u002Fxml-navigator\n(статья на Хабре): XMLReader идёт по\nдокументу потоком, а каждый элемент с нужным тегом HierarchyComposer\nпревращает в массив — n имя, v значение, a атрибуты, s вложенные\nэлементы.",{"title":219,"path":220,"stem":221,"description":105},"Компоненты","\u002Fmodules\u002Finsync\u002Fcomponents","3.modules\u002F3.insync\u002F5.components",{"title":223,"path":224,"stem":225,"description":226},"Страницы","\u002Fmodules\u002Finsync\u002Fpage","3.modules\u002F3.insync\u002F6.page","Страницы модуля — в левом меню, штатным разделом intranet\n(Bitrix\\Intranet\\CustomSection): раздел «SH Импорт», код shinsync.\nВерхней панели и shef.uiclear больше нет.",{"title":228,"path":229,"stem":230,"description":231},"[`\\Shef\\InSync\\Main\\Options`] Опции настроек модуля","\u002Fmodules\u002Finsync\u002Foptions","3.modules\u002F3.insync\u002F7.options","Опции для страницы настроек модуля импорта (на ShOptionsConfig из\nshef.options): добавьте их во вкладку своего options_conf.php.",{"title":128,"path":233,"stem":234,"description":105},"\u002Fmodules\u002Finsync\u002Fagent-rules","3.modules\u002F3.insync\u002F8.agent-rules",{"title":82,"path":236,"stem":237,"description":85},"\u002Fmodules\u002Finsync\u002Fbuild-and-install","3.modules\u002F3.insync\u002F9.build-and-install",{"id":239,"title":92,"body":240,"description":197,"extension":1616,"meta":1617,"navigation":1618,"path":195,"rawbody":1619,"seo":1620,"stem":196,"__hash__":1621},"docs\u002F3.modules\u002F3.insync\u002F11.portal-check.md",{"type":241,"value":242,"toc":1599},"minimark",[243,246,254,266,271,396,403,407,418,546,550,557,627,634,668,672,705,737,749,753,756,761,795,834,861,868,885,888,918,923,927,984,994,1014,1018,1026,1031,1042,1046,1053,1068,1156,1167,1200,1206,1210,1216,1245,1262,1266,1280,1297,1301,1308,1324,1328,1331,1365,1386,1390,1399,1403,1442,1452,1466,1470,1480,1484,1554,1570,1574,1582,1595],[244,245,197],"p",{},[244,247,248,249,253],{},"Процедура рассчитана на ",[250,251,252],"strong",{},"отдельный стенд",", а не на боевой портал. Шаги\n«удалить модуль» и «поставить на CP1251» на рабочем портале делать нельзя:\nудаление стирает таблицу импорта.",[244,255,256,257,261,262,265],{},"Раскладка репозитория — в ",[258,259,260],"a",{"href":192},"module-structure.md",", сборка —\nв ",[258,263,264],{"href":236},"build-and-install.md",".",[267,268,270],"h2",{"id":269},"что-понадобится","Что понадобится",[272,273,274,285],"table",{},[275,276,277],"thead",{},[278,279,280,283],"tr",{},[281,282],"th",{},[281,284],{},[286,287,288,306,324,334,346,357,369,380],"tbody",{},[278,289,290,294],{},[291,292,293],"td",{},"портал",[291,295,296,297,301,302,305],{},"«коробка» Битрикс24 (для левого меню нужен ",[298,299,300],"code",{},"intranet",") или БУС, главный модуль ",[250,303,304],{},"22.600.300"," и выше",[278,307,308,311],{},[291,309,310],{},"PHP",[291,312,313,316,317,320,321],{},[250,314,315],{},"8.2"," и выше, расширения ",[298,318,319],{},"mbstring"," и ",[298,322,323],{},"xmlreader",[278,325,326,329],{},[291,327,328],{},"кодировка",[291,330,331],{},[250,332,333],{},"только UTF-8",[278,335,336,340],{},[291,337,338],{},[298,339,70],{},[291,341,342,345],{},[250,343,344],{},"3.0.0"," и выше, установлен",[278,347,348,352],{},[291,349,350],{},[298,351,132],{},[291,353,354,345],{},[250,355,356],{},"2.0.0",[278,358,359,362],{},[291,360,361],{},"доступ",[291,363,364,365,368],{},"администратор портала, второй пользователь ",[250,366,367],{},"без"," прав администратора, доступ к файлам по ssh",[278,370,371,374],{},[291,372,373],{},"архив",[291,375,376,377],{},"со страницы релиза либо собранный ",[298,378,379],{},".\u002Fbuild.sh",[278,381,382,385],{},[291,383,384],{},"модуль-импорт",[291,386,387,388,391,392,395],{},"любой модуль с наследником ",[298,389,390],{},"Sync\\FromFile\\AFileProcess"," и страницей ",[298,393,394],{},"shef.insync:import.from.file"," в левом меню — например, shef.demosync",[244,397,398,399,402],{},"Для сценария «обновление» нужен стенд, где уже стоит ",[250,400,401],{},"1.2.x"," — на нём\nпроверяется то, ради чего 2.0.0 сделана мажорной.",[267,404,406],{"id":405},"перед-началом","Перед началом",[244,408,409,410,413,414,417],{},"Снимите копию каталога модуля, настроек, таблицы импорта и компонентов 1.x в\n",[298,411,412],{},"\u002Flocal"," — шаги с удалением необратимы, а установщик удаляет\n",[298,415,416],{},"\u002Flocal\u002Fcomponents\u002Fshef.insync"," без проверки содержимого (в 1.x там мог\nправить проект):",[419,420,424],"pre",{"className":421,"code":422,"language":423,"meta":105,"style":105},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","cp -a \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fmodules\u002Fshef.insync \u002Ftmp\u002Fshef.insync.before 2>\u002Fdev\u002Fnull\ncp -a \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync \u002Ftmp\u002Flocal-components.before 2>\u002Fdev\u002Fnull\nmysqldump -u… portal b_option --where=\"MODULE_ID='shef.insync'\" > \u002Ftmp\u002Fopt.before.sql\nmysqldump -u… portal shef_insync_model > \u002Ftmp\u002Fmodel.before.sql\nls \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002F \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fcomponents\u002F \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fjs\u002F | sort > \u002Ftmp\u002Fpublic.before\n","bash",[298,425,426,453,470,503,520],{"__ignoreMap":105},[427,428,431,435,439,443,446,450],"span",{"class":429,"line":430},"line",1,[427,432,434],{"class":433},"sbgvK","cp",[427,436,438],{"class":437},"stzsN"," -a",[427,440,442],{"class":441},"s_sjI"," \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fmodules\u002Fshef.insync",[427,444,445],{"class":441}," \u002Ftmp\u002Fshef.insync.before",[427,447,449],{"class":448},"smGrS"," 2>",[427,451,452],{"class":441},"\u002Fdev\u002Fnull\n",[427,454,456,458,460,463,466,468],{"class":429,"line":455},2,[427,457,434],{"class":433},[427,459,438],{"class":437},[427,461,462],{"class":441}," \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync",[427,464,465],{"class":441}," \u002Ftmp\u002Flocal-components.before",[427,467,449],{"class":448},[427,469,452],{"class":441},[427,471,473,476,479,482,485,488,492,495,497,500],{"class":429,"line":472},3,[427,474,475],{"class":433},"mysqldump",[427,477,478],{"class":437}," -u…",[427,480,481],{"class":441}," portal",[427,483,484],{"class":441}," b_option",[427,486,487],{"class":437}," --where=",[427,489,491],{"class":490},"sjJ54","\"",[427,493,494],{"class":441},"MODULE_ID='shef.insync'",[427,496,491],{"class":490},[427,498,499],{"class":448}," >",[427,501,502],{"class":441}," \u002Ftmp\u002Fopt.before.sql\n",[427,504,506,508,510,512,515,517],{"class":429,"line":505},4,[427,507,475],{"class":433},[427,509,478],{"class":437},[427,511,481],{"class":441},[427,513,514],{"class":441}," shef_insync_model",[427,516,499],{"class":448},[427,518,519],{"class":441}," \u002Ftmp\u002Fmodel.before.sql\n",[427,521,523,526,529,532,535,538,541,543],{"class":429,"line":522},5,[427,524,525],{"class":433},"ls",[427,527,528],{"class":441}," \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002F",[427,530,531],{"class":441}," \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fcomponents\u002F",[427,533,534],{"class":441}," \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fjs\u002F",[427,536,537],{"class":448}," |",[427,539,540],{"class":433}," sort",[427,542,499],{"class":448},[427,544,545],{"class":441}," \u002Ftmp\u002Fpublic.before\n",[267,547,549],{"id":548},"_0-архив-тот-самый","0. Архив — тот самый",[244,551,552,553,556],{},"Архив собирается ",[250,554,555],{},"побайтово одинаково"," у всех, кто взял тот же коммит:",[419,558,560],{"className":421,"code":559,"language":423,"meta":105,"style":105},"git clone https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Finsync.git\ncd insync && git checkout \u003Cтег проверяемой версии>\n.\u002Fbuild.sh                       # последняя строка напечатает sha256\nsha256sum \u002Fпуть\u002Fк\u002Fскачанному\u002Fshef.insync.zip\n",[298,561,562,573,611,619],{"__ignoreMap":105},[427,563,564,567,570],{"class":429,"line":430},[427,565,566],{"class":433},"git",[427,568,569],{"class":441}," clone",[427,571,572],{"class":441}," https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Finsync.git\n",[427,574,575,579,582,586,589,592,595,598,601,604,608],{"class":429,"line":455},[427,576,578],{"class":577},"sptTA","cd",[427,580,581],{"class":441}," insync",[427,583,585],{"class":584},"sP7_E"," &&",[427,587,588],{"class":433}," git",[427,590,591],{"class":441}," checkout",[427,593,594],{"class":448}," \u003C",[427,596,597],{"class":441},"тег",[427,599,600],{"class":441}," проверяемой",[427,602,603],{"class":441}," верси",[427,605,607],{"class":606},"su5hD","и",[427,609,610],{"class":448},">\n",[427,612,613,615],{"class":429,"line":472},[427,614,379],{"class":433},[427,616,618],{"class":617},"sutJx","                       # последняя строка напечатает sha256\n",[427,620,621,624],{"class":429,"line":505},[427,622,623],{"class":433},"sha256sum",[427,625,626],{"class":441}," \u002Fпуть\u002Fк\u002Fскачанному\u002Fshef.insync.zip\n",[244,628,629,630,633],{},"Хеши обязаны совпасть. Первым уровнем внутри архива — ровно ",[298,631,632],{},"shef.insync\u002F",":",[419,635,637],{"className":421,"code":636,"language":423,"meta":105,"style":105},"unzip -Z1 shef.insync.zip | cut -d\u002F -f1 | sort -u\n",[298,638,639],{"__ignoreMap":105},[427,640,641,644,647,650,652,655,658,661,663,665],{"class":429,"line":430},[427,642,643],{"class":433},"unzip",[427,645,646],{"class":437}," -Z1",[427,648,649],{"class":441}," shef.insync.zip",[427,651,537],{"class":448},[427,653,654],{"class":433}," cut",[427,656,657],{"class":437}," -d\u002F",[427,659,660],{"class":437}," -f1",[427,662,537],{"class":448},[427,664,540],{"class":433},[427,666,667],{"class":437}," -u\n",[267,669,671],{"id":670},"a-чистая-установка","A. Чистая установка",[673,674,675,685,695],"ol",{},[676,677,678,679,681,682,684],"li",{},"Убедиться, что ",[298,680,70],{}," 3.0.0+ и ",[298,683,132],{}," 2.0.0+ стоят.",[676,686,687,688,691,692,265],{},"Распаковать в ",[298,689,690],{},"bitrix\u002Fmodules\u002F",", чтобы получилось ",[298,693,694],{},"bitrix\u002Fmodules\u002Fshef.insync\u002F",[676,696,697,700,701,704],{},[250,698,699],{},"Marketplace → Установленные решения"," → «",[427,702,703],{},"SH"," InSync» → установить.",[244,706,707,710,711,714,715,718,719,722,723,725,726,729,730,733,734,736],{},[250,708,709],{},"Ожидается:"," «Модуль успешно установлен»; появились\n",[298,712,713],{},"\u002Fbitrix\u002Fcomponents\u002Fshef.insync\u002F"," (два компонента) и\n",[298,716,717],{},"\u002Fbitrix\u002Fjs\u002Fshef-insync\u002Fui-anchors\u002F","; в ",[298,720,721],{},"\u002Flocal\u002Fcomponents\u002F"," каталога\n",[298,724,180],{}," ",[250,727,728],{},"нет","; в БД появилась таблица ",[298,731,732],{},"shef_insync_model","; в левом меню\nпоявился раздел «",[427,735,703],{}," Импорт» со страницами «Статистика» и «Записи импорта».",[244,738,739,742,743,745,746,748],{},[250,740,741],{},"Отдельно:"," на стенде без ",[298,744,70],{}," 3.x или без ",[298,747,132],{}," 2.x\nустановка обязана отказать с текстом про модуль и версию — а не поставиться и\nупасть на первой странице.",[267,750,752],{"id":751},"b-обновление-с-12x-главный-сценарий-200","B. Обновление с 1.2.x — главный сценарий 2.0.0",[244,754,755],{},"Делается на стенде, где стоит 1.2.x, есть строки в таблице импорта и хотя бы\nодин агент импорта.",[673,757,758],{},[676,759,760],{},"Запомнить, что было:",[419,762,764],{"className":421,"code":763,"language":423,"meta":105,"style":105},"ls \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F      # в 1.x есть\nmysql -e \"SELECT COUNT(*) FROM shef_insync_model\" portal\n",[298,765,766,776],{"__ignoreMap":105},[427,767,768,770,773],{"class":429,"line":430},[427,769,525],{"class":433},[427,771,772],{"class":441}," \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F",[427,774,775],{"class":617},"      # в 1.x есть\n",[427,777,778,781,784,787,790,792],{"class":429,"line":455},[427,779,780],{"class":433},"mysql",[427,782,783],{"class":437}," -e",[427,785,786],{"class":490}," \"",[427,788,789],{"class":441},"SELECT COUNT(*) FROM shef_insync_model",[427,791,491],{"class":490},[427,793,794],{"class":441}," portal\n",[673,796,797,815,824],{"start":455},[676,798,799,802,803,806,807,810,811,814],{},[250,800,801],{},"Выключить агенты импорта"," (",[298,804,805],{},"\u002Fbitrix\u002Fadmin\u002Fagent_list.php",", модули\nимпорта) и дождаться, пока текущий запуск закончится. Модели 2.0.0 знают\nколонку ",[298,808,809],{},"ID",", которой в таблице 1.x нет: между заменой файлов и\n",[298,812,813],{},"SyncTable::init()"," каждый запрос агента к таблице упадёт.",[676,816,817,818,820,821,823],{},"Обновить ",[298,819,70],{}," до 3.x и ",[298,822,132],{}," до 2.x.",[676,825,826,827,830,831,833],{},"Заменить файлы модуля содержимым архива 2.0.0. ",[250,828,829],{},"Замена файлов не запускает\nустановщик",": компоненты 1.x в ",[298,832,416],{}," останутся и\nперекроют новые. Разложите файлы установщиком, не удаляя модуль (удаление\nстёрло бы таблицу импорта) — в «Командной PHP-строке» администратора:",[419,835,839],{"className":836,"code":837,"language":838,"meta":105,"style":105},"language-php shiki shiki-themes material-theme-lighter github-light github-dark","require $_SERVER['DOCUMENT_ROOT'].'\u002Fbitrix\u002Fmodules\u002Fshef.insync\u002Finstall\u002Findex.php';\n(new shef_insync())->InstallFiles();\n\\Bitrix\\Main\\Loader::includeModule('shef.insync');\n\\Shef\\InSync\\Sync\\Model\\SyncTable::init();   \u002F\u002F ключ таблицы 1.x -> 2.x\n","php",[298,840,841,846,851,856],{"__ignoreMap":105},[427,842,843],{"class":429,"line":430},[427,844,845],{},"require $_SERVER['DOCUMENT_ROOT'].'\u002Fbitrix\u002Fmodules\u002Fshef.insync\u002Finstall\u002Findex.php';\n",[427,847,848],{"class":429,"line":455},[427,849,850],{},"(new shef_insync())->InstallFiles();\n",[427,852,853],{"class":429,"line":472},[427,854,855],{},"\\Bitrix\\Main\\Loader::includeModule('shef.insync');\n",[427,857,858],{"class":429,"line":505},[427,859,860],{},"\\Shef\\InSync\\Sync\\Model\\SyncTable::init();   \u002F\u002F ключ таблицы 1.x -> 2.x\n",[244,862,863,864,867],{},"До перевода проверьте, что внешние коды не совпадают в первых 191 символе —\nиначе уникальный индекс не встанет и ",[298,865,866],{},"init()"," откажет (строки не тронет):",[419,869,873],{"className":870,"code":871,"language":872,"meta":105,"style":105},"language-sql shiki shiki-themes material-theme-lighter github-light github-dark","SELECT ORIGINATOR_ID, LEFT(ORIGIN_ID, 191) AS K, COUNT(*) FROM shef_insync_model\nGROUP BY ORIGINATOR_ID, K HAVING COUNT(*) > 1;\n","sql",[298,874,875,880],{"__ignoreMap":105},[427,876,877],{"class":429,"line":430},[427,878,879],{},"SELECT ORIGINATOR_ID, LEFT(ORIGIN_ID, 191) AS K, COUNT(*) FROM shef_insync_model\n",[427,881,882],{"class":429,"line":455},[427,883,884],{},"GROUP BY ORIGINATOR_ID, K HAVING COUNT(*) > 1;\n",[244,886,887],{},"Пусто — переводите. Нет — лишние строки (обычно давно упавшие) удалить или\nразобрать до перевода.",[244,889,890,892,893,895,896,899,900,899,903,906,907,910,911,914,915,917],{},[298,891,866],{}," переводит таблицу импорта 1.x на ключ 2.x: первичный ключ — новая\nколонка ",[298,894,809],{},", внешний код уникален в пределах кода импорта, индексы 1.x\n(",[298,897,898],{},"_origs",", ",[298,901,902],{},"_orig_id",[298,904,905],{},"_originator_id",") снимаются. Строки остаются;\nповторный вызов ничего не делает. Перевод — один ",[298,908,909],{},"ALTER TABLE",", MySQL\nперестраивает таблицу и на это время не пускает запись: большую таблицу\n(",[298,912,913],{},"SELECT COUNT(*)"," из п. 1) переводите в окно без импорта. Ключ таблицы не\n1.x и не 2.x — ",[298,916,866],{}," отказывает и ничего не меняет.",[673,919,920],{"start":522},[676,921,922],{},"Включить агенты импорта обратно.",[244,924,925],{},[250,926,709],{},[928,929,930,939,945,965,968,971],"ul",{},[676,931,932,935,936,938],{},[298,933,934],{},"\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F"," удалён, ",[298,937,713],{}," на месте;",[676,940,941,942,944],{},"число строк в ",[298,943,732],{}," то же;",[676,946,947,950,951,954,955,957,958,954,961,964],{},[298,948,949],{},"SHOW KEYS FROM shef_insync_model"," — ровно два ключа: ",[298,952,953],{},"PRIMARY"," на ",[298,956,809],{}," и\nуникальный ",[298,959,960],{},"shef_insync_model_origin",[298,962,963],{},"ORIGINATOR_ID, ORIGIN_ID",";\nиндексы, которые проект завёл на таблице сам, — на месте;",[676,966,967],{},"страница «Статистика» открывается администратору, грид и список агентов на\nместе, кнопки агентов работают (см. D);",[676,969,970],{},"страница настроек модуля открывается (см. C) — в 1.x она падала бы на\nshef.options 3.x с «Unknown named parameter»;",[676,972,973,974,899,977,980,981,265],{},"в журнале PHP нет ",[298,975,976],{},"Undefined array key",[298,978,979],{},"Class \"Shef\\UiClear\\...\" not found",",\n",[298,982,983],{},"Call to undefined function _showError()",[673,985,987],{"start":986},6,[676,988,989,990,993],{},"Перенести каталог импорта за корень сайта и перенастроить обмены — по\n",[258,991,992],{"href":200},"security.md",", «После обновления с 1.x».",[244,995,996,998,999,1002,1003,980,1006,1009,1010,1013],{},[250,997,709],{}," файлы из ",[298,1000,1001],{},"\u002Fupload\u002Fimport\u002F"," лежат в ",[298,1004,1005],{},"\u003Cкаталог импорта>\u002F",[298,1007,1008],{},"\u002Fupload\u002Fimport"," удалён, обмен кладёт новый файл в ",[298,1011,1012],{},"\u003Cкаталог импорта>\u002F\u003Cкод>\u002F",",\nагент его забирает.",[267,1015,1017],{"id":1016},"c-страница-настроек","C. Страница настроек",[244,1019,1020],{},[250,1021,1022,1023,1025],{},"Настройки → Настройки модулей → ",[427,1024,703],{}," InSync.",[244,1027,1028,1030],{},[250,1029,709],{}," вкладка «Общие», в ней «Сколько дней хранится файл в результате\nимпорта» со значениями 1, 2, 3, 5, 15, 30; по умолчанию — 3. Сохранить 15 —\nзначение сохранилось.",[244,1032,1033,1034,1037,1038,1041],{},"Если модуль-импорт выводит на своей странице настроек опции\n",[298,1035,1036],{},"Options\\Agent\\Option"," или ",[298,1039,1040],{},"Options\\Import\\FromFile\\Option",": у администратора\nкнопки запуска\u002Fостановки агента и импорта работают; у пользователя с правом\n«Чтение» на тот модуль кнопки агента не видны.",[267,1043,1045],{"id":1044},"d-права-на-страницах-и-в-ajax","D. Права на страницах и в ajax",[244,1047,1048,1049,1052],{},"Под ",[250,1050,1051],{},"пользователем без прав"," (не администратор, прав на модули нет):",[673,1054,1055,1065],{},[676,1056,1057,1058,1060,1061,1064],{},"Раздел «",[427,1059,703],{}," Импорт» в левом меню — страниц модуля не видно; прямой адрес\n",[298,1062,1063],{},"\u002Fpage\u002Fshinsync\u002Fstatimportlocal\u002F"," — «Недостаточно прав».",[676,1066,1067],{},"Прямой вызов действия из консоли браузера на любой странице портала:",[419,1069,1073],{"className":1070,"code":1071,"language":1072,"meta":105,"style":105},"language-js shiki shiki-themes material-theme-lighter github-light github-dark","BX.ajax.runComponentAction('shef.insync:import.stat.local', 'stopAgent', {mode: 'class', data: {id: 1}})\n","js",[298,1074,1075],{"__ignoreMap":105},[427,1076,1077,1081,1083,1086,1088,1092,1095,1098,1101,1103,1106,1109,1112,1114,1116,1119,1123,1125,1127,1130,1132,1134,1137,1139,1141,1144,1146,1150,1153],{"class":429,"line":430},[427,1078,1080],{"class":1079},"s_hVV","BX",[427,1082,265],{"class":584},[427,1084,1085],{"class":606},"ajax",[427,1087,265],{"class":584},[427,1089,1091],{"class":1090},"sGLFI","runComponentAction",[427,1093,1094],{"class":606},"(",[427,1096,1097],{"class":490},"'",[427,1099,1100],{"class":441},"shef.insync:import.stat.local",[427,1102,1097],{"class":490},[427,1104,1105],{"class":584},",",[427,1107,1108],{"class":490}," '",[427,1110,1111],{"class":441},"stopAgent",[427,1113,1097],{"class":490},[427,1115,1105],{"class":584},[427,1117,1118],{"class":584}," {",[427,1120,1122],{"class":1121},"skxfh","mode",[427,1124,633],{"class":584},[427,1126,1108],{"class":490},[427,1128,1129],{"class":441},"class",[427,1131,1097],{"class":490},[427,1133,1105],{"class":584},[427,1135,1136],{"class":1121}," data",[427,1138,633],{"class":584},[427,1140,1118],{"class":584},[427,1142,1143],{"class":1121},"id",[427,1145,633],{"class":584},[427,1147,1149],{"class":1148},"srdBf"," 1",[427,1151,1152],{"class":584},"}}",[427,1154,1155],{"class":606},")\n",[244,1157,1158,1160,1161,1164,1165,265],{},[250,1159,709],{}," ошибка, агент с ID 1 (агент ядра) ",[250,1162,1163],{},"не"," выключен —\nпроверить на ",[298,1166,805],{},[673,1168,1169,1187],{"start":472},[676,1170,1171,1172,1175,1176,1179,1180,802,1183,1186],{},"То же для контроллера страницы настроек: скопировать под администратором\nадрес кнопки агента (",[298,1173,1174],{},"\u002Fbitrix\u002Fservices\u002Fmain\u002Fajax.php?action=…stopAgent&…","),\nоткрыть его под пользователем без прав, подставив ",[298,1177,1178],{},"agentId=1&moduleId=main","\nи его ",[298,1181,1182],{},"sessid",[298,1184,1185],{},"BX.bitrix_sessid()",") — ошибка, агент не тронут.",[676,1188,1189,1190,1193,1194,320,1196,1199],{},"Пользователю дать «Запись» на ",[298,1191,1192],{},"sale"," (или другой модуль ядра со своими\nагентами), повторить п. 3 с ID агента ",[298,1195,1192],{},[298,1197,1198],{},"moduleId=sale"," — ошибка\n«Agent not found», агент не тронут: модуль трогает только агенты импорта.",[244,1201,1048,1202,1205],{},[250,1203,1204],{},"администратором:"," страница статистики открывается, агент модуля-импорта\nвыключается и включается кнопкой, «Очистить» у строки грида удаляет только\nстроки этой загрузки.",[267,1207,1209],{"id":1208},"e-импорт-файла","E. Импорт файла",[244,1211,1212,1213,1215],{},"На странице импорта из файла модуля-импорта (левое меню «",[427,1214,703],{}," Импорт»):",[673,1217,1218,1221,1224,1234],{},[676,1219,1220],{},"«Скачать пример» — скачивается файл-пример.",[676,1222,1223],{},"Загрузить этот пример — «Загрузка произведена», статистика по строкам.",[676,1225,1226,1227,1230,1231,1233],{},"Загрузить файл ",[298,1228,1229],{},"test.php"," (переименуйте любой текстовый) — отказ «Wrong\nfile type», в ",[298,1232,1012],{}," файла нет.",[676,1235,1236,1237,1240,1241,1244],{},"Файл, в строках которого есть ",[298,1238,1239],{},"\u003Cb>жирный\u003C\u002Fb>"," и ошибка разбора, — в блоке\nошибок текст виден ",[250,1242,1243],{},"как текст",", а не жирным.",[244,1246,1247,1249,1250,1253,1254,1257,1258,1261],{},[250,1248,709],{}," каталог импорта — вне корня сайта (",[298,1251,1252],{},"\u002Fhome\u002Fbitrix\u002Fsh_import"," на\nBitrixVM, если не задан свой); в ",[298,1255,1256],{},"\u003Cкаталог импорта>\u002Fcopy\u002F\u003Cкод>\u002F"," архив с именем\n",[298,1259,1260],{},"done_\u003Cкод>_\u003Cдата>_\u003C16 символов>.\u003Cрасш>"," — хвост случайный.",[267,1263,1265],{"id":1264},"f-откуда-взяты-библиотеки-xml","F. Откуда взяты библиотеки XML",[419,1267,1269],{"className":836,"code":1268,"language":838,"meta":105,"style":105},"\\Bitrix\\Main\\Loader::includeModule('shef.insync');\necho (new ReflectionClass(\\SbWereWolf\\XmlNavigator\\Extraction\\HierarchyComposer::class))->getFileName();\n",[298,1270,1271,1275],{"__ignoreMap":105},[427,1272,1273],{"class":429,"line":430},[427,1274,855],{},[427,1276,1277],{"class":429,"line":455},[427,1278,1279],{},"echo (new ReflectionClass(\\SbWereWolf\\XmlNavigator\\Extraction\\HierarchyComposer::class))->getFileName();\n",[244,1281,1282,1284,1285,1288,1289,1292,1293,1296],{},[250,1283,709],{}," проект без Composer — путь в ",[298,1286,1287],{},"…\u002Fshef.insync\u002Fvendor\u002Fsbwerewolf\u002F…",";\nпроект с Composer, где стоит ",[298,1290,1291],{},"sbwerewolf\u002Fxml-navigator",", — путь в vendor\nпроекта. Во втором случае версия там обязана быть ",[298,1294,1295],{},"7.2.x",": ветки 8+ требуют\nPHP 8.4 и разбирают XML в тот же формат, но модуль на них не проверялся.",[267,1298,1300],{"id":1299},"g-агент-импорта","G. Агент импорта",[244,1302,1303,1304,1307],{},"Агент модуля-импорта (наследник ",[298,1305,1306],{},"Sync\\FromFile\\AAgent",") после загрузки файла:",[244,1309,1310,1312,1313,1315,1316,1319,1320,1323],{},[250,1311,709],{}," строки из ",[298,1314,732],{}," уходят пачками, успешные\nудаляются, ошибочные остаются со статусом ",[298,1317,1318],{},"F"," и сообщением; в журнале событий\nпроблемы с типом ",[298,1321,1322],{},"SH_PROBLEMS_SYNC","; страница статистики обновляется сама\n(pull), без ошибок в консоли браузера.",[267,1325,1327],{"id":1326},"g2-драйверы-каталога","G2. Драйверы каталога",[244,1329,1330],{},"Из PHP-консоли на товаре торгового каталога (ID и тип цены — свои):",[419,1332,1334],{"className":836,"code":1333,"language":838,"meta":105,"style":105},"\\Bitrix\\Main\\Loader::includeModule('shef.insync');\n$price = new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Price();\nvar_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 10, 'CURRENCY' => 'BYN'])->isSuccess());\nvar_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 12.5, 'CURRENCY' => 'BYN'])->isSuccess());\nvar_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Product())->save(['ID' => 1], ['WEIGHT' => 250])->isSuccess());\nvar_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Amount())->save(['PRODUCT_ID' => 1], ['STORE_ID' => 1, 'AMOUNT' => 7])->isSuccess());\n",[298,1335,1336,1340,1345,1350,1355,1360],{"__ignoreMap":105},[427,1337,1338],{"class":429,"line":430},[427,1339,855],{},[427,1341,1342],{"class":429,"line":455},[427,1343,1344],{},"$price = new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Price();\n",[427,1346,1347],{"class":429,"line":472},[427,1348,1349],{},"var_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 10, 'CURRENCY' => 'BYN'])->isSuccess());\n",[427,1351,1352],{"class":429,"line":505},[427,1353,1354],{},"var_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 12.5, 'CURRENCY' => 'BYN'])->isSuccess());\n",[427,1356,1357],{"class":429,"line":522},[427,1358,1359],{},"var_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Product())->save(['ID' => 1], ['WEIGHT' => 250])->isSuccess());\n",[427,1361,1362],{"class":429,"line":986},[427,1363,1364],{},"var_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Amount())->save(['PRODUCT_ID' => 1], ['STORE_ID' => 1, 'AMOUNT' => 7])->isSuccess());\n",[244,1366,1367,1369,1370,1373,1374,1377,1378,1381,1382,1385],{},[250,1368,709],{}," четыре ",[298,1371,1372],{},"true",", ни одного ",[298,1375,1376],{},"Warning","; у товара ",[250,1379,1380],{},"одна"," цена\nэтого типа — 12.50, ",[298,1383,1384],{},"PRICE_SCALE"," заполнен; вес 250; остаток на складе 1 — 7\n(при включённом складском учёте ядро остаток так не примет — это верно).",[267,1387,1389],{"id":1388},"h-удаление","H. Удаление",[673,1391,1392],{},[676,1393,1394,700,1396,1398],{},[250,1395,699],{},[427,1397,703],{}," InSync» → удалить.",[244,1400,1401],{},[250,1402,709],{},[928,1404,1405,1416,1429,1435],{},[676,1406,1407,899,1409,1412,1413,1415],{},[298,1408,713],{},[298,1410,1411],{},"\u002Fbitrix\u002Fjs\u002Fshef-insync\u002F"," и\n",[298,1414,934],{}," (если был) удалены, чужие компоненты на месте;",[676,1417,1418,1419,1421,1422,1425,1426,1428],{},"таблицы ",[298,1420,732],{}," нет, настроек модуля в ",[298,1423,1424],{},"b_option"," нет,\nнастройки ",[298,1427,70],{}," — на месте;",[676,1430,1431,1432,1434],{},"раздел «",[427,1433,703],{}," Импорт» из левого меню ушёл;",[676,1436,1437,1438,1441],{},"файлы в каталоге импорта ",[250,1439,1440],{},"остались",": это данные проекта.",[244,1443,1444,1445,1448,1449,265],{},"Формы «сохранить данные?» у модуля нет: удаление из админки стирает таблицу\nимпорта всегда. Оставить данные — только из PHP-консоли:\n",[298,1446,1447],{},"(new shef_insync())->UnInstallDB(['savedata' => 'Y'])"," после подключения\n",[298,1450,1451],{},"\u002Fbitrix\u002Fmodules\u002Fshef.insync\u002Finstall\u002Findex.php",[244,1453,1454,1455,1458,1459,1461,1462,1465],{},"Если модуль зависит от других (",[298,1456,1457],{},"shef.*"," с ",[298,1460,180],{}," в ",[298,1463,1464],{},"requireModules","),\nудаление обязано отказать и назвать их.",[267,1467,1469],{"id":1468},"i-портал-в-cp1251","I. Портал в CP1251",[244,1471,1472,1473,1476,1477,1479],{},"Установка обязана отказать с текстом про UTF-8. На современных ядрах ветка\nнедостижима — ",[298,1474,1475],{},"Application::isUtfMode()"," возвращает ",[298,1478,1372],{}," без условий, — тогда\nв бланке отмечается «пропущено», и это верный ответ.",[267,1481,1483],{"id":1482},"j-примеры-на-живом-ядре","J. Примеры на живом ядре",[419,1485,1487],{"className":421,"code":1486,"language":423,"meta":105,"style":105},"for e in agent xml; do DOCUMENT_ROOT=\u002Fvar\u002Fwww\u002Fportal php examples\u002F$e.php || echo \"FAIL $e\"; done\n",[298,1488,1489],{"__ignoreMap":105},[427,1490,1491,1495,1498,1501,1504,1507,1510,1513,1516,1519,1522,1525,1528,1531,1534,1537,1540,1542,1545,1547,1549,1551],{"class":429,"line":430},[427,1492,1494],{"class":1493},"sVHd0","for",[427,1496,1497],{"class":606}," e ",[427,1499,1500],{"class":1493},"in",[427,1502,1503],{"class":441}," agent",[427,1505,1506],{"class":441}," xml",[427,1508,1509],{"class":584},";",[427,1511,1512],{"class":1493}," do",[427,1514,1515],{"class":606}," DOCUMENT_ROOT",[427,1517,1518],{"class":448},"=",[427,1520,1521],{"class":441},"\u002Fvar\u002Fwww\u002Fportal",[427,1523,1524],{"class":433}," php",[427,1526,1527],{"class":441}," examples\u002F",[427,1529,1530],{"class":606},"$e",[427,1532,1533],{"class":441},".php",[427,1535,1536],{"class":448}," ||",[427,1538,1539],{"class":577}," echo",[427,1541,786],{"class":490},[427,1543,1544],{"class":441},"FAIL ",[427,1546,1530],{"class":606},[427,1548,491],{"class":490},[427,1550,1509],{"class":584},[427,1552,1553],{"class":1493}," done\n",[244,1555,1556,1558,1559,1373,1562,899,1565,980,1567,265],{},[250,1557,709],{}," два раза ",[298,1560,1561],{},"ГОТОВО: …",[298,1563,1564],{},"FAIL",[298,1566,1376],{},[298,1568,1569],{},"Deprecated",[267,1571,1573],{"id":1572},"бланк-результата","Бланк результата",[419,1575,1580],{"className":1576,"code":1578,"language":1579},[1577],"language-text","Версия: ____  Коммит: ____  sha256 архива сошёлся: да \u002F нет\nЯдро main: ____  PHP: ____  shef.options: ____  shef.problems: ____\nComposer в проекте: да \u002F нет   intranet: да \u002F нет\n\n0. Архив .................................. ок \u002F не ок\nA. Чистая установка ....................... ок \u002F не ок\n   без shef.options 3 \u002F shef.problems 2 — отказ .. ок \u002F не ок\nB. Обновление с 1.2.x ..................... ок \u002F не ок \u002F нет стенда\nC. Страница настроек ...................... ок \u002F не ок\nD. Права: без прав — отказ ................ ок \u002F не ок\n   агент ядра не тронут ................... ок \u002F не ок\n   «W» на sale — агенты sale не тронуты ... ок \u002F не ок\nE. Импорт файла ........................... ок \u002F не ок\n   .php отклонён .......................... ок \u002F не ок\nF. Библиотеки XML взяты из ................ модуль \u002F Composer\nG. Агент импорта .......................... ок \u002F не ок\nG2. Драйверы каталога ..................... ок \u002F не ок\nH. Удаление ............................... ок \u002F не ок\nI. CP1251 ................................. ок \u002F пропущено\nJ. Примеры на живом ядре .................. ок \u002F не ок\n\nЗамечания:\n","text",[298,1581,1578],{"__ignoreMap":105},[1583,1584,1585],"note",{},[244,1586,1587,1588,1594],{},"Источник: ",[258,1589,1593],{"href":1590,"rel":1591},"https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Finsync\u002Fblob\u002Fmain\u002Fdocs\u002Fportal-check.md",[1592],"nofollow","insync\u002Fdocs\u002Fportal-check.md"," — правки туда, сайт пересобирается сам.",[1596,1597,1598],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":105,"searchDepth":472,"depth":472,"links":1600},[1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615],{"id":269,"depth":455,"text":270},{"id":405,"depth":455,"text":406},{"id":548,"depth":455,"text":549},{"id":670,"depth":455,"text":671},{"id":751,"depth":455,"text":752},{"id":1016,"depth":455,"text":1017},{"id":1044,"depth":455,"text":1045},{"id":1208,"depth":455,"text":1209},{"id":1264,"depth":455,"text":1265},{"id":1299,"depth":455,"text":1300},{"id":1326,"depth":455,"text":1327},{"id":1388,"depth":455,"text":1389},{"id":1468,"depth":455,"text":1469},{"id":1482,"depth":455,"text":1483},{"id":1572,"depth":455,"text":1573},"md",{},true,"---\ntitle: \"Проверка на портале\"\n---\n\nВсё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое\nменю, раскладка компонентов, агенты, таблица импорта, поведение при\nобновлении. Проверять это приходится руками — и лучше по списку, потому что\nзабытый шаг находит не разработчик, а клиент.\n\nПроцедура рассчитана на **отдельный стенд**, а не на боевой портал. Шаги\n«удалить модуль» и «поставить на CP1251» на рабочем портале делать нельзя:\nудаление стирает таблицу импорта.\n\nРаскладка репозитория — в [module-structure.md](\u002Fmodules\u002Finsync\u002Fmodule-structure), сборка —\nв [build-and-install.md](\u002Fmodules\u002Finsync\u002Fbuild-and-install).\n\n## Что понадобится\n\n| | |\n|---|---|\n| портал | «коробка» Битрикс24 (для левого меню нужен `intranet`) или БУС, главный модуль **22.600.300** и выше |\n| PHP | **8.2** и выше, расширения `mbstring` и `xmlreader` |\n| кодировка | **только UTF-8** |\n| `shef.options` | **3.0.0** и выше, установлен |\n| `shef.problems` | **2.0.0** и выше, установлен |\n| доступ | администратор портала, второй пользователь **без** прав администратора, доступ к файлам по ssh |\n| архив | со страницы релиза либо собранный `.\u002Fbuild.sh` |\n| модуль-импорт | любой модуль с наследником `Sync\\FromFile\\AFileProcess` и страницей `shef.insync:import.from.file` в левом меню — например, shef.demosync |\n\nДля сценария «обновление» нужен стенд, где уже стоит **1.2.x** — на нём\nпроверяется то, ради чего 2.0.0 сделана мажорной.\n\n## Перед началом\n\nСнимите копию каталога модуля, настроек, таблицы импорта и компонентов 1.x в\n`\u002Flocal` — шаги с удалением необратимы, а установщик удаляет\n`\u002Flocal\u002Fcomponents\u002Fshef.insync` без проверки содержимого (в 1.x там мог\nправить проект):\n\n```bash\ncp -a \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fmodules\u002Fshef.insync \u002Ftmp\u002Fshef.insync.before 2>\u002Fdev\u002Fnull\ncp -a \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync \u002Ftmp\u002Flocal-components.before 2>\u002Fdev\u002Fnull\nmysqldump -u… portal b_option --where=\"MODULE_ID='shef.insync'\" > \u002Ftmp\u002Fopt.before.sql\nmysqldump -u… portal shef_insync_model > \u002Ftmp\u002Fmodel.before.sql\nls \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002F \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fcomponents\u002F \u002Fvar\u002Fwww\u002Fportal\u002Fbitrix\u002Fjs\u002F | sort > \u002Ftmp\u002Fpublic.before\n```\n\n## 0. Архив — тот самый\n\nАрхив собирается **побайтово одинаково** у всех, кто взял тот же коммит:\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Finsync.git\ncd insync && git checkout \u003Cтег проверяемой версии>\n.\u002Fbuild.sh                       # последняя строка напечатает sha256\nsha256sum \u002Fпуть\u002Fк\u002Fскачанному\u002Fshef.insync.zip\n```\n\nХеши обязаны совпасть. Первым уровнем внутри архива — ровно `shef.insync\u002F`:\n\n```bash\nunzip -Z1 shef.insync.zip | cut -d\u002F -f1 | sort -u\n```\n\n## A. Чистая установка\n\n1. Убедиться, что `shef.options` 3.0.0+ и `shef.problems` 2.0.0+ стоят.\n2. Распаковать в `bitrix\u002Fmodules\u002F`, чтобы получилось `bitrix\u002Fmodules\u002Fshef.insync\u002F`.\n3. **Marketplace → Установленные решения** → «[SH] InSync» → установить.\n\n**Ожидается:** «Модуль успешно установлен»; появились\n`\u002Fbitrix\u002Fcomponents\u002Fshef.insync\u002F` (два компонента) и\n`\u002Fbitrix\u002Fjs\u002Fshef-insync\u002Fui-anchors\u002F`; в `\u002Flocal\u002Fcomponents\u002F` каталога\n`shef.insync` **нет**; в БД появилась таблица `shef_insync_model`; в левом меню\nпоявился раздел «[SH] Импорт» со страницами «Статистика» и «Записи импорта».\n\n**Отдельно:** на стенде без `shef.options` 3.x или без `shef.problems` 2.x\nустановка обязана отказать с текстом про модуль и версию — а не поставиться и\nупасть на первой странице.\n\n## B. Обновление с 1.2.x — главный сценарий 2.0.0\n\nДелается на стенде, где стоит 1.2.x, есть строки в таблице импорта и хотя бы\nодин агент импорта.\n\n1. Запомнить, что было:\n\n```bash\nls \u002Fvar\u002Fwww\u002Fportal\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F      # в 1.x есть\nmysql -e \"SELECT COUNT(*) FROM shef_insync_model\" portal\n```\n\n2. **Выключить агенты импорта** (`\u002Fbitrix\u002Fadmin\u002Fagent_list.php`, модули\n   импорта) и дождаться, пока текущий запуск закончится. Модели 2.0.0 знают\n   колонку `ID`, которой в таблице 1.x нет: между заменой файлов и\n   `SyncTable::init()` каждый запрос агента к таблице упадёт.\n3. Обновить `shef.options` до 3.x и `shef.problems` до 2.x.\n4. Заменить файлы модуля содержимым архива 2.0.0. **Замена файлов не запускает\n   установщик**: компоненты 1.x в `\u002Flocal\u002Fcomponents\u002Fshef.insync` останутся и\n   перекроют новые. Разложите файлы установщиком, не удаляя модуль (удаление\n   стёрло бы таблицу импорта) — в «Командной PHP-строке» администратора:\n\n```php\nrequire $_SERVER['DOCUMENT_ROOT'].'\u002Fbitrix\u002Fmodules\u002Fshef.insync\u002Finstall\u002Findex.php';\n(new shef_insync())->InstallFiles();\n\\Bitrix\\Main\\Loader::includeModule('shef.insync');\n\\Shef\\InSync\\Sync\\Model\\SyncTable::init();   \u002F\u002F ключ таблицы 1.x -> 2.x\n```\n\nДо перевода проверьте, что внешние коды не совпадают в первых 191 символе —\nиначе уникальный индекс не встанет и `init()` откажет (строки не тронет):\n\n```sql\nSELECT ORIGINATOR_ID, LEFT(ORIGIN_ID, 191) AS K, COUNT(*) FROM shef_insync_model\nGROUP BY ORIGINATOR_ID, K HAVING COUNT(*) > 1;\n```\n\nПусто — переводите. Нет — лишние строки (обычно давно упавшие) удалить или\nразобрать до перевода.\n\n`init()` переводит таблицу импорта 1.x на ключ 2.x: первичный ключ — новая\nколонка `ID`, внешний код уникален в пределах кода импорта, индексы 1.x\n(`_origs`, `_orig_id`, `_originator_id`) снимаются. Строки остаются;\nповторный вызов ничего не делает. Перевод — один `ALTER TABLE`, MySQL\nперестраивает таблицу и на это время не пускает запись: большую таблицу\n(`SELECT COUNT(*)` из п. 1) переводите в окно без импорта. Ключ таблицы не\n1.x и не 2.x — `init()` отказывает и ничего не меняет.\n\n5. Включить агенты импорта обратно.\n\n**Ожидается:**\n\n* `\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F` удалён, `\u002Fbitrix\u002Fcomponents\u002Fshef.insync\u002F` на месте;\n* число строк в `shef_insync_model` то же;\n* `SHOW KEYS FROM shef_insync_model` — ровно два ключа: `PRIMARY` на `ID` и\n  уникальный `shef_insync_model_origin` на `ORIGINATOR_ID, ORIGIN_ID`;\n  индексы, которые проект завёл на таблице сам, — на месте;\n* страница «Статистика» открывается администратору, грид и список агентов на\n  месте, кнопки агентов работают (см. D);\n* страница настроек модуля открывается (см. C) — в 1.x она падала бы на\n  shef.options 3.x с «Unknown named parameter»;\n* в журнале PHP нет `Undefined array key`, `Class \"Shef\\UiClear\\...\" not found`,\n  `Call to undefined function _showError()`.\n\n6. Перенести каталог импорта за корень сайта и перенастроить обмены — по\n   [security.md](\u002Fmodules\u002Finsync\u002Fsecurity), «После обновления с 1.x».\n\n**Ожидается:** файлы из `\u002Fupload\u002Fimport\u002F` лежат в `\u003Cкаталог импорта>\u002F`,\n`\u002Fupload\u002Fimport` удалён, обмен кладёт новый файл в `\u003Cкаталог импорта>\u002F\u003Cкод>\u002F`,\nагент его забирает.\n\n## C. Страница настроек\n\n**Настройки → Настройки модулей → [SH] InSync.**\n\n**Ожидается:** вкладка «Общие», в ней «Сколько дней хранится файл в результате\nимпорта» со значениями 1, 2, 3, 5, 15, 30; по умолчанию — 3. Сохранить 15 —\nзначение сохранилось.\n\nЕсли модуль-импорт выводит на своей странице настроек опции\n`Options\\Agent\\Option` или `Options\\Import\\FromFile\\Option`: у администратора\nкнопки запуска\u002Fостановки агента и импорта работают; у пользователя с правом\n«Чтение» на тот модуль кнопки агента не видны.\n\n## D. Права на страницах и в ajax\n\nПод **пользователем без прав** (не администратор, прав на модули нет):\n\n1. Раздел «[SH] Импорт» в левом меню — страниц модуля не видно; прямой адрес\n   `\u002Fpage\u002Fshinsync\u002Fstatimportlocal\u002F` — «Недостаточно прав».\n2. Прямой вызов действия из консоли браузера на любой странице портала:\n\n```js\nBX.ajax.runComponentAction('shef.insync:import.stat.local', 'stopAgent', {mode: 'class', data: {id: 1}})\n```\n\n**Ожидается:** ошибка, агент с ID 1 (агент ядра) **не** выключен —\nпроверить на `\u002Fbitrix\u002Fadmin\u002Fagent_list.php`.\n\n3. То же для контроллера страницы настроек: скопировать под администратором\n   адрес кнопки агента (`\u002Fbitrix\u002Fservices\u002Fmain\u002Fajax.php?action=…stopAgent&…`),\n   открыть его под пользователем без прав, подставив `agentId=1&moduleId=main`\n   и его `sessid` (`BX.bitrix_sessid()`) — ошибка, агент не тронут.\n4. Пользователю дать «Запись» на `sale` (или другой модуль ядра со своими\n   агентами), повторить п. 3 с ID агента `sale` и `moduleId=sale` — ошибка\n   «Agent not found», агент не тронут: модуль трогает только агенты импорта.\n\nПод **администратором:** страница статистики открывается, агент модуля-импорта\nвыключается и включается кнопкой, «Очистить» у строки грида удаляет только\nстроки этой загрузки.\n\n## E. Импорт файла\n\nНа странице импорта из файла модуля-импорта (левое меню «[SH] Импорт»):\n\n1. «Скачать пример» — скачивается файл-пример.\n2. Загрузить этот пример — «Загрузка произведена», статистика по строкам.\n3. Загрузить файл `test.php` (переименуйте любой текстовый) — отказ «Wrong\n   file type», в `\u003Cкаталог импорта>\u002F\u003Cкод>\u002F` файла нет.\n4. Файл, в строках которого есть `\u003Cb>жирный\u003C\u002Fb>` и ошибка разбора, — в блоке\n   ошибок текст виден **как текст**, а не жирным.\n\n**Ожидается:** каталог импорта — вне корня сайта (`\u002Fhome\u002Fbitrix\u002Fsh_import` на\nBitrixVM, если не задан свой); в `\u003Cкаталог импорта>\u002Fcopy\u002F\u003Cкод>\u002F` архив с именем\n`done_\u003Cкод>_\u003Cдата>_\u003C16 символов>.\u003Cрасш>` — хвост случайный.\n\n## F. Откуда взяты библиотеки XML\n\n```php\n\\Bitrix\\Main\\Loader::includeModule('shef.insync');\necho (new ReflectionClass(\\SbWereWolf\\XmlNavigator\\Extraction\\HierarchyComposer::class))->getFileName();\n```\n\n**Ожидается:** проект без Composer — путь в `…\u002Fshef.insync\u002Fvendor\u002Fsbwerewolf\u002F…`;\nпроект с Composer, где стоит `sbwerewolf\u002Fxml-navigator`, — путь в vendor\nпроекта. Во втором случае версия там обязана быть `7.2.x`: ветки 8+ требуют\nPHP 8.4 и разбирают XML в тот же формат, но модуль на них не проверялся.\n\n## G. Агент импорта\n\nАгент модуля-импорта (наследник `Sync\\FromFile\\AAgent`) после загрузки файла:\n\n**Ожидается:** строки из `shef_insync_model` уходят пачками, успешные\nудаляются, ошибочные остаются со статусом `F` и сообщением; в журнале событий\nпроблемы с типом `SH_PROBLEMS_SYNC`; страница статистики обновляется сама\n(pull), без ошибок в консоли браузера.\n\n## G2. Драйверы каталога\n\nИз PHP-консоли на товаре торгового каталога (ID и тип цены — свои):\n\n```php\n\\Bitrix\\Main\\Loader::includeModule('shef.insync');\n$price = new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Price();\nvar_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 10, 'CURRENCY' => 'BYN'])->isSuccess());\nvar_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 12.5, 'CURRENCY' => 'BYN'])->isSuccess());\nvar_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Product())->save(['ID' => 1], ['WEIGHT' => 250])->isSuccess());\nvar_dump((new \\Shef\\InSync\\Sync\\Model\\Catalog\\Driver\\Amount())->save(['PRODUCT_ID' => 1], ['STORE_ID' => 1, 'AMOUNT' => 7])->isSuccess());\n```\n\n**Ожидается:** четыре `true`, ни одного `Warning`; у товара **одна** цена\nэтого типа — 12.50, `PRICE_SCALE` заполнен; вес 250; остаток на складе 1 — 7\n(при включённом складском учёте ядро остаток так не примет — это верно).\n\n## H. Удаление\n\n1. **Marketplace → Установленные решения** → «[SH] InSync» → удалить.\n\n**Ожидается:**\n\n* `\u002Fbitrix\u002Fcomponents\u002Fshef.insync\u002F`, `\u002Fbitrix\u002Fjs\u002Fshef-insync\u002F` и\n  `\u002Flocal\u002Fcomponents\u002Fshef.insync\u002F` (если был) удалены, чужие компоненты на месте;\n* таблицы `shef_insync_model` нет, настроек модуля в `b_option` нет,\n  настройки `shef.options` — на месте;\n* раздел «[SH] Импорт» из левого меню ушёл;\n* файлы в каталоге импорта **остались**: это данные проекта.\n\nФормы «сохранить данные?» у модуля нет: удаление из админки стирает таблицу\nимпорта всегда. Оставить данные — только из PHP-консоли:\n`(new shef_insync())->UnInstallDB(['savedata' => 'Y'])` после подключения\n`\u002Fbitrix\u002Fmodules\u002Fshef.insync\u002Finstall\u002Findex.php`.\n\nЕсли модуль зависит от других (`shef.*` с `shef.insync` в `requireModules`),\nудаление обязано отказать и назвать их.\n\n## I. Портал в CP1251\n\nУстановка обязана отказать с текстом про UTF-8. На современных ядрах ветка\nнедостижима — `Application::isUtfMode()` возвращает `true` без условий, — тогда\nв бланке отмечается «пропущено», и это верный ответ.\n\n## J. Примеры на живом ядре\n\n```bash\nfor e in agent xml; do DOCUMENT_ROOT=\u002Fvar\u002Fwww\u002Fportal php examples\u002F$e.php || echo \"FAIL $e\"; done\n```\n\n**Ожидается:** два раза `ГОТОВО: …`, ни одного `FAIL`, `Warning`,\n`Deprecated`.\n\n## Бланк результата\n\n```\nВерсия: ____  Коммит: ____  sha256 архива сошёлся: да \u002F нет\nЯдро main: ____  PHP: ____  shef.options: ____  shef.problems: ____\nComposer в проекте: да \u002F нет   intranet: да \u002F нет\n\n0. Архив .................................. ок \u002F не ок\nA. Чистая установка ....................... ок \u002F не ок\n   без shef.options 3 \u002F shef.problems 2 — отказ .. ок \u002F не ок\nB. Обновление с 1.2.x ..................... ок \u002F не ок \u002F нет стенда\nC. Страница настроек ...................... ок \u002F не ок\nD. Права: без прав — отказ ................ ок \u002F не ок\n   агент ядра не тронут ................... ок \u002F не ок\n   «W» на sale — агенты sale не тронуты ... ок \u002F не ок\nE. Импорт файла ........................... ок \u002F не ок\n   .php отклонён .......................... ок \u002F не ок\nF. Библиотеки XML взяты из ................ модуль \u002F Composer\nG. Агент импорта .......................... ок \u002F не ок\nG2. Драйверы каталога ..................... ок \u002F не ок\nH. Удаление ............................... ок \u002F не ок\nI. CP1251 ................................. ок \u002F пропущено\nJ. Примеры на живом ядре .................. ок \u002F не ок\n\nЗамечания:\n```\n\n::note\nИсточник: [insync\u002Fdocs\u002Fportal-check.md](https:\u002F\u002Fgithub.com\u002Fbx-shef\u002Finsync\u002Fblob\u002Fmain\u002Fdocs\u002Fportal-check.md) — правки туда, сайт пересобирается сам.\n::\n\n",{"title":92,"description":197},"KrBPrPaSXF2-qDazlnwuTqTgCjEdFPqFiagh8ZC3r5E",[1623,1624],{"title":87,"path":192,"stem":193,"description":90,"children":-1},{"title":199,"path":200,"stem":201,"description":202,"children":-1},1790857270353]