From 7ae3dfc366391d52501a4e4c7208f037f4c5c006 Mon Sep 17 00:00:00 2001 From: pavlov346346-source Date: Tue, 8 Sep 2026 13:05:04 +0300 Subject: [PATCH] Version v17.7.0 server order automation migration --- ...PABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 ops/sql/SUPABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql diff --git a/ops/sql/SUPABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql b/ops/sql/SUPABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql new file mode 100644 index 0000000..a881fd0 --- /dev/null +++ b/ops/sql/SUPABASE-V17.7.0-SERVER-ORDER-AUTOMATION.sql @@ -0,0 +1,88 @@ +alter table public.sun_workspaces add column if not exists timezone text not null default 'Europe/Moscow'; + +create or replace function public.sun_order_due_at(p_data jsonb,p_timezone text) +returns timestamptz +language plpgsql +stable +set search_path='public' as $$ +declare v_date date; v_time time; v_tz text; +begin + if coalesce(p_data->>'date','') !~ '^\d{4}-\d{2}-\d{2}$' or coalesce(p_data->>'time','') !~ '^\d{2}:\d{2}$' then return null; end if; + v_date := (p_data->>'date')::date; + v_time := (p_data->>'time')::time; + v_tz := coalesce(nullif(trim(p_timezone),''),'Europe/Moscow'); + return ((v_date::timestamp + v_time) at time zone v_tz) + interval '1 minute'; +exception when others then return null; +end;$$; + +create or replace function public.sun_process_due_orders_internal(p_workspace uuid,p_now timestamptz default now()) +returns jsonb +language plpgsql +security definer +set search_path='public' as $$ +declare v_tz text; v_changed integer:=0; v_ids text[]:=array[]::text[]; r record; v_total numeric; v_iso text; v_orders jsonb; +begin + select timezone into v_tz from public.sun_workspaces where id=p_workspace; + if v_tz is null then return jsonb_build_object('changed',0,'ids','[]'::jsonb); end if; + v_iso:=to_char(p_now at time zone 'UTC','YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'); + for r in + select order_id,data,version from public.sun_v17_orders + where workspace_id=p_workspace + and lower(coalesce(data->>'status','')) not in ('отменён','отменен','отдан заказчику','завершён','завершен') + and coalesce(data->>'sunAutoCompletedAt','')='' + and public.sun_order_due_at(data,v_tz) is not null + and public.sun_order_due_at(data,v_tz) <= p_now + for update + loop + v_total:=case when coalesce(r.data->>'total','') ~ '^-?\d+(\.\d+)?$' then greatest(0,(r.data->>'total')::numeric) else 0 end; + update public.sun_v17_orders + set data=r.data||jsonb_build_object('prepayment',v_total,'balance',0,'status','Отдан заказчику','paymentStatus','paid','completedAt',coalesce(nullif(r.data->>'completedAt',''),v_iso),'paymentCompletedAt',coalesce(nullif(r.data->>'paymentCompletedAt',''),v_iso),'sunAutoCompletedAt',v_iso,'sunAutoCompletedV1770',true,'sunAutoCompletedVersion','17.7.0'),version=version+1,updated_at=p_now,updated_by=null + where workspace_id=p_workspace and order_id=r.order_id; + insert into public.sun_v17_change_events(workspace_id,entity,entity_key,operation,version,client_id,created_by) + values(p_workspace,'order',r.order_id,'server_auto_complete',r.version+1,'server:auto-complete',null); + v_changed:=v_changed+1;v_ids:=array_append(v_ids,r.order_id); + end loop; + if v_changed>0 then + select coalesce(jsonb_agg(o.data order by case when o.order_id ~ '^\d+$' then o.order_id::bigint else null end,o.order_id),'[]'::jsonb) into v_orders from public.sun_v17_orders o where o.workspace_id=p_workspace; + update public.sun_app_state s set payload=jsonb_set(coalesce(s.payload,'{}'::jsonb),'{storage,sunOrders}',jsonb_build_object('t','j','v',v_orders),true),revision=s.revision+1,updated_at=p_now,client_id='server:auto-complete' where s.workspace_id=p_workspace; + if not found then insert into public.sun_app_state(workspace_id,payload,revision,updated_at,client_id) values(p_workspace,jsonb_build_object('format','sun-cloud-v2','version',2,'storage',jsonb_build_object('sunOrders',jsonb_build_object('t','j','v',v_orders))),1,p_now,'server:auto-complete'); end if; + end if; + return jsonb_build_object('changed',v_changed,'ids',to_jsonb(v_ids),'workspace',p_workspace,'timezone',v_tz,'processed_at',v_iso); +end;$$; + +create or replace function public.sun_run_order_automation(p_workspace uuid) +returns jsonb +language plpgsql +security definer +set search_path='public' as $$ +declare v_result jsonb; v_ids text[]; v_orders jsonb; +begin + if public.sun_member_role(p_workspace) is null then raise exception 'Access denied'; end if; + if public.sun_subscription_access_mode(p_workspace)='blocked' then raise exception 'Подписка закончилась'; end if; + v_result:=public.sun_process_due_orders_internal(p_workspace,now()); + select coalesce(array_agg(value::text),'{}'::text[]) into v_ids from jsonb_array_elements_text(coalesce(v_result->'ids','[]'::jsonb)); + if coalesce(array_length(v_ids,1),0)>0 then select coalesce(jsonb_agg(o.data order by o.order_id),'[]'::jsonb) into v_orders from public.sun_v17_orders o where o.workspace_id=p_workspace and o.order_id=any(v_ids); else v_orders:='[]'::jsonb; end if; + return v_result||jsonb_build_object('orders',v_orders); +end;$$; + +create or replace function public.caterium_process_due_orders_all() +returns jsonb +language plpgsql +security definer +set search_path='public' as $$ +declare r record; v_total integer:=0; v_result jsonb; +begin + for r in select id from public.sun_workspaces loop v_result:=public.sun_process_due_orders_internal(r.id,now());v_total:=v_total+coalesce((v_result->>'changed')::integer,0);end loop; + return jsonb_build_object('changed',v_total,'processed_at',now()); +end;$$; + +revoke all on function public.sun_process_due_orders_internal(uuid,timestamptz) from public,anon,authenticated; +revoke all on function public.caterium_process_due_orders_all() from public,anon,authenticated; +revoke all on function public.sun_order_due_at(jsonb,text) from anon; +grant execute on function public.sun_run_order_automation(uuid) to authenticated; + +do $$ declare v_job bigint; begin + select jobid into v_job from cron.job where jobname='caterium-order-auto-complete'; + if v_job is not null then perform cron.unschedule(v_job); end if; + perform cron.schedule('caterium-order-auto-complete','* * * * *','select public.caterium_process_due_orders_all();'); +end$$;