BEGIN; CREATE OR REPLACE FUNCTION public.homecare_is_arrival_pending_status(p_status TEXT) RETURNS BOOLEAN LANGUAGE sql IMMUTABLE AS $$ SELECT upper(coalesce(trim(p_status), '')) IN ( 'ARRIVAL_PENDING', 'WAITING_CONSUMER_CONFIRM', 'WAITING_ARRIVAL_CONFIRM' ) $$; CREATE OR REPLACE FUNCTION public.homecare_sync_arrival_pending_from_confirmation() RETURNS trigger LANGUAGE plpgsql SET search_path = public AS $$ BEGIN IF NEW.confirmation_type = 'ARRIVAL' AND upper(coalesce(NEW.status, '')) IN ('PENDING', 'WAITING', 'ARRIVAL_PENDING') THEN UPDATE public.ec_care_tasks SET status = 'ARRIVAL_PENDING', checked_in_at = COALESCE(checked_in_at, NEW.created_at), updated_at = now() WHERE id = NEW.work_order_id AND coalesce(status, '') <> 'ARRIVAL_PENDING'; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS trg_homecare_sync_arrival_pending_from_confirmation ON public.hc_work_order_confirmations; CREATE TRIGGER trg_homecare_sync_arrival_pending_from_confirmation AFTER INSERT OR UPDATE OF status ON public.hc_work_order_confirmations FOR EACH ROW EXECUTE FUNCTION public.homecare_sync_arrival_pending_from_confirmation(); CREATE OR REPLACE FUNCTION public.homecare_find_related_work_order_id(p_order JSONB) RETURNS UUID LANGUAGE plpgsql STABLE SET search_path = public AS $$ DECLARE v_id_text TEXT := coalesce(p_order ->> 'resolvedWorkOrderId', p_order ->> 'workOrderId', p_order ->> 'work_order_id', p_order ->> 'id', ''); v_request_id TEXT := coalesce(p_order ->> 'requestId', p_order ->> 'request_id', ''); v_order_no TEXT := coalesce(p_order ->> 'orderNo', p_order ->> 'order_no', ''); v_work_order_id UUID; BEGIN BEGIN IF v_id_text ~* '^[0-9a-f-]{36}$' THEN RETURN v_id_text::uuid; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; BEGIN SELECT t.id INTO v_work_order_id FROM public.ec_care_tasks t WHERE (v_request_id <> '' AND coalesce(t.request_id::text, '') = v_request_id) OR (v_order_no <> '' AND coalesce(t.task_no, '') = v_order_no) ORDER BY coalesce(t.updated_at, t.created_at) DESC, t.created_at DESC LIMIT 1; EXCEPTION WHEN undefined_table OR undefined_column THEN v_work_order_id := NULL; END; RETURN v_work_order_id; END; $$; CREATE OR REPLACE FUNCTION public.homecare_apply_arrival_pending_order(p_order JSONB) RETURNS JSONB LANGUAGE plpgsql STABLE SET search_path = public AS $$ DECLARE v_order JSONB := coalesce(p_order, '{}'::jsonb); v_status TEXT := coalesce(v_order ->> 'status', ''); v_original_status TEXT := coalesce(v_order ->> 'status', ''); v_waiting BOOLEAN := lower(coalesce(v_order ->> 'waitingConsumerConfirm', v_order ->> 'waiting_consumer_confirm', 'false')) = 'true'; v_has_pending_log BOOLEAN := false; v_has_pending_timeline BOOLEAN := false; v_work_order_id UUID; v_confirmation_status TEXT := ''; v_time_text TEXT := coalesce(v_order ->> 'checkinTime', v_order ->> 'arriveTime', v_order ->> 'updatedAt', v_order ->> 'createdAt', ''); v_timeline_item JSONB; v_status_log_item JSONB; BEGIN IF jsonb_typeof(v_order -> 'statusLog') = 'array' THEN SELECT EXISTS ( SELECT 1 FROM jsonb_array_elements(v_order -> 'statusLog') AS item WHERE public.homecare_is_arrival_pending_status(coalesce(item ->> 'toStatus', item ->> 'to_status', item ->> 'status', '')) ) INTO v_has_pending_log; END IF; IF jsonb_typeof(v_order -> 'timeline') = 'array' THEN SELECT EXISTS ( SELECT 1 FROM jsonb_array_elements(v_order -> 'timeline') AS item WHERE position('等待消费者确认到达' IN coalesce(item ->> 'title', '')) > 0 ) INTO v_has_pending_timeline; END IF; IF NOT v_waiting AND NOT public.homecare_is_arrival_pending_status(v_status) AND NOT v_has_pending_log THEN v_work_order_id := public.homecare_find_related_work_order_id(v_order); IF v_work_order_id IS NOT NULL THEN BEGIN SELECT upper(coalesce(c.status, '')) INTO v_confirmation_status FROM public.hc_work_order_confirmations c WHERE c.work_order_id = v_work_order_id AND c.confirmation_type = 'ARRIVAL' ORDER BY coalesce(c.updated_at, c.created_at) DESC, c.created_at DESC LIMIT 1; EXCEPTION WHEN undefined_table OR undefined_column THEN v_confirmation_status := ''; END; IF v_confirmation_status IN ('PENDING', 'WAITING', 'ARRIVAL_PENDING') THEN v_waiting := true; END IF; END IF; END IF; IF v_waiting OR public.homecare_is_arrival_pending_status(v_status) OR v_has_pending_log THEN v_order := v_order || jsonb_build_object( 'status', 'ARRIVAL_PENDING', 'statusText', '等待消费者确认到达', 'statusTone', 'warning', 'waitingConsumerConfirm', true ); IF NOT v_has_pending_timeline THEN v_timeline_item := jsonb_build_object( 'id', coalesce(v_order ->> 'id', 'order') || '-arrival-pending', 'title', '等待消费者确认到达', 'time', v_time_text, 'description', '服务人员已提交到达签到,请确认其是否已到达服务地点' ); v_order := jsonb_set( v_order, '{timeline}', jsonb_build_array(v_timeline_item) || coalesce(v_order -> 'timeline', '[]'::jsonb) ); END IF; IF NOT v_has_pending_log THEN v_status_log_item := jsonb_build_object( 'id', coalesce(v_order ->> 'id', 'order') || '-arrival-pending', 'orderId', coalesce(v_order ->> 'id', ''), 'fromStatus', v_original_status, 'toStatus', 'ARRIVAL_PENDING', 'operatorRole', 'delivery', 'operatorId', '', 'remark', '服务人员已提交到达签到,等待消费者确认', 'createdAt', v_time_text ); v_order := jsonb_set( v_order, '{statusLog}', jsonb_build_array(v_status_log_item) || coalesce(v_order -> 'statusLog', '[]'::jsonb) ); END IF; END IF; RETURN v_order; END; $$; CREATE OR REPLACE FUNCTION public.delivery_get_legacy_order_json(p_order_id TEXT) RETURNS JSONB LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public AS $$ DECLARE v_staff_id UUID := public.delivery_current_staff_id(); v_raw JSONB; v_logs JSONB := '[]'::jsonb; v_records JSONB := '[]'::jsonb; v_evidence JSONB := '[]'::jsonb; BEGIN SELECT to_jsonb(o) INTO v_raw FROM public.hss_service_orders o WHERE o.id = p_order_id AND o.deleted_at IS NULL AND (v_staff_id IS NULL OR o.current_staff_id = v_staff_id) LIMIT 1; IF v_raw IS NULL THEN RETURN NULL; END IF; SELECT coalesce(jsonb_agg(to_jsonb(l) ORDER BY l.created_at DESC), '[]'::jsonb) INTO v_logs FROM public.hss_service_order_status_logs l WHERE l.order_id = p_order_id; SELECT coalesce(jsonb_agg(to_jsonb(r) ORDER BY r.created_at DESC), '[]'::jsonb) INTO v_records FROM public.hss_service_execution_records r WHERE r.order_id = p_order_id; SELECT coalesce(jsonb_agg(to_jsonb(e) ORDER BY e.created_at DESC), '[]'::jsonb) INTO v_evidence FROM public.hss_service_evidence_files e WHERE e.order_id = p_order_id; RETURN public.homecare_apply_arrival_pending_order( public.delivery_build_order_json(v_raw, v_logs, v_records, v_evidence, NULL, 'legacy') ); END; $$; CREATE OR REPLACE FUNCTION public.delivery_get_care_order_json(p_order_id TEXT) RETURNS JSONB LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public AS $$ DECLARE v_user_id UUID := public.delivery_current_user_id(); v_raw JSONB; v_request JSONB; v_logs JSONB := '[]'::jsonb; v_records JSONB := '[]'::jsonb; v_evidence JSONB := '[]'::jsonb; v_exception JSONB; BEGIN IF NOT public.delivery_table_exists('ec_care_tasks') THEN RETURN NULL; END IF; BEGIN EXECUTE 'SELECT to_jsonb(t) FROM public.ec_care_tasks t WHERE t.id = $1::uuid AND ($2 IS NULL OR t.assigned_to = $2) LIMIT 1' INTO v_raw USING p_order_id, v_user_id; EXCEPTION WHEN OTHERS THEN RETURN NULL; END; IF v_raw IS NULL THEN RETURN NULL; END IF; BEGIN IF public.delivery_table_exists('ec_service_requests') AND coalesce(v_raw ->> 'request_id', '') <> '' THEN EXECUTE 'SELECT to_jsonb(r) FROM public.ec_service_requests r WHERE r.id = $1::uuid LIMIT 1' INTO v_request USING (v_raw ->> 'request_id'); END IF; EXCEPTION WHEN OTHERS THEN v_request := NULL; END; IF v_request IS NOT NULL THEN v_raw := v_raw || jsonb_strip_nulls( jsonb_build_object( 'service_name', coalesce(nullif(v_raw ->> 'service_name', ''), nullif(v_request ->> 'service_name', '')), 'service_category', coalesce(nullif(v_raw ->> 'service_category', ''), nullif(v_request ->> 'service_category', '')), 'elder_name', coalesce(nullif(v_raw ->> 'elder_name', ''), nullif(v_request ->> 'elder_name', '')), 'elder_phone', coalesce(nullif(v_raw ->> 'elder_phone', ''), nullif(v_request ->> 'elder_phone', '')), 'contact_name', coalesce(nullif(v_raw ->> 'contact_name', ''), nullif(v_request ->> 'contact_name', '')), 'contact_phone', coalesce(nullif(v_raw ->> 'contact_phone', ''), nullif(v_request ->> 'contact_phone', '')), 'remark', coalesce(nullif(v_raw ->> 'remark', ''), nullif(v_request ->> 'remark', '')), 'scheduled_at', coalesce(nullif(v_raw ->> 'scheduled_at', ''), nullif(v_request ->> 'scheduled_at', '')), 'appointment_time', coalesce(nullif(v_raw ->> 'appointment_time', ''), nullif(v_request ->> 'scheduled_at', '')), 'service_snapshot_json', coalesce( nullif(v_raw -> 'service_snapshot_json', '{}'::jsonb), nullif(v_request -> 'service_snapshot_json', '{}'::jsonb), jsonb_build_object('category', coalesce(v_request ->> 'service_category', ''), 'price', 0) ), 'address_snapshot_json', coalesce( nullif(v_raw -> 'address_snapshot_json', '{}'::jsonb), nullif(v_raw -> 'address_snapshot', '{}'::jsonb), nullif(v_request -> 'address_snapshot_json', '{}'::jsonb), nullif(v_request -> 'address_snapshot', '{}'::jsonb) ) ) ); END IF; BEGIN IF public.delivery_table_exists('hc_work_order_events') THEN EXECUTE 'SELECT coalesce(jsonb_agg(to_jsonb(e) ORDER BY e.created_at DESC), ''[]''::jsonb) FROM public.hc_work_order_events e WHERE e.work_order_id = $1::uuid' INTO v_logs USING p_order_id; END IF; IF public.delivery_table_exists('ec_care_records') THEN EXECUTE 'SELECT coalesce(jsonb_agg(to_jsonb(r) ORDER BY r.created_at DESC), ''[]''::jsonb) FROM public.ec_care_records r WHERE r.task_id = $1::uuid' INTO v_records USING p_order_id; END IF; IF public.delivery_table_exists('hc_evidence_files') THEN EXECUTE 'SELECT coalesce(jsonb_agg(to_jsonb(f) ORDER BY f.created_at DESC), ''[]''::jsonb) FROM public.hc_evidence_files f WHERE f.work_order_id = $1::uuid' INTO v_evidence USING p_order_id; END IF; IF public.delivery_table_exists('hc_work_order_exceptions') THEN EXECUTE 'SELECT to_jsonb(x) FROM public.hc_work_order_exceptions x WHERE x.work_order_id = $1::uuid ORDER BY x.created_at DESC LIMIT 1' INTO v_exception USING p_order_id; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; RETURN public.homecare_apply_arrival_pending_order( public.delivery_build_order_json(v_raw, v_logs, v_records, v_evidence, v_exception, 'care') ); END; $$; CREATE OR REPLACE FUNCTION public.rpc_delivery_order_detail(p_order_id TEXT) RETURNS JSONB LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public AS $$ BEGIN IF auth.uid() IS NULL THEN RAISE EXCEPTION 'Permission denied'; END IF; RETURN public.homecare_apply_arrival_pending_order(public.delivery_get_order_json(p_order_id)); END; $$; CREATE OR REPLACE FUNCTION public.rpc_delivery_order_list( p_staff_id UUID DEFAULT NULL, p_tab TEXT DEFAULT 'all', p_keyword TEXT DEFAULT '' ) RETURNS JSONB LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public AS $$ DECLARE v_user_id UUID := public.delivery_current_user_id(); v_staff_id UUID := COALESCE(p_staff_id, public.delivery_current_staff_id()); v_result JSONB := '[]'::jsonb; v_task JSONB; v_order JSONB; v_order_id TEXT; BEGIN PERFORM public.delivery_assert_staff_access(v_staff_id); IF public.delivery_table_exists('ec_care_tasks') THEN BEGIN FOR v_task IN EXECUTE 'SELECT to_jsonb(t) FROM public.ec_care_tasks t WHERE ($1 IS NULL OR t.assigned_to = $1) ORDER BY t.created_at DESC' USING v_user_id LOOP v_order := public.homecare_apply_arrival_pending_order( public.delivery_get_care_order_json(v_task ->> 'id') ); v_result := public.delivery_append_if_match(v_result, v_order, p_tab, p_keyword); END LOOP; EXCEPTION WHEN OTHERS THEN NULL; END; END IF; FOR v_order_id IN SELECT o.id FROM public.hss_service_orders o WHERE o.deleted_at IS NULL AND (v_staff_id IS NULL OR o.current_staff_id = v_staff_id) ORDER BY COALESCE(o.updated_at, o.created_at) DESC, o.created_at DESC LOOP v_order := public.homecare_apply_arrival_pending_order( public.delivery_get_legacy_order_json(v_order_id) ); v_result := public.delivery_append_if_match(v_result, v_order, p_tab, p_keyword); END LOOP; RETURN COALESCE(v_result, '[]'::jsonb); END; $$; COMMIT;