camper/deploy/compute_new_invoice_amount.sql

65 lines
2.1 KiB
PL/PgSQL

-- Deploy camper:compute_new_invoice_amount to pg
-- requires: schema_camper
-- requires: company
-- requires: currency
-- requires: tax
-- requires: new_invoice_product
-- requires: new_invoice_amount
begin;
set search_path to camper, public;
create or replace function compute_new_invoice_amount(company_id integer, products new_invoice_product[]) returns new_invoice_amount as
$$
declare
result new_invoice_amount;
begin
if array_length(products, 1) is null then
select to_price(0, decimal_digits), array[]::text[][], to_price(0, decimal_digits)
from company
join currency using (currency_code)
where company.company_id = compute_new_invoice_amount.company_id
into result.subtotal, result.taxes, result.total;
else
with product as (
select round(parse_price(price, currency.decimal_digits) * quantity * (1 - discount_rate))::integer as subtotal
, tax
, decimal_digits
from unnest(products)
join company on company.company_id = compute_new_invoice_amount.company_id
join currency using (currency_code)
)
, tax_amount as (
select tax_id
, sum(round(subtotal * tax.rate)::integer)::integer as amount
, decimal_digits
from product, unnest(product.tax) as product_tax(tax_id)
join tax using (tax_id)
group by tax_id, decimal_digits
)
, tax_total as (
select sum(amount)::integer as amount, array_agg(array[name, to_price(amount, decimal_digits)]) as taxes
from tax_amount
join tax using (tax_id)
)
select to_price(sum(subtotal)::integer, decimal_digits)
, coalesce(taxes, array[]::text[][])
, to_price(sum(subtotal)::integer + coalesce(tax_total.amount, 0), decimal_digits) as total
from product, tax_total
group by tax_total.amount, taxes, decimal_digits
into result.subtotal, result.taxes, result.total;
end if;
return result;
end
$$
language plpgsql
stable;
revoke execute on function compute_new_invoice_amount(integer, new_invoice_product[]) from public;
grant execute on function compute_new_invoice_amount(integer, new_invoice_product[]) to employee;
grant execute on function compute_new_invoice_amount(integer, new_invoice_product[]) to admin;
commit;