From 62447495454f747d07b5114bcdd70ebc10f115c3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 20 May 2026 12:19:30 +0300 Subject: [PATCH] feat: unify manual_required status and driver label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - orderGroupViews: unify notification manual_required + pending delivery_status into single "Требуется ручное управление" status - LogisticsReadinessBoard: use status:manual_required in funnel instead of delivery:manual_confirmation_required - DriverDeliveryPlanner: show "Назначено вам" for driver_assigned instead of "Назначен водитель" - Add sync-manual-status.sql trigger patch for backend --- .../driver/DriverDeliveryPlanner.jsx | 4 +- .../logistics/LogisticsReadinessBoard.jsx | 2 +- src/services/orderGroupViews.js | 25 ++++++-- supabase/sync-manual-status.sql | 61 +++++++++++++++++++ 4 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 supabase/sync-manual-status.sql diff --git a/src/components/driver/DriverDeliveryPlanner.jsx b/src/components/driver/DriverDeliveryPlanner.jsx index af4240f..04ec81b 100644 --- a/src/components/driver/DriverDeliveryPlanner.jsx +++ b/src/components/driver/DriverDeliveryPlanner.jsx @@ -17,7 +17,7 @@ const DRIVER_DELIVERY_STATUS_OPTIONS = [ { value: "all", label: "Все статусы" }, ...DRIVER_VISIBLE_DELIVERY_STATUSES.map((status) => ({ value: status, - label: getOrderGroupDeliveryStatusLabel(status), + label: status === "driver_assigned" ? "Назначено вам" : getOrderGroupDeliveryStatusLabel(status), })), ]; @@ -211,7 +211,7 @@ export const DriverDeliveryPlanner = ({ orderGroups = [], onOpenOrder, currentUs - {getOrderGroupDeliveryStatusLabel(item.deliveryStatus || item.delivery_status)} + {(() => { const s = item.deliveryStatus || item.delivery_status; return s === "driver_assigned" ? "Назначено вам" : getOrderGroupDeliveryStatusLabel(s); })()} diff --git a/src/components/logistics/LogisticsReadinessBoard.jsx b/src/components/logistics/LogisticsReadinessBoard.jsx index 699b539..ba2744f 100644 --- a/src/components/logistics/LogisticsReadinessBoard.jsx +++ b/src/components/logistics/LogisticsReadinessBoard.jsx @@ -55,7 +55,7 @@ export const LogisticsReadinessBoard = ({ orderGroups = [], onSelectSet, statusO const FUNNEL_ORDER = [ "status:ready_for_notification", "delivery:pending_confirmation", - "delivery:manual_confirmation_required", + "status:manual_required", "status:first_sms_sent", "status:second_sms_sent", "delivery:agreed", diff --git a/src/services/orderGroupViews.js b/src/services/orderGroupViews.js index 65d7a39..d3b0d1d 100644 --- a/src/services/orderGroupViews.js +++ b/src/services/orderGroupViews.js @@ -4,7 +4,7 @@ const getDeliveryDate = (group) => normalizeDate(group.deliveryDate || group.cus export const DELIVERY_GROUP_STATUS_LABELS = { pending_confirmation: "Ожидает согласования", - manual_confirmation_required: "Требуется ручное подтверждение", + manual_confirmation_required: "Взят в ручное управление", agreed: "Согласовано", driver_assigned: "Назначен водитель", loaded: "Загружено", @@ -22,7 +22,7 @@ export const NOTIFICATION_STATUS_LABELS = { second_sms_sent: "2-е приглашение отправлено", send_failed: "Ошибка отправки", confirmed: "Согласовано", - manual_required: "Переведено в ручное", + manual_required: "Требуется ручное подтверждение", }; export const DRIVER_VISIBLE_DELIVERY_STATUSES = [ @@ -140,12 +140,19 @@ export const getOrderGroupDeliveryStatusLabel = (status) => export const getOrderGroupDisplayStatusLabel = (group) => { const deliveryStatus = group?.deliveryStatus || group?.delivery_status; + const notificationStatus = group?.notificationStatus || group?.notification_status; - if (deliveryStatus && deliveryStatus !== "pending_confirmation") { + // When auto-SMS failed and logistics hasn't taken action yet → show as a todo item + const isManualRequired = notificationStatus === "manual_required"; + const isStillPending = !deliveryStatus || deliveryStatus === "pending_confirmation" || deliveryStatus === "manual_confirmation_required"; + if (isManualRequired && isStillPending) { + return "Требуется ручное управление"; + } + + if (deliveryStatus && deliveryStatus !== "pending_confirmation" && deliveryStatus !== "manual_confirmation_required") { return getOrderGroupDeliveryStatusLabel(deliveryStatus); } - const notificationStatus = group?.notificationStatus || group?.notification_status; const notificationLabel = NOTIFICATION_STATUS_LABELS[notificationStatus]; if (notificationLabel && notificationStatus !== "link_ready" && notificationStatus !== "not_started") { return notificationLabel; @@ -156,8 +163,16 @@ export const getOrderGroupDisplayStatusLabel = (group) => { export const getOrderGroupDisplayStatusValue = (group) => { const deliveryStatus = group?.deliveryStatus || group?.delivery_status; + const notificationStatus = group?.notificationStatus || group?.notification_status; - if (deliveryStatus) { + // Unify manual_required into a single bucket regardless of delivery_status detail + const isManualRequired = notificationStatus === "manual_required"; + const isStillPending = !deliveryStatus || deliveryStatus === "pending_confirmation" || deliveryStatus === "manual_confirmation_required"; + if (isManualRequired && isStillPending) { + return "status:manual_required"; + } + + if (deliveryStatus && deliveryStatus !== "pending_confirmation" && deliveryStatus !== "manual_confirmation_required") { return `delivery:${deliveryStatus}`; } diff --git a/supabase/sync-manual-status.sql b/supabase/sync-manual-status.sql new file mode 100644 index 0000000..a145590 --- /dev/null +++ b/supabase/sync-manual-status.sql @@ -0,0 +1,61 @@ +-- Sync manual_required notification_status into unified "Требуется ручное управление" workflow +-- and clear it when logistics takes action (changes delivery_status). + +-- 1. Backfill: normalize existing rows where notification_status is manual_required +-- and delivery_status is still pending/manual_confirmation_required. +update public.order_groups +set delivery_status = 'pending_confirmation', + updated_at = timezone('utc', now()) +where notification_status = 'manual_required' + and delivery_status = 'manual_confirmation_required'; + +-- 2. When notification_status becomes manual_required, ensure delivery_status stays pending +-- so the group appears in the unified "Требуется ручное управление" bucket. +create or replace function public.sync_manual_required_notification() +returns trigger +language plpgsql +security definer +set search_path = public +as $$ +begin + -- Only act when notification_status changed to manual_required + if new.notification_status = 'manual_required' + and (old is null or old.notification_status is distinct from new.notification_status) then + if new.delivery_status is null or new.delivery_status = 'manual_confirmation_required' then + new.delivery_status := 'pending_confirmation'; + end if; + end if; + return new; +end; +$$; + +drop trigger if exists sync_manual_required_notification_trigger on public.order_groups; +create trigger sync_manual_required_notification_trigger + before insert or update on public.order_groups + for each row + execute function public.sync_manual_required_notification(); + +-- 3. When delivery_status is changed by logistics (away from pending/manual_confirmation_required), +-- clear notification_status so the group leaves the manual-work bucket. +create or replace function public.clear_manual_required_on_action() +returns trigger +language plpgsql +security definer +set search_path = public +as $$ +begin + if old.delivery_status in ('pending_confirmation', 'manual_confirmation_required') + and new.delivery_status not in ('pending_confirmation', 'manual_confirmation_required') + and old.notification_status = 'manual_required' then + new.notification_status := 'confirmed'; + end if; + return new; +end; +$$; + +drop trigger if exists clear_manual_required_on_action_trigger on public.order_groups; +create trigger clear_manual_required_on_action_trigger + before update on public.order_groups + for each row + when (new.delivery_status is distinct from old.delivery_status) + execute function public.clear_manual_required_on_action();