docs: update documentation for pickup (самовывоз) feature and autodeploy

This commit is contained in:
root 2026-06-10 12:22:56 +00:00
parent 3651dbb484
commit 14fe89f899
7 changed files with 248 additions and 53 deletions

View File

@ -9,9 +9,26 @@ npm install
npm run dev npm run dev
``` ```
## Деплой
Приложение разворачивается через Docker (`docker-compose.app.yml`). Сборка и запуск:
```bash
docker compose -f docker-compose.app.yml up -d --build
```
### Автодеплой
Настроен webhook в Gitea: при пуше в `main` автоматически запускается деплой.
- **Webhook listener**: systemd-сервис `supersam-webhook` на порту 9000
- **Gitea hook**: push в `main``POST http://10.0.2.1:9000/webhook/supersam`
- **deploy.sh**: `git pull origin main``docker compose up -d --build`
- Репозиторий: `https://git.supersamsev.ru/mihail/supersam`
## Главный документ ## Главный документ
- [Обзор системы](/Users/mihailkucer/Documents/super-sam/docs/product-overview.md) — назначение приложения, роли, сценарии, клиентский flow и подготовка к показу. - [Обзор системы](docs/product-overview.md) — назначение приложения, роли, сценарии, клиентский flow и подготовка к показу.
## Что уже есть ## Что уже есть
@ -19,15 +36,23 @@ npm run dev
- Role-based dashboard для менеджера, логиста и водителя. - Role-based dashboard для менеджера, логиста и водителя.
- Карточка заказа с составом, комментариями и историей. - Карточка заказа с составом, комментариями и историей.
- Публичная страница `/delivery/:token` для выбора даты, половины дня и просмотра состава заказа. - Публичная страница `/delivery/:token` для выбора даты, половины дня и просмотра состава заказа.
- **Самовывоз** — вкладки Доставка/Самовывоз на клиентской странице, выбор даты и половины дня самовывоза, информация о бесплатном хранении (2 рабочих дня) и платном (300₽/день).
- Supabase SQL-схема, таблицы приглашений и Edge Functions для invitation flow. - Supabase SQL-схема, таблицы приглашений и Edge Functions для invitation flow.
- Документация по продукту, архитектуре и сценариям. - Документация по продукту, архитектуре и сценариям.
## Структура ## Структура
- `src/` — интерфейс и клиентская логика. - `src/` — интерфейс и клиентская логика.
- `src/constants/deliveryWorkflow.js` — статусы доставки, включая самовывоз.
- `src/components/client/DeliverySlotsPicker.jsx` — виджет выбора слотов доставки.
- `src/components/client/PickupSlotsPicker.jsx` — виджет выбора слотов самовывоза.
- `src/components/client/DeliveryChoiceFlow.jsx` — флоу согласования доставки/самовывоза.
- `src/pages/ClientDeliveryPage.jsx` — публичная страница с вкладками Доставка/Самовывоз.
- `src/components/orders/OrderDetailPanel.jsx` — карточка заказа с управлением доставкой и самовывозом.
- `supabase/schema.sql` — структура БД, роли, индексы, RLS, триггеры. - `supabase/schema.sql` — структура БД, роли, индексы, RLS, триггеры.
- `supabase/functions/` — Edge Functions для приглашений, статусов и чат-коммуникаций. - `supabase/functions/` — Edge Functions для приглашений, статусов и чат-коммуникаций.
- `supabase/seed/stage-1-demo.sql` — набор seed-данных для показа заказчику. - `supabase/seed/stage-1-demo.sql` — набор seed-данных для показа заказчику.
- `docs/architecture.md` — архитектура фронтенда и модулей. - `docs/architecture.md` — архитектура фронтенда и модулей.
- `docs/product-overview.md` — общий обзор продукта, ролей и сценариев. - `docs/product-overview.md` — общий обзор продукта, ролей и сценариев.
- `docs/scenarios.md` — сценарии жизненного цикла заказа. - `docs/scenarios.md` — сценарии жизненного цикла заказа.
- `docs/n8n-order-group-delivery-flow.md` — потоки n8n для оркестрации доставки.

View File

