161 lines
6.3 KiB
PL/PgSQL
161 lines
6.3 KiB
PL/PgSQL
-- 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$;
|