Add cash management schema and immediate variance alerts
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
-- =====================================================================
|
||||
-- 0028_live_drawer.sql
|
||||
--
|
||||
-- Cashiers and owners need an in-shift view of what the drawer should
|
||||
-- currently hold before the blind close. The existing close flow already
|
||||
-- computes this from app.cash_movements; this migration exposes the same
|
||||
-- math as a read-only RPC for the live UI.
|
||||
-- =====================================================================
|
||||
|
||||
set search_path = app, public;
|
||||
|
||||
create or replace function app.live_drawer(p_shift_id uuid)
|
||||
returns table (
|
||||
shift_id uuid,
|
||||
expected_usd numeric,
|
||||
expected_lbp numeric,
|
||||
customer_in_usd numeric,
|
||||
customer_in_lbp numeric,
|
||||
payout_out_usd numeric,
|
||||
payout_out_lbp numeric,
|
||||
dropped_to_safe_usd numeric,
|
||||
dropped_to_safe_lbp numeric,
|
||||
fx_net_usd numeric,
|
||||
fx_net_lbp numeric,
|
||||
txn_count bigint,
|
||||
last_txn_at timestamptz
|
||||
)
|
||||
language sql
|
||||
security definer
|
||||
set search_path = app, public
|
||||
stable
|
||||
as $$
|
||||
with s as (
|
||||
select sh.id, sh.shop_id, sh.user_id, sh.status
|
||||
from app.shifts sh
|
||||
where sh.id = p_shift_id
|
||||
),
|
||||
authz as (
|
||||
select 1
|
||||
from s
|
||||
where s.user_id = auth.uid()
|
||||
or app.has_any_role_in_shop(
|
||||
s.shop_id,
|
||||
array['owner','manager','auditor']::app.business_role[]
|
||||
)
|
||||
),
|
||||
cash as (
|
||||
select
|
||||
cm.shift_id,
|
||||
coalesce(sum(cm.amount) filter (where cm.currency = 'USD'), 0) as expected_usd,
|
||||
coalesce(sum(cm.amount) filter (where cm.currency = 'LBP'), 0) as expected_lbp,
|
||||
coalesce(sum(cm.amount) filter (where cm.type = 'sale_in' and cm.currency = 'USD'), 0) as customer_in_usd,
|
||||
coalesce(sum(cm.amount) filter (where cm.type = 'sale_in' and cm.currency = 'LBP'), 0) as customer_in_lbp,
|
||||
coalesce(sum(-cm.amount) filter (where cm.type = 'payout_out' and cm.currency = 'USD'), 0) as payout_out_usd,
|
||||
coalesce(sum(-cm.amount) filter (where cm.type = 'payout_out' and cm.currency = 'LBP'), 0) as payout_out_lbp,
|
||||
coalesce(sum(-cm.amount) filter (where cm.type = 'drop_to_safe' and cm.currency = 'USD'), 0) as dropped_to_safe_usd,
|
||||
coalesce(sum(-cm.amount) filter (where cm.type = 'drop_to_safe' and cm.currency = 'LBP'), 0) as dropped_to_safe_lbp,
|
||||
coalesce(sum(cm.amount) filter (where cm.type in ('fx_swap_in', 'fx_swap_out') and cm.currency = 'USD'), 0) as fx_net_usd,
|
||||
coalesce(sum(cm.amount) filter (where cm.type in ('fx_swap_in', 'fx_swap_out') and cm.currency = 'LBP'), 0) as fx_net_lbp
|
||||
from app.cash_movements cm
|
||||
where cm.shift_id = p_shift_id
|
||||
group by cm.shift_id
|
||||
),
|
||||
tx as (
|
||||
select
|
||||
t.shift_id,
|
||||
count(*) filter (where t.status = 'completed') as txn_count,
|
||||
max(t.occurred_at) filter (where t.status = 'completed') as last_txn_at
|
||||
from app.transactions t
|
||||
where t.shift_id = p_shift_id
|
||||
group by t.shift_id
|
||||
)
|
||||
select
|
||||
s.id as shift_id,
|
||||
coalesce(cash.expected_usd, 0) as expected_usd,
|
||||
coalesce(cash.expected_lbp, 0) as expected_lbp,
|
||||
coalesce(cash.customer_in_usd, 0) as customer_in_usd,
|
||||
coalesce(cash.customer_in_lbp, 0) as customer_in_lbp,
|
||||
coalesce(cash.payout_out_usd, 0) as payout_out_usd,
|
||||
coalesce(cash.payout_out_lbp, 0) as payout_out_lbp,
|
||||
coalesce(cash.dropped_to_safe_usd, 0) as dropped_to_safe_usd,
|
||||
coalesce(cash.dropped_to_safe_lbp, 0) as dropped_to_safe_lbp,
|
||||
coalesce(cash.fx_net_usd, 0) as fx_net_usd,
|
||||
coalesce(cash.fx_net_lbp, 0) as fx_net_lbp,
|
||||
coalesce(tx.txn_count, 0) as txn_count,
|
||||
tx.last_txn_at
|
||||
from s
|
||||
join authz on true
|
||||
left join cash on cash.shift_id = s.id
|
||||
left join tx on tx.shift_id = s.id;
|
||||
$$;
|
||||
|
||||
revoke all on function app.live_drawer(uuid) from public;
|
||||
grant execute on function app.live_drawer(uuid) to authenticated;
|
||||
Reference in New Issue
Block a user