|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DO |
|
$$ |
|
BEGIN |
|
IF NOT EXISTS(SELECT 1 |
|
FROM pg_type t |
|
JOIN pg_namespace n ON n.oid = t.typnamespace |
|
WHERE t.typname = 'subscription_status' |
|
AND n.nspname = 'basejump') THEN |
|
create type basejump.subscription_status as enum ( |
|
'trialing', |
|
'active', |
|
'canceled', |
|
'incomplete', |
|
'incomplete_expired', |
|
'past_due', |
|
'unpaid' |
|
); |
|
end if; |
|
end; |
|
$$; |
|
|
|
|
|
|
|
|
|
|
|
|
|
create table if not exists basejump.billing_customers |
|
( |
|
|
|
account_id uuid references basejump.accounts (id) on delete cascade not null, |
|
|
|
id text primary key, |
|
|
|
email text, |
|
|
|
active boolean, |
|
|
|
provider text |
|
); |
|
|
|
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE basejump.billing_customers TO service_role; |
|
GRANT SELECT ON TABLE basejump.billing_customers TO authenticated; |
|
|
|
|
|
|
|
alter table |
|
basejump.billing_customers |
|
enable row level security; |
|
|
|
|
|
|
|
|
|
|
|
create table if not exists basejump.billing_subscriptions |
|
( |
|
|
|
id text primary key, |
|
account_id uuid references basejump.accounts (id) on delete cascade not null, |
|
billing_customer_id text references basejump.billing_customers (id) on delete cascade not null, |
|
|
|
status basejump.subscription_status, |
|
|
|
metadata jsonb, |
|
|
|
price_id text, |
|
plan_name text, |
|
|
|
quantity integer, |
|
|
|
cancel_at_period_end boolean, |
|
|
|
created timestamp with time zone default timezone('utc' :: text, now()) not null, |
|
|
|
current_period_start timestamp with time zone default timezone('utc' :: text, now()) not null, |
|
|
|
current_period_end timestamp with time zone default timezone('utc' :: text, now()) not null, |
|
|
|
ended_at timestamp with time zone default timezone('utc' :: text, now()), |
|
|
|
cancel_at timestamp with time zone default timezone('utc' :: text, now()), |
|
|
|
canceled_at timestamp with time zone default timezone('utc' :: text, now()), |
|
|
|
trial_start timestamp with time zone default timezone('utc' :: text, now()), |
|
|
|
trial_end timestamp with time zone default timezone('utc' :: text, now()), |
|
provider text |
|
); |
|
|
|
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE basejump.billing_subscriptions TO service_role; |
|
GRANT SELECT ON TABLE basejump.billing_subscriptions TO authenticated; |
|
|
|
|
|
alter table |
|
basejump.billing_subscriptions |
|
enable row level security; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
create policy "Can only view own billing customer data." on basejump.billing_customers for |
|
select |
|
using ( |
|
basejump.has_role_on_account(account_id) = true |
|
); |
|
|
|
|
|
create policy "Can only view own billing subscription data." on basejump.billing_subscriptions for |
|
select |
|
using ( |
|
basejump.has_role_on_account(account_id) = true |
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION public.get_account_billing_status(account_id uuid) |
|
RETURNS jsonb |
|
security definer |
|
set search_path = public, basejump |
|
AS |
|
$$ |
|
DECLARE |
|
result jsonb; |
|
role_result jsonb; |
|
BEGIN |
|
select public.current_user_account_role(get_account_billing_status.account_id) into role_result; |
|
|
|
select jsonb_build_object( |
|
'account_id', get_account_billing_status.account_id, |
|
'billing_subscription_id', s.id, |
|
'billing_enabled', case |
|
when a.personal_account = true then config.enable_personal_account_billing |
|
else config.enable_team_account_billing end, |
|
'billing_status', s.status, |
|
'billing_customer_id', c.id, |
|
'billing_provider', config.billing_provider, |
|
'billing_email', |
|
coalesce(c.email, u.email) |
|
) |
|
into result |
|
from basejump.accounts a |
|
join auth.users u on u.id = a.primary_owner_user_id |
|
left join basejump.billing_subscriptions s on s.account_id = a.id |
|
left join basejump.billing_customers c on c.account_id = coalesce(s.account_id, a.id) |
|
join basejump.config config on true |
|
where a.id = get_account_billing_status.account_id |
|
order by s.created desc |
|
limit 1; |
|
|
|
return result || role_result; |
|
END; |
|
$$ LANGUAGE plpgsql; |
|
|
|
grant execute on function public.get_account_billing_status(uuid) to authenticated; |
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION public.service_role_upsert_customer_subscription(account_id uuid, |
|
customer jsonb default null, |
|
subscription jsonb default null) |
|
RETURNS void AS |
|
$$ |
|
BEGIN |
|
|
|
if customer is not null then |
|
insert into basejump.billing_customers (id, account_id, email, provider) |
|
values (customer ->> 'id', service_role_upsert_customer_subscription.account_id, customer ->> 'billing_email', |
|
(customer ->> 'provider')) |
|
on conflict (id) do update |
|
set email = customer ->> 'billing_email'; |
|
end if; |
|
|
|
|
|
if subscription is not null then |
|
insert into basejump.billing_subscriptions (id, account_id, billing_customer_id, status, metadata, price_id, |
|
quantity, cancel_at_period_end, created, current_period_start, |
|
current_period_end, ended_at, cancel_at, canceled_at, trial_start, |
|
trial_end, plan_name, provider) |
|
values (subscription ->> 'id', service_role_upsert_customer_subscription.account_id, |
|
subscription ->> 'billing_customer_id', (subscription ->> 'status')::basejump.subscription_status, |
|
subscription -> 'metadata', |
|
subscription ->> 'price_id', (subscription ->> 'quantity')::int, |
|
(subscription ->> 'cancel_at_period_end')::boolean, |
|
(subscription ->> 'created')::timestamptz, (subscription ->> 'current_period_start')::timestamptz, |
|
(subscription ->> 'current_period_end')::timestamptz, (subscription ->> 'ended_at')::timestamptz, |
|
(subscription ->> 'cancel_at')::timestamptz, |
|
(subscription ->> 'canceled_at')::timestamptz, (subscription ->> 'trial_start')::timestamptz, |
|
(subscription ->> 'trial_end')::timestamptz, |
|
subscription ->> 'plan_name', (subscription ->> 'provider')) |
|
on conflict (id) do update |
|
set billing_customer_id = subscription ->> 'billing_customer_id', |
|
status = (subscription ->> 'status')::basejump.subscription_status, |
|
metadata = subscription -> 'metadata', |
|
price_id = subscription ->> 'price_id', |
|
quantity = (subscription ->> 'quantity')::int, |
|
cancel_at_period_end = (subscription ->> 'cancel_at_period_end')::boolean, |
|
current_period_start = (subscription ->> 'current_period_start')::timestamptz, |
|
current_period_end = (subscription ->> 'current_period_end')::timestamptz, |
|
ended_at = (subscription ->> 'ended_at')::timestamptz, |
|
cancel_at = (subscription ->> 'cancel_at')::timestamptz, |
|
canceled_at = (subscription ->> 'canceled_at')::timestamptz, |
|
trial_start = (subscription ->> 'trial_start')::timestamptz, |
|
trial_end = (subscription ->> 'trial_end')::timestamptz, |
|
plan_name = subscription ->> 'plan_name'; |
|
end if; |
|
end; |
|
$$ LANGUAGE plpgsql; |
|
|
|
GRANT EXECUTE ON FUNCTION public.service_role_upsert_customer_subscription(uuid, jsonb, jsonb) TO service_role; |