@ -1,30 +1,6 @@
#!/bin/bash #!/bin/bash
set -e set -e
cd /opt/supersam cd /opt/supersam
git pull origin main
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deploy starting..."
# Pull latest from main
git fetch origin main
BEFORE=$(git rev-parse HEAD)
git reset --hard origin/main
AFTER=$(git rev-parse HEAD)
if [ "$BEFORE" = "$AFTER" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] No changes, skipping rebuild."
exit 0
fi
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Updated: ${BEFORE:0:7} -> ${AFTER:0:7}"
# Rebuild and restart
docker compose -f docker-compose.app.yml up -d --build docker compose -f docker-compose.app.yml up -d --build
echo 'Deploy completed at' $(date)
# Wait for container to be healthy
sleep 3
if docker ps --format '{{.Names}}' | grep -q 'supersam-app'; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deploy complete. Container running."
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Container not running after deploy!"
exit 1
fi

View File

@ -6,17 +6,25 @@
- `src/context/ThemeContext.jsx` — управление светлой и тёмной темой через `data-theme`. - `src/context/ThemeContext.jsx` — управление светлой и тёмной темой через `data-theme`.
- `src/hooks/usePwaStatus.js` — клиентское состояние PWA: online/offline, install prompt, standalone и offline readiness. - `src/hooks/usePwaStatus.js` — клиентское состояние PWA: online/offline, install prompt, standalone и offline readiness.
- `src/hooks/useOrders.js` — локальный state заказов, истории, чатов, фильтров, действий и **сгруппированных наборов доставки** (deliverySetBuckets). - `src/hooks/useOrders.js` — локальный state заказов, истории, чатов, фильтров, действий и **сгруппированных наборов доставки** (deliverySetBuckets).
- `src/hooks/useOrderGroups.js` — работа с группами заказов: загрузка, обновление статусов, ручное согласование доставки и самовывоза. Метод `saveManualDeliveryChoice` принимает `deliveryType`, `pickupDate`, `pickupTimeSlot`.
- `src/services/deliverySetViews.js` — чистые функции группировки импортированных заказов в наборы доставки с buckets: «На подходе», «Готово к запуску», «Ожидает клиента», «Нужна ручная работа», «Согласовано», «Завершено». - `src/services/deliverySetViews.js` — чистые функции группировки импортированных заказов в наборы доставки с buckets: «На подходе», «Готово к запуску», «Ожидает клиента», «Нужна ручная работа», «Согласовано», «Завершено».
- `src/services/orderService.js` — чистые функции бизнес-логики заказов, покрытые тестами. - `src/services/orderService.js` — чистые функции бизнес-логики заказов, покрытые тестами.
- `src/services/supabase/orderRepository.js` — адаптер реальных чтений/записей заказов и чатов в Supabase, включая source-поля 1С и delivery-set поля. - `src/services/supabase/orderRepository.js` — адаптер реальных чтений/записей заказов и чатов в Supabase, включая source-поля 1С и delivery-set поля.
- `src/services/supabase/orderGroupRepository.js` — репозиторий групп заказов. Маппинг полей включает `deliveryType`, `pickupDate`, `pickupTimeSlot`. Метод `updateOrderGroupDeliveryChoice` поддерживает как доставку, так и самовывоз.
- `src/services/deliveryWorkflow.js` — карта статусов доставки и переходов. Включает статус `pickup` (Самовывоз) с переходами в/из других статусов.
- `src/services/orderGroupViews.js` — метки и цвета для статусов, включая `pickup: "Самовывоз"`.
- `src/services/deliveryInvitationApi.js` — API для приглашений доставки. `confirmDeliveryChoice` принимает `deliveryType`, `pickupDate`, `pickupTimeSlot`.
- `src/services/driverDeliveries.js` — фильтрация и группировка доставок для рабочей области водителя. - `src/services/driverDeliveries.js` — фильтрация и группировка доставок для рабочей области водителя.
- `src/layouts/AppShell.jsx` — общий shell с боковой навигацией, уведомлениями и переключением темы. - `src/layouts/AppShell.jsx` — общий shell с боковой навигацией, уведомлениями и переключением темы.
- `src/components/logistics/LogisticsReadinessBoard.jsx` — интерактивная доска с bucket-ами наборов доставки. - `src/components/logistics/LogisticsReadinessBoard.jsx` — интерактивная доска с bucket-ами наборов доставки.
- `src/components/logistics/DeliverySetDetailPanel.jsx` — детальная карточка набора доставки: source-поля 1С, production-шаги, слоты, действия. - `src/components/logistics/DeliverySetDetailPanel.jsx` — детальная карточка набора доставки: source-поля 1С, production-шаги, слоты, действия.
- `src/components/client/DeliverySlotsPicker.jsx` — публичный виджет выбора даты и половины дня доставки. - `src/components/client/DeliverySlotsPicker.jsx` — публичный виджет выбора даты и половины дня доставки.
- `src/components/client/DeliveryChoiceFlow.jsx` — публичный поток согласования доставки по приглашению. - `src/components/client/PickupSlotsPicker.jsx` — публичный виджет выбора даты и половины дня самовывоза. Отображает доступные даты (сегодня до 12:00, завтра, послезавтра, без выходных), слоты «До обеда»/«После обеда», и информационный блок о стоимости хранения: «Бесплатное хранение — 2 рабочих дня. С 3-го рабочего дня — 300₽/день.».
- `src/components/client/DeliveryChoiceFlow.jsx` — публичный поток согласования доставки или самовывоза по приглашению. Принимает `deliveryType` и показывает динамические лейблы.
- `src/components/client/DeliveryStateNotice.jsx` — информационный экран для clients со статусом ссылки. - `src/components/client/DeliveryStateNotice.jsx` — информационный экран для clients со статусом ссылки.
- `src/pages/ClientDeliveryPage.jsx` — публичная страница согласования доставки с вкладками 🚚 Доставка / 🏪 Самовывоз. Переключение типа получения, отображение соответствующего пикера слотов.
- `src/components/orders/*` — фильтры, список заказов, карточка заказа, история статусов и поиск по чату. - `src/components/orders/*` — фильтры, список заказов, карточка заказа, история статусов и поиск по чату.
- `src/components/orders/OrderDetailPanel.jsx` — карточка заказа с управлением доставкой и самовывозом. Вкладки Доставка/Самовывоз, поля даты самовывоза и половины дня, кнопка статуса «Самовывоз».
- `src/components/orders/OrderEditorPanel.jsx` — создание и редактирование заказа менеджером или администратором. - `src/components/orders/OrderEditorPanel.jsx` — создание и редактирование заказа менеджером или администратором.
- `src/components/dashboard/ProductionQueuePanel.jsx` — отдельный блок производственной очереди. - `src/components/dashboard/ProductionQueuePanel.jsx` — отдельный блок производственной очереди.
- `src/components/dashboard/RoleWorkspacePanel.jsx` — рабочая панель с delivery-set bucket-ами для логиста. - `src/components/dashboard/RoleWorkspacePanel.jsx` — рабочая панель с delivery-set bucket-ами для логиста.
@ -31,15 +39,42 @@
- **Логист** видит наборы доставки, слоты, сообщения чатбота и ручную обработку исключений. - **Логист** видит наборы доставки, слоты, сообщения чатбота и ручную обработку исключений.
- **Водитель** видит только назначенные доставки и может переводить их через статусы `Загружен`, `В пути`, `Доставлен`, `Проблема доставки`. - **Водитель** видит только назначенные доставки и может переводить их через статусы `Загружен`, `В пути`, `Доставлен`, `Проблема доставки`.
- **Администратор** видит весь массив заказов, доставок и системные логи. - **Администратор** видит весь массив заказов, доставок и системные логи.
- **Менеджер** может назначить тип доставки (доставка/самовывоз), дату и половину дня.
- Клиент не является авторизованным пользователем приложения. Клиент использует публичную ссылку приглашения. - Клиент не является авторизованным пользователем приложения. Клиент использует публичную ссылку приглашения.
## Ключевые экраны ## Ключевые экраны
- `/login` — email + OTP flow. При отсутствии `VITE_SUPABASE_*` включается demo-режим. Подсказка проверять входящие и спам. Неизвестный email: «Email не найден в системе. Обратитесь к администратору.» - `/login` — email + OTP flow. При отсутствии `VITE_SUPABASE_*` включается demo-режим. Подсказка проверять входящие и спам. Неизвестный email: «Email не найден в системе. Обратитесь к администратору.»
- `/dashboard` — role-based control center: для логиста — LogisticsReadinessBoard с наборами доставки, для водителя — план маршрута и быстрые действия. - `/dashboard` — role-based control center: для логиста — LogisticsReadinessBoard с наборами доставки, для водителя — план маршрута и быстрые действия.
- `/delivery/:token` — публичная страница согласования доставки для клиента. - `/delivery/:token` — публичная страница согласования доставки для клиента с вкладками Доставка/Самовывоз.
- `public/manifest.webmanifest` + `public/service-worker.js` — installable PWA-оболочка и базовое кеширование shell для demo offline. - `public/manifest.webmanifest` + `public/service-worker.js` — installable PWA-оболочка и базовое кеширование shell для demo offline.
## Тип получения: Доставка и Самовывоз
### Переключатель типа
На клиентской странице (`ClientDeliveryPage`) и в карточке заказа (`OrderDetailPanel`) реализованы вкладки:
- **🚚 Доставка** — стандартный флоу с выбором даты и половины дня.
- **🏪 Самовывоз** — выбор даты самовывоза (сегодня/завтра/послезавтра, без выходных) и половины дня.
### Статус «Самовывоз»
В `deliveryWorkflow.js` добавлен статус `pickup` с переходами:
- `pending_confirmation``pickup`
- `manual_confirmation_required``pickup`
- `pickup``assigned_to_driver`, `delivered`, `cancelled`
### База данных
Колонки в `order_groups`:
- `delivery_type text DEFAULT 'delivery'` — тип получения
- `pickup_date date` — дата самовывоза
- `pickup_time_slot text` — «До обеда» / «После обеда»
RPC `confirm_delivery_choice_by_token` обновлён: при `delivery_type = 'pickup'` устанавливает `delivery_status = 'pickup'`, `pickup_date` и `pickup_time_slot`.
Edge function `confirm-delivery-choice` передаёт `p_delivery_type`, `p_pickup_date`, `p_pickup_time_slot` в RPC.
## Источник заказов: 1С → Supabase ## Источник заказов: 1С → Supabase
- Заказы импортируются из 1С через XML и сохраняются в `public.orders` с source-полями: `source_order_number`, `source_customer_name`, `source_accept_at`, `source_ship_at` и т.д. - Заказы импортируются из 1С через XML и сохраняются в `public.orders` с source-полями: `source_order_number`, `source_customer_name`, `source_accept_at`, `source_ship_at` и т.д.
@ -59,4 +94,10 @@
- `src/supabaseClient.js` создаёт клиент Supabase через env-переменные. - `src/supabaseClient.js` создаёт клиент Supabase через env-переменные.
- `src/services/safeSupabaseCall.js` стандартизирует обработку ошибок. - `src/services/safeSupabaseCall.js` стандартизирует обработку ошибок.
- Данные UI разложены по сущностям, совпадающим с таблицами Supabase: `orders`, `order_history`, `chat_messages`, `delivery_slots`, `delivery_invitations`. - Данные UI разложены по сущностям, совпадающим с таблицами Supabase: `orders`, `order_history`, `chat_messages`, `delivery_slots`, `delivery_invitations`.
- В `orders` синхронизированы поля `status`, `delivery_agreement_status`, `assigned_driver_id`, а также source-поля 1С и delivery-set данные. - В `orders` синхронизированы поля `status`, `delivery_agreement_status`, `assigned_driver_id`, а также source-поля 1С и delivery-set данные.
## Деплой
- Docker-сборка через `docker-compose.app.yml` (multi-stage: Node.js build → Caddy serve).
- Автодеплой: Gitea webhook → systemd `supersam-webhook``deploy.sh` (git pull + docker build).
- Домен: `https://dost.supersamsev.ru/`

