Владелец: «нужно видеть, как всё происходит: push отправили — реакции не было, потом SMS,
потом звонок; с какого раза человек ответил на звонок, кто вообще не поднимает трубку».
Один RPC admin_comms_funnel(p_days, p_date_from, p_date_to) — период считается как у
admin_automation_economics (30 = группы, созданные за 30 дней; 0 = всё время) — отдаёт:
этапы цепочки по когорте (группы → push → первое SMS → открыли ссылку → позвонили →
взяли трубку → согласовано → в ручную → выдано), разбивку звонков по попыткам
(всего/взяли/согласовали/не взяли + % ответов), каналы подтверждения (робот / менеджер /
ссылка), список «не поднимают трубку» и «открыли ссылку, но не подтвердили», и «silent» —
кого не достали ни ссылкой, ни звонком.
Блок CommsFunnelBlock на «Аналитике» под KPI-карточками, те же табы периода, mobile-first,
время в МСК. За 30 дней: 396 групп, первое SMS 340, открыли ссылку 1, звонили 26,
взяли трубку 14, согласовано 128, в ручную 22, выдано 357; 265 (66.9%) не достали никак.
С попыток: 1-я — 42 ответа из 64, 2-я — 2 из 6, 3-я — 4 из 4.
Тест: src/components/admin/analytics/CommsFunnelBlock.test.jsx (7 проверок, фикстура по
реальному ответу RPC). SW: v123 -> v124.
В узкой колонке «Вторая половина дня» переносилась посреди фразы («Вторая /
половина дня»). Дата — первой строкой, половина дня — второй, мелким. SW: v123.
Владелец: «в таблице всех доставок и самовывоза, если согласована доставка, дата
и время указаны, а если самовывоз — нет; нужно и самовывоз выводить».
Причина: колонка «Дата» (LogisticsReadinessBoard) читала только delivery_date/
delivery_time, а у самовывоза дата и половина дня лежат в pickup_date/
pickup_time_slot — поэтому строка самовывоза показывала «—», хотя слот согласован.
Тот же пропуск был в фильтре по периоду и группировке по датам: getDeliveryDate()
смотрела только на delivery_date, и при выбранном периоде заказы самовывоза
пропадали из реестра (падали в дату заказа).
Введены общие хелперы в orderGroupViews: isPickupGroup, getGroupSlotDate,
getGroupSlotTime (камелкеис и snake_case). Реестр показывает дату и время слота
по типу заказа, сортировка — по этой же показанной дате, фильтр по периоду и
группировка — тоже по ней. Подпись колонки «Доставка» → «Дата» (в колонке теперь
и дата выдачи).
Попутно поправлено устаревшее ожидание в тесте (getOrderGroupDisplayStatusLabel
для черновика ждало «draft», подпись локализована в «Черновик») — тест падал и до
этой правки.
SW: v121 -> v122.
Владелец: «в субботу звонки не должны происходить, всё это настраивается из
админки». В панели «Автодозвон» в блоке «Окно звонков» были только часы, а дни
(work_days) править из админки было нечем — их приходилось менять в БД, хотя
планировщик именно по ним и решает, звонить ли сегодня.
Добавлены таблетки дней Пн–Вс тем же механизмом и в том же виде, что в панели
SMS-кампаний: пустой набор не подменяется дефолтом (снял все дни — значит
звонков нет, и в панели это видно). Подсказка в панели теперь честно описывает
поведение: вне окна робот не звонит вообще, попытка уходит на ближайшее
рабочее утро.
Харнесс check_autocall_window.py считает ожидания ИЗ НАСТРОЕК (часы + дни),
поэтому проверка не устаревает при смене графика.
SW: v120 -> v121.
В блоке «История действий по заказу» автодозвон не был виден в цепочке шагов —
там были только «Добавлен», «SMS», «Согласовано» и далее, хотя робот звонит по
этим же заказам. Теперь шаг «Звонок» идёт сразу после SMS в обеих цепочках
(доставка и самовывоз) и имеет собственное состояние: ✓ пройден, если робот
согласовал слот; янтарный — если звонили без результата; серый — если звонков
не было. Шаг не считается пройденным только потому, что заказ уже согласован
(согласовать могли по ссылке из SMS, без звонка). Подсказка при наведении —
последний исход и число звонков.
SW: v119 -> v120.
Клиентская страница согласования:
- приглашение теперь отдаёт deliveryType и pickupCode (public view) — до этого
страница не знала, что заказ самовывозный, и говорила «Доставка заказа /
Согласование доставки» даже для самовывоза; в шапке и hero-тексте выбор по типу
- в блоке с кодом: «Ваш номер доставки 010796» + «Ваш код выдачи 7598»
(номер берём из состава заказа, «ТП\-010796» → «010796»)
- ссылка на заказ теперь «Доставка ТП-010796» вместо «Счет ТП\-010796»,
экранированный дефис из обмена с 1С больше не показывается
SMS: в шаблоны добавились переменные {order}/{номер}/{номер_доставки} (номер
доставки) и {code}/{код}/{код_выдачи} (код выдачи) — работают и в шаблоне
кампании, и в тексте профиля города. Дефолтные тексты самовывоза (и значения в
БД, см. supabase/sms_pickup_code_placeholders.sql) теперь содержат номер и код;
в админке у полей появилась памятка по переменным и предпросмотр с подстановкой.
service-worker v118 → v119
Раньше текст был зашит в кампании и всегда говорил про доставку; настраиваемый
в админке sms_text_template не читался скриптами вообще. Сначала выяснилось,
что всем 909 pickup-группам уходило «Согласуйте дату доставки по ссылке».
- sms_campaign_settings.sms_text_template_pickup (новая колонка) + значения
sms_text_template = «…дату доставки…», pickup = «…дату самовывоза…»
(supabase/sms_text_templates_pickup.sql = миграция с фактическими текстами)
- sms_first_campaign / sms_second_campaign / sms_paid_storage_campaign:
build_sms_text(group, settings) — шаблон выбирается по og.delivery_type,
{link} подставляется ссылкой; приоритет профиль города (режим «Уведомление»)
→ шаблон кампании → дефолт скрипта
- вторая SMS и платное хранение тоже получили pickup-вариант (кампании были
выключены, поэтому в текстах жил только «доставка»)
- SmsCampaignPanel: два поля ввода (📦 Доставка / 🏪 Самовывоз) + длины и
предпросмотр с подставленной ссылкой + пояснение приоритета
- service-worker v117 (обязательный бамп при деплое фронта)
- activate: delete ALL caches except current STATIC/RUNTIME (was keeping every
previous construction-delivery-* cache forever → 3GB storage, 30-40s caches.match)
- fetch: only cache same-origin static assets (js/css/img/fonts); API/data and
cross-origin requests go straight to network, never cached
- bump to v115
- FontSettingsContext: body zone first in CSS (specific zones win)
- Arbitrary px sizes (10-14px) overrides in table/card zones
- fs-zone-table on OrdersTable + LogisticsReadinessBoard
- fs-zone-body/heading/nav in AppShell + const navigate = useNavigate()
- Stale delivery highlight: isStale() 24h + bg tint, isLinkOpened 👁
- fmtTime defined in OrderDetailPanel (was used but never declared)
- SmsStatusCard synced from prod
- SW v49 (fixed: addEventListener was broken by sed)
- LogisticsReadinessBoard: @dnd-kit/sortable for drag-and-drop section reordering
- Drag handle (6-dot grip icon) on left of each section header
- Custom order persists in localStorage (key: logistics-section-order)
- Default: agreed → manual_required → funnel order
- Flat rows (no Button/rounded), matches OrdersTable style
- 7 columns: Клиент | Город | Тип | Дата | Водитель | Статус | Обновлён
- Horizontal scroll: overflow-x-auto + min-w-[1080px]
- Type column wide enough for Самовывоз/Доставка in one line
- OrdersTable: widened Type column (minmax 70px→100px), min-w 920→1080px
for consistent horizontal scroll across tables
- test_mode + test_phone columns in sms_campaign_settings (DB)
- Script reads test_mode from DB settings, not env vars
- Admin panel: toggle Test/Production mode with visual indicator
- test_mode=true (default): SMS only to test_phone
- test_mode=false: SMS to real customers
- Service worker cache v9 → v10 (fixes white screen)
Button component forces inline-flex items-center justify-center rounded-full
which was overriding all alignment. Switched to native <button> with
flex flex-col items-start justify-start. SW v8→v9.
Mobile: removed phone + buildGroupSummary, kept name + type badge + status +
order numbers + count badge (N сч.)
Caddyfile: Cache-Control immutable for assets, no-cache for HTML+SW
SW v7→v8