Replaced card-style delivery items with proper table:
- № счёта (order numbers, accent color)
- Клиент (customer name)
- Телефон (tel: link, clickable)
- Город (extracted from address)
- Часть дня (delivery half-day)
Problem rows highlighted with red tint + ⚠ icon
DriverDeliveryPlanner:
- Text search (name, address, phone, order numbers)
- Half-day filter (morning/afternoon/unknown)
- 'Reset all filters' button
- tel: link on phone in delivery cards
- Order numbers badges in cards
- Partial delivery warning badge
- Problems-first sorting
saveShipmentData fix:
- Partial shipment with problems → status 'problem' (not 'delivered')
- Full shipment → 'delivered' (unchanged)
DriverShipmentPanel:
- Reset button: confirmation dialog when status is final
- Calls onResetStatus to revert delivery status to 'loaded'
OrderDetailPanel (driver status section):
- 'Return to work' button for delivered/problem/picked_up statuses
- Passes onResetStatus + isSavingStatusChange to DriverShipmentPanel
LogisticsReadinessBoard:
- Warning badge for has_delivery_problem groups in table rows
- Shows delivery_problem_note as tooltip
- 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)
- fs-zone-table on OrdersTable + LogisticsReadinessBoard (was missing)
- fs-zone-body on main content area
- fs-zone-heading on mobile + desktop headers
- fs-zone-nav on mobile tab nav
- CSS: added arbitrary px size overrides (10px/11px/12px/13px/14px)
- CSS: reordered body zone last so table/card/nav/heading win at equal specificity
- Manual campaign doesn't write to sms_campaign_log, so the tab was always empty
- Now loads order_groups with notification_status='manual_required'
- Shows: customer name, phone, first/second SMS timestamps, last update
- Red 'не отправлена' badge for groups where second SMS was never sent
- Also shows manual count on the campaign card
Bug: sms_manual_campaign.py condition 2 caught first_sms_sent groups after 3h
WITHOUT checking if second SMS was already sent. This caused manual campaign
(5min timer) to move groups to manual_required before second campaign (10min timer)
could send the second SMS.
Fix: added second_sms_sent_at IS NOT NULL check to condition 2.
Now manual only moves groups where second SMS was already sent AND client
still didn't agree after 3 more hours.
Also restored 17 groups that were incorrectly moved to manual_required back
to first_sms_sent so second campaign can send their second SMS.
- Removed OrdersTable from dashboard, all roles now use LogisticsReadinessBoard
- Logistician, admin, mega_admin, manager — same grouped board with drag-and-drop
- Driver still uses DriverDeliveryPlanner (card view)
- Bundle size reduced (OrdersTable no longer imported)
- 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
- SmsCampaignPanel: 4 sub-tabs (first_sms/second_sms/manual/paid_storage)
- 'Проверить снова' button sets needs_check=true in sms_campaign_log
- Auto-refresh every 30s with toggle
- Elapsed time display per row
- Script: after send, notification_status='sms_sending' (not 'link_ready')
→ double protection against re-sending to same group
- Script: get_sms_to_check includes needs_check=true records regardless of age
- Script: checked_at timestamp on each status check
- DB: needs_check boolean + checked_at timestamptz columns added
- 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)
- sms_campaign_log table: full audit trail (phone, sms_id, status, code, attempts)
- sms_campaign_settings: editable by megaadmin (wait times, max attempts, delays)
- New tab 'SMS-кампании' in mega_admin navigation
- State machine: no blocking sleeps, fast cron runs
- Protection: no duplicate SMS within 24h, code 231/132 = limit, not retry
- sms_first_campaign.py: full replacement for n8n workflow JnfZwOnpjEazseW5
- sms_campaign_log table: full audit trail in Supabase (visible in admin)
- sms_campaign_settings table: configurable by megaadmin (wait times, attempts, schedule)
- systemd service + timer (NOT activated, ready for deployment)
- Logic: send SMS → wait 25s → check status (102=in transit, 103=delivered)
→ retry check up to 90 min → retry SMS send up to 2 attempts → manual_required
- Telegram notifications after each send/delivery/failure
- Log file: /var/log/supersam-sms-first.log
n8n workflow writes status='first_sms_sent' but leaves notification_status='link_ready'.
Added first_sms_sent/second_sms_sent to ORDER_GROUP_STATUS_LABELS and tone logic.
customer_date in DB is stored as 23.06.2026 (DD.MM.YYYY) but parseGroupDate
only matched DD.MM.YY (2-digit year). This caused date filter to reject all
groups when filtering by date range, since parseGroupDate returned null
for 4-digit year dates.
- Add delivery_invitation nested select (opened_at, access_count, last_accessed_at)
- Map to invitationOpenedAt, invitationAccessCount, invitationLastAccessedAt
- Show in 'Ссылка на согласование' panel: 'Клиент открывал страницу X раз, последний раз DD.MM'
- Or 'Клиент ещё не открывал страницу согласования'
- Data only updated by client-facing RPC, not by admin actions
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
Mobile card: removed phone, dates, updatedAt, buildGroupSummary — kept only
name + delivery type badge + status badge + order numbers + problem alert
Desktop first column: removed duplicate name and groupKey (phone|date),
kept only name + phone
- orderGroupRepository: added manager_name, manager_email, manager_tel, payed_ship, is_payed_ship to SELECT
- OrderDetailPanel: manager name + tel, payment status with amount (✓ Оплачено + ₽), hidden for drivers
- OrdersTable mobile: delivery type badge moved to header row next to status badge
- 🏪 Самовывоз (accent color) / 🚚 Доставка — immediately visible at top of card
- Map delivery_link DB field to deliveryLink in order group object
- New panel in OrderDetailPanel: 'Ссылка на согласование'
- Two buttons: open approval page (link) + copy link to clipboard
- Visible for all roles except driver
- Shows when order.deliveryLink is present
- OrdersTable: replaced 'Проблема' column with 'Тип' (Самовывоз/Доставка)
- Problem rows highlighted red (bg rgba danger 10%)
- Mobile cards also show Тип label
- OrderFilters: added deliveryType dropdown (Доставка/Самовывоз)
- filterOrderGroups: filter by deliveryType
- useOrderGroups: deliveryType in default filters state
- Cleaned ORDER_GROUP_DISPLAY_STATUS_OPTIONS: removed 'Повторное SMS' and 'SMS отправлены' (not used)
Раньше: все позиции отгружены → delivered, иначе → problem
Теперь: все отгружены ИЛИ все неотгруженные с комментарием → delivered
Только если есть неотгруженные без комментария → problem
- Все позиции отгружены → delivery_status = 'delivered'
- Частичная отгрузка (есть неотгруженные) → delivery_status = 'problem'
- Без сохранения отгрузки — статус не меняется
- saveShipmentData автоматически заполняет has_delivery_problem (boolean) и delivery_problem_note (текст с перечислением неотгруженных позиций и причин)
- OrdersTable: колонка 'Проблема' показывает ⚠ Проблема + детали из delivery_problem_note
- orderGroupViews: warning-тон для групп с hasDeliveryProblem
- n8n/1C: просто читать has_delivery_problem (0/1) и delivery_problem_note
- Водитель не мог сохранить данные отгрузки — RLS блокировал UPDATE
- Добавлена политика: driver может UPDATE order_groups где assigned_driver_id = auth.uid()
- Сохранена SQL-миграция в docs/sql/
- После нажатия 'Сохранить отгрузку' показывается заметный summary-блок
- Каждая позиция в отдельной карточке: зелёная рамка (отгружено) / оранжевая рамка (не отгружено)
- Причина неотгрузки показана внутри карточки
- Кнопка 'Изменить' позволяет вернуться к редактированию
- При повторном открытии — компактная плашка 'Отгрузка ранее сохранена'