Перейти к содержанию

Техническая реализация — сбор данных

Таблица: «Калькулятор маржинальности Brodeks» (1yTZW_8iWFMMsk3JzgIK2CzvawHS2kr-Wov_vxMCrIqs; переименована 06.07.2026, ранее называлась «AGT планирование продаж V1» — id и содержимое не менялись, только название файла в Google Drive), сервис-аккаунт claude-sheets@my-project-93453-01-04-26.iam.gserviceaccount.com.

Статус документа: восстановлен 03.07.2026 задним числом по ответам пользователя и прямому осмотру листов через gspread — исходные скрипты, которыми собирались данные, не сохранены (выполнялись как разовый ad-hoc код другим ИИ-инстансом, файлы не найдены ни в проекте, ни на Google Drive, ни на «Gemini Home VM»). Дальше — правило: каждый шаг реализации документируется сразу после выполнения, чтобы не терять историю повторно.


1. Лист prodazhi_po_kanalam_only_1c_mt — история продаж по каналам

  • Источник: SQL-запрос через pgapi (https://pg.dimavp.ru) к таблице prodazhi_po_kanalam_only_1c_mt — обновляется ежедневно по cron на офисном сервере.
  • Технология загрузки: та же база pgapi, что используется в проектах FBO Маркетплейсы и Отчет по сравнению остатков склада и организации (см. scripts/pgapi_config.js там — PGAPI_URL/PGAPI_KEY, эндпоинт /files/download для файлов; для SQL-таблиц используется отдельный SQL-эндпоint pgapi, конкретный запрос текущей выгрузки не сохранён).
  • Объём: 208 166 строк, период июль 2025 – июль 2026.
  • Каналы (podrazdelenie): В2В, Дилеры Brodeks, Розница, Интернет-магазин, Маркетплейс Озон, Маркетплейс Wildberries. В файл включены только 3 группы (В2В, Дилеры, Розница+ИМ) — Ozon/Wildberries сознательно исключены (см. 02_Решения, 03.07.2026).
  • ⚠️ Открыто: точный SQL-запрос (фильтры, агрегация по месяцам) не восстановлен — при пересборке нужно реконструировать по итоговой структуре листа.

2. Лист API_прайс_лист — прайс-лист

  • Источник: файл Прайс-лист XLSX.xlsx на офисном сервере (ВДС офис), лист API_прайс_лист внутри него — Артикул / Номенклатура / Базовая цена / Цена продажи (4 810 позиций).
  • Технология загрузки: pgapiDownloadFile_(fileName) — тот же паттерн, что в scripts/pgapi_config.js проекта «Отчет по сравнению остатков склада и организации» (скачивание xlsx через pg.dimavp.ru/files/download, конвертация в Google Sheets через Drive.Files.copy, парсинг, удаление временных файлов).
  • ⚠️ Открыто: это плоский прайс-лист без формул скидок по каналам — справочник 0.5 («цены/скидки по каналам», 07) в полном виде (с параметрами каналов) пока не построен поверх него.

3. Листы _RAW_себестоимостьAPI_себестоимость — себестоимость

  • Источник: файл Себестоимость товаров организаций по брендам - июль 25-дек 25 (XLSX).xlsx на офисном сервере — тот же файл, что использует проект «Отчет по сравнению остатков склада и организации».
  • Технология загрузки (эталон): scripts/load_sebestoimost.js в том проекте, функции loadSebestoimost() + aggregateSebestoimost():
  • Скачать xlsx через pgapiDownloadFile_, сконвертировать в Google Sheet.
  • Найти строку шапки по ключевым словам («Марка (бренд)» / «Артикул»), построить плоские имена колонок (buildColNames_).
  • Записать сырые данные в _RAW_себестоимость (Бренд, Артикул, Номенклатура, 4 пары Кол-во/Сумма, дата файла) — лист скрыт.
  • Агрегация в API_себестоимость: себестоимость единицы = Сумма / Кол-во, приоритет самой свежей ненулевой пары (J/K → H/I → F/G → D/E), округление до целого.
  • Кастомизация для AGT планирования (03.07.2026): добавлена колонка «с НДС 22%» — фиксированная ставка, копейки отбрасываются (floor, не округление) — этого нет в эталонном скрипте, добавлено отдельно. Итог: 2 898 артикулов, 5 колонок (без НДС / с НДС).
  • ⚠️ Открыто: точный скрипт, добавивший колонку «с НДС», не сохранён — логика (floor, ставка 22%) известна из 02_Решения.md, но код нужно восстанавливать заново при следующей пересборке.

4. Лист ABC_анализ — ABC-классификация

  • Метод восстановлен 03.07.2026 обратным анализом данных (лист содержит статические значения, не формулы — расчёт делался внешним скриптом, результат вставлен как значения).
  • Структура: Бренд | Артикул | Сумма продаж, руб (июль 2025 – июль 2026) | Признак ABC (внутри бренда).
  • Методология (подтверждена расчётом по всем 87 брендам в файле):
  • Артикулы группируются отдельно по каждому бренду (не по компании в целом).
  • Внутри бренда — сортировка по убыванию суммы продаж за весь период (13 мес, июль 2025 – июль 2026, все доступные периоды).
  • Строится накопительный % от суммы продаж бренда.
  • Классика Парето: A — куммулятивно до ~80% выручки бренда, B — от ~80% до ~95%, C — свыше ~95%. Границы подтверждены статистически: у всех крупных брендов первое появление B стабильно на 80.2–80.7% кумулятивной выручки, C — на 95.0–95.6%.
  • Не покрыто: обновление листа по расписанию — источник (история продаж) обновляется ежедневно, но ABC_анализ — статический снимок, требует пересчёта вручную/по кнопке (кнопки пока нет).

5. Лист «Дилеры Brodeks» — встроенный расчёт прибыли (задача 3.8)

Реализовано 03.07.2026 напрямую через gspread/Sheets API (эта сессия) — единственный шаг с полностью сохранённой историей.

  • Колонки «Категория», «ABC» — из справочника модель-цвет / листа ABC_анализ (способ проставления в существующих строках не проверялся отдельно — колонки уже были заполнены на момент осмотра).
  • Строка чекбоксов (TRUE/FALSE, ряд 2) — включение месяца ПЛАН в «Итого план».
  • CA = «Цена продажи, руб (с НДС)» — =IFERROR(VLOOKUP($B{row}, 'API_прайс_лист'!$A:$D, 4, FALSE), 0).
  • CB = «Цена продажи со скидкой, руб (с НДС)» — НОВАЯ колонка, добавлена 03.07.2026 19:5x:
  • CB2 — коэффициент скидки канала, редактируемый вручную. Установлен 0.67 (Дилеры = скидка 33% от РРЦ, см. 07).
  • CB{row} = =CA{row}*$CB$2.
  • Причина: до правки «Сумма выручки» в блоке ПЛАН считалась от полной цены (CA) без скидки дилера — прибыль и выручка были завышены на канале «Дилеры». Проверено на первом месяце плана: сумма выручки до правки 28 921 730 ₽ → после 19 377 559 ₽ (≈ ×0.67, совпадает с ожидаемым).
  • CC = «Себестоимость, руб (с НДС)» (была CB до вставки колонки, сдвинута автоматически).
  • Блок ПЛАН (24 месяца, авг.2026 – июл.2028): каждый месяц — Шт | Сумма выручки | Прибыль.
  • «Сумма выручки» переключена с CA (полная цена) на CB (цена со скидкой) — правка применена ко всем 24 месяцам, строки 6–6005 (буфер под будущие артикулы).
  • «Прибыль» = Сумма выручки − Шт × Себестоимость — формула не менялась, автоматически стала корректной после правки выручки.
  • Область применения: правка сделана только на листе «Дилеры Brodeks» — по прямому указанию пользователя. Листы «В2В» и «Розница+ИМ» ещё старой структуры (без Категории/ABC/чекбоксов/скидки/маржи) — не трогались.
  • Отложено на потом (по решению пользователя 03.07.2026): форматирование новой колонки (числовой формат — сейчас CB2 отображается как «1» из-за унаследованного целочисленного формата ячейки, хотя значение 0.67) и цветовая раскраска листа.

6. Раскраска листа «Дилеры Brodeks» (первый проход, 03.07.2026 20:14)

  • Шапка (строки 1–4) — по смысловым блокам:
  • A1:F4 (Бренд/Артикул/Наименование/Категория/ABC/Ключ) — тёмно-серый фон, белый жирный текст.
  • G1:BY4 (блок ФАКТ, история 36 мес) — светло-синий.
  • CA1:CC4 (Цена продажи / Цена со скидкой / Себестоимость) — светло-оранжевый.
  • CD1:EY4 (блок ПЛАН, 24 мес + Итого) — светло-зелёный; заголовки колонок «Прибыль» (24 шт.) — более тёмный зелёный, чтобы визуально выделялся денежный итог месяца.
  • Строка 2 от CB2 до EY2 (коэффициенты и чекбоксы месяцев) — жёлтый фон: маркер «это редактируется руками».
  • Первые 10 строк данных (6–15) — условное форматирование (динамическое, не статичная заливка):
  • A6:C15 (имя товара) — фон по значению ABC в колонке E: A — зелёный, B — жёлтый, C — серый. Сейчас все 10 строк класса A (сортировка по выручке), так и должно быть.
  • D6:D15 (Категория) — фон по значению текста категории: Куртки/Кофты — синий, Брюки/Полукомбезы/Шорты/Вейдерсы — бежевый, Костюмы/Комбезы — сиреневый, Обувь — розовый, Перчатки — жёлтый, Аксессуары — светло-серый.
  • Правила динамические (Google Sheets Conditional Formatting, не разовая заливка) — при изменении ABC/категории строки цвет пересчитается автоматически. Область пока жёстко ограничена строками 6–15 (по прямому запросу «первые 10 строк») — при расширении на весь лист нужно расширить диапазоны правил.
  • Не сделано (открыт вопрос): формат чисел «сумма» — сейчас разделитель тысяч запятая (19,377,559), т.к. локаль файла en_US. Per-cell локаль-оверрайд ([$-ru-RU]/[$-419]) в число-форматах Sheets не меняет разделитель группировки — он жёстко завязан на локаль всего файла. Единственный способ получить пробел — сменить локаль всего файла на ru_RU, что также поменяет: разделитель формул в UI (запятая → точка с запятой) и десятичный разделитель (точка → запятая) — влияет на все листы и всех соавторов. Решение отложено, нужно подтверждение пользователя.

6.1. Раскраска — расширение на весь лист + бренды (03.07.2026 20:17)

  • Обнаружен дубль правил: при повторном осмотре листа найдено 19 правил Conditional Formatting вместо ожидаемых 9 (включая незапрошенные правила подсветки знака «Прибыль» и вариант ABC-правил с диапазоном A:F вместо A:C) — похоже, лист параллельно редактировала ещё одна сессия/ИИ. Все 19 старых правил удалены, набор пересобран с нуля.
  • Новый чистый набор — 13 правил, диапазон строк везде 6:6005 (весь буфер листа, не только первые 10 строк):
  • ABC по имени товара (A:C) — 3 правила (A/B/C).
  • Категория (D) — 6 правил (см. раздел 6).
  • Знак прибыли (все 24 колонки «Прибыль» блока ПЛАН) — 2 правила: отрицательная — красный фон/тёмно-красный текст, положительная — зелёный фон.
  • Бренд (A:F, весь ID-блок) — 2 правила, добавлено по запросу «чтобы бросалось в глаза»: Brodeks (216 из 221 артикулов) — без заливки (нейтральный фон), Portwest (4 шт.) — яркий синий, BASE (1 шт.) — яркий красный/розовый. Смысл: на канале «Дилеры Brodeks» подавляющее большинство — сам бренд Brodeks, но есть единичные посторонние бренды (Portwest, BASE) — теперь они визуально выделяются в общей массе.
  • Все правила — Conditional Formatting (динамические), не разовая заливка; применены только на листе «Дилеры Brodeks».

6.2. Доработка раскраски + колонка рентабельности (03.07.2026 20:21–20:27)

  • Уточнение по цвету (пользователь): типы данных нужно различать явно — «Шт» оставить белым, суммовые типы («Сумма», «Цена/Скидка/Себестоимость», «Сумма выручки», «Прибыль») — в цвете своего блока. Единый фон блока — оставлен, «сразу видно, в каком блоке находишься».
  • Сброшены на белый все 60 колонок «Шт» (строки 5–6005) — 36 в ФАКТ + 24 в ПЛАН.
  • Шапка ID-блока (A1:F4) сделана светлее: было тёмно-серый/белый текст → стало светло-серо-голубой фон (#E6EDF2-подобный) с тёмным текстом.
  • Добавлен фон для баннеров строки 1 (ФАКТ/ПЛАН/коэффициент-подсказка) — раньше текст висел без подложки.
  • Данные всего блока ФАКТ/Цена/ПЛАН (строки 5–6005) получили лёгкую тонировку под цвет заголовка блока (бледно-синий/бледно-оранжевый/бледно-зелёный).
  • Разделители между месяцами (правые границы колонок) — предложены, но пользователь отменил выполнение (updateBorders не применён) — отложено, ждём отдельного решения.
  • Новая колонка EZ — «Рентабельность, % (по отмеченным месяцам)»:
  • Формула по строке: =IF(EY{row}=0,0,ROUND((Σ IF(<чекбокс месяца>$2,<Прибыль месяца>{row},0))/EY{row}*100,1)) — сумма прибыли только по отмеченным чекбоксом месяцам (тот же фильтр, что уже использует EX/EY для Итого план шт/выручки), делённая на итоговую выручку, ×100.
  • Строка ИТОГО (EZ5) — аналогичная формула на уровне колоночных сумм (CF5, CI5, …), не пересум по строкам (проценты не суммируются).
  • Формат числа — не нативный Sheets PERCENT (тот делит на 100 сам, было бы двойное умножение), а кастомный 0.0"%" (уже готовое значение ×100 из формулы, просто дописывается знак).
  • Оформление — бирюзовый акцент в шапке (#99CCC7-подобный) и лёгкая бирюзовая тонировка данных — отдельный визуальный класс «KPI-показатель», не сумма и не количество.
  • Проверено: EZ5 (весь ассортимент) = 51%, отдельные строки — 24.2–50.7% в выборке.

6.3. Сжатие шапки: удаление строки 2, локаль ru_RU, чекбоксы (03.07.2026 20:27–20:37)

  • Формат сумм — пробел вместо запятой: сменена локаль всей таблицы на ru_RU (updateSpreadsheetProperties). Побочный эффект подтверждён и принят: разделитель аргументов формул в UI — ; вместо , (значения не изменились, Sheets хранит формулы независимо от локали и просто по-другому их показывает), десятичный разделитель — , вместо .. Формулы, записанные ранее через API при локали en_US, продолжили работать корректно после смены локали (проверено).
  • A5 («свод. строка») → A5:F5 кратко, единообразно во всех 6 колонках ID-блока — чтобы не засорять выпадающий список фильтра по этим колонкам смешанными служебными текстами.
  • Экономия строки в шапке (запрос пользователя):
  • Месячный коэффициент прогноза перенесён из <Шт-колонка>$2 в <колонка Сумма выручки>$3 (пример: CD2→CE3), галочка учёта месяца — из <Сумма выручки>$2 в <Прибыль>$3 (пример: CE2→CF3). Коэффициент скидки канала CB2 (0.67) — аналогично в CB3.
  • Формулы блока ПЛАН (Шт, EX/EY/EZ, CB со скидкой) — переписаны под новые адреса, для всех 24 месяцев × 6000 строк.
  • Найден и исправлен побочный баг: перенос значения галочки через values.update скопировал только логическое значение (TRUE/FALSE), но не саму проверку данных (Data Validation, тип BOOLEAN) — визуально чекбоксы превратились в обычный текст «TRUE»/«FALSE» без виджета («везде TRUE» на вид). Восстановлено через setDataValidation (BOOLEAN, showCustomUi: true) на новых 24 ячейках.
  • Старая строка 2 (уже не используется формулами) — удалена целиком через deleteDimension (ROWS). Google Sheets автоматически сдвинул все формулы, диапазоны SUM, правила условного форматирования и data validation на строку вверх — проверено: EY4 (было EY5) = SUM(EY5:EY6004), итог не изменился (1 362 273 018 ₽), 13 правил форматирования не потеряны, чекбокс-виджет пережил сдвиг.
  • Итог структуры шапки: было 5 строк до данных (1 баннер + 2 служебные + 1 заголовки колонок + 1 ИТОГО), стало 4 (баннер + месяц/коэфф/чекбокс совмещены + заголовки колонок + ИТОГО). Данные теперь с строки 5 (было — с 6).
  • CB1 (комментарий «Коэфф. скидки канала…») — удалён по просьбе пользователя, лишний текст.
  • Строку 1 (баннер ФАКТ/ПЛАН) решили не трогать — вынести баннер больше некуда без потери контекста.

7. Проверка полноты списка артикулов (03.07.2026 20:14)

По сигналу пользователя («всегда 226 строк, должно быть больше») сверил список артикулов листа с сырыми данными prodazhi_po_kanalam_only_1c_mt, отфильтрованными по podrazdelenie = "Дилеры Brodeks" (без фильтра по бренду — канал изредка продаёт не только Brodeks) за весь период (13 мес, июль 2025 – июль 2026): 221 артикул в сырых данных = 221 артикул на листе, 0 пропущенных, 0 лишних. Лист полный и корректный, расхождения нет. ssylka_na_document (первый столбец сырой таблицы) для этого подразделения всегда заполнен — пустым он бывает только у Ozon/Wildberries/«Нет продаж», что не влияет на этот лист, но важно учесть при будущей сборке МП-каналов (эти подразделения сейчас не включены, см. раздел 1).

6.4. Индекс ABC для сортировки + исправление буфера «Прибыль» (03.07.2026 20:40–20:45)

  • Найден и исправлен пропуск: формулы «Прибыль» (все 24 месяца ПЛАН) были протянуты только до строки 225 (реальные данные), а не до конца буфера (6004), в отличие от всех остальных формул листа. Дозаполнено ={Сумма выручки}{row}-{Шт}{row}*CC{row} до строки 6004 во всех 24 колонках.
  • Новая колонка «Индекс ABC» — ранг товара внутри группы (бренд + класс ABC) по убыванию выручки, слитный формат A001, A002, … C133 и т.д. Цель — сортировка основного листа по этому индексу (самый продаваемый товар класса — первый).
  • Источник расчёта — лист ABC_анализ (не сам «Дилеры Brodeks»): добавлена колонка E=D{row}&TEXT(SUMPRODUCT(($A$2:$A$2756=A{row})*($D$2:$D$2756=D{row})*($C$2:$C$2756>C{row}))+1;"000") — считает, сколько товаров того же бренда и того же класса ABC имеют выручку больше текущего, +1 = ранг. Посчитано один раз на компактной таблице (2755 строк), а не на большом листе плана (~6000×24) — так быстрее и не нагружает лист планировщика тяжёлым SUMPRODUCT по 6000 строкам.
  • В «Дилеры Brodeks» — новая колонка F (вставлена после ABC, до Ключа — вся таблица сдвинулась на 1 колонку вправо, автосдвиг Sheets прошёл чисто, проверено) — простой VLOOKUP по артикулу в ABC_анализ!B:E, колонка 4.
  • Важный урок по локали: после смены локали файла на ru_RU (см. 6.3) формулы, записанные через API с , как разделителем аргументов, дают #ERROR! — нужно использовать ;. Отловлено сразу на первой попытке записи формулы ранга, исправлено.

6.5. Инцидент с сортировкой, восстановление, полное удаление буфера (03.07.2026 20:45–21:03)

Что произошло

  • Пользователь отсортировал лист по колонке «Индекс ABC» через встроенную сортировку по столбцу (UI). Буфер формул был протянут на 6000 строк вперёд (реальных артикулов — 221, остальные ~5780 строк — формулы, дающие пустую строку "" через IFERROR(...,"")).
  • Причина поломки: "" (результат формулы) — это не то же самое, что физически пустая ячейка. При сортировке по возрастанию такие ячейки трактуются как «меньше» любого текста и улетают наверх, перемешиваясь с реальными данными. При по убыванию — данные в основном уходят вниз, но сама операция сортировки (через sortSpecs заложенный в basicFilter) зацепила и служебную строку «Итого» (была в строке 4, эту же строку отсортировало вместе со всеми — уехала на строку 5783), а 221 реальный товар оказался сдвинут единым блоком в конец диапазона (строки 5784–6004).
  • Дополнительно: до этого была попытка настроить basicFilter со скрытием пустых строк по столбцу B (Артикул) через setDataValidation-подобный FilterCriteria.condition. Первая попытка (type: BLANK) не сработала (ничего не скрывала), вторая (type: NOT_BLANK) неожиданно скрыла все строки, включая реальные. Фильтр был немедленно снят (clearBasicFilter) — семантика условия BLANK/NOT_BLANK в Sheets API в связке с уже существующим sortSpecs от пользователя вела себя непредсказуемо, для дальнейшей работы отказались от этого пути.

Восстановление

  1. Найдены точные позиции: строка «Итого» — 5783 (со сбитым диапазоном SUM(EY5784:EY11783) — сдвинулся вместе со строкой, поэтому диапазон «уехал» далеко за пределы реальных данных, но численно считал верно, т.к. лишние строки пустые), 221 товар — строки 5784–6004 (без пропусков).
  2. Оба блока возвращены на место через cutPaste (аналог вырезать→вставить, Sheets автоматически поддерlive относительные ссылки формул — так же надёжно сработало ранее при удалении строки 2): «Итого» → строка 4, товары → строки 5–225.
  3. Обнаружена и исправлена вторая, независимая проблема: при вставке колонки «Индекс ABC» (см. 6.4) весь блок «Итого план шт / Итого план выручки / Рентабельность» физически сдвинулся с EX/EY/EZ на EY/EZ/FA — а более поздняя точечная работа (перекраска блока «Итого» по типам данных, см. 6.3–6.4) ссылалась на старые буквы EX/EY/EZ по памяти, не сверяясь заново с шапкой. Формулы в реальных EY/EZ/FA при этом тоже оказались перепутаны местами (Шт↔Выручка↔Прибыль) — источник путаницы: тройной сдвиг (удаление строки 2 → вставка колонки Индекс ABC → сортировка/cutPaste) без промежуточной пере-проверки жёстко прописанных буквенных ссылок в скриптах.
  4. Правило на будущее: после любой структурной операции (вставка/удаление строки или колонки) — заново вычислять буквы колонок через сканирование заголовков (row_values + фильтр по тексту), а не переиспользовать буквы из предыдущего шага скрипта.
  5. EY/EZ/FA полностью пересобраны с нуля по свежесканированным колонкам Шт/Сумма выручки/Прибыль (24 месяца), проверено: EZ4 (Итого выручка) = 1 362 273 018 ₽, FA4 (Рентабельность) = 51,0% — совпадает с ранее известными верными значениями.

Решение: буфер удалён полностью

  • Пользователь: «Пустые строки не нужны, только ты будешь добавлять новые строки в лист».
  • Все строки после 225 (реальные данные) — удалены физически (deleteDimension, было 6009 строк → стало 225). Буфера больше нет вообще.
  • Новый рабочий процесс: при появлении новых артикулов строки добавляет ИИ (Claude) с полным набором формул по образцу существующих — не заводится заранее «про запас».
  • Следствие: сортировка любым способом (по возрастанию/убыванию, через UI) теперь безопасна — скрывать/сортировать нечего, все 225 строк содержательны (4 шапки + 221 товар).

6.6. Лист «Инструкция» и финальная полировка — первая версия завершена (03.07.2026 21:03–21:31)

  • Создан лист «Инструкция» (первая вкладка книги) — пользовательская документация по листу «Дилеры Brodeks»: структура блоков, что означают цвета, как работают коэффициент прогноза и галочка «учитывать в Итого», что такое Индекс ABC, как безопасно сортировать/фильтровать, как добавлять новые товары (только через Claude, буфера строк больше нет), где искать техническую документацию.
  • Оформление: объединённые ячейки (заголовки и абзацы — на всю ширину, двухколоночные строки — метка + описание на всю оставшуюся ширину), перенос текста (WRAP), высота строк пересчитана под контент.
  • Раскраска — содержательная, не декоративная: строки, описывающие блоки листа (A–G/ФАКТ/Цена/ПЛАН/Итого) и легенда цветов (п.3) — покрашены в те же цвета, которые описывают. Легенда буквально показывает свой цвет.
  • Исправлен формат ячейки CC2 (коэффициент скидки канала) — показывал «1» вместо «0,67» из-за унаследованного целочисленного формата (pattern: "0"). Установлен 0.00. Остальные коэффициенты (CF2, CI2 и т.д., по месяцам) — были в порядке, проверены отдельно.
  • Различены цветом колонки цены/скидки/себестоимости (раньше — единый оранжевый, сливались): «Цена продажи» — светло-персиковый, «Цена продажи со скидкой» — насыщенный оранжевый, «Себестоимость» — коричнево-бежевый.

Итог: первая версия листа «Дилеры Brodeks» завершена

Работа 03.07.2026 (с учётом всех сессий дня) закрывает пилотную реализацию задачи 3.8 (встроенный расчёт прибыли поверх задачи 2.3, планировщик продаж) для канала «Дилеры Brodeks»: - Полная структура: карточка товара + Индекс ABC → история продаж (36 мес) → цена/скидка/себестоимость → план (24 мес, Шт/Выручка/Прибыль) → Итого (шт/выручка/рентабельность). - Данные проверены на полноту (221 = 221 артикулов за весь период). - Формулы восстановлены и проверены после инцидента с сортировкой (см. 6.5), буфер убран — риск повторной поломки исключён. - Раскраска по смыслу (тип данных, ABC, категория, бренд, знак прибыли) на весь лист. - Документация для пользователя (лист «Инструкция») и для разработчика (этот файл) готовы.

Следующий шаг (по решению пользователя 03.07.2026 21:31): переходим от подготовки к получению обратной связи от Глеба — показ пилотного канала «Дилеры Brodeks», сбор замечаний, далее — решение о репликации структуры на «В2В»/«Розница+ИМ» и/или доработке по замечаниям. Листы «В2В» и «Розница+ИМ» пока не трогали — ждут результата обратной связи.

6.7. Скрипты оформлены задним числом (04.07.2026)

По запросу пользователя весь код, которым сегодня (03.07.2026) правился лист «Дилеры Brodeks» через терминал (gspread, ad-hoc), оформлен в виде файлов в scripts/ — закрывает пробел, отмеченный в разделах 6.1–6.5 («скрипты не найдены/не зафиксированы»). Список файлов и порядок применения — scripts/README.md.

Важная оговорка: эти файлы — не «код, который был буквально выполнен один в один», а реконструкция подхода в переиспользуемом виде (функции с параметрами, без хардкода букв колонок там, где это возможно). Каждый файл содержит предупреждения о рисках (пересканировать заголовки после структурных правок, проверить локаль перед записью формул и т.д.), извлечённые из реальных ошибок сегодняшнего дня (см. разделы 6.5–6.6).

8. Лист «Дилеры Brodeks v2» — ручная РРЦ, план с июля, ручное Шт (06.07.2026)

По прямому запросу пользователя, не дожидаясь обратной связи от Глеба (см. итог раздела 6.6/задача 3.9 — она остаётся в статусе «ожидает показа», обратная связь ещё не поступала). Оригинальный лист «Дилеры Brodeks» не тронут — все правки на копии «Дилеры Brodeks v2» (Дилеры Brodeks.duplicate()). Генератор — scripts/18_dealers_v2_price_override.py.

8.1. Структурные изменения

  1. Новая колонка «РРЦ канала вручную, руб.» между «Цена продажи со скидкой» (была CC) и «Себестоимость» (была CD, теперь сдвинута на CE). Пусто по умолчанию. Если человек вписывает число — это значение используется ВЕЗДЕ вместо расчётной цены со скидкой, во всех формулах выручки/прибыли по всем месяцам сразу (цена в этой колонке одна на строку/SKU, не помесячная — важно понимать: правка одной ячейки меняет весь план по этому товару, не один месяц).
  2. Горизонт плана расширен на 1 месяц в прошлое: было авг.26–июл.28 (24 мес), стало июл.26–июл.28 (25 мес). Чекбокс «учитывать в Итого» (строка 2) включён по умолчанию для первых 12 месяцев нового горизонта (июл.26–июн.27), выключен для оставшихся 13 (июл.27–июл.28) — тот же принцип «скользящий год вперёд», что был в оригинале, просто стартовая точка на месяц раньше.
  3. В каждом месяце плана — новая колонка «Шт вручную» (после расчётного «Шт», перед «Сумма выручки»). Пусто по умолчанию. Если заполнена человеком — используется вместо расчётного количества в формулах Сумма выручки/Прибыль этого месяца И в Итого-блоке (Итого-Шт теперь считает «эффективное» количество: IF(ручное<>"";ручное;расчётное) по каждому отмеченному месяцу).
  4. Блок Итого расширен с (Шт/Выручка/Рентабельность) до (Шт/Выручка/Себестоимость/Прибыль/Рентабельность). Итого-Себестоимость = Итого-Шт(эффективный) × Себестоимость строки. Итого-Прибыль = Итого-Выручка − Итого-Себестоимость.
  5. Сравнительный блок (через 2 пустые колонки после Рентабельности): «Итого выручка (РРЦ канала до ручной правки)» — тот же эффективный Шт, но по БАЗОВОЙ цене со скидкой (колонка «Цена продажи со скидкой», игнорируя ручную РРЦ) и «Дельта прибыли» = Итого-Прибыль(факт., с ручной РРЦ) − (baseline-выручка − Итого-Себестоимость). Изолирует именно эффект ручной правки цены, при тех же количестве и себестоимости.

8.2. Инцидент и исправление: строка 4 («ИТОГО») — не реальный SKU

Себестоимость/Цена-со-скидкой на строке 4 (там B4="—", не настоящий артикул) — VLOOKUP не находит ничего, IFERROR(...,0) даёт 0. Формулы «Итого-Себестоимость = Итого-Шт × Себестоимость-строки» и «baseline-выручка = Итого-Шт × Цена-строки», написанные по единому шаблону для всех строк, на строке 4 считали 0 (себестоимость всей строки «Итого» = 0 → прибыль = вся выручка → рентабельность 100% → бессмысленные числа). Обнаружено сразу при проверке (GD4/GI4 = 0, GF4 = 100%, GJ4 ≈ выручка целиком). Исправлено точечно: только на строке 4 GD4/GI4 переопределены как SUM(GD5:GD225)/SUM(GI5:GI225) — сумма по реальным строкам, а не Шт×цена-строки-4. После исправления: GD4 = 175 877 082 ₽, GE4 (прибыль) = 185 944 874 ₽, GF4 (рентаб.) = 51,4% — согласуется с исходным пилотом (51,6% на 03.07, отличие ожидаемо из-за сдвига чек-бокс-окна на 1 месяц раньше).

Правило на будущее: если границы данных (сейчас строки 5–225) изменятся, формулы GD4/GI4 нужно поправить вручную на новый диапазон SUM — это единственные две ячейки листа, которые НЕ следуют общему построчному шаблону.

8.3. Проверка на реальных данных (строка 5, KW204BLACK)

Временно внесены значения CD5=20000 (ручная РРЦ) и CG5=50 (ручное Шт на июл.26), затем удалены после проверки. Результат пересчёта совпал с ручным расчётом на бумаге по всем цепочкам (Сумма выручки июл.26 = 50×20000 = 1 000 000; Итого-Шт вырос на 38 (50−12); Итого-Выручка/Себестоимость/Прибыль/Рентабельность/baseline/дельта — все пересчитались корректно, включая дельту прибыли = 10 009 215 ₽, изолирующую эффект именно ценовой правки). Тестовые значения очищены (batch_clear), лист возвращён к чистому состоянию без ручных вводов.

8.4. ABC_анализ v2 — новая методология ранжирования

По запросу пользователя логика ABC полностью пересобрана (не патч старой, а параллельная система — старый лист ABC_анализ не тронут). Генератор — scripts/17_abc_analysis_v2.py, результат — лист ABC_анализ v2 (2887 строк = все бренды/артикулы, встречавшиеся хоть в одном из 4 каналов).

  • Источник: тот же лист prodazhi_po_kanalam_only_1c_mt (208 156 строк), уже загруженный в эту книгу — не понадобилось новых выгрузок через pgapi.
  • 4 канала: Дил = «Дилеры Brodeks»; B2B = «В2В»; Роз = «Розница» + «Интернет магазин»; МП = «Маркетплейс Озон» + «Маркетплейс Wildberries» — по решению пользователя 06.07.2026: эти данные ЕСТЬ в сыром источнике (34 751 и 8 795 строк соответственно), их разделение из общего проекта, отмеченное в разделе 1 и в 03_Задачи.md, касалось только уже built-планировщиков каналов, не сырых данных. «Нет продаж» (33 542 строки) исключены как не-канал.
  • 5 параллельных ранжирований на каждый SKU:
  • 4 колонки «в бренде» (Дил-ABC (в бренде) и т.д.) — ранг товара среди товаров ТОГО ЖЕ бренда по продажам ОДНОГО канала. Используется в листах-планировщиках (колонка «ABC»).
  • 4 колонки «в канале» — ранг среди ВСЕХ брендов, тоже по одному каналу (кросс-брендовая важность для канала).
  • 1 колонка AGT-ABC — глобальный ранг по сумме продаж по ВСЕМ каналам и брендам сразу. Используется в планировщиках как «Индекс ABC».
  • Методология классов — та же восстановленная логика Парето (раздел 1): A ≤ 80%, B 80–95%, C > 95% накопительной выручки в своей популяции; SKU без продаж в данном разрезе — пустой код (не притягивается к C).
  • Ключ строки — составной Ключ (Бренд+Артикул) (первая колонка, формат Brodeks__KW204BLACK, тот же паттерн, что и в планировщиках), а не голый Артикул: найдено 9 коллизий одинаковых артикулов у разных брендов в общем справочнике всех 87+ брендов (включая 2 реальных для Brodeks — KW101GREY, KW603COBALT совпадают с артикулами других брендов/«!Нет бренда»). VLOOKUP по одному артикулу подтягивал бы случайный бренд.
  • Инцидент при первой сборке: индексы pandas-таблицы после groupby/sort_values внутри классификации не были переиндексированы перед присвоением результата колонкой (pivot[col] = [список] — присвоение по ПОЗИЦИИ, а не по индексу), из-за чего колонки «в канале» и AGT-ABC изначально были рассинхронизированы (лидер по выручке получал код ранга ~470 вместо ~1–5). Обнаружено сразу проверкой (KW204BLACK должен быть в топ-3 по общей выручке, но показывал AGT-B467), исправлено через .reindex(pivot.index) перед сборкой строк, пересчитано и перепроверено (KS302BLACK → AGT-A001, KS209BLACK → AGT-A002, KW204BLACK → AGT-A003, порядок теперь совпадает с сортировкой по итоговой выручке).

8.5. Подключение ABC v2 к «Дилеры Brodeks v2»

  • Колонка E («ABC») — было статическое значение (буква), стало VLOOKUP на «Дил-ABC (в бренде)» из ABC_анализ v2 по ключу Бренд+Артикул.
  • Колонка F («Индекс ABC») — было VLOOKUP на старый лист ABC_анализ, стало VLOOKUP на AGT-ABC из ABC_анализ v2.
  • Побочный эффект, исправлен: 3 правила условного форматирования (закраска строки по классу — зелёный/оранжевый/серый для A/B/C) были завязаны на точное совпадение $E4="A" — сломались бы, т.к. в E теперь строка вида Дил-A007, а не голая буква. Формулы правил переписаны на MID($E4;5;1)="A" (и аналогично для B/C) — класс всегда 5-й символ строки (после 3-буквенного префикса канала и дефиса).

8.6. Лист «Все каналы_Глеб» — полная копия структуры «Дилеры Brodeks v2» на всех SKU

Первая версия была урезанным статическим срезом (идентификация + суммы), но пользователь уточнил: «Все каналы_Глеб» должен полностью повторять «Дилеры Brodeks v2» (весь ФАКТ-блок на 36 месяцев, цена/себестоимость/ручная РРЦ, ПЛАН на 25 месяцев с ручным Шт, расширенный блок Итого, сравнение с базовой РРЦ) — просто с суммой продаж по ВСЕМ 4 каналам вместо одного, и на всём универсуме 2887 SKU (не только 221 артикул канала Дилеры). Пересобрано начисто, генератор — scripts/19_vse_kanaly_gleb.py.

  • Приём реализации: не пересборка формул с нуля, а (1) дублирование «Дилеры Brodeks v2» (все формулы/раскраска уже верные), (2) расширение до 2891 строк (add_rows), (3) copyPaste строки 5 на весь диапазон 5:2891 — Sheets сам тиражирует формулы с адаптацией относительных ссылок построчно (ровно как протяжка маркером заполнения), статические данные при этом копируются как есть — переписываются следующим шагом, (4) перезапись статических колонок (Бренд/Артикул/Наименование/Категория/Ключ/ФАКТ-блок) реальными данными по всем каналам сразу, отсортированными по итоговой выручке.
  • ФАКТ-блок — не продажи одного канала, а сумма kolichestvo/summa по всем 4 каналам (Дил+B2B+Роз+МП) на каждый месяц, из тех же сырых продаж prodazhi_po_kanalam_only_1c_mt, группировка по (brend1c, article1c, god_mesyac).
  • Коэффициент скидки канала (CC2) переопределён на 1.0 (полная РРЦ без скидки) — у смешанного «все каналы сразу» разреза нет единого канального дисконта (Дилеры −33%, у остальных каналов другие условия). Пользователь может поставить нужный коэффициент вручную или использовать «РРЦ канала вручную» на конкретных SKU.
  • ABC-колонки — по прямому указанию пользователя: столбец «ABC» (E) всегда пуст (очищен batch_clear на весь диапазон данных) — нет единого канала-контекста для ранга «в бренде»; столбец «Индекс ABC» (F) = общий AGT-Axxx (та же формула VLOOKUP на ABC_анализ v2 по ключу Бренд+Артикул, унаследована через copyPaste и адаптировалась сама). Следствие: 3 правила подсветки строк по классу A/B/C (MID($E4;5;1)="A" и т.п.) на этом листе никогда не сработают — E пуст всегда, это ожидаемо, не баг.
  • Особые ячейки (не по общему построчному шаблону, как и в разделе 8.2): GD4/GI4 (Итого-Себестоимость/baseline-выручка на строке «ИТОГО») переопределены на SUM(...5:...2891) — диапазон новых границ данных.
  • Инцидент при сборке (ложная тревога): пользователь на середине процесса увидел «много дублей строк» — это был промежуточный copyPaste-этап (строка 5 тиражирована на все 2891 строки ДО перезаписи реальными данными, поэтому всё временно выглядело как повтор Brodeks/KS302BLACK). После завершения перезаписи проверено: 2887 уникальных пар Бренд+Артикул, дублей нет (проверено 3 способами: точное совпадение, без учёта регистра/пробелов, и напрямую на живом листе).
  • Проверено на выборке: строка 5 (лидер по общей выручке, KS302BLACK) — E5 пусто, F5="AGT-A001", CC5=CB5 (коэффициент 1.0, без скидки), Итого-Шт/Выручка/Рентабельность посчитаны. Строка 4 (ИТОГО, все каналы, все 2887 SKU): 350 887 план-штук, ≈1,97 млрд ₽ план-выручки, рентабельность 61,3% (выше, чем в «Дилеры Brodeks v2», ожидаемо — там коэффициент 0.67, здесь 1.0).

9. Переименование файла Google Sheets (06.07.2026)

Файл переименован пользователем в Google Drive: было «AGT планирование продаж V1», стало «Калькулятор маржинальности Brodeks». ID файла и всё содержимое (листы, формулы, данные) не изменились — 1yTZW_8iWFMMsk3JzgIK2CzvawHS2kr-Wov_vxMCrIqs, доступ через тот же сервис-аккаунт. Обновлены упоминания названия в активно сопровождаемых файлах проекта (этот файл, 03_Задачи.md, 02_Решения.md, docs/index.md). Не тронуты: датированные записи в 51_Claude.md/56_OpenCode_*.md/70_Kimi.md (исторические логи сессий) и видения других моделей в docs/ (DeepSeek/GLM/Qwen/Kimi/MiniMax) — там название отражает состояние на момент написания, задним числом не меняем.

10. Лист «В2В» пересобран по аналогии с «Дилеры Brodeks v2» (06.07.2026)

По прямому запросу пользователя («заполняем лист В2В по аналогии с дилерами и учти особенности сортировки по ABC»). Старый лист (4 идентификационные колонки, без Категории/ABC/Индекс ABC/ручных override, буфер на 6010 строк) сохранён как «В2В (архив, старая структура)» — переименован, не удалён. Генератор — scripts/20_b2b_v2.py, приём реализации тот же, что и в 8.6/19 (дублирование «Дилеры Brodeks v2» → copyPaste строки-образца на весь диапазон → перезапись статических колонок данными канала).

  • Состав: 1234 уникальных Бренд+Артикул (все SKU, когда-либо проданные через канал «В2В» за весь период), ФАКТ-блок — продажи только этого канала.
  • Колонка «ABC» (E) — не «Дил-Axxx», а B2B-ABC (в бренде) из ABC_анализ v2 (колонка J, индекс 10 относительно $A:$Q). Колонка «Индекс ABC» (F) — как и на всех листах, общий AGT-Axxx.
  • Коэффициент скидки (CC2) = 0.96 — эмпирическая оценка, не согласованное решение. Рассчитан как факт.выручка / выручка-по-РРЦ на 56 831 сопоставленных строках канала В2В за весь период (≈3,9% фактической скидки). Частично отвечает на открытый вопрос В2 (см. 06_Открытые_вопросы) — цифра расчётная, требует подтверждения Глебом/Аркадьевым; при другом согласованном значении — просто заменить CC2.
  • Особенности сортировки по ABC (учтено по прямому указанию пользователя):
  • Буфера строк больше нет — ровно 1234 + 4 строки, без запаса «на будущее». Именно буфер стал причиной инцидента при сортировке на самом первом пилоте «Дилеры Brodeks» (раздел 6.5) — без буфера сортировка через UI безопасна.
  • Физический порядок строк = по убыванию выручки канала В2В за весь период — это НЕ то же самое, что порядок по колонке E (ранг внутри бренда) и не то же самое, что колонка F (общий ранг AGT) — три разные сортировки одновременно, это нормально (так же устроено в «Дилеры Brodeks v2»/«Все каналы_Глеб»).
  • Грабли при записи: коэффициент 0.96, записанный как СТРОКА через USER_ENTERED, на локали ru_RU интерпретируется как текст (точка — не разделитель дробной части в этой локали) → все зависимые формулы дали #VALUE!. Исправлено записью через value_input_option='RAW' с питоновским float. Обнаружено и исправлено сразу же при проверке (GC5/GF5/строка ИТОГО).
  • Проверено: строка 5 (лидер по выручке В2В — KW204BLACK) — E5="B2B-A001", F5="AGT-A003" (общий рейтинг ниже, т.к. AGT считает по сумме всех каналов, а не только В2В). Строка 4 (ИТОГО): 140 395 план-штук, 778,2 млн ₽ выручки, рентабельность 62%.

11. Лист «Розница+ИМ» пересобран (06.07.2026)

По тому же образцу, что «В2В» (раздел 10). Старый лист сохранён как «Розница+ИМ (архив, старая структура)». Генератор — scripts/21_roznica_v2.py.

  • Важное уточнение пользователя: несмотря на название листа, ФАКТ-блок строится только по подразделению «Розница» («данные по подразделению Розница» — прямая цитата), БЕЗ «Интернет магазин». Это отличается от того, как считался «Роз» в ABC_анализ v2/«Все каналы_Глеб» (там Роз = Розница + Интернет магазин суммарно) — там отдельного ранжирования только по «Розница» без ИМ не строили. Колонка E на этом листе всё равно ссылается на комбинированный Роз-ABC (в бренде) из ABC_анализ v2 (столбец K, индекс 11) — небольшая осознанная несогласованность, зафиксирована здесь на случай вопросов.
  • 1234 → 2281 SKU (подразделение «Розница», весь период) — не путать с 1234 у В2В, разные каналы разного объёма.
  • Коэффициент скидки (CC2) = 1.0 — согласовано (не черновая оценка, в отличие от В2В): по справочнику, Розница = «Полная РРЦ», скидка 0% (решение 29.06.2026, 07_Справочники_классификаторы).
  • Проверено: строка 5 (лидер по выручке Розницы — KS305BLACK) — E5="Роз-A001", F5="AGT-A004". Строка 4 (ИТОГО): 24 777 план-штук, 127,2 млн ₽ выручки, рентабельность 41,1%.

12. Лист «Маркетплейсы» создан (06.07.2026)

Новый лист (старой версии не было, в отличие от Дилеры/В2В/Розница+ИМ) — по прямому запросу пользователя. Тот же приём (дублирование «Дилеры Brodeks v2»). Генератор — scripts/22_marketpleisy_v2.py.

  • ФАКТ-блок — сумма 2 подразделений: «Маркетплейс Озон» + «Маркетплейс Wildberries» (МП = Ozon+WB, тот же принцип объединения, что в ABC_анализ v2/«Все каналы_Глеб» — в отличие от «Розница+ИМ», где по прямому уточнению пользователя берётся только «Розница» без ИМ). 1583 SKU.
  • Коэффициент (CC2) = 0.5 — по справочнику (07_Справочники_классификаторы: «MP — доля от выручки — 50%»). Механически та же формула (Цена со скидкой = РРЦ × коэффициент), но смысл другой: не «цена для покупателя», а «доля выручки, которая реально достаётся компании» после комиссии площадки.
  • Открытый вопрос НЕ решён этим листом (см. В3, 06_Открытые_вопросы): методика Ozon «выручка + баллы» — как баллы включаются в 50%. Сырое summa взято как есть из prodazhi_po_kanalam_only_1c_mt, без корректировок на баллы.
  • Проверено: строка 5 (лидер — KS302BLACK) — E5="МП-A001", F5="AGT-A001" (топ и по МП, и по всем каналам сразу). Строка 4 (ИТОГО): 86 139 план-штук, 225,5 млн ₽ выручки, рентабельность 15,4% — заметно ниже остальных каналов, ожидаемо из-за модели «50% выручки» (та же полная себестоимость, но вдвое меньшая цена реализации).

Итог: все 4 канала Глеба (Дилеры/В2В/Розница+ИМ/Маркетплейсы) теперь на структуре v2 как отдельные планировщики.

13. Разбивка «Маркетплейсы» на «Ozon» и «Wildberries» (06.07.2026)

По прямому запросу пользователя, с явным условием — не сломать сортировку/ранги ни на одном из существующих листов. Старый лист «Маркетплейсы» переименован в «Маркетплейсы (не используется, архив Ozon+WB)» — не удалён.

Как решена задача «не сломать сортировку»

Все листы-планировщики читают ABC_анализ v2 через VLOOKUP(...;'ABC_анализ v2'!$A:$Q;<номер колонки>;FALSE) с жёстко зашитым номером колонки (9/10/11/17 и т.д.), а не именем. Если бы новые колонки для Ozon/WB были вставлены В СЕРЕДИНУ существующего диапазона (например, рядом со старыми колонками «МП»), это сдвинуло бы номера ВСЕХ колонок правее точки вставки — и VLOOKUP на «Дилеры Brodeks v2»/«В2В»/«Розница+ИМ»/«Все каналы_Глеб» стали бы указывать не туда одновременно на всех листах.

Решение: новые колонки добавлены ТОЛЬКО В КОНЕЦ (R:W, после существующей Q), без единой вставки/удаления в диапазоне A:Q. Старые колонки (включая комбинированные «МП-ABC» — они больше не используются ни одним листом, но и не мешают) не тронуты. Генератор — scripts/23_abc_v2_append_ozon_wb.py, порядок строк перед записью проверен assert на точное совпадение Ключа (Бренд+Артикул) построчно с уже существующим листом.

  • Новые колонки ABC_анализ v2: R=Сумма Ozon, S=Сумма Wildberries, T=Ozon-ABC (в бренде), U=WB-ABC (в бренде), V=Ozon-ABC (в канале), W=WB-ABC (в канале).
  • AGT-ABC (столбец Q, общий ранг) пересчитывать не потребовалось — Ozon+Wildberries суммарно математически равны прежней «Сумме МП», общий итог по SKU от разделения канала не меняется.

Листы «Ozon» и «Wildberries»

Тот же приём, что в 19–22 (дублирование «Дилеры Brodeks v2» → copyPaste строки-образца → перезапись статических колонок). Генератор — scripts/24_ozon_wb_channels.py.

  • Ozon: 1534 SKU. Колонка E → VLOOKUP на Ozon-ABC (в бренде) (диапазон расширен до $A:$W — только на ЭТИХ двух новых листах, старые остаются на $A:$Q). Строка 4 (ИТОГО): 70 941 план-штук, 185,1 млн ₽ выручки, рентабельность 11,4%.
  • Wildberries: 359 SKU. Колонка E → VLOOKUP на WB-ABC (в бренде). Строка 4: 15 200 план-штук, 40,5 млн ₽ выручки, рентабельность 33,7% — заметно выше Ozon (более узкий, но маржинальный ассортимент).
  • Коэффициент (CC2) = 0.5 для ОБОИХ — унаследован от прежнего объединённого «МП», отдельного коэффициента по площадкам не согласовано. Открытый вопрос В3 (баллы Ozon) по-прежнему не решён.
  • Проверено: оба листа — 0 дублей по (Бренд+Артикул); листы «Дилеры Brodeks v2»/«В2В» перепроверены ПОСЛЕ добавления колонок в ABC_анализ v2 — их E/F не изменились (Дил-A001/AGT-A002 и B2B-A001/AGT-A003 соответственно) — подтверждает, что append-стратегия ничего не сломала.
  • Побочный баг найден и исправлен (по замечанию пользователя): ячейка A1 на листе «В2В» ошибочно показывала «Дилеры Brodeks» — унаследовано от шаблона «Дилеры Brodeks v2» и не было перезаписано при сборке 20-м скриптом (в отличие от остальных статических колонок A:D/G:CA, ячейка A1 — это отдельная надпись-заголовок листа вне зоны данных, про неё генератор не знал). Исправлено точечно на «В2В»; заодно проверено, что на «Ozon»/«Wildberries»/«Розница+ИМ»/«Все каналы_Глеб» эта ячейка уже верна. Урок: при следующей репликации структуры v2 на новый канал — явно проверять и переписывать A1 (название канала), это не входит в диапазон, который перезаписывают скрипты 19–24.