supersam/supabase/migrations/20260929_confirmation_chann...

161 lines
6.3 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 20260929_confirmation_channel.sql
-- Каким каналом клиент согласовал доставку/самовывоз.
--
-- Владелец: «нужно видеть, согласование прошло через пуш / смс / звонок / вручную
-- через менеджера», потому что в реестре и карточке было просто «Согласовано».
--
-- Источник правды — order_groups.delivery_date_source. Его уже пишут:
-- manual — логист в админке;
-- autocall — робот (edge fn autocall-result).
-- Здесь добавляем клиентские каналы: страница /delivery/{hash}?src=<канал> передаёт
-- src в RPC, а RPC сохраняет его в delivery_date_source и в action_logs.details.
DROP FUNCTION IF EXISTS public.confirm_delivery_choice_by_token(
text, text, text, text, text, text, text
);
CREATE OR REPLACE FUNCTION public.confirm_delivery_choice_by_token(
p_token text,
p_delivery_date text,
p_delivery_time text,
p_delivery_type text DEFAULT 'delivery'::text,
p_pickup_date text DEFAULT NULL::text,
p_pickup_time_slot text DEFAULT NULL::text,
p_delivery_address text DEFAULT NULL::text,
p_src text DEFAULT NULL::text
)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public', 'extensions'
AS $function$
DECLARE
v_invitation record;
v_order_group_id uuid;
v_current_status text;
v_delivery_status text;
v_notification_status text;
v_delivery_date_val date;
v_existing_address text;
v_effective_address text;
v_delivery_days int[];
v_dow int;
v_day_num int;
v_channel text;
BEGIN
-- Канал подтверждения: push / sms / messenger из ссылки, иначе «клиент» (прямой заход).
v_channel := CASE
WHEN p_src IN ('push', 'sms', 'messenger') THEN p_src
ELSE 'client'
END;
SELECT * INTO v_invitation
FROM delivery_invitations
WHERE token_hash = encode(digest(p_token, 'sha256'), 'hex')
AND state IN ('awaiting_choice', 'sent')
LIMIT 1;
IF NOT found THEN
RETURN jsonb_build_object('ok', false, 'error', 'Invitation not found or not active');
END IF;
v_order_group_id := v_invitation.order_group_id;
SELECT delivery_status, customer_address INTO v_current_status, v_existing_address
FROM order_groups
WHERE id = v_order_group_id;
IF v_existing_address IS NOT NULL AND UPPER(TRIM(v_existing_address)) = 'САМОВЫВОЗ' THEN
v_existing_address := NULL;
END IF;
IF v_current_status NOT IN ('pending_confirmation', 'manual_confirmation_required') THEN
RETURN jsonb_build_object('ok', false, 'error', 'Order is not pending confirmation');
END IF;
v_effective_address := COALESCE(NULLIF(p_delivery_address, ''), v_existing_address);
IF p_delivery_type = 'pickup' THEN
v_delivery_status := 'pickup';
v_notification_status := 'confirmed';
ELSIF v_effective_address IS NOT NULL AND v_effective_address != '' THEN
v_delivery_status := 'agreed';
v_notification_status := 'confirmed';
ELSE
v_delivery_status := 'requires_address';
v_notification_status := 'address_required';
END IF;
v_delivery_date_val := CASE WHEN p_delivery_date IS NOT NULL AND p_delivery_date != '' THEN p_delivery_date::date ELSE NULL END;
-- Check delivery_days from business_schedule_settings (only for delivery type)
IF p_delivery_type = 'delivery' AND v_delivery_date_val IS NOT NULL THEN
SELECT delivery_days INTO v_delivery_days FROM business_schedule_settings WHERE id = 1;
IF v_delivery_days IS NULL THEN
v_delivery_days := ARRAY[1,2,3,4,5];
END IF;
-- extract(dow): 0=Sunday, 1=Monday, ..., 6=Saturday
-- business_schedule uses 1=Monday ... 7=Sunday
v_dow := extract(dow from v_delivery_date_val)::int;
v_day_num := CASE WHEN v_dow = 0 THEN 7 ELSE v_dow END;
IF NOT (v_day_num = ANY(v_delivery_days)) THEN
RETURN jsonb_build_object('ok', false, 'error', 'Delivery is not available on this day');
END IF;
END IF;
UPDATE delivery_invitations SET
state = 'agreed',
delivery_date = COALESCE(v_delivery_date_val, delivery_date),
delivery_time = COALESCE(NULLIF(p_delivery_time, ''), delivery_time),
confirmed_at = now(),
access_count = COALESCE(access_count, 0) + 1,
last_accessed_at = now()
WHERE id = v_invitation.id;
UPDATE order_groups SET
delivery_status = v_delivery_status,
delivery_date = COALESCE(v_delivery_date_val, delivery_date),
delivery_time = COALESCE(NULLIF(p_delivery_time, ''), delivery_time),
delivery_type = p_delivery_type,
notification_status = v_notification_status,
delivery_date_source = v_channel,
pickup_date = CASE WHEN p_delivery_type = 'pickup' THEN COALESCE(NULLIF(p_pickup_date, '')::date, v_delivery_date_val) ELSE NULL END,
pickup_time_slot = CASE WHEN p_delivery_type = 'pickup' THEN COALESCE(NULLIF(p_pickup_time_slot, ''), p_delivery_time) ELSE NULL END,
delivery_address = CASE WHEN p_delivery_type = 'delivery' AND v_effective_address IS NOT NULL AND v_effective_address != '' THEN v_effective_address ELSE delivery_address END,
customer_address = CASE WHEN p_delivery_type = 'delivery' AND v_effective_address IS NOT NULL AND v_effective_address != '' THEN v_effective_address ELSE customer_address END,
assigned_driver_id = CASE WHEN p_delivery_type = 'pickup' THEN NULL ELSE assigned_driver_id END,
status = CASE
WHEN p_delivery_type = 'pickup' AND v_delivery_status = 'pickup' THEN 'pickup'
WHEN v_delivery_status = 'agreed' THEN 'agreed'
WHEN v_delivery_status = 'requires_address' THEN 'requires_address'
ELSE status
END,
updated_at = now()
WHERE id = v_order_group_id;
INSERT INTO action_logs (order_group_id, action, old_value, new_value, details)
VALUES (
v_order_group_id,
'client_confirmed',
v_current_status,
v_delivery_status,
jsonb_build_object(
'delivery_date', p_delivery_date,
'delivery_time', p_delivery_time,
'delivery_type', p_delivery_type,
'pickup_date', p_pickup_date,
'pickup_time_slot', p_pickup_time_slot,
'source', 'auto',
'channel', v_channel
)
);
RETURN jsonb_build_object(
'ok', true,
'orderGroupId', v_order_group_id,
'deliveryStatus', v_delivery_status,
'channel', v_channel
);
END;
$function$;