View File

@ -26,7 +26,9 @@
- `second_sms_sent_at` - время второй SMS - `second_sms_sent_at` - время второй SMS
- `last_sms_error` - текст последней ошибки провайдера - `last_sms_error` - текст последней ошибки провайдера
- `next_notification_check_at` - когда `n8n` должен вернуться к записи - `next_notification_check_at` - когда `n8n` должен вернуться к записи
- `delivery_date` и `delivery_time` - выбранный слот после подтверждения клиентом - `delivery_date` и `delivery_time` - выбранный слот доставки после подтверждения клиентом
- `delivery_type` - тип получения: `delivery` (доставка) или `pickup` (самовывоз)
- `pickup_date` и `pickup_time_slot` - выбранный слот самовывоза после подтверждения клиентом
## Окно отправки SMS ## Окно отправки SMS
@ -66,6 +68,7 @@ public.next_order_group_sms_check_at(start_from timestamptz, delay interval)
- `out_for_delivery` - водитель уже в работе - `out_for_delivery` - водитель уже в работе
- `delivered` - доставка завершена - `delivered` - доставка завершена
- `cancelled` - группу больше не нужно обрабатывать - `cancelled` - группу больше не нужно обрабатывать
- `pickup` - клиент выбрал самовывоз
### `notification_status` ### `notification_status`
@ -275,6 +278,14 @@ docs/sql/order-groups-auto-delivery-link.sql
Никакой логики SMS на фронтенде быть не должно. Никакой логики SMS на фронтенде быть не должно.
Никакой генерации ссылок на фронтенде быть не должно. Никакой генерации ссылок на фронтенде быть не должно.
## Самовывоз
Когда клиент выбирает вкладку «Самовывоз» на публичной странице:
1. `confirm-delivery-choice` получает `delivery_type = 'pickup'` вместе с `pickup_date` и `pickup_time_slot`.
2. RPC `confirm_delivery_choice_by_token` устанавливает `delivery_status = 'pickup'`, `delivery_type = 'pickup'`, `pickup_date`, `pickup_time_slot`.
3. SMS-потоки n8n должны игнорировать строки со `delivery_status = 'pickup'` — клиент сам забирает заказ, напоминания о доставке не нужны.
## Минимальный порядок внедрения ## Минимальный порядок внедрения
1. Развернуть обновленную схему `Supabase` и `docs/sql/order-groups-auto-delivery-link.sql`. 1. Развернуть обновленную схему `Supabase` и `docs/sql/order-groups-auto-delivery-link.sql`.

