Add cash management schema and immediate variance alerts
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
-- =====================================================================
|
||||
-- 0027_till_management.sql
|
||||
--
|
||||
-- Owner-facing till management:
|
||||
-- - app.create_till(shop, name) -> uuid
|
||||
-- - app.rename_till(till, name) -> void
|
||||
-- - app.set_till_active(till, is_active) -> void
|
||||
-- - v_manage_tills view (owner sees all, including inactive)
|
||||
-- =====================================================================
|
||||
|
||||
set search_path = app, public;
|
||||
|
||||
create or replace function app.create_till(
|
||||
p_shop uuid,
|
||||
p_name text
|
||||
) returns uuid
|
||||
language plpgsql
|
||||
security definer
|
||||
set search_path = app, public
|
||||
as $$
|
||||
declare
|
||||
v_id uuid;
|
||||
v_name text := nullif(btrim(p_name), '');
|
||||
begin
|
||||
if v_name is null then raise exception 'till name is required'; end if;
|
||||
if not app.has_role_in_shop(p_shop, 'owner') then
|
||||
raise exception 'owner role required';
|
||||
end if;
|
||||
insert into app.tills(shop_id, name) values (p_shop, v_name)
|
||||
returning id into v_id;
|
||||
perform app.log_auth_event('till_created', p_shop, null,
|
||||
jsonb_build_object('till_id', v_id, 'name', v_name));
|
||||
return v_id;
|
||||
exception
|
||||
when unique_violation then
|
||||
raise exception 'a till with this name already exists in the shop';
|
||||
end;
|
||||
$$;
|
||||
revoke all on function app.create_till(uuid, text) from public;
|
||||
grant execute on function app.create_till(uuid, text) to authenticated;
|
||||
|
||||
create or replace function app.rename_till(
|
||||
p_till uuid,
|
||||
p_name text
|
||||
) returns void
|
||||
language plpgsql
|
||||
security definer
|
||||
set search_path = app, public
|
||||
as $$
|
||||
declare
|
||||
v_shop uuid;
|
||||
v_name text := nullif(btrim(p_name), '');
|
||||
begin
|
||||
if v_name is null then raise exception 'till name is required'; end if;
|
||||
select shop_id into v_shop from app.tills where id = p_till;
|
||||
if v_shop is null then raise exception 'till not found'; end if;
|
||||
if not app.has_role_in_shop(v_shop, 'owner') then
|
||||
raise exception 'owner role required';
|
||||
end if;
|
||||
update app.tills set name = v_name where id = p_till;
|
||||
perform app.log_auth_event('till_renamed', v_shop, null,
|
||||
jsonb_build_object('till_id', p_till, 'name', v_name));
|
||||
exception
|
||||
when unique_violation then
|
||||
raise exception 'a till with this name already exists in the shop';
|
||||
end;
|
||||
$$;
|
||||
revoke all on function app.rename_till(uuid, text) from public;
|
||||
grant execute on function app.rename_till(uuid, text) to authenticated;
|
||||
|
||||
create or replace function app.set_till_active(
|
||||
p_till uuid,
|
||||
p_active boolean
|
||||
) returns void
|
||||
language plpgsql
|
||||
security definer
|
||||
set search_path = app, public
|
||||
as $$
|
||||
declare
|
||||
v_shop uuid;
|
||||
begin
|
||||
select shop_id into v_shop from app.tills where id = p_till;
|
||||
if v_shop is null then raise exception 'till not found'; end if;
|
||||
if not app.has_role_in_shop(v_shop, 'owner') then
|
||||
raise exception 'owner role required';
|
||||
end if;
|
||||
-- Block deactivating a till that has an open shift on it.
|
||||
if p_active = false and exists (
|
||||
select 1 from app.shifts where till_id = p_till and status <> 'closed'
|
||||
) then
|
||||
raise exception 'cannot deactivate a till with an open or pending shift';
|
||||
end if;
|
||||
update app.tills set is_active = coalesce(p_active, true) where id = p_till;
|
||||
perform app.log_auth_event(
|
||||
case when p_active then 'till_activated' else 'till_deactivated' end,
|
||||
v_shop, null, jsonb_build_object('till_id', p_till));
|
||||
end;
|
||||
$$;
|
||||
revoke all on function app.set_till_active(uuid, boolean) from public;
|
||||
grant execute on function app.set_till_active(uuid, boolean) to authenticated;
|
||||
|
||||
-- Owner view that also includes inactive tills, for the management UI.
|
||||
drop view if exists app.v_manage_tills;
|
||||
create view app.v_manage_tills as
|
||||
select t.id as till_id, t.shop_id, t.name, t.is_active, t.created_at
|
||||
from app.tills t
|
||||
where exists (
|
||||
select 1 from app.user_shop_assignments a
|
||||
where a.shop_id = t.shop_id
|
||||
and a.user_id = auth.uid()
|
||||
and a.role in ('owner', 'manager')
|
||||
);
|
||||
grant select on app.v_manage_tills to authenticated;
|
||||
Reference in New Issue
Block a user