Владелец: «нужно видеть, согласование прошло через пуш/смс/звонок/вручную через
менеджера» и «в колонке с именем клиента пишется просто «Согласовано» — непонятно
как и кем». Плюс в карточке «завтра/послезавтра» читалось как дата заказа.
Источник правды — order_groups.delivery_date_source: manual (логист), autocall
(робот), и теперь push/sms/messenger/client от клиентской страницы. Раньше клиентское
подтверждение канал не писало вовсе — такие записи разбираются по confirmed_at
приглашения (канал «link» → «По ссылке»).
- миграция 20260929_confirmation_channel.sql: confirm_delivery_choice_by_token
принимает p_src и сохраняет канал в delivery_date_source + action_logs.details;
- клиентская страница читает ?src= из ссылки и прокидывает в RPC (SMS-ссылка уже
содержит src=sms);
- orderGroupViews: resolveConfirmChannel/confirmChannelMeta — единый источник подписей
канала, плюс invitationConfirmedAt в репозитории (и в списке, и в карточке);
- реестр доставок/самовывозов: под статусом чип «как согласовано» (📞 звонок робота,
✉️ SMS-ссылка, 🔔 push, 🧑💼 логист, 🔗 по ссылке);
- карточка заказа: рядом с «Согласовано» тот же чип;
- AutocallStatusCard: «робот предлагал: завтра или послезавтра» вместо голого
«завтра/послезавтра» (читалось как дата заказа);
- Аналитика: в «Пути заказа» блок «Как согласовали дату» — полосы по каналам
(за 30 дней: логист 135, по ссылке 20, звонок робота 7, push 0).
Тесты: orderGroupViews +4, OrderPathFunnelBlock +1 (37 зелёных в этих файлах). SW v128.
- mapOrderGroupRowToDeliveryGroup dropped called/called_at/called_comment
fields (they were selected but never mapped) so the panel always read
'not called' and freshly saved calls appeared to vanish.
- CalledPanel: one-tap 'Звонили' marks called with now; app-styled
date/time dropdowns (CallDateTime) default to current moment for fast
entry; comment edit form pre-filled.
- OrderDetailPanel: forward real onRefreshOrder (was a silent no-op) so
the card refreshes from DB after a save.
- add fetchOrderGroupById (single .eq(id).single() query)
- useOrderGroups gains groupId mode: fetches one group, not full 2.6MB list
- GroupDetailPage passes groupId — fixes 30-40s card open on slow connections
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
- 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
- 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
Раньше: все позиции отгружены → 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
Edge function confirm-delivery-choice:
- currentGroup использовался до объявления — перемещён вверх
- pickup не очищал assigned_driver_id — добавлена очистка
- выборка currentGroup теперь включает delivery_address, customer_address
Edge function update-order-group-delivery-choice:
- добавлена поддержка deliveryType=pickup (ранее всегда ставил 'agreed')
- pickup очищает assigned_driver_id, устанавливает pickup_date/time_slot
- дата доставки не обязательна для pickup
Фронтенд:
- assignDriverToOrderGroup: null → 'agreed' (NOT NULL constraint)
- isDeliveryAgreed включает статус 'pickup'
- orderGroupViews: warning-тон для групп с проблемами отгрузки
- OrdersTable: колонка Отгрузка с визуализацией проблем
Bug 1: deliveryType='delivery' перезаписывался на 'pickup' маппером из-за адреса/источника. Теперь если БД явно содержит delivery_type='delivery', маппер это уважает.
Bug 2: водитель не мог сохранить частичную отгрузку — добавлена кнопка 'Сохранить отгрузку' в DriverShipmentPanel + saveShipmentData() в репозитории.
Bug 3: при смене типа на самовывоз assigned_driver_id не очищался — добавлено assigned_driver_id: null в updatePayload.
- P0-1: Move all hooks (useState, useCallback, useMemo) before early return to fix Rules of Hooks violation
- P0-3: Replace 7 inline isPickupOrder checks with single computed variable
- P1: Extract getErrorMessage, normalizeNom to shared utils/deliveryUtils.js
- P1: Replace duplicate STATUS_LABELS with DELIVERY_GROUP_STATUS_LABELS import
- P1: Add requires_address to DELIVERY_GROUP_STATUS_LABELS
- Remove duplicate getErrorMessage from useOrderGroups.js and OrderDetailPanel.jsx
- Remove duplicate normalizeNom from OrderDetailPanel.jsx and orderGroupRepository.js
- Added delivery address input field in manual agreement form (visible when delivery type)
- Pickup switching clears delivery_address in DB, delivery switching preserves/updates it
- useOrderGroups passes deliveryType, deliveryAddress, pickupDate, pickupTimeSlot to API
- orderGroupRepository: updateOrderGroupDeliveryChoice now handles delivery_type and address
- Pickup orders: address cleared, pickup_date/pickup_time_slot saved
- Delivery orders: address saved, pickup fields cleared
- Updated tests to match new payload structure
- orderGroupRepository: detect pickup from source_orders.ship='САМОВЫВОЗ' and address='САМОВЫВОЗ'
- orderGroupRepository: set effectiveDeliveryType='pickup' when source data indicates pickup even if DB says 'delivery'
- orderGroupRepository: clear deliveryAddress when it's just 'САМОВЫВОЗ' placeholder
- OrderDetailPanel: dynamic header 'Карточка группы самовывоза' vs 'Карточка группы доставки'
- OrderDetailPanel: subtitle now includes orderNumbers for visibility
- OrderDetailPanel: label changed from 'Номер счёта' to 'Заказ' with '+N сч.' for sub-bills
- GroupDetailPage: neutral 'Группа не найдена' instead of 'Группа доставки не найдена'
- Added pickup-specific test case
- Replaced window.confirm with inline confirmation panel in app style
- Shows confirmation block with 'Yes, transfer' / 'Cancel' buttons
- After transfer: shows 'Transferred to paid storage' with date and yellow indicator
- Added cancel button to revert from paid_storage back to pending_confirmation