View File

@ -7,7 +7,7 @@
- показать менеджеру единый реестр доставочных заказов с поиском и карточкой заказа; - показать менеджеру единый реестр доставочных заказов с поиском и карточкой заказа;
- показать логисту список доставок на сегодня и ближайшие дни с половинами дня; - показать логисту список доставок на сегодня и ближайшие дни с половинами дня;
- показать водителю свои доставки, адрес, состав заказа и базовые статусы; - показать водителю свои доставки, адрес, состав заказа и базовые статусы;
- дать клиенту публичную ссылку, по которой он выбирает дату и половину дня доставки; - дать клиенту публичную ссылку, по которой он выбирает дату и половину дня доставки **или самовывоза**;
- хранить состояние заказов, приглашений и истории изменений в Supabase. - хранить состояние заказов, приглашений и истории изменений в Supabase.
## Роли ## Роли
@ -17,6 +17,7 @@
- видит список заказов доставки; - видит список заказов доставки;
- ищет по номеру заказа, клиенту и телефону; - ищет по номеру заказа, клиенту и телефону;
- открывает карточку заказа и смотрит состав, комментарии и историю; - открывает карточку заказа и смотрит состав, комментарии и историю;
- может назначить тип доставки (доставка/самовывоз), дату самовывоза и половину дня;
- не работает с созданием заказов и внутренними служебными экранами. - не работает с созданием заказов и внутренними служебными экранами.
### Логист ### Логист
@ -24,7 +25,8 @@
- видит заказы, готовые к доставке; - видит заказы, готовые к доставке;
- смотрит ближайшие даты: сегодня, завтра и послезавтра; - смотрит ближайшие даты: сегодня, завтра и послезавтра;
- смотрит половину дня и текущий статус доставки; - смотрит половину дня и текущий статус доставки;
- открывает карточку заказа, чтобы свериться с деталями. - открывает карточку заказа, чтобы свериться с деталями;
- может перевести статус заказа в «Самовывоз» и указать дату.
### Водитель ### Водитель
@ -36,9 +38,40 @@
- получает публичную ссылку вида `/delivery/:token`; - получает публичную ссылку вида `/delivery/:token`;
- видит номер заказа и состав заказа; - видит номер заказа и состав заказа;
- выбирает дату и половину дня: `До обеда` или `После обеда`; - **выбирает тип получения: Доставка или Самовывоз**;
- при выборе доставки — выбирает дату и половину дня: `До обеда` или `После обеда`;
- при выборе самовывоза — выбирает дату (сегодня/завтра/послезавтра с учётом выходных) и половину дня;
- видит информацию о бесплатном хранении (2 рабочих дня) и платном (300₽/день начиная с 3-го рабочего дня);
- подтверждает выбор без входа во внутренний кабинет. - подтверждает выбор без входа во внутренний кабинет.
## Самовывоз
### Клиентский флоу
1. Клиент открывает ссылку `/delivery/:token`.
2. Видит две вкладки: **🚚 Доставка** и **🏪 Самовывоз**.
3. На вкладке «Самовывоз» видит:
- Доступные даты: сегодня (если до 12:00 текущего дня готовности), завтра, послезавтра (выходные пропускаются).
- Две половины дня: «До обеда» и «После обеда».
- Информационный блок: «Бесплатное хранение — 2 рабочих дня. С 3-го рабочего дня — 300₽/день.»
4. Выбирает дату и половину дня, подтверждает.
5. Статус заказа переходит в `pickup`, в БД сохраняются `pickup_date` и `pickup_time_slot`.
### Управление в карточке заказа
- Менеджер, логист и администратор могут переключить тип доставки (Доставка ↔ Самовывоз).
- При самовывозе доступны поля: дата самовывоза и половина дня.
- Статус «Самовывоз» доступен в кнопках смены статуса.
### База данных
В таблице `order_groups` добавлены колонки:
- `delivery_type text DEFAULT 'delivery'` — тип получения: `delivery` или `pickup`
- `pickup_date date` — дата самовывоза
- `pickup_time_slot text` — половина дня самовывоза (`До обеда` / `После обеда`)
Статус `delivery_status` пополнился значением `pickup` — «Самовывоз».
## Основные сценарии ## Основные сценарии
### Внутренний сценарий ### Внутренний сценарий
@ -48,7 +81,7 @@
3. Логист отслеживает готовность и ближайшее окно доставки. 3. Логист отслеживает готовность и ближайшее окно доставки.
4. Водитель получает свою доставку и доводит её до результата. 4. Водитель получает свою доставку и доводит её до результата.
### Сценарий клиента ### Сценарий клиента (доставка)
Клиентская страница работает по token из таблицы `public.delivery_invitations`. Клиентская страница работает по token из таблицы `public.delivery_invitations`.
@ -59,21 +92,27 @@
Эта ссылка показывает: Эта ссылка показывает:
- заказ `CD-240031`; - заказ `CD-240031`;
- состав заказа; - состав заказа;
- четыре варианта слота; - вкладки «Доставка» и «Самовывоз»;
- две даты; - на вкладке «Доставка» — четыре варианта слота, две даты, две половины дня.
- две половины дня: `До обеда` и `После обеда`.
После подтверждения выбора: ### Сценарий клиента (самовывоз)
- invitation переводится в состояние `agreed`;
- заказ переводится в `Доставка согласована`; При выборе вкладки «Самовывоз»:
- в `order_history` появляется запись о подтверждении; - доступны даты начиная с дня готовности (если до 12:00) или завтра;
- в `delivery_slots` фиксируется подтверждённый слот. - две половины дня: «До обеда» и «После обеда»;
- информационный блок о стоимости хранения;
- подтверждение устанавливает `delivery_type = 'pickup'`, `delivery_status = 'pickup'`.
## Что хранится в Supabase ## Что хранится в Supabase
- `public.users` — пользователи и роли; - `public.users` — пользователи и роли;
- `public.orders` — заказы и текущие статусы; - `public.orders` — заказы и текущие статусы;
- `public.order_history` — история изменений; - `public.order_history` — история изменений;
- `public.order_groups` — группы заказов с полями доставки и самовывоза:
- `delivery_type``delivery` или `pickup`;
- `delivery_date`, `delivery_time` — слот доставки;
- `pickup_date`, `pickup_time_slot` — слот самовывоза;
- `delivery_status` — статус согласования (включая `pickup`);
- `public.delivery_slots` — возможные и подтверждённые слоты доставки; - `public.delivery_slots` — возможные и подтверждённые слоты доставки;
- `public.delivery_invitations` — публичные invitation token и состояние клиентского flow; - `public.delivery_invitations` — публичные invitation token и состояние клиентского flow;
- `public.integration_events` — технические и интеграционные события. - `public.integration_events` — технические и интеграционные события.
@ -95,11 +134,13 @@
- реестр заказов и карточку заказа; - реестр заказов и карточку заказа;
- список доставок по датам для логиста; - список доставок по датам для логиста;
- карточку доставки водителя; - карточку доставки водителя;
- клиентскую ссылку с выбором даты и половины дня. - клиентскую ссылку с выбором типа получения (доставка/самовывоз) и датой;
- информационный блок о стоимости хранения при самовывозе.
## Полезные документы ## Полезные документы
- [README](/Users/mihailkucer/Documents/super-sam/README.md) - [README](../README.md)
- [Архитектура](/Users/mihailkucer/Documents/super-sam/docs/architecture.md) - [Архитектура](architecture.md)
- [Сценарии](/Users/mihailkucer/Documents/super-sam/docs/scenarios.md) - [Сценарии](scenarios.md)
- [Edge Functions](/Users/mihailkucer/Documents/super-sam/supabase/functions/README.md) - [Поток n8n](n8n-order-group-delivery-flow.md)
- [Edge Functions](../supabase/functions/README.md)

