mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 21:41:16 +00:00
73 lines
2.8 KiB
PL/PgSQL
73 lines
2.8 KiB
PL/PgSQL
-- Zeigt die nächste Rechnungsnummer an, ohne den Zähler zu erhöhen (für Vorbelegung im Dialog).
|
|
-- Die echte Nummer vergibt weiterhin next_invoice_number() beim Insert.
|
|
create or replace function public.peek_next_invoice_number()
|
|
returns text language plpgsql stable security definer set search_path = '' as $$
|
|
declare
|
|
y int := extract(year from current_date)::int;
|
|
n int;
|
|
begin
|
|
if not public.is_admin() then
|
|
raise exception 'forbidden' using errcode = '42501';
|
|
end if;
|
|
select coalesce(last_number, 0) + 1 into n from public.invoice_counters where year = y;
|
|
return format('RE-%s-%s', y, lpad(coalesce(n, 1)::text, 4, '0'));
|
|
end $$;
|
|
|
|
-- Rechnung + Positionen in einer Transaktion anlegen, damit bei Fehlern
|
|
-- keine Rechnung ohne Positionen (und keine verbrauchte Nummer) übrig bleibt.
|
|
-- security invoker: RLS (admin_insert / admin_all) greift.
|
|
create or replace function public.create_invoice(
|
|
p_client_id uuid,
|
|
p_invoice_date date,
|
|
p_due_date date,
|
|
p_company_name text,
|
|
p_billing_street text,
|
|
p_billing_postal_code text,
|
|
p_billing_city text,
|
|
p_billing_country char(2),
|
|
p_items jsonb
|
|
) returns uuid
|
|
language plpgsql
|
|
security invoker
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_invoice_id uuid;
|
|
begin
|
|
if not public.is_admin() then
|
|
raise exception 'forbidden' using errcode = '42501';
|
|
end if;
|
|
|
|
if p_items is null or jsonb_array_length(p_items) = 0 then
|
|
raise exception 'invoice needs at least one item' using errcode = '22023';
|
|
end if;
|
|
|
|
insert into public.invoices (
|
|
client_id, invoice_date, due_date,
|
|
company_name, billing_street, billing_postal_code, billing_city, billing_country
|
|
) values (
|
|
p_client_id, p_invoice_date, p_due_date,
|
|
p_company_name, p_billing_street, p_billing_postal_code, p_billing_city, p_billing_country
|
|
)
|
|
returning id into v_invoice_id;
|
|
|
|
insert into public.invoice_items (
|
|
invoice_id, position, product_template_id, description, quantity, unit_price, tax_rate
|
|
)
|
|
select
|
|
v_invoice_id,
|
|
item.ordinality::int,
|
|
nullif(item.value->>'product_template_id', '')::uuid,
|
|
item.value->>'description',
|
|
(item.value->>'quantity')::numeric,
|
|
(item.value->>'unit_price')::numeric,
|
|
(item.value->>'tax_rate')::numeric
|
|
from jsonb_array_elements(p_items) with ordinality as item(value, ordinality);
|
|
|
|
return v_invoice_id;
|
|
end $$;
|
|
|
|
revoke execute on function public.peek_next_invoice_number() from public, anon;
|
|
revoke execute on function public.create_invoice(uuid, date, date, text, text, text, text, char(2), jsonb) from public, anon;
|
|
grant execute on function public.peek_next_invoice_number() to authenticated;
|
|
grant execute on function public.create_invoice(uuid, date, date, text, text, text, text, char(2), jsonb) to authenticated;
|