View File

@ -20,15 +20,16 @@
- Перечнем заказов набора, их 1С-номерами и шагами производства (раскрой, склейка, криволинейные, контроль качества, отгрузка). - Перечнем заказов набора, их 1С-номерами и шагами производства (раскрой, склейка, криволинейные, контроль качества, отгрузка).
- Телефоном и email клиента, городом, связанными счетами. - Телефоном и email клиента, городом, связанными счетами.
- Текущим статусом слота. - Текущим статусом слота.
3. Логист может запустить приглашение, назначить водителя или перейти к ручной обработке.
## 3. Согласование доставки с клиентом ## 3. Согласование доставки с клиентом
1. Когда набор доставки готов, логист запускает отправку приглашения клиенту. 1. Когда набор доставки готов, логист запускает отправку приглашения клиенту.
2. Клиент получает ссылку на `/delivery/:token`. 2. Клиент получает ссылку на `/delivery/:token`.
3. На странице клиент видит **DeliverySlotsPicker** с доступными датами и половинами дня. 3. На странице клиент видит вкладки **🚚 Доставка** и **🏪 Самовывоз**.
4. Клиент выбирает слот и подтверждает. Статус набора переходит в «Ожидает клиента» → «Согласовано». 4. На вкладке «Доставка» — **DeliverySlotsPicker** с доступными датами и половинами дня.
5. Если клиент не отвечает, система или логист переводит набор в «Нужна ручная работа». 5. На вкладке «Самовывоз» — **PickupSlotsPicker** с датами (сегодня до 12:00, завтра, послезавтра, без выходных) и половинами дня, а также информационный блок: «Бесплатное хранение — 2 рабочих дня. С 3-го рабочего дня — 300₽/день.»
6. Клиент выбирает тип получения, слот и подтверждает. Статус набора переходит в «Ожидает клиента» → «Согласовано» или «Самовывоз».
7. Если клиент не отвечает, система или логист переводит набор в «Нужна ручная работа».
## 4. Перенос доставки ## 4. Перенос доставки
@ -55,6 +56,30 @@
2. После закрытия всех заказов набора он переходит в «Завершено». 2. После закрытия всех заказов набора он переходит в «Завершено».
3. В истории появляется финальная запись, а чат закрывается для активных действий. 3. В истории появляется финальная запись, а чат закрывается для активных действий.
## 8. Самовывоз
### Клиентский сценарий
1. Клиент открывает ссылку `/delivery/:token`.
2. Выбирает вкладку **🏪 Самовывоз**.
3. Видит доступные даты: сегодня (если до 12:00 текущего дня готовности), завтра, послезавтра (выходные пропускаются).
4. Выбирает дату и половину дня: «До обеда» или «После обеда».
5. Видит информационный блок: «Бесплатное хранение — 2 рабочих дня. С 3-го рабочего дня — 300₽/день.»
6. Подтверждает выбор.
7. В БД устанавливаются: `delivery_type = 'pickup'`, `delivery_status = 'pickup'`, `pickup_date`, `pickup_time_slot`.
### Сценарий менеджера/логиста
1. В карточке заказа (**OrderDetailPanel**) менеджер видит вкладки Доставка/Самовывоз.
2. При выборе «Самовывоз» — поля даты и половины дня для самовывоза.
3. Кнопка статуса «Самовывоз» доступна для менеджера, логиста и администратора.
4. Менеджер может переключить тип доставки в любой момент до передачи водителю.
### Статусы самовывоза
- `pickup` — заказ ожидает самовывоза клиентом.
- Переходы: `pending_confirmation``pickup`, `manual_confirmation_required``pickup`, `pickup``assigned_to_driver`, `pickup``delivered`, `pickup``cancelled`.
## Сценарий показа заказчику ## Сценарий показа заказчику
1. Зайти под логистом. 1. Зайти под логистом.
@ -65,6 +90,6 @@
- Фролова И.Д. — «Нужна ручная работа» (платное хранение). - Фролова И.Д. — «Нужна ручная работа» (платное хранение).
- Орлова Н.С. — «Завершено». - Орлова Н.С. — «Завершено».
3. Кликнуть по набору Савина — увидеть source-поля, production-шаги, готовность к запуску. 3. Кликнуть по набору Савина — увидеть source-поля, production-шаги, готовность к запуску.
4. Перейти на публичную страницу приглашения — увидеть `DeliverySlotsPicker` с выбором даты и половины дня. 4. Перейти на публичную страницу приглашения — увидеть вкладки «Доставка» и «Самовывоз» с выбором даты и половины дня.
5. Зайти под водителем — увидеть назначенные доставки с адресами и быстрыми действиями. 5. Зайти под водителем — увидеть назначенные доставки с адресами и быстрыми действиями.
6. Зайти под несуществующим email — увидеть «Email не найден в системе. Обратитесь к администратору.» 6. Зайти под несуществующим email — увидеть «Email не найден в системе. Обратитесь к администратору.»

76
webhook-listener.py Executable file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""Simple webhook listener for Gitea push events to trigger supersam deploy."""
import json
import hashlib
import hmac
import subprocess
import logging
from http.server import HTTPServer, BaseHTTPRequestHandler
SECRET = '1032ef91aacd726907bb72c023813c6827f56354902cc7b30e72626690c6d51d'
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
logger = logging.getLogger('webhook')
class WebhookHandler(BaseHTTPRequestHandler):
def verify_signature(self, body):
signature = self.headers.get('X-Gitea-Signature', '')
if not signature:
return False
computed = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, computed)
def do_POST(self):
if self.path == '/webhook/supersam':
content_length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(content_length) if content_length else b''
if not self.verify_signature(body):
self.send_response(403)
self.end_headers()
self.wfile.write(b'{"error": "invalid signature"}')
return
try:
payload = json.loads(body) if body else {}
ref = payload.get('ref', '')
if ref == 'refs/heads/main':
logger.info('Push to main detected, starting deploy...')
result = subprocess.run(
['/opt/supersam/deploy.sh'],
capture_output=True, text=True, timeout=600
)
logger.info('Deploy exit code: %s', result.returncode)
if result.returncode != 0:
logger.error('Deploy stderr: %s', result.stderr[-2000:])
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'status': 'deployed', 'exit_code': result.returncode}).encode())
else:
logger.info('Ignoring push to %s', ref)
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(b'{"status": "ignored"}')
except Exception as e:
logger.error('Error: %s', e)
self.send_response(500)
self.end_headers()
self.wfile.write(json.dumps({'error': str(e)}).encode())
else:
self.send_response(404)
self.end_headers()
def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(b'{"status": "ok"}')
else:
self.send_response(404)
self.end_headers()
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 9000), WebhookHandler)
logger.info('Webhook listener on http://0.0.0.0:9000')
server.serve_forever()