Compare commits
2 Commits
c3fa23727f
...
ad5bc271b6
Author | SHA1 | Date |
---|---|---|
jordi fita mas | ad5bc271b6 | |
jordi fita mas | f546632a89 |
|
@ -0,0 +1,67 @@
|
||||||
|
-- Deploy numerus:add_payment to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment
|
||||||
|
-- requires: expense_payment
|
||||||
|
-- requires: company
|
||||||
|
-- requires: currency
|
||||||
|
-- requires: parse_price
|
||||||
|
-- requires: tag_name
|
||||||
|
-- requires: update_expense_payment_status
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function add_payment(company integer, expense_id integer, payment_date date, payment_account_id integer, description text, amount text, tags tag_name[]) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
pslug uuid;
|
||||||
|
pid integer;
|
||||||
|
amount_cents integer;
|
||||||
|
begin
|
||||||
|
insert into payment
|
||||||
|
( company_id
|
||||||
|
, payment_account_id
|
||||||
|
, description
|
||||||
|
, payment_date
|
||||||
|
, amount
|
||||||
|
, currency_code
|
||||||
|
, payment_status
|
||||||
|
, tags
|
||||||
|
)
|
||||||
|
select company_id
|
||||||
|
, payment_account_id
|
||||||
|
, description
|
||||||
|
, payment_date
|
||||||
|
, parse_price(amount, currency.decimal_digits)
|
||||||
|
, currency_code
|
||||||
|
, 'complete'
|
||||||
|
, tags
|
||||||
|
from company
|
||||||
|
join currency using (currency_code)
|
||||||
|
where company.company_id = add_payment.company
|
||||||
|
returning payment_id, slug, payment.amount
|
||||||
|
into pid, pslug, amount_cents
|
||||||
|
;
|
||||||
|
|
||||||
|
if expense_id is not null then
|
||||||
|
-- must be inserted before updating statuses, so that it can see this
|
||||||
|
-- payment’s amount too.
|
||||||
|
insert into expense_payment (expense_id, payment_id)
|
||||||
|
values (expense_id, pid);
|
||||||
|
|
||||||
|
perform update_expense_payment_status(pid, expense_id, amount_cents);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return pslug;
|
||||||
|
end
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function add_payment(integer, integer, date, integer, text, text, tag_name[]) from public;
|
||||||
|
grant execute on function add_payment(integer, integer, date, integer, text, text, tag_name[]) to invoicer;
|
||||||
|
grant execute on function add_payment(integer, integer, date, integer, text, text, tag_name[]) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,35 @@
|
||||||
|
-- Deploy numerus:add_payment_account_bank to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: payment_account_bank
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function add_payment_account_bank(company integer, name text, iban iban) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
account_id integer;
|
||||||
|
account_slug uuid;
|
||||||
|
begin
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
select company, 'bank', add_payment_account_bank.name
|
||||||
|
returning payment_account_id, slug into account_id, account_slug;
|
||||||
|
|
||||||
|
insert into payment_account_bank (payment_account_id, iban)
|
||||||
|
values (account_id, iban)
|
||||||
|
;
|
||||||
|
|
||||||
|
return account_slug;
|
||||||
|
end;
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function add_payment_account_bank(integer, text, iban) from public;
|
||||||
|
grant execute on function add_payment_account_bank(integer, text, iban) to invoicer;
|
||||||
|
grant execute on function add_payment_account_bank(integer, text, iban) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,34 @@
|
||||||
|
-- Deploy numerus:add_payment_account_card to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: payment_account_card
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function add_payment_account_card(company integer, name text, four_digits text, exp_date date) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
account_id integer;
|
||||||
|
account_slug uuid;
|
||||||
|
begin
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
select company, 'card', add_payment_account_card.name
|
||||||
|
returning payment_account_id, slug into account_id, account_slug;
|
||||||
|
|
||||||
|
insert into payment_account_card (payment_account_id, last_four_digits, expiration_date)
|
||||||
|
values (account_id, four_digits, exp_date);
|
||||||
|
|
||||||
|
return account_slug;
|
||||||
|
end
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function add_payment_account_card(integer, text, text, date) from public;
|
||||||
|
grant execute on function add_payment_account_card(integer, text, text, date) to invoicer;
|
||||||
|
grant execute on function add_payment_account_card(integer, text, text, date) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,23 @@
|
||||||
|
-- Deploy numerus:add_payment_account_cash to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function add_payment_account_cash(company integer, name text) returns uuid as
|
||||||
|
$$
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
values (company, 'cash', name)
|
||||||
|
returning slug;
|
||||||
|
$$
|
||||||
|
language sql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function add_payment_account_cash(integer, text) from public;
|
||||||
|
grant execute on function add_payment_account_cash(integer, text) to invoicer;
|
||||||
|
grant execute on function add_payment_account_cash(integer, text) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,23 @@
|
||||||
|
-- Deploy numerus:add_payment_account_other to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function add_payment_account_other(company integer, name text) returns uuid as
|
||||||
|
$$
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
values (company, 'other', name)
|
||||||
|
returning slug;
|
||||||
|
$$
|
||||||
|
language sql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function add_payment_account_other(integer, text) from public;
|
||||||
|
grant execute on function add_payment_account_other(integer, text) to invoicer;
|
||||||
|
grant execute on function add_payment_account_other(integer, text) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -9,14 +9,19 @@ set search_path to numerus;
|
||||||
|
|
||||||
insert into expense_status (expense_status, name)
|
insert into expense_status (expense_status, name)
|
||||||
values ('pending', 'Pending')
|
values ('pending', 'Pending')
|
||||||
|
, ('partial', 'Partial')
|
||||||
, ('paid', 'Paid')
|
, ('paid', 'Paid')
|
||||||
|
on conflict (expense_status) do nothing
|
||||||
;
|
;
|
||||||
|
|
||||||
insert into expense_status_i18n (expense_status, lang_tag, name)
|
insert into expense_status_i18n (expense_status, lang_tag, name)
|
||||||
values ('pending', 'ca', 'Pendent')
|
values ('pending', 'ca', 'Pendent')
|
||||||
|
, ('partial', 'ca', 'Parcial')
|
||||||
, ('paid', 'ca', 'Pagada')
|
, ('paid', 'ca', 'Pagada')
|
||||||
, ('pending', 'es', 'Pendiente')
|
, ('pending', 'es', 'Pendiente')
|
||||||
|
, ('partial', 'es', 'Parcial')
|
||||||
, ('paid', 'es', 'Pagada')
|
, ('paid', 'es', 'Pagada')
|
||||||
|
on conflict (expense_status, lang_tag) do nothing
|
||||||
;
|
;
|
||||||
|
|
||||||
commit;
|
commit;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- Deploy numerus:available_expense_status to pg
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: expense_status
|
||||||
|
-- requires: expense_status_i18n
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
insert into expense_status (expense_status, name)
|
||||||
|
values ('pending', 'Pending')
|
||||||
|
, ('paid', 'Paid')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense_status_i18n (expense_status, lang_tag, name)
|
||||||
|
values ('pending', 'ca', 'Pendent')
|
||||||
|
, ('paid', 'ca', 'Pagada')
|
||||||
|
, ('pending', 'es', 'Pendiente')
|
||||||
|
, ('paid', 'es', 'Pagada')
|
||||||
|
;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,28 @@
|
||||||
|
-- Deploy numerus:available_payment_account_types to pg
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account_type
|
||||||
|
-- requires: payment_account_type_i18n
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
insert into payment_account_type (payment_account_type, name)
|
||||||
|
values ('bank', 'Bank')
|
||||||
|
, ('card', 'Credit Card')
|
||||||
|
, ('cash', 'Cash')
|
||||||
|
, ('other', 'Other')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account_type_i18n (payment_account_type, lang_tag, name)
|
||||||
|
values ('bank', 'ca', 'Banc')
|
||||||
|
, ('card', 'ca', 'Targeta de crèdit')
|
||||||
|
, ('cash', 'ca', 'Efectiu')
|
||||||
|
, ('other', 'ca', 'Altres')
|
||||||
|
, ('bank', 'es', 'Banco')
|
||||||
|
, ('card', 'es', 'Tarjeta de crédito')
|
||||||
|
, ('cash', 'es', 'Efectivo')
|
||||||
|
, ('other', 'es', 'Otros')
|
||||||
|
;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- Deploy numerus:available_payment_status to pg
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_status
|
||||||
|
-- requires: payment_status_i18n
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
insert into payment_status (payment_status, name)
|
||||||
|
values ('partial', 'Partial')
|
||||||
|
, ('complete', 'Complete')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_status_i18n (payment_status, lang_tag, name)
|
||||||
|
values ('partial', 'ca', 'Parcial')
|
||||||
|
, ('partial', 'es', 'Parcial')
|
||||||
|
, ('complete', 'ca', 'Complet')
|
||||||
|
, ('complete', 'es', 'Completo')
|
||||||
|
;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,53 @@
|
||||||
|
-- Deploy numerus:edit_payment to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment
|
||||||
|
-- requires: expense_payment
|
||||||
|
-- requires: currency
|
||||||
|
-- requires: parse_price
|
||||||
|
-- requires: tag_name
|
||||||
|
-- requires: update_expense_payment_status
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function edit_payment(payment_slug uuid, payment_date date, payment_account_id integer, description text, amount text, tags tag_name[]) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
pid integer;
|
||||||
|
eid integer;
|
||||||
|
amount_cents integer;
|
||||||
|
begin
|
||||||
|
update payment
|
||||||
|
set payment_date = edit_payment.payment_date
|
||||||
|
, payment_account_id = edit_payment.payment_account_id
|
||||||
|
, description = edit_payment.description
|
||||||
|
, amount = parse_price(edit_payment.amount, decimal_digits)
|
||||||
|
, tags = edit_payment.tags
|
||||||
|
from currency
|
||||||
|
where slug = payment_slug
|
||||||
|
and currency.currency_code = payment.currency_code
|
||||||
|
returning payment_id, payment.amount
|
||||||
|
into pid, amount_cents
|
||||||
|
;
|
||||||
|
|
||||||
|
select expense_id into eid
|
||||||
|
from expense_payment
|
||||||
|
where payment_id = pid;
|
||||||
|
|
||||||
|
if eid is not null then
|
||||||
|
perform update_expense_payment_status(pid, eid, amount_cents);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return payment_slug;
|
||||||
|
end
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function edit_payment(uuid, date, integer, text, text, tag_name[]) from public;
|
||||||
|
grant execute on function edit_payment(uuid, date, integer, text, text, tag_name[]) to invoicer;
|
||||||
|
grant execute on function edit_payment(uuid, date, integer, text, text, tag_name[]) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,44 @@
|
||||||
|
-- Deploy numerus:edit_payment_account_bank to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: payment_account_bank
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
-- requires: extension_iban
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function edit_payment_account_bank(account_slug uuid, new_name text, new_iban iban) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
account_id int;
|
||||||
|
begin
|
||||||
|
update payment_account
|
||||||
|
set name = new_name
|
||||||
|
where slug = account_slug
|
||||||
|
and payment_account_type = 'bank'
|
||||||
|
returning payment_account_id into account_id
|
||||||
|
;
|
||||||
|
|
||||||
|
if account_id is null then
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
update payment_account_bank
|
||||||
|
set iban = new_iban
|
||||||
|
where payment_account_id = account_id
|
||||||
|
;
|
||||||
|
|
||||||
|
return account_slug;
|
||||||
|
end
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function edit_payment_account_bank(uuid, text, iban) from public;
|
||||||
|
grant execute on function edit_payment_account_bank(uuid, text, iban) to invoicer;
|
||||||
|
grant execute on function edit_payment_account_bank(uuid, text, iban) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,44 @@
|
||||||
|
-- Deploy numerus:edit_payment_account_card to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: payment_account_card
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function edit_payment_account_card(account_slug uuid, new_name text, new_last_digits text, new_exp_date date) returns uuid as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
account_id integer;
|
||||||
|
begin
|
||||||
|
update payment_account
|
||||||
|
set name = new_name
|
||||||
|
where slug = account_slug
|
||||||
|
and payment_account_type = 'card'
|
||||||
|
returning payment_account_id into account_id
|
||||||
|
;
|
||||||
|
|
||||||
|
if account_id is null then
|
||||||
|
return null;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
update payment_account_card
|
||||||
|
set last_four_digits = new_last_digits
|
||||||
|
, expiration_date = new_exp_date
|
||||||
|
where payment_account_id = account_id
|
||||||
|
;
|
||||||
|
|
||||||
|
return account_slug;
|
||||||
|
end
|
||||||
|
$$
|
||||||
|
language plpgsql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function edit_payment_account_card(uuid, text, text, date) from public;
|
||||||
|
grant execute on function edit_payment_account_card(uuid, text, text, date) to invoicer;
|
||||||
|
grant execute on function edit_payment_account_card(uuid, text, text, date) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,27 @@
|
||||||
|
-- Deploy numerus:edit_payment_account_cash to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function edit_payment_account_cash(account_slug uuid, new_name text) returns uuid as
|
||||||
|
$$
|
||||||
|
update payment_account
|
||||||
|
set name = new_name
|
||||||
|
where slug = account_slug
|
||||||
|
and payment_account_type = 'cash'
|
||||||
|
returning slug
|
||||||
|
;
|
||||||
|
$$
|
||||||
|
language sql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function edit_payment_account_cash(uuid, text) from public;
|
||||||
|
grant execute on function edit_payment_account_cash(uuid, text) to invoicer;
|
||||||
|
grant execute on function edit_payment_account_cash(uuid, text) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,27 @@
|
||||||
|
-- Deploy numerus:edit_payment_account_other to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function edit_payment_account_other(account_slug uuid, new_name text) returns uuid as
|
||||||
|
$$
|
||||||
|
update payment_account
|
||||||
|
set name = new_name
|
||||||
|
where slug = account_slug
|
||||||
|
and payment_account_type = 'other'
|
||||||
|
returning slug
|
||||||
|
;
|
||||||
|
$$
|
||||||
|
language sql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function edit_payment_account_other(uuid, text) from public;
|
||||||
|
grant execute on function edit_payment_account_other(uuid, text) to invoicer;
|
||||||
|
grant execute on function edit_payment_account_other(uuid, text) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,32 @@
|
||||||
|
-- Deploy numerus:expense_payment to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: expense
|
||||||
|
-- requires: payment
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table expense_payment (
|
||||||
|
expense_id integer not null references expense,
|
||||||
|
payment_id integer not null references payment,
|
||||||
|
primary key (expense_id, payment_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table expense_payment to invoicer;
|
||||||
|
grant select, insert, update, delete on table expense_payment to admin;
|
||||||
|
|
||||||
|
alter table expense_payment enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on expense_payment
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from expense
|
||||||
|
where expense.expense_id = expense_payment.expense_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,47 @@
|
||||||
|
-- Deploy numerus:payment to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: company
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: currency
|
||||||
|
-- requires: tag_name
|
||||||
|
-- requires: payment_status
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment (
|
||||||
|
payment_id integer generated by default as identity primary key,
|
||||||
|
company_id integer not null references company,
|
||||||
|
slug uuid not null unique default gen_random_uuid(),
|
||||||
|
description text not null,
|
||||||
|
payment_date date not null default current_date,
|
||||||
|
payment_account_id integer not null references payment_account,
|
||||||
|
amount integer not null,
|
||||||
|
currency_code text not null references currency,
|
||||||
|
tags tag_name[] not null default '{}',
|
||||||
|
payment_status text not null default 'complete' references payment_status,
|
||||||
|
created_at timestamptz not null default current_timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
create index on payment using gin (tags);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table payment to invoicer;
|
||||||
|
grant select, insert, update, delete on table payment to admin;
|
||||||
|
|
||||||
|
alter table payment enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on payment
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from company_user
|
||||||
|
join user_profile using (user_id)
|
||||||
|
where company_user.company_id = payment.company_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,38 @@
|
||||||
|
-- Deploy numerus:payment_account to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: company
|
||||||
|
-- requires: payment_account_type
|
||||||
|
-- requires: extension_pgcrypto
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_account (
|
||||||
|
payment_account_id integer generated by default as identity primary key,
|
||||||
|
company_id integer not null references company,
|
||||||
|
slug uuid not null unique default gen_random_uuid(),
|
||||||
|
payment_account_type text not null references payment_account_type,
|
||||||
|
name text not null constraint payment_account_name_not_empty check(length(trim(name)) > 0),
|
||||||
|
unique (payment_account_id, payment_account_type)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table payment_account to invoicer;
|
||||||
|
grant select, insert, update, delete on table payment_account to admin;
|
||||||
|
|
||||||
|
alter table payment_account enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on payment_account
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from company_user
|
||||||
|
join user_profile using (user_id)
|
||||||
|
where company_user.company_id = payment_account.company_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- Deploy numerus:payment_account_bank to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
-- requires: extension_iban
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_account_bank (
|
||||||
|
payment_account_id integer primary key,
|
||||||
|
payment_account_type text not null default 'bank' constraint payment_account_type_is_bank check (payment_account_type = 'bank'),
|
||||||
|
iban iban not null,
|
||||||
|
foreign key (payment_account_id, payment_account_type) references payment_account (payment_account_id, payment_account_type)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table payment_account_bank to invoicer;
|
||||||
|
grant select, insert, update, delete on table payment_account_bank to admin;
|
||||||
|
|
||||||
|
alter table payment_account_bank enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on payment_account_bank
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from payment_account
|
||||||
|
where payment_account.payment_account_id = payment_account_bank.payment_account_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- Deploy numerus:payment_account_card to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_account_card (
|
||||||
|
payment_account_id integer primary key,
|
||||||
|
payment_account_type text not null default 'card' constraint payment_account_type_is_card check (payment_account_type = 'card'),
|
||||||
|
last_four_digits text not null constraint last_four_digits_are_digits check ( last_four_digits ~ '^\d{4}$'),
|
||||||
|
expiration_date date not null,
|
||||||
|
foreign key (payment_account_id, payment_account_type) references payment_account (payment_account_id, payment_account_type)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select, insert, update, delete on table payment_account_card to invoicer;
|
||||||
|
grant select, insert, update, delete on table payment_account_card to admin;
|
||||||
|
|
||||||
|
alter table payment_account_card enable row level security;
|
||||||
|
|
||||||
|
create policy company_policy
|
||||||
|
on payment_account_card
|
||||||
|
using (
|
||||||
|
exists(
|
||||||
|
select 1
|
||||||
|
from payment_account
|
||||||
|
where payment_account.payment_account_id = payment_account_card.payment_account_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,17 @@
|
||||||
|
-- Deploy numerus:payment_account_type to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_account_type (
|
||||||
|
payment_account_type text primary key,
|
||||||
|
name text not null
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select on table payment_account_type to invoicer;
|
||||||
|
grant select on table payment_account_type to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- Deploy numerus:payment_account_type_i18n to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_account_type
|
||||||
|
-- requires: language
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_account_type_i18n (
|
||||||
|
payment_account_type text not null references payment_account_type,
|
||||||
|
lang_tag text not null references language,
|
||||||
|
name text not null,
|
||||||
|
primary key (payment_account_type, lang_tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select on table payment_account_type_i18n to invoicer;
|
||||||
|
grant select on table payment_account_type_i18n to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,17 @@
|
||||||
|
-- Deploy numerus:payment_status to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_status (
|
||||||
|
payment_status text primary key,
|
||||||
|
name text not null
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select on table payment_status to invoicer;
|
||||||
|
grant select on table payment_status to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- Deploy numerus:payment_status_i18n to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: payment_status
|
||||||
|
-- requires: language
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create table payment_status_i18n (
|
||||||
|
payment_status text not null references payment_status,
|
||||||
|
lang_tag text not null references language,
|
||||||
|
name text not null,
|
||||||
|
primary key (payment_status, lang_tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
grant select on table payment_status_i18n to invoicer;
|
||||||
|
grant select on table payment_status_i18n to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,43 @@
|
||||||
|
-- Deploy numerus:update_expense_payment_status to pg
|
||||||
|
-- requires: roles
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: expense
|
||||||
|
-- requires: payment
|
||||||
|
-- requires: expense_payment
|
||||||
|
-- requires: available_expense_status
|
||||||
|
-- requires: available_payment_status
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
create or replace function update_expense_payment_status(pid integer, eid integer, amount_cents integer) returns void as
|
||||||
|
$$
|
||||||
|
update payment
|
||||||
|
set payment_status = case when expense.amount > amount_cents or exists (select 1 from expense_payment as ep where ep.expense_id = expense.expense_id and payment_id <> pid) then 'partial' else 'complete' end
|
||||||
|
from expense
|
||||||
|
where expense.expense_id = eid
|
||||||
|
and payment_id = pid
|
||||||
|
;
|
||||||
|
|
||||||
|
update expense
|
||||||
|
set expense_status = case when paid_amount >= expense.amount then 'paid' else 'partial' end
|
||||||
|
from (
|
||||||
|
select expense_payment.expense_id
|
||||||
|
, sum(payment.amount) as paid_amount
|
||||||
|
from expense_payment
|
||||||
|
join payment using (payment_id)
|
||||||
|
group by expense_payment.expense_id
|
||||||
|
) as payment
|
||||||
|
where payment.expense_id = expense.expense_id
|
||||||
|
and expense.expense_id = eid
|
||||||
|
;
|
||||||
|
$$
|
||||||
|
language sql
|
||||||
|
;
|
||||||
|
|
||||||
|
revoke execute on function update_expense_payment_status(integer, integer, integer) from public;
|
||||||
|
grant execute on function update_expense_payment_status(integer, integer, integer) to invoicer;
|
||||||
|
grant execute on function update_expense_payment_status(integer, integer, integer) to admin;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,340 @@
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/jackc/pgtype"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExpirationDateFormat = "01/06"
|
||||||
|
AccountTypeBank = "bank"
|
||||||
|
AccountTypeCard = "card"
|
||||||
|
AccountTypeCash = "cash"
|
||||||
|
AccountTypeOther = "other"
|
||||||
|
)
|
||||||
|
|
||||||
|
func servePaymentAccountIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
conn := getConn(r)
|
||||||
|
locale := getLocale(r)
|
||||||
|
|
||||||
|
page := NewPaymentAccountIndexPage(r.Context(), conn, locale)
|
||||||
|
page.MustRender(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentAccountIndexPage struct {
|
||||||
|
Accounts []*PaymentAccountEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPaymentAccountIndexPage(ctx context.Context, conn *Conn, locale *Locale) *PaymentAccountIndexPage {
|
||||||
|
return &PaymentAccountIndexPage{
|
||||||
|
Accounts: mustCollectPaymentAccountEntries(ctx, conn, locale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (page *PaymentAccountIndexPage) MustRender(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mustRenderMainTemplate(w, r, "payments/accounts/index.gohtml", page)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentAccountEntry struct {
|
||||||
|
ID int
|
||||||
|
Slug string
|
||||||
|
Type string
|
||||||
|
TypeLabel string
|
||||||
|
Name string
|
||||||
|
IBAN string
|
||||||
|
LastFourDigits string
|
||||||
|
ExpirationDate string
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustCollectPaymentAccountEntries(ctx context.Context, conn *Conn, locale *Locale) []*PaymentAccountEntry {
|
||||||
|
rows := conn.MustQuery(ctx, `
|
||||||
|
select payment_account_id
|
||||||
|
, slug
|
||||||
|
, payment_account.payment_account_type
|
||||||
|
, coalesce(i18n.name, payment_account_type.name)
|
||||||
|
, payment_account.name
|
||||||
|
, coalesce(iban::text, '') as iban
|
||||||
|
, coalesce(last_four_digits, '') as last_four_digits
|
||||||
|
, expiration_date
|
||||||
|
from payment_account
|
||||||
|
left join payment_account_bank using (payment_account_id, payment_account_type)
|
||||||
|
left join payment_account_card using (payment_account_id, payment_account_type)
|
||||||
|
join payment_account_type using (payment_account_type)
|
||||||
|
left join payment_account_type_i18n as i18n on payment_account_type.payment_account_type = i18n.payment_account_type and i18n.lang_tag = $1
|
||||||
|
order by payment_account_id
|
||||||
|
`, locale.Language.String())
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var entries []*PaymentAccountEntry
|
||||||
|
for rows.Next() {
|
||||||
|
entry := &PaymentAccountEntry{}
|
||||||
|
var expirationDate pgtype.Date
|
||||||
|
if err := rows.Scan(&entry.ID, &entry.Slug, &entry.Type, &entry.TypeLabel, &entry.Name, &entry.IBAN, &entry.LastFourDigits, &expirationDate); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if expirationDate.Status == pgtype.Present {
|
||||||
|
entry.ExpirationDate = expirationDate.Time.Format(ExpirationDateFormat)
|
||||||
|
}
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
panic(rows.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
func servePaymentAccountForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
locale := getLocale(r)
|
||||||
|
conn := getConn(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentAccountForm(r.Context(), conn, locale, company)
|
||||||
|
slug := params[0].Value
|
||||||
|
if slug == "new" {
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !ValidUuid(slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.MustFillFromDatabase(r.Context(), conn, slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentAccountForm struct {
|
||||||
|
locale *Locale
|
||||||
|
company *Company
|
||||||
|
Slug string
|
||||||
|
Type *RadioField
|
||||||
|
Name *InputField
|
||||||
|
IBAN *InputField
|
||||||
|
LastFourDigits *InputField
|
||||||
|
ExpirationMonthYear *InputField
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPaymentAccountForm(ctx context.Context, conn *Conn, locale *Locale, company *Company) *PaymentAccountForm {
|
||||||
|
return &PaymentAccountForm{
|
||||||
|
locale: locale,
|
||||||
|
company: company,
|
||||||
|
Type: &RadioField{
|
||||||
|
Name: "payment_account_type",
|
||||||
|
Label: pgettext("input", "Type", locale),
|
||||||
|
Required: true,
|
||||||
|
Options: MustGetRadioOptions(ctx, conn, "select payment_account_type, i18n.name from payment_account_type join payment_account_type_i18n as i18n using (payment_account_type) where i18n.lang_tag = $1 order by payment_account_type", locale.Language.String()),
|
||||||
|
Attributes: []template.HTMLAttr{
|
||||||
|
`x-model="type"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Name: &InputField{
|
||||||
|
Name: "name",
|
||||||
|
Label: pgettext("input", "Name", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
IBAN: &InputField{
|
||||||
|
Name: "iban",
|
||||||
|
Label: pgettext("input", "IBAN", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
LastFourDigits: &InputField{
|
||||||
|
Name: "last_four_digits",
|
||||||
|
Label: pgettext("input", "Card’s last four digits", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "text",
|
||||||
|
Attributes: []template.HTMLAttr{
|
||||||
|
`maxlength="4"`,
|
||||||
|
`minlength="4"`,
|
||||||
|
`pattern="[0-9]{4}"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpirationMonthYear: &InputField{
|
||||||
|
Name: "expiration_date",
|
||||||
|
Label: pgettext("input", "Expiration date", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "text",
|
||||||
|
Attributes: []template.HTMLAttr{
|
||||||
|
`maxlength="5"`,
|
||||||
|
`minlength="5"`,
|
||||||
|
`pattern="[0-9]{2}/[0-9]{2}"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentAccountForm) MustRender(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if f.Slug == "" {
|
||||||
|
mustRenderMainTemplate(w, r, "payments/accounts/new.gohtml", f)
|
||||||
|
} else {
|
||||||
|
mustRenderMainTemplate(w, r, "payments/accounts/edit.gohtml", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentAccountForm) MustFillFromDatabase(ctx context.Context, conn *Conn, slug string) bool {
|
||||||
|
selectedType := f.Type.Selected
|
||||||
|
var expirationDate pgtype.Date
|
||||||
|
if notFoundErrorOrPanic(conn.QueryRow(ctx, `
|
||||||
|
select payment_account_type
|
||||||
|
, name
|
||||||
|
, coalesce(iban::text, '') as iban
|
||||||
|
, coalesce(last_four_digits, '') as last_four_digits
|
||||||
|
, expiration_date
|
||||||
|
from payment_account
|
||||||
|
left join payment_account_bank using (payment_account_id, payment_account_type)
|
||||||
|
left join payment_account_card using (payment_account_id, payment_account_type)
|
||||||
|
where slug = $1
|
||||||
|
`, slug).Scan(
|
||||||
|
f.Type,
|
||||||
|
f.Name,
|
||||||
|
f.IBAN,
|
||||||
|
f.LastFourDigits,
|
||||||
|
&expirationDate)) {
|
||||||
|
f.Type.Selected = selectedType
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.Slug = slug
|
||||||
|
if expirationDate.Status == pgtype.Present {
|
||||||
|
f.ExpirationMonthYear.Val = expirationDate.Time.Format(ExpirationDateFormat)
|
||||||
|
} else {
|
||||||
|
f.ExpirationMonthYear.Val = ""
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentAccountForm) Parse(r *http.Request) error {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Type.FillValue(r)
|
||||||
|
f.Name.FillValue(r)
|
||||||
|
f.IBAN.FillValue(r)
|
||||||
|
f.LastFourDigits.FillValue(r)
|
||||||
|
f.ExpirationMonthYear.FillValue(r)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentAccountForm) Validate(ctx context.Context, conn *Conn) bool {
|
||||||
|
validator := newFormValidator()
|
||||||
|
|
||||||
|
if validator.CheckValidRadioOption(f.Type, gettext("Selected payment account type is not valid.", f.locale)) {
|
||||||
|
switch f.Type.Selected {
|
||||||
|
case AccountTypeBank:
|
||||||
|
if validator.CheckRequiredInput(f.IBAN, gettext("IBAN can not be empty.", f.locale)) {
|
||||||
|
validator.CheckValidIBANInput(ctx, conn, f.IBAN, gettext("This value is not a valid IBAN.", f.locale))
|
||||||
|
}
|
||||||
|
case AccountTypeCard:
|
||||||
|
if validator.CheckRequiredInput(f.LastFourDigits, gettext("Last four digits can not be empty.", f.locale)) {
|
||||||
|
if validator.CheckInputLength(f.LastFourDigits, 4, gettext("You must enter the card’s last four digits", f.locale)) {
|
||||||
|
validator.CheckValidInteger(f.LastFourDigits, 0, 9999, gettext("Last four digits must be a number.", f.locale))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if validator.CheckRequiredInput(f.ExpirationMonthYear, gettext("Expiration date can not be empty.", f.locale)) {
|
||||||
|
_, err := time.Parse(ExpirationDateFormat, f.ExpirationMonthYear.Val)
|
||||||
|
validator.checkInput(f.ExpirationMonthYear, err == nil, gettext("Expiration date should be a valid date in format MM/YY (e.g., 08/24).", f.locale))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validator.CheckRequiredInput(f.Name, gettext("Payment account name can not be empty.", f.locale))
|
||||||
|
|
||||||
|
return validator.AllOK()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentAccountForm) ExpirationDate() (time.Time, error) {
|
||||||
|
date, err := time.Parse(ExpirationDateFormat, f.ExpirationMonthYear.Val)
|
||||||
|
if err != nil {
|
||||||
|
return date, err
|
||||||
|
}
|
||||||
|
return date.AddDate(0, 1, -1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleAddPaymentAccount(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
locale := getLocale(r)
|
||||||
|
conn := getConn(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentAccountForm(r.Context(), conn, locale, company)
|
||||||
|
if err := form.Parse(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.Validate(r.Context(), conn) {
|
||||||
|
if !IsHTMxRequest(r) {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch form.Type.Selected {
|
||||||
|
case AccountTypeBank:
|
||||||
|
conn.MustExec(r.Context(), "select add_payment_account_bank($1, $2, $3)", company.Id, form.Name, form.IBAN)
|
||||||
|
case AccountTypeCard:
|
||||||
|
date, err := form.ExpirationDate()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
conn.MustExec(r.Context(), "select add_payment_account_card($1, $2, $3, $4)", company.Id, form.Name, form.LastFourDigits, date)
|
||||||
|
case AccountTypeCash:
|
||||||
|
conn.MustExec(r.Context(), "select add_payment_account_cash($1, $2)", company.Id, form.Name)
|
||||||
|
case AccountTypeOther:
|
||||||
|
conn.MustExec(r.Context(), "select add_payment_account_other($1, $2)", company.Id, form.Name)
|
||||||
|
}
|
||||||
|
htmxRedirect(w, r, companyURI(company, "/payment-accounts"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEditPaymentAccount(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
conn := getConn(r)
|
||||||
|
locale := getLocale(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentAccountForm(r.Context(), conn, locale, company)
|
||||||
|
form.Slug = params[0].Value
|
||||||
|
if !ValidUuid(form.Slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := form.Parse(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.Validate(r.Context(), conn) {
|
||||||
|
if !IsHTMxRequest(r) {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var found string
|
||||||
|
switch form.Type.Selected {
|
||||||
|
case AccountTypeBank:
|
||||||
|
found = conn.MustGetText(r.Context(), "", "select edit_payment_account_bank($1, $2, $3)", form.Slug, form.Name, form.IBAN)
|
||||||
|
case AccountTypeCard:
|
||||||
|
date, err := form.ExpirationDate()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
found = conn.MustGetText(r.Context(), "", "select edit_payment_account_card($1, $2, $3, $4)", form.Slug, form.Name, form.LastFourDigits, date)
|
||||||
|
case AccountTypeCash:
|
||||||
|
found = conn.MustGetText(r.Context(), "", "select edit_payment_account_cash($1, $2)", form.Slug, form.Name)
|
||||||
|
case AccountTypeOther:
|
||||||
|
found = conn.MustGetText(r.Context(), "", "select edit_payment_account_other($1, $2)", form.Slug, form.Name)
|
||||||
|
}
|
||||||
|
if found == "" {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
htmxRedirect(w, r, companyURI(company, "/payment-accounts"))
|
||||||
|
}
|
|
@ -421,7 +421,6 @@ func (form *expenseForm) MustFillFromDatabase(ctx context.Context, conn *Conn, s
|
||||||
if len(form.Tax.Selected) == 1 && form.Tax.Selected[0] == "" {
|
if len(form.Tax.Selected) == 1 && form.Tax.Selected[0] == "" {
|
||||||
form.Tax.Selected = nil
|
form.Tax.Selected = nil
|
||||||
}
|
}
|
||||||
fmt.Println(form.Tax.Selected)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
func HandleUpdateExpense(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
func HandleUpdateExpense(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
|
43
pkg/form.go
43
pkg/form.go
|
@ -295,6 +295,33 @@ func (field *RadioField) isValidOption(selected string) bool {
|
||||||
return field.FindOption(selected) != nil
|
return field.FindOption(selected) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (field *RadioField) HasValidOption() bool {
|
||||||
|
return field.isValidOption(field.Selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustGetRadioOptions(ctx context.Context, conn *Conn, sql string, args ...interface{}) []*RadioOption {
|
||||||
|
rows, err := conn.Query(ctx, sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var options []*RadioOption
|
||||||
|
for rows.Next() {
|
||||||
|
option := &RadioOption{}
|
||||||
|
err = rows.Scan(&option.Value, &option.Label)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
options = append(options, option)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
panic(rows.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
type CheckField struct {
|
type CheckField struct {
|
||||||
Name string
|
Name string
|
||||||
Label string
|
Label string
|
||||||
|
@ -452,6 +479,10 @@ func (v *FormValidator) CheckInputMinLength(field *InputField, min int, message
|
||||||
return v.checkInput(field, len(field.Val) >= min, message)
|
return v.checkInput(field, len(field.Val) >= min, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *FormValidator) CheckInputLength(field *InputField, length int, message string) bool {
|
||||||
|
return v.checkInput(field, len(field.Val) == length, message)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *FormValidator) CheckValidEmailInput(field *InputField, message string) bool {
|
func (v *FormValidator) CheckValidEmailInput(field *InputField, message string) bool {
|
||||||
_, err := mail.ParseAddress(field.Val)
|
_, err := mail.ParseAddress(field.Val)
|
||||||
return v.checkInput(field, err == nil, message)
|
return v.checkInput(field, err == nil, message)
|
||||||
|
@ -481,6 +512,10 @@ func (v *FormValidator) CheckValidSelectOption(field *SelectField, message strin
|
||||||
return v.checkSelect(field, field.HasValidOptions(), message)
|
return v.checkSelect(field, field.HasValidOptions(), message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *FormValidator) CheckValidRadioOption(field *RadioField, message string) bool {
|
||||||
|
return v.checkRadio(field, field.HasValidOption(), message)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *FormValidator) CheckAtMostOneOfEachGroup(field *SelectField, message string) bool {
|
func (v *FormValidator) CheckAtMostOneOfEachGroup(field *SelectField, message string) bool {
|
||||||
repeated := false
|
repeated := false
|
||||||
groups := map[string]bool{}
|
groups := map[string]bool{}
|
||||||
|
@ -539,3 +574,11 @@ func (v *FormValidator) checkSelect(field *SelectField, ok bool, message string)
|
||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *FormValidator) checkRadio(field *RadioField, ok bool, message string) bool {
|
||||||
|
if !ok {
|
||||||
|
field.Errors = append(field.Errors, errors.New(message))
|
||||||
|
v.Valid = false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"html/template"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func servePaymentIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
conn := getConn(r)
|
||||||
|
locale := getLocale(r)
|
||||||
|
|
||||||
|
page := NewPaymentIndexPage(r.Context(), conn, locale)
|
||||||
|
page.MustRender(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentIndexPage struct {
|
||||||
|
Payments []*PaymentEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPaymentIndexPage(ctx context.Context, conn *Conn, locale *Locale) *PaymentIndexPage {
|
||||||
|
return &PaymentIndexPage{
|
||||||
|
Payments: mustCollectPaymentEntries(ctx, conn, locale),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (page *PaymentIndexPage) MustRender(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mustRenderMainTemplate(w, r, "payments/index.gohtml", page)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentEntry struct {
|
||||||
|
ID int
|
||||||
|
Slug string
|
||||||
|
PaymentDate time.Time
|
||||||
|
Description string
|
||||||
|
Total string
|
||||||
|
Tags []string
|
||||||
|
Status string
|
||||||
|
StatusLabel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustCollectPaymentEntries(ctx context.Context, conn *Conn, locale *Locale) []*PaymentEntry {
|
||||||
|
rows := conn.MustQuery(ctx, `
|
||||||
|
select payment_id
|
||||||
|
, payment.slug
|
||||||
|
, payment_date
|
||||||
|
, description
|
||||||
|
, to_price(payment.amount, decimal_digits) as total
|
||||||
|
, payment.tags
|
||||||
|
, payment.payment_status
|
||||||
|
, psi18n.name
|
||||||
|
from payment
|
||||||
|
join payment_status_i18n psi18n on payment.payment_status = psi18n.payment_status and psi18n.lang_tag = $1
|
||||||
|
join currency using (currency_code)
|
||||||
|
order by payment_date desc, total desc
|
||||||
|
`, locale.Language)
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var entries []*PaymentEntry
|
||||||
|
for rows.Next() {
|
||||||
|
entry := &PaymentEntry{}
|
||||||
|
if err := rows.Scan(&entry.ID, &entry.Slug, &entry.PaymentDate, &entry.Description, &entry.Total, &entry.Tags, &entry.Status, &entry.StatusLabel); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
if rows.Err() != nil {
|
||||||
|
panic(rows.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
func servePaymentForm(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
locale := getLocale(r)
|
||||||
|
conn := getConn(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentForm(r.Context(), conn, locale, company)
|
||||||
|
slug := params[0].Value
|
||||||
|
if slug == "new" {
|
||||||
|
form.PaymentDate.Val = time.Now().Format("2006-01-02")
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !ValidUuid(slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.MustFillFromDatabase(r.Context(), conn, slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentForm struct {
|
||||||
|
locale *Locale
|
||||||
|
company *Company
|
||||||
|
Slug string
|
||||||
|
Description *InputField
|
||||||
|
PaymentDate *InputField
|
||||||
|
PaymentAccount *SelectField
|
||||||
|
Amount *InputField
|
||||||
|
Tags *TagsField
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPaymentForm(ctx context.Context, conn *Conn, locale *Locale, company *Company) *PaymentForm {
|
||||||
|
return &PaymentForm{
|
||||||
|
locale: locale,
|
||||||
|
company: company,
|
||||||
|
Description: &InputField{
|
||||||
|
Name: "description",
|
||||||
|
Label: pgettext("input", "Description", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "text",
|
||||||
|
},
|
||||||
|
PaymentDate: &InputField{
|
||||||
|
Name: "payment_date",
|
||||||
|
Label: pgettext("input", "Invoice Date", locale),
|
||||||
|
Required: true,
|
||||||
|
Type: "date",
|
||||||
|
},
|
||||||
|
PaymentAccount: &SelectField{
|
||||||
|
Name: "payment_account",
|
||||||
|
Label: pgettext("input", "Account", locale),
|
||||||
|
Required: true,
|
||||||
|
Options: MustGetOptions(ctx, conn, "select payment_account_id::text, name from payment_account order by name"),
|
||||||
|
},
|
||||||
|
Amount: &InputField{
|
||||||
|
Name: "amount",
|
||||||
|
Label: pgettext("input", "Amount", locale),
|
||||||
|
Type: "number",
|
||||||
|
Required: true,
|
||||||
|
Attributes: []template.HTMLAttr{
|
||||||
|
`min="0"`,
|
||||||
|
template.HTMLAttr(fmt.Sprintf(`step="%v"`, company.MinCents())),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: &TagsField{
|
||||||
|
Name: "tags",
|
||||||
|
Label: pgettext("input", "Tags", locale),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentForm) MustRender(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if f.Slug == "" {
|
||||||
|
f.PaymentAccount.EmptyLabel = gettext("Select an account.", f.locale)
|
||||||
|
mustRenderMainTemplate(w, r, "payments/new.gohtml", f)
|
||||||
|
} else {
|
||||||
|
mustRenderMainTemplate(w, r, "payments/edit.gohtml", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentForm) MustFillFromDatabase(ctx context.Context, conn *Conn, slug string) bool {
|
||||||
|
selectedPaymentAccount := f.PaymentAccount.Selected
|
||||||
|
f.PaymentAccount.Clear()
|
||||||
|
if notFoundErrorOrPanic(conn.QueryRow(ctx, `
|
||||||
|
select description
|
||||||
|
, payment_date
|
||||||
|
, payment_account_id::text
|
||||||
|
, to_price(amount, decimal_digits)
|
||||||
|
, tags
|
||||||
|
from payment
|
||||||
|
join currency using (currency_code)
|
||||||
|
where payment.slug = $1
|
||||||
|
`, slug).Scan(
|
||||||
|
f.Description,
|
||||||
|
f.PaymentDate,
|
||||||
|
f.PaymentAccount,
|
||||||
|
f.Amount,
|
||||||
|
f.Tags)) {
|
||||||
|
f.PaymentAccount.Selected = selectedPaymentAccount
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.Slug = slug
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentForm) Parse(r *http.Request) error {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Description.FillValue(r)
|
||||||
|
f.PaymentDate.FillValue(r)
|
||||||
|
f.PaymentAccount.FillValue(r)
|
||||||
|
f.Amount.FillValue(r)
|
||||||
|
f.Tags.FillValue(r)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *PaymentForm) Validate() bool {
|
||||||
|
validator := newFormValidator()
|
||||||
|
validator.CheckRequiredInput(f.Description, gettext("Description can not be empty.", f.locale))
|
||||||
|
validator.CheckValidSelectOption(f.PaymentAccount, gettext("Selected payment account is not valid.", f.locale))
|
||||||
|
validator.CheckValidDate(f.PaymentDate, gettext("Payment date must be a valid date.", f.locale))
|
||||||
|
if validator.CheckRequiredInput(f.Amount, gettext("Amount can not be empty.", f.locale)) {
|
||||||
|
validator.CheckValidDecimal(f.Amount, f.company.MinCents(), math.MaxFloat64, gettext("Amount must be a number greater than zero.", f.locale))
|
||||||
|
}
|
||||||
|
return validator.AllOK()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleAddPayment(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
|
locale := getLocale(r)
|
||||||
|
conn := getConn(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentForm(r.Context(), conn, locale, company)
|
||||||
|
if err := form.Parse(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.Validate() {
|
||||||
|
if !IsHTMxRequest(r) {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.MustExec(r.Context(), "select add_payment($1, $2, $3, $4, $5, $6, $7)", company.Id, nil, form.PaymentDate, form.PaymentAccount, form.Description, form.Amount, form.Tags)
|
||||||
|
htmxRedirect(w, r, companyURI(company, "/payments"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleEditPayment(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
conn := getConn(r)
|
||||||
|
locale := getLocale(r)
|
||||||
|
company := mustGetCompany(r)
|
||||||
|
form := newPaymentForm(r.Context(), conn, locale, company)
|
||||||
|
form.Slug = params[0].Value
|
||||||
|
if !ValidUuid(form.Slug) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := form.Parse(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := verifyCsrfTokenValid(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !form.Validate() {
|
||||||
|
if !IsHTMxRequest(r) {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
}
|
||||||
|
form.MustRender(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if found := conn.MustGetText(r.Context(), "", "select edit_payment($1, $2, $3, $4, $5, $6)", form.Slug, form.PaymentDate, form.PaymentAccount, form.Description, form.Amount, form.Tags); found == "" {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
htmxRedirect(w, r, companyURI(company, "/payments"))
|
||||||
|
}
|
|
@ -58,6 +58,14 @@ func NewRouter(db *Db, demo bool) http.Handler {
|
||||||
companyRouter.PUT("/expenses/:slug/tags", HandleUpdateExpenseTags)
|
companyRouter.PUT("/expenses/:slug/tags", HandleUpdateExpenseTags)
|
||||||
companyRouter.GET("/expenses/:slug/tags/edit", ServeEditExpenseTags)
|
companyRouter.GET("/expenses/:slug/tags/edit", ServeEditExpenseTags)
|
||||||
companyRouter.GET("/expenses/:slug/download/:filename", ServeExpenseAttachment)
|
companyRouter.GET("/expenses/:slug/download/:filename", ServeExpenseAttachment)
|
||||||
|
companyRouter.GET("/payments", servePaymentIndex)
|
||||||
|
companyRouter.POST("/payments", handleAddPayment)
|
||||||
|
companyRouter.GET("/payments/:slug", servePaymentForm)
|
||||||
|
companyRouter.PUT("/payments/:slug", handleEditPayment)
|
||||||
|
companyRouter.GET("/payment-accounts", servePaymentAccountIndex)
|
||||||
|
companyRouter.POST("/payment-accounts", handleAddPaymentAccount)
|
||||||
|
companyRouter.GET("/payment-accounts/:slug", servePaymentAccountForm)
|
||||||
|
companyRouter.PUT("/payment-accounts/:slug", handleEditPaymentAccount)
|
||||||
companyRouter.GET("/", ServeDashboard)
|
companyRouter.GET("/", ServeDashboard)
|
||||||
|
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
270
po/ca.po
270
po/ca.po
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: numerus\n"
|
"Project-Id-Version: numerus\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||||
"POT-Creation-Date: 2024-07-20 22:51+0200\n"
|
"POT-Creation-Date: 2024-08-10 04:08+0200\n"
|
||||||
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
|
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Catalan <ca@dodds.net>\n"
|
"Language-Team: Catalan <ca@dodds.net>\n"
|
||||||
|
@ -35,6 +35,11 @@ msgstr "Afegeix productes a la factura"
|
||||||
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10
|
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10
|
||||||
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9
|
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9
|
||||||
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10
|
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10
|
||||||
|
#: web/template/payments/new.gohtml:10 web/template/payments/index.gohtml:10
|
||||||
|
#: web/template/payments/edit.gohtml:10
|
||||||
|
#: web/template/payments/accounts/new.gohtml:10
|
||||||
|
#: web/template/payments/accounts/index.gohtml:10
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:10
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Inici"
|
msgstr "Inici"
|
||||||
|
@ -61,6 +66,7 @@ msgstr "Tots"
|
||||||
#: web/template/invoices/products.gohtml:49
|
#: web/template/invoices/products.gohtml:49
|
||||||
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49
|
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49
|
||||||
#: web/template/products/index.gohtml:45
|
#: web/template/products/index.gohtml:45
|
||||||
|
#: web/template/payments/accounts/index.gohtml:25
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
@ -107,7 +113,7 @@ msgstr "Subtotal"
|
||||||
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
|
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
|
||||||
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
|
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
|
||||||
#: web/template/expenses/new.gohtml:47 web/template/expenses/index.gohtml:74
|
#: web/template/expenses/new.gohtml:47 web/template/expenses/index.gohtml:74
|
||||||
#: web/template/expenses/edit.gohtml:49
|
#: web/template/expenses/edit.gohtml:49 web/template/payments/index.gohtml:29
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -115,6 +121,8 @@ msgstr "Total"
|
||||||
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
|
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
|
||||||
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
|
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
|
||||||
#: web/template/expenses/new.gohtml:57 web/template/expenses/edit.gohtml:59
|
#: web/template/expenses/new.gohtml:57 web/template/expenses/edit.gohtml:59
|
||||||
|
#: web/template/payments/edit.gohtml:35
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:38
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Actualitza"
|
msgstr "Actualitza"
|
||||||
|
@ -124,6 +132,8 @@ msgstr "Actualitza"
|
||||||
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
|
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
|
||||||
#: web/template/expenses/new.gohtml:60 web/template/expenses/edit.gohtml:62
|
#: web/template/expenses/new.gohtml:60 web/template/expenses/edit.gohtml:62
|
||||||
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
|
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
|
||||||
|
#: web/template/payments/new.gohtml:33
|
||||||
|
#: web/template/payments/accounts/new.gohtml:41
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Desa"
|
msgstr "Desa"
|
||||||
|
@ -180,14 +190,14 @@ msgid "Customer"
|
||||||
msgstr "Client"
|
msgstr "Client"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
|
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
|
||||||
#: web/template/expenses/index.gohtml:68
|
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:27
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Estat"
|
msgstr "Estat"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
|
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
|
||||||
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
|
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
|
||||||
#: web/template/products/index.gohtml:46
|
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:28
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Etiquetes"
|
msgstr "Etiquetes"
|
||||||
|
@ -326,7 +336,7 @@ msgctxt "input"
|
||||||
msgid "(Max. %s)"
|
msgid "(Max. %s)"
|
||||||
msgstr "(Màx. %s)"
|
msgstr "(Màx. %s)"
|
||||||
|
|
||||||
#: web/template/form.gohtml:200
|
#: web/template/form.gohtml:202
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Filters"
|
msgid "Filters"
|
||||||
msgstr "Filtra"
|
msgstr "Filtra"
|
||||||
|
@ -489,15 +499,20 @@ msgstr "Despeses"
|
||||||
|
|
||||||
#: web/template/app.gohtml:57
|
#: web/template/app.gohtml:57
|
||||||
msgctxt "nav"
|
msgctxt "nav"
|
||||||
|
msgid "Payments"
|
||||||
|
msgstr "Pagaments"
|
||||||
|
|
||||||
|
#: web/template/app.gohtml:58
|
||||||
|
msgctxt "nav"
|
||||||
msgid "Products"
|
msgid "Products"
|
||||||
msgstr "Productes"
|
msgstr "Productes"
|
||||||
|
|
||||||
#: web/template/app.gohtml:58
|
#: web/template/app.gohtml:59
|
||||||
msgctxt "nav"
|
msgctxt "nav"
|
||||||
msgid "Contacts"
|
msgid "Contacts"
|
||||||
msgstr "Contactes"
|
msgstr "Contactes"
|
||||||
|
|
||||||
#: web/template/app.gohtml:66
|
#: web/template/app.gohtml:67
|
||||||
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
|
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
|
||||||
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versió: %s"
|
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versió: %s"
|
||||||
|
|
||||||
|
@ -731,6 +746,84 @@ msgctxt "title"
|
||||||
msgid "Edit Product “%s”"
|
msgid "Edit Product “%s”"
|
||||||
msgstr "Edició del producte «%s»"
|
msgstr "Edició del producte «%s»"
|
||||||
|
|
||||||
|
#: web/template/payments/new.gohtml:3 web/template/payments/new.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "New Payment"
|
||||||
|
msgstr "Nou pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/new.gohtml:11 web/template/payments/index.gohtml:3
|
||||||
|
#: web/template/payments/index.gohtml:11 web/template/payments/edit.gohtml:11
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payments"
|
||||||
|
msgstr "Pagaments"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "New payment"
|
||||||
|
msgstr "Nou pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:25
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Date"
|
||||||
|
msgstr "Data del pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:26
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Descripció"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:54
|
||||||
|
msgid "No payments added yet."
|
||||||
|
msgstr "No hi ha cap pagament."
|
||||||
|
|
||||||
|
#: web/template/payments/edit.gohtml:3
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Edit Payment “%s”"
|
||||||
|
msgstr "Edició del pagament «%s»"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/new.gohtml:3
|
||||||
|
#: web/template/payments/accounts/new.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "New Payment Account"
|
||||||
|
msgstr "Nou compte de pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/new.gohtml:11
|
||||||
|
#: web/template/payments/accounts/index.gohtml:3
|
||||||
|
#: web/template/payments/accounts/index.gohtml:11
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:11
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Accounts"
|
||||||
|
msgstr "Comptes de pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "New payment account"
|
||||||
|
msgstr "Nou compte de pagament"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:26
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Tipus"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:27
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Number"
|
||||||
|
msgstr "Número"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:28
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Expiration Date"
|
||||||
|
msgstr "Data de caducitat"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:51
|
||||||
|
msgid "No payment accounts added yet."
|
||||||
|
msgstr "No hi ha cap compte de pagament."
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:3
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Edit Payment Account “%s”"
|
||||||
|
msgstr "Edició del compte de pagament «%s»"
|
||||||
|
|
||||||
#: pkg/ods.go:62 pkg/ods.go:106
|
#: pkg/ods.go:62 pkg/ods.go:106
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "VAT number"
|
msgid "VAT number"
|
||||||
|
@ -762,49 +855,50 @@ msgstr "No podeu deixar la contrasenya en blanc."
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nom d’usuari o contrasenya incorrectes."
|
msgstr "Nom d’usuari o contrasenya incorrectes."
|
||||||
|
|
||||||
#: pkg/products.go:172 pkg/products.go:276 pkg/quote.go:901
|
#: pkg/products.go:172 pkg/products.go:276 pkg/quote.go:901 pkg/accounts.go:138
|
||||||
#: pkg/invoices.go:1147 pkg/contacts.go:149 pkg/contacts.go:262
|
#: pkg/invoices.go:1147 pkg/contacts.go:149 pkg/contacts.go:262
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708
|
#: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708
|
||||||
#: pkg/expenses.go:343 pkg/expenses.go:511 pkg/invoices.go:177
|
#: pkg/payments.go:145 pkg/expenses.go:343 pkg/expenses.go:510
|
||||||
#: pkg/invoices.go:877 pkg/invoices.go:1462 pkg/contacts.go:154
|
#: pkg/invoices.go:177 pkg/invoices.go:877 pkg/invoices.go:1462
|
||||||
#: pkg/contacts.go:362
|
#: pkg/contacts.go:154 pkg/contacts.go:362
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Etiquetes"
|
msgstr "Etiquetes"
|
||||||
|
|
||||||
#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:521 pkg/invoices.go:181
|
#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:520 pkg/invoices.go:181
|
||||||
#: pkg/contacts.go:158
|
#: pkg/contacts.go:158
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tags Condition"
|
msgid "Tags Condition"
|
||||||
msgstr "Condició de les etiquetes"
|
msgstr "Condició de les etiquetes"
|
||||||
|
|
||||||
#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:525 pkg/invoices.go:185
|
#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:524 pkg/invoices.go:185
|
||||||
#: pkg/contacts.go:162
|
#: pkg/contacts.go:162
|
||||||
msgctxt "tag condition"
|
msgctxt "tag condition"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Totes"
|
msgstr "Totes"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/expenses.go:526 pkg/invoices.go:186
|
#: pkg/products.go:186 pkg/expenses.go:525 pkg/invoices.go:186
|
||||||
#: pkg/contacts.go:163
|
#: pkg/contacts.go:163
|
||||||
msgid "Invoices must have all the specified labels."
|
msgid "Invoices must have all the specified labels."
|
||||||
msgstr "Les factures han de tenir totes les etiquetes."
|
msgstr "Les factures han de tenir totes les etiquetes."
|
||||||
|
|
||||||
#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:530 pkg/invoices.go:190
|
#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:529 pkg/invoices.go:190
|
||||||
#: pkg/contacts.go:167
|
#: pkg/contacts.go:167
|
||||||
msgctxt "tag condition"
|
msgctxt "tag condition"
|
||||||
msgid "Any"
|
msgid "Any"
|
||||||
msgstr "Qualsevol"
|
msgstr "Qualsevol"
|
||||||
|
|
||||||
#: pkg/products.go:191 pkg/expenses.go:531 pkg/invoices.go:191
|
#: pkg/products.go:191 pkg/expenses.go:530 pkg/invoices.go:191
|
||||||
#: pkg/contacts.go:168
|
#: pkg/contacts.go:168
|
||||||
msgid "Invoices must have at least one of the specified labels."
|
msgid "Invoices must have at least one of the specified labels."
|
||||||
msgstr "Les factures han de tenir com a mínim una de les etiquetes."
|
msgstr "Les factures han de tenir com a mínim una de les etiquetes."
|
||||||
|
|
||||||
#: pkg/products.go:282 pkg/quote.go:915 pkg/invoices.go:1161
|
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:117
|
||||||
|
#: pkg/invoices.go:1161
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
@ -1062,7 +1156,7 @@ msgctxt "input"
|
||||||
msgid "Quotation Status"
|
msgid "Quotation Status"
|
||||||
msgstr "Estat del pressupost"
|
msgstr "Estat del pressupost"
|
||||||
|
|
||||||
#: pkg/quote.go:154 pkg/expenses.go:516 pkg/invoices.go:157
|
#: pkg/quote.go:154 pkg/expenses.go:515 pkg/invoices.go:157
|
||||||
msgid "All status"
|
msgid "All status"
|
||||||
msgstr "Tots els estats"
|
msgstr "Tots els estats"
|
||||||
|
|
||||||
|
@ -1071,12 +1165,12 @@ msgctxt "input"
|
||||||
msgid "Quotation Number"
|
msgid "Quotation Number"
|
||||||
msgstr "Número de pressupost"
|
msgstr "Número de pressupost"
|
||||||
|
|
||||||
#: pkg/quote.go:164 pkg/expenses.go:501 pkg/invoices.go:167
|
#: pkg/quote.go:164 pkg/expenses.go:500 pkg/invoices.go:167
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "From Date"
|
msgid "From Date"
|
||||||
msgstr "A partir de la data"
|
msgstr "A partir de la data"
|
||||||
|
|
||||||
#: pkg/quote.go:169 pkg/expenses.go:506 pkg/invoices.go:172
|
#: pkg/quote.go:169 pkg/expenses.go:505 pkg/invoices.go:172
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "To Date"
|
msgid "To Date"
|
||||||
msgstr "Fins la data"
|
msgstr "Fins la data"
|
||||||
|
@ -1097,8 +1191,8 @@ msgstr "pressuposts.zip"
|
||||||
msgid "quotations.ods"
|
msgid "quotations.ods"
|
||||||
msgstr "pressuposts.ods"
|
msgstr "pressuposts.ods"
|
||||||
|
|
||||||
#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:720
|
#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:719
|
||||||
#: pkg/expenses.go:750 pkg/invoices.go:684 pkg/invoices.go:1437
|
#: pkg/expenses.go:749 pkg/invoices.go:684 pkg/invoices.go:1437
|
||||||
#: pkg/invoices.go:1445
|
#: pkg/invoices.go:1445
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acció invàlida."
|
msgstr "Acció invàlida."
|
||||||
|
@ -1218,6 +1312,101 @@ msgstr "La confirmació no és igual a la contrasenya."
|
||||||
msgid "Selected language is not valid."
|
msgid "Selected language is not valid."
|
||||||
msgstr "Heu seleccionat un idioma que no és vàlid."
|
msgstr "Heu seleccionat un idioma que no és vàlid."
|
||||||
|
|
||||||
|
#: pkg/payments.go:123 pkg/expenses.go:305 pkg/invoices.go:866
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Invoice Date"
|
||||||
|
msgstr "Data de factura"
|
||||||
|
|
||||||
|
#: pkg/payments.go:129
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Account"
|
||||||
|
msgstr "Compte"
|
||||||
|
|
||||||
|
#: pkg/payments.go:135 pkg/expenses.go:320
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Amount"
|
||||||
|
msgstr "Import"
|
||||||
|
|
||||||
|
#: pkg/payments.go:152
|
||||||
|
msgid "Select an account."
|
||||||
|
msgstr "Escolliu un compte."
|
||||||
|
|
||||||
|
#: pkg/payments.go:198
|
||||||
|
msgid "Description can not be empty."
|
||||||
|
msgstr "No podeu deixar la descripció en blanc."
|
||||||
|
|
||||||
|
#: pkg/payments.go:199
|
||||||
|
msgid "Selected payment account is not valid."
|
||||||
|
msgstr "Heu seleccionat un compte de pagament que no és vàlid."
|
||||||
|
|
||||||
|
#: pkg/payments.go:200
|
||||||
|
msgid "Payment date must be a valid date."
|
||||||
|
msgstr "La data de pagament ha de ser vàlida."
|
||||||
|
|
||||||
|
#: pkg/payments.go:201 pkg/expenses.go:381
|
||||||
|
msgid "Amount can not be empty."
|
||||||
|
msgstr "No podeu deixar l’import en blanc."
|
||||||
|
|
||||||
|
#: pkg/payments.go:202 pkg/expenses.go:382
|
||||||
|
msgid "Amount must be a number greater than zero."
|
||||||
|
msgstr "L’import ha de ser un número major a zero."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:129
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Tipus"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:144 pkg/contacts.go:352
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "IBAN"
|
||||||
|
msgstr "IBAN"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:150
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Card’s last four digits"
|
||||||
|
msgstr "Els quatre darrers dígits de la targeta"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:161
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Expiration date"
|
||||||
|
msgstr "Data de caducitat"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:227
|
||||||
|
msgid "Selected payment account type is not valid."
|
||||||
|
msgstr "Heu seleccionat un tipus de compte de pagament que no és vàlid."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:230
|
||||||
|
msgid "IBAN can not be empty."
|
||||||
|
msgstr "No podeu deixar l’IBAN en blanc."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:231
|
||||||
|
msgid "This value is not a valid IBAN."
|
||||||
|
msgstr "Aquest valor no és un IBAN vàlid."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:234
|
||||||
|
msgid "Last four digits can not be empty."
|
||||||
|
msgstr "No podeu deixar el quatre darrers dígits en blanc."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:235
|
||||||
|
msgid "You must enter the card’s last four digits"
|
||||||
|
msgstr "Heu d’entrar els quatre darrers dígits de la targeta"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:236
|
||||||
|
msgid "Last four digits must be a number."
|
||||||
|
msgstr "El quatre darrera dígits han de ser un número."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:239
|
||||||
|
msgid "Expiration date can not be empty."
|
||||||
|
msgstr "No podeu deixar la data de pagament en blanc."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:241
|
||||||
|
msgid "Expiration date should be a valid date in format MM/YY (e.g., 08/24)."
|
||||||
|
msgstr "La data de caducitat has de ser vàlida i en format MM/AA (p. ex., 08/24)."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:245
|
||||||
|
msgid "Payment account name can not be empty."
|
||||||
|
msgstr "No podeu deixar el nom del compte de pagament en blanc."
|
||||||
|
|
||||||
#: pkg/dashboard.go:138
|
#: pkg/dashboard.go:138
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
|
@ -1257,7 +1446,7 @@ msgstr "Any anterior"
|
||||||
msgid "Select a contact."
|
msgid "Select a contact."
|
||||||
msgstr "Escolliu un contacte."
|
msgstr "Escolliu un contacte."
|
||||||
|
|
||||||
#: pkg/expenses.go:294 pkg/expenses.go:490
|
#: pkg/expenses.go:294 pkg/expenses.go:489
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr "Contacte"
|
msgstr "Contacte"
|
||||||
|
@ -1267,22 +1456,12 @@ msgctxt "input"
|
||||||
msgid "Invoice number"
|
msgid "Invoice number"
|
||||||
msgstr "Número de factura"
|
msgstr "Número de factura"
|
||||||
|
|
||||||
#: pkg/expenses.go:305 pkg/invoices.go:866
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "Invoice Date"
|
|
||||||
msgstr "Data de factura"
|
|
||||||
|
|
||||||
#: pkg/expenses.go:320
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "Amount"
|
|
||||||
msgstr "Import"
|
|
||||||
|
|
||||||
#: pkg/expenses.go:331 pkg/invoices.go:888
|
#: pkg/expenses.go:331 pkg/invoices.go:888
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Fitxer"
|
msgstr "Fitxer"
|
||||||
|
|
||||||
#: pkg/expenses.go:337 pkg/expenses.go:515
|
#: pkg/expenses.go:337 pkg/expenses.go:514
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Expense Status"
|
msgid "Expense Status"
|
||||||
msgstr "Estat de la despesa"
|
msgstr "Estat de la despesa"
|
||||||
|
@ -1295,28 +1474,20 @@ msgstr "Heu seleccionat un contacte que no és vàlid."
|
||||||
msgid "Invoice date must be a valid date."
|
msgid "Invoice date must be a valid date."
|
||||||
msgstr "La data de facturació ha de ser vàlida."
|
msgstr "La data de facturació ha de ser vàlida."
|
||||||
|
|
||||||
#: pkg/expenses.go:381
|
|
||||||
msgid "Amount can not be empty."
|
|
||||||
msgstr "No podeu deixar l’import en blanc."
|
|
||||||
|
|
||||||
#: pkg/expenses.go:382
|
|
||||||
msgid "Amount must be a number greater than zero."
|
|
||||||
msgstr "L’import ha de ser un número major a zero."
|
|
||||||
|
|
||||||
#: pkg/expenses.go:384
|
#: pkg/expenses.go:384
|
||||||
msgid "Selected expense status is not valid."
|
msgid "Selected expense status is not valid."
|
||||||
msgstr "Heu seleccionat un estat de despesa que no és vàlid."
|
msgstr "Heu seleccionat un estat de despesa que no és vàlid."
|
||||||
|
|
||||||
#: pkg/expenses.go:491
|
#: pkg/expenses.go:490
|
||||||
msgid "All contacts"
|
msgid "All contacts"
|
||||||
msgstr "Tots els contactes"
|
msgstr "Tots els contactes"
|
||||||
|
|
||||||
#: pkg/expenses.go:496 pkg/invoices.go:162
|
#: pkg/expenses.go:495 pkg/invoices.go:162
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Number"
|
msgid "Invoice Number"
|
||||||
msgstr "Número de factura"
|
msgstr "Número de factura"
|
||||||
|
|
||||||
#: pkg/expenses.go:748
|
#: pkg/expenses.go:747
|
||||||
msgid "expenses.ods"
|
msgid "expenses.ods"
|
||||||
msgstr "despeses.ods"
|
msgstr "despeses.ods"
|
||||||
|
|
||||||
|
@ -1364,11 +1535,6 @@ msgctxt "input"
|
||||||
msgid "Need to input tax details"
|
msgid "Need to input tax details"
|
||||||
msgstr "Necessito poder facturar aquest contacte"
|
msgstr "Necessito poder facturar aquest contacte"
|
||||||
|
|
||||||
#: pkg/contacts.go:352
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "IBAN"
|
|
||||||
msgstr "IBAN"
|
|
||||||
|
|
||||||
#: pkg/contacts.go:357
|
#: pkg/contacts.go:357
|
||||||
msgctxt "bic"
|
msgctxt "bic"
|
||||||
msgid "BIC"
|
msgid "BIC"
|
||||||
|
@ -1445,10 +1611,6 @@ msgstr "Fitxer Excel del Holded"
|
||||||
#~ msgid "Product ID can not be empty."
|
#~ msgid "Product ID can not be empty."
|
||||||
#~ msgstr "No podeu deixar l’identificador del producte en blanc."
|
#~ msgstr "No podeu deixar l’identificador del producte en blanc."
|
||||||
|
|
||||||
#~ msgctxt "input"
|
|
||||||
#~ msgid "Number"
|
|
||||||
#~ msgstr "Número"
|
|
||||||
|
|
||||||
#~ msgctxt "title"
|
#~ msgctxt "title"
|
||||||
#~ msgid "Label"
|
#~ msgid "Label"
|
||||||
#~ msgstr "Etiqueta"
|
#~ msgstr "Etiqueta"
|
||||||
|
|
270
po/es.po
270
po/es.po
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: numerus\n"
|
"Project-Id-Version: numerus\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
|
||||||
"POT-Creation-Date: 2024-07-20 22:51+0200\n"
|
"POT-Creation-Date: 2024-08-10 04:08+0200\n"
|
||||||
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
|
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||||
|
@ -35,6 +35,11 @@ msgstr "Añadir productos a la factura"
|
||||||
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10
|
#: web/template/expenses/index.gohtml:10 web/template/expenses/edit.gohtml:10
|
||||||
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9
|
#: web/template/tax-details.gohtml:9 web/template/products/new.gohtml:9
|
||||||
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10
|
#: web/template/products/index.gohtml:9 web/template/products/edit.gohtml:10
|
||||||
|
#: web/template/payments/new.gohtml:10 web/template/payments/index.gohtml:10
|
||||||
|
#: web/template/payments/edit.gohtml:10
|
||||||
|
#: web/template/payments/accounts/new.gohtml:10
|
||||||
|
#: web/template/payments/accounts/index.gohtml:10
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:10
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "Inicio"
|
msgstr "Inicio"
|
||||||
|
@ -61,6 +66,7 @@ msgstr "Todos"
|
||||||
#: web/template/invoices/products.gohtml:49
|
#: web/template/invoices/products.gohtml:49
|
||||||
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49
|
#: web/template/switch-company.gohtml:22 web/template/quotes/products.gohtml:49
|
||||||
#: web/template/products/index.gohtml:45
|
#: web/template/products/index.gohtml:45
|
||||||
|
#: web/template/payments/accounts/index.gohtml:25
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
@ -107,7 +113,7 @@ msgstr "Subtotal"
|
||||||
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
|
#: web/template/quotes/new.gohtml:74 web/template/quotes/view.gohtml:82
|
||||||
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
|
#: web/template/quotes/view.gohtml:122 web/template/quotes/edit.gohtml:75
|
||||||
#: web/template/expenses/new.gohtml:47 web/template/expenses/index.gohtml:74
|
#: web/template/expenses/new.gohtml:47 web/template/expenses/index.gohtml:74
|
||||||
#: web/template/expenses/edit.gohtml:49
|
#: web/template/expenses/edit.gohtml:49 web/template/payments/index.gohtml:29
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Total"
|
msgid "Total"
|
||||||
msgstr "Total"
|
msgstr "Total"
|
||||||
|
@ -115,6 +121,8 @@ msgstr "Total"
|
||||||
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
|
#: web/template/invoices/new.gohtml:92 web/template/invoices/edit.gohtml:93
|
||||||
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
|
#: web/template/quotes/new.gohtml:92 web/template/quotes/edit.gohtml:93
|
||||||
#: web/template/expenses/new.gohtml:57 web/template/expenses/edit.gohtml:59
|
#: web/template/expenses/new.gohtml:57 web/template/expenses/edit.gohtml:59
|
||||||
|
#: web/template/payments/edit.gohtml:35
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:38
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Actualizar"
|
msgstr "Actualizar"
|
||||||
|
@ -124,6 +132,8 @@ msgstr "Actualizar"
|
||||||
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
|
#: web/template/contacts/new.gohtml:49 web/template/contacts/edit.gohtml:53
|
||||||
#: web/template/expenses/new.gohtml:60 web/template/expenses/edit.gohtml:62
|
#: web/template/expenses/new.gohtml:60 web/template/expenses/edit.gohtml:62
|
||||||
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
|
#: web/template/products/new.gohtml:30 web/template/products/edit.gohtml:36
|
||||||
|
#: web/template/payments/new.gohtml:33
|
||||||
|
#: web/template/payments/accounts/new.gohtml:41
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Guardad"
|
msgstr "Guardad"
|
||||||
|
@ -180,14 +190,14 @@ msgid "Customer"
|
||||||
msgstr "Cliente"
|
msgstr "Cliente"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
|
#: web/template/invoices/index.gohtml:70 web/template/quotes/index.gohtml:70
|
||||||
#: web/template/expenses/index.gohtml:68
|
#: web/template/expenses/index.gohtml:68 web/template/payments/index.gohtml:27
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Estado"
|
msgstr "Estado"
|
||||||
|
|
||||||
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
|
#: web/template/invoices/index.gohtml:71 web/template/quotes/index.gohtml:71
|
||||||
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
|
#: web/template/contacts/index.gohtml:50 web/template/expenses/index.gohtml:69
|
||||||
#: web/template/products/index.gohtml:46
|
#: web/template/products/index.gohtml:46 web/template/payments/index.gohtml:28
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Etiquetes"
|
msgstr "Etiquetes"
|
||||||
|
@ -326,7 +336,7 @@ msgctxt "input"
|
||||||
msgid "(Max. %s)"
|
msgid "(Max. %s)"
|
||||||
msgstr "(Máx. %s)"
|
msgstr "(Máx. %s)"
|
||||||
|
|
||||||
#: web/template/form.gohtml:200
|
#: web/template/form.gohtml:202
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "Filters"
|
msgid "Filters"
|
||||||
msgstr "Filtrar"
|
msgstr "Filtrar"
|
||||||
|
@ -489,15 +499,20 @@ msgstr "Gastos"
|
||||||
|
|
||||||
#: web/template/app.gohtml:57
|
#: web/template/app.gohtml:57
|
||||||
msgctxt "nav"
|
msgctxt "nav"
|
||||||
|
msgid "Payments"
|
||||||
|
msgstr "Pagos"
|
||||||
|
|
||||||
|
#: web/template/app.gohtml:58
|
||||||
|
msgctxt "nav"
|
||||||
msgid "Products"
|
msgid "Products"
|
||||||
msgstr "Productos"
|
msgstr "Productos"
|
||||||
|
|
||||||
#: web/template/app.gohtml:58
|
#: web/template/app.gohtml:59
|
||||||
msgctxt "nav"
|
msgctxt "nav"
|
||||||
msgid "Contacts"
|
msgid "Contacts"
|
||||||
msgstr "Contactos"
|
msgstr "Contactos"
|
||||||
|
|
||||||
#: web/template/app.gohtml:66
|
#: web/template/app.gohtml:67
|
||||||
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
|
msgid "<a href=\"https://numerus.cat/\">Numerus</a> Version: %s"
|
||||||
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versión: %s"
|
msgstr "<a href=\"https://numerus.cat/\">Numerus</a> versión: %s"
|
||||||
|
|
||||||
|
@ -731,6 +746,84 @@ msgctxt "title"
|
||||||
msgid "Edit Product “%s”"
|
msgid "Edit Product “%s”"
|
||||||
msgstr "Edición del producto «%s»"
|
msgstr "Edición del producto «%s»"
|
||||||
|
|
||||||
|
#: web/template/payments/new.gohtml:3 web/template/payments/new.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "New Payment"
|
||||||
|
msgstr "Nuevo pago"
|
||||||
|
|
||||||
|
#: web/template/payments/new.gohtml:11 web/template/payments/index.gohtml:3
|
||||||
|
#: web/template/payments/index.gohtml:11 web/template/payments/edit.gohtml:11
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payments"
|
||||||
|
msgstr "Pagos"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "New payment"
|
||||||
|
msgstr "Nuevo pago"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:25
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Date"
|
||||||
|
msgstr "Fecha del pago"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:26
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Descripción"
|
||||||
|
|
||||||
|
#: web/template/payments/index.gohtml:54
|
||||||
|
msgid "No payments added yet."
|
||||||
|
msgstr "No hay pagos."
|
||||||
|
|
||||||
|
#: web/template/payments/edit.gohtml:3
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Edit Payment “%s”"
|
||||||
|
msgstr "Edición del pago «%s»"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/new.gohtml:3
|
||||||
|
#: web/template/payments/accounts/new.gohtml:12
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "New Payment Account"
|
||||||
|
msgstr "Nueva cuenta de pago"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/new.gohtml:11
|
||||||
|
#: web/template/payments/accounts/index.gohtml:3
|
||||||
|
#: web/template/payments/accounts/index.gohtml:11
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:11
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Payment Accounts"
|
||||||
|
msgstr "Cuenta de pago"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:16
|
||||||
|
msgctxt "action"
|
||||||
|
msgid "New payment account"
|
||||||
|
msgstr "Nuevo cuenta de pago"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:26
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Tipo"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:27
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Number"
|
||||||
|
msgstr "Número"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:28
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Expiration Date"
|
||||||
|
msgstr "Fecha de caducidad"
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/index.gohtml:51
|
||||||
|
msgid "No payment accounts added yet."
|
||||||
|
msgstr "No hay cuentas de pago."
|
||||||
|
|
||||||
|
#: web/template/payments/accounts/edit.gohtml:3
|
||||||
|
msgctxt "title"
|
||||||
|
msgid "Edit Payment Account “%s”"
|
||||||
|
msgstr "Edición de la cuenta de pago «%s»"
|
||||||
|
|
||||||
#: pkg/ods.go:62 pkg/ods.go:106
|
#: pkg/ods.go:62 pkg/ods.go:106
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "VAT number"
|
msgid "VAT number"
|
||||||
|
@ -762,49 +855,50 @@ msgstr "No podéis dejar la contraseña en blanco."
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nombre de usuario o contraseña inválido."
|
msgstr "Nombre de usuario o contraseña inválido."
|
||||||
|
|
||||||
#: pkg/products.go:172 pkg/products.go:276 pkg/quote.go:901
|
#: pkg/products.go:172 pkg/products.go:276 pkg/quote.go:901 pkg/accounts.go:138
|
||||||
#: pkg/invoices.go:1147 pkg/contacts.go:149 pkg/contacts.go:262
|
#: pkg/invoices.go:1147 pkg/contacts.go:149 pkg/contacts.go:262
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
#: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708
|
#: pkg/products.go:177 pkg/products.go:303 pkg/quote.go:174 pkg/quote.go:708
|
||||||
#: pkg/expenses.go:343 pkg/expenses.go:511 pkg/invoices.go:177
|
#: pkg/payments.go:145 pkg/expenses.go:343 pkg/expenses.go:510
|
||||||
#: pkg/invoices.go:877 pkg/invoices.go:1462 pkg/contacts.go:154
|
#: pkg/invoices.go:177 pkg/invoices.go:877 pkg/invoices.go:1462
|
||||||
#: pkg/contacts.go:362
|
#: pkg/contacts.go:154 pkg/contacts.go:362
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr "Etiquetes"
|
msgstr "Etiquetes"
|
||||||
|
|
||||||
#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:521 pkg/invoices.go:181
|
#: pkg/products.go:181 pkg/quote.go:178 pkg/expenses.go:520 pkg/invoices.go:181
|
||||||
#: pkg/contacts.go:158
|
#: pkg/contacts.go:158
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Tags Condition"
|
msgid "Tags Condition"
|
||||||
msgstr "Condición de las etiquetas"
|
msgstr "Condición de las etiquetas"
|
||||||
|
|
||||||
#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:525 pkg/invoices.go:185
|
#: pkg/products.go:185 pkg/quote.go:182 pkg/expenses.go:524 pkg/invoices.go:185
|
||||||
#: pkg/contacts.go:162
|
#: pkg/contacts.go:162
|
||||||
msgctxt "tag condition"
|
msgctxt "tag condition"
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todas"
|
msgstr "Todas"
|
||||||
|
|
||||||
#: pkg/products.go:186 pkg/expenses.go:526 pkg/invoices.go:186
|
#: pkg/products.go:186 pkg/expenses.go:525 pkg/invoices.go:186
|
||||||
#: pkg/contacts.go:163
|
#: pkg/contacts.go:163
|
||||||
msgid "Invoices must have all the specified labels."
|
msgid "Invoices must have all the specified labels."
|
||||||
msgstr "Las facturas deben tener todas las etiquetas."
|
msgstr "Las facturas deben tener todas las etiquetas."
|
||||||
|
|
||||||
#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:530 pkg/invoices.go:190
|
#: pkg/products.go:190 pkg/quote.go:187 pkg/expenses.go:529 pkg/invoices.go:190
|
||||||
#: pkg/contacts.go:167
|
#: pkg/contacts.go:167
|
||||||
msgctxt "tag condition"
|
msgctxt "tag condition"
|
||||||
msgid "Any"
|
msgid "Any"
|
||||||
msgstr "Cualquiera"
|
msgstr "Cualquiera"
|
||||||
|
|
||||||
#: pkg/products.go:191 pkg/expenses.go:531 pkg/invoices.go:191
|
#: pkg/products.go:191 pkg/expenses.go:530 pkg/invoices.go:191
|
||||||
#: pkg/contacts.go:168
|
#: pkg/contacts.go:168
|
||||||
msgid "Invoices must have at least one of the specified labels."
|
msgid "Invoices must have at least one of the specified labels."
|
||||||
msgstr "Las facturas deben tener como mínimo una de las etiquetas."
|
msgstr "Las facturas deben tener como mínimo una de las etiquetas."
|
||||||
|
|
||||||
#: pkg/products.go:282 pkg/quote.go:915 pkg/invoices.go:1161
|
#: pkg/products.go:282 pkg/quote.go:915 pkg/payments.go:117
|
||||||
|
#: pkg/invoices.go:1161
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripción"
|
msgstr "Descripción"
|
||||||
|
@ -1062,7 +1156,7 @@ msgctxt "input"
|
||||||
msgid "Quotation Status"
|
msgid "Quotation Status"
|
||||||
msgstr "Estado del presupuesto"
|
msgstr "Estado del presupuesto"
|
||||||
|
|
||||||
#: pkg/quote.go:154 pkg/expenses.go:516 pkg/invoices.go:157
|
#: pkg/quote.go:154 pkg/expenses.go:515 pkg/invoices.go:157
|
||||||
msgid "All status"
|
msgid "All status"
|
||||||
msgstr "Todos los estados"
|
msgstr "Todos los estados"
|
||||||
|
|
||||||
|
@ -1071,12 +1165,12 @@ msgctxt "input"
|
||||||
msgid "Quotation Number"
|
msgid "Quotation Number"
|
||||||
msgstr "Número de presupuesto"
|
msgstr "Número de presupuesto"
|
||||||
|
|
||||||
#: pkg/quote.go:164 pkg/expenses.go:501 pkg/invoices.go:167
|
#: pkg/quote.go:164 pkg/expenses.go:500 pkg/invoices.go:167
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "From Date"
|
msgid "From Date"
|
||||||
msgstr "A partir de la fecha"
|
msgstr "A partir de la fecha"
|
||||||
|
|
||||||
#: pkg/quote.go:169 pkg/expenses.go:506 pkg/invoices.go:172
|
#: pkg/quote.go:169 pkg/expenses.go:505 pkg/invoices.go:172
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "To Date"
|
msgid "To Date"
|
||||||
msgstr "Hasta la fecha"
|
msgstr "Hasta la fecha"
|
||||||
|
@ -1097,8 +1191,8 @@ msgstr "presupuestos.zip"
|
||||||
msgid "quotations.ods"
|
msgid "quotations.ods"
|
||||||
msgstr "presupuestos.ods"
|
msgstr "presupuestos.ods"
|
||||||
|
|
||||||
#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:720
|
#: pkg/quote.go:634 pkg/quote.go:1176 pkg/quote.go:1184 pkg/expenses.go:719
|
||||||
#: pkg/expenses.go:750 pkg/invoices.go:684 pkg/invoices.go:1437
|
#: pkg/expenses.go:749 pkg/invoices.go:684 pkg/invoices.go:1437
|
||||||
#: pkg/invoices.go:1445
|
#: pkg/invoices.go:1445
|
||||||
msgid "Invalid action"
|
msgid "Invalid action"
|
||||||
msgstr "Acción inválida."
|
msgstr "Acción inválida."
|
||||||
|
@ -1218,6 +1312,101 @@ msgstr "La confirmación no corresponde con la contraseña."
|
||||||
msgid "Selected language is not valid."
|
msgid "Selected language is not valid."
|
||||||
msgstr "Habéis escogido un idioma que no es válido."
|
msgstr "Habéis escogido un idioma que no es válido."
|
||||||
|
|
||||||
|
#: pkg/payments.go:123 pkg/expenses.go:305 pkg/invoices.go:866
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Invoice Date"
|
||||||
|
msgstr "Fecha de factura"
|
||||||
|
|
||||||
|
#: pkg/payments.go:129
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Account"
|
||||||
|
msgstr "Cuenta"
|
||||||
|
|
||||||
|
#: pkg/payments.go:135 pkg/expenses.go:320
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Amount"
|
||||||
|
msgstr "Importe"
|
||||||
|
|
||||||
|
#: pkg/payments.go:152
|
||||||
|
msgid "Select an account."
|
||||||
|
msgstr "Escoged una cuenta."
|
||||||
|
|
||||||
|
#: pkg/payments.go:198
|
||||||
|
msgid "Description can not be empty."
|
||||||
|
msgstr "No podéis dejar la descripción en blanco."
|
||||||
|
|
||||||
|
#: pkg/payments.go:199
|
||||||
|
msgid "Selected payment account is not valid."
|
||||||
|
msgstr "Habéis escogido una cuenta de pago que no es válida."
|
||||||
|
|
||||||
|
#: pkg/payments.go:200
|
||||||
|
msgid "Payment date must be a valid date."
|
||||||
|
msgstr "La fecha de pago debe ser válida."
|
||||||
|
|
||||||
|
#: pkg/payments.go:201 pkg/expenses.go:381
|
||||||
|
msgid "Amount can not be empty."
|
||||||
|
msgstr "No podéis dejar el importe en blanco."
|
||||||
|
|
||||||
|
#: pkg/payments.go:202 pkg/expenses.go:382
|
||||||
|
msgid "Amount must be a number greater than zero."
|
||||||
|
msgstr "El importe tiene que ser un número mayor a cero."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:129
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "Tipo"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:144 pkg/contacts.go:352
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "IBAN"
|
||||||
|
msgstr "IBAN"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:150
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Card’s last four digits"
|
||||||
|
msgstr "Últimos cuatro dígitos de la tarjeta"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:161
|
||||||
|
msgctxt "input"
|
||||||
|
msgid "Expiration date"
|
||||||
|
msgstr "Fecha de caducidad"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:227
|
||||||
|
msgid "Selected payment account type is not valid."
|
||||||
|
msgstr "Habéis escogido un tipo de cuenta de pago que no es válido."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:230
|
||||||
|
msgid "IBAN can not be empty."
|
||||||
|
msgstr "No podéis dejar el IBAN en blanco."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:231
|
||||||
|
msgid "This value is not a valid IBAN."
|
||||||
|
msgstr "Este valor no es un IBAN válido."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:234
|
||||||
|
msgid "Last four digits can not be empty."
|
||||||
|
msgstr "No podéis dejar los cuatro últimos dígitos en blanco."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:235
|
||||||
|
msgid "You must enter the card’s last four digits"
|
||||||
|
msgstr "Debéis entrar los cuatro últimos dígitos de la tarjeta"
|
||||||
|
|
||||||
|
#: pkg/accounts.go:236
|
||||||
|
msgid "Last four digits must be a number."
|
||||||
|
msgstr "Los cuatro últimos dígitos tienen que ser un número."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:239
|
||||||
|
msgid "Expiration date can not be empty."
|
||||||
|
msgstr "No podéis dejar la fecha de caducidad en blanco."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:241
|
||||||
|
msgid "Expiration date should be a valid date in format MM/YY (e.g., 08/24)."
|
||||||
|
msgstr "La fecha de caducidad tiene que ser válida y en formato MM/AA (p. ej., 08/24)."
|
||||||
|
|
||||||
|
#: pkg/accounts.go:245
|
||||||
|
msgid "Payment account name can not be empty."
|
||||||
|
msgstr "No podéis dejar el nombre de la cuenta de pago en blanco."
|
||||||
|
|
||||||
#: pkg/dashboard.go:138
|
#: pkg/dashboard.go:138
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
|
@ -1257,7 +1446,7 @@ msgstr "Año anterior"
|
||||||
msgid "Select a contact."
|
msgid "Select a contact."
|
||||||
msgstr "Escoged un contacto"
|
msgstr "Escoged un contacto"
|
||||||
|
|
||||||
#: pkg/expenses.go:294 pkg/expenses.go:490
|
#: pkg/expenses.go:294 pkg/expenses.go:489
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr "Contacto"
|
msgstr "Contacto"
|
||||||
|
@ -1267,22 +1456,12 @@ msgctxt "input"
|
||||||
msgid "Invoice number"
|
msgid "Invoice number"
|
||||||
msgstr "Número de factura"
|
msgstr "Número de factura"
|
||||||
|
|
||||||
#: pkg/expenses.go:305 pkg/invoices.go:866
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "Invoice Date"
|
|
||||||
msgstr "Fecha de factura"
|
|
||||||
|
|
||||||
#: pkg/expenses.go:320
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "Amount"
|
|
||||||
msgstr "Importe"
|
|
||||||
|
|
||||||
#: pkg/expenses.go:331 pkg/invoices.go:888
|
#: pkg/expenses.go:331 pkg/invoices.go:888
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Archivo"
|
msgstr "Archivo"
|
||||||
|
|
||||||
#: pkg/expenses.go:337 pkg/expenses.go:515
|
#: pkg/expenses.go:337 pkg/expenses.go:514
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Expense Status"
|
msgid "Expense Status"
|
||||||
msgstr "Estado del gasto"
|
msgstr "Estado del gasto"
|
||||||
|
@ -1295,28 +1474,20 @@ msgstr "Habéis escogido un contacto que no es válido."
|
||||||
msgid "Invoice date must be a valid date."
|
msgid "Invoice date must be a valid date."
|
||||||
msgstr "La fecha de factura debe ser válida."
|
msgstr "La fecha de factura debe ser válida."
|
||||||
|
|
||||||
#: pkg/expenses.go:381
|
|
||||||
msgid "Amount can not be empty."
|
|
||||||
msgstr "No podéis dejar el importe en blanco."
|
|
||||||
|
|
||||||
#: pkg/expenses.go:382
|
|
||||||
msgid "Amount must be a number greater than zero."
|
|
||||||
msgstr "El importe tiene que ser un número mayor a cero."
|
|
||||||
|
|
||||||
#: pkg/expenses.go:384
|
#: pkg/expenses.go:384
|
||||||
msgid "Selected expense status is not valid."
|
msgid "Selected expense status is not valid."
|
||||||
msgstr "Habéis escogido un estado de gasto que no es válido."
|
msgstr "Habéis escogido un estado de gasto que no es válido."
|
||||||
|
|
||||||
#: pkg/expenses.go:491
|
#: pkg/expenses.go:490
|
||||||
msgid "All contacts"
|
msgid "All contacts"
|
||||||
msgstr "Todos los contactos"
|
msgstr "Todos los contactos"
|
||||||
|
|
||||||
#: pkg/expenses.go:496 pkg/invoices.go:162
|
#: pkg/expenses.go:495 pkg/invoices.go:162
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Invoice Number"
|
msgid "Invoice Number"
|
||||||
msgstr "Número de factura"
|
msgstr "Número de factura"
|
||||||
|
|
||||||
#: pkg/expenses.go:748
|
#: pkg/expenses.go:747
|
||||||
msgid "expenses.ods"
|
msgid "expenses.ods"
|
||||||
msgstr "gastos.ods"
|
msgstr "gastos.ods"
|
||||||
|
|
||||||
|
@ -1364,11 +1535,6 @@ msgctxt "input"
|
||||||
msgid "Need to input tax details"
|
msgid "Need to input tax details"
|
||||||
msgstr "Necesito facturar este contacto"
|
msgstr "Necesito facturar este contacto"
|
||||||
|
|
||||||
#: pkg/contacts.go:352
|
|
||||||
msgctxt "input"
|
|
||||||
msgid "IBAN"
|
|
||||||
msgstr "IBAN"
|
|
||||||
|
|
||||||
#: pkg/contacts.go:357
|
#: pkg/contacts.go:357
|
||||||
msgctxt "bic"
|
msgctxt "bic"
|
||||||
msgid "BIC"
|
msgid "BIC"
|
||||||
|
@ -1441,10 +1607,6 @@ msgstr "Archivo Excel de Holded"
|
||||||
#~ msgid "Product ID can not be empty."
|
#~ msgid "Product ID can not be empty."
|
||||||
#~ msgstr "No podéis dejar el identificador de producto en blanco."
|
#~ msgstr "No podéis dejar el identificador de producto en blanco."
|
||||||
|
|
||||||
#~ msgctxt "input"
|
|
||||||
#~ msgid "Number"
|
|
||||||
#~ msgstr "Número"
|
|
||||||
|
|
||||||
#~ msgctxt "title"
|
#~ msgctxt "title"
|
||||||
#~ msgid "Label"
|
#~ msgid "Label"
|
||||||
#~ msgstr "Etiqueta"
|
#~ msgstr "Etiqueta"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:add_payment from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.add_payment(integer, integer, date, integer, text, text, numerus.tag_name[]);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:add_payment_account_bank from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.add_payment_account_bank(integer, text, iban);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:add_payment_account_card from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.add_payment_account_card(integer, text, text, date);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:add_payment_account_cash from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.add_payment_account_cash(integer, text);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:add_payment_account_other from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.add_payment_account_other(integer, text);
|
||||||
|
|
||||||
|
commit;
|
|
@ -1,10 +1,13 @@
|
||||||
-- Revert numerus:available_expense_status from pg
|
-- Deploy numerus:available_expense_status to pg
|
||||||
|
-- requires: schema_numerus
|
||||||
|
-- requires: expense_status
|
||||||
|
-- requires: expense_status_i18n
|
||||||
|
|
||||||
begin;
|
begin;
|
||||||
|
|
||||||
set search_path to numerus;
|
set search_path to numerus;
|
||||||
|
|
||||||
delete from expense_status_i18n;
|
delete from expense_status_i18n where expense_status = 'partial';
|
||||||
delete from expense_status;
|
delete from expense_status where expense_status = 'partial';
|
||||||
|
|
||||||
commit;
|
commit;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- Revert numerus:available_expense_status from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
delete from expense_status_i18n;
|
||||||
|
delete from expense_status;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- Revert numerus:available_payment_account_types from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
delete from payment_account_type_i18n;
|
||||||
|
delete from payment_account_type;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- Revert numerus:available_payment_status from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
delete from payment_status_i18n;
|
||||||
|
delete from payment_status;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:edit_payment from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.edit_payment(uuid, date, integer, text, text, numerus.tag_name[]);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:edit_payment_account_bank from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.edit_payment_account_bank(uuid, text, iban);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:edit_payment_account_card from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.edit_payment_account_card(uuid, text, text, date);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:edit_payment_account_cash from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.edit_payment_account_cash(uuid, text);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:edit_payment_account_other from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.edit_payment_account_other(uuid, text);
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:expense_payment from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.expense_payment;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_account from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_account;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_account_bank from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_account_bank;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_account_card from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_account_card;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_account_type from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_account_type;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_account_type_i18n from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_account_type_i18n;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_status from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_status;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:payment_status_i18n from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop table if exists numerus.payment_status_i18n;
|
||||||
|
|
||||||
|
commit;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Revert numerus:update_expense_payment_status from pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
drop function if exists numerus.update_expense_payment_status(integer, integer, integer);
|
||||||
|
|
||||||
|
commit;
|
25
sqitch.plan
25
sqitch.plan
|
@ -127,3 +127,28 @@ attach_to_invoice [schema_numerus roles invoice invoice_attachment] 2023-07-12T1
|
||||||
new_expense_amount [schema_numerus] 2023-07-13T17:45:33Z jordi fita mas <jordi@tandem.blog> # Add type to return when computing new expense amounts
|
new_expense_amount [schema_numerus] 2023-07-13T17:45:33Z jordi fita mas <jordi@tandem.blog> # Add type to return when computing new expense amounts
|
||||||
compute_new_expense_amount [schema_numerus roles company tax new_expense_amount] 2023-07-13T17:34:12Z jordi fita mas <jordi@tandem.blog> # Add function to compute the taxes and total for a new expense
|
compute_new_expense_amount [schema_numerus roles company tax new_expense_amount] 2023-07-13T17:34:12Z jordi fita mas <jordi@tandem.blog> # Add function to compute the taxes and total for a new expense
|
||||||
parse_price [parse_price@v1] 2023-08-25T11:59:54Z jordi fita mas <jordi@tandem.blog> # Throw when subtotal is empty string
|
parse_price [parse_price@v1] 2023-08-25T11:59:54Z jordi fita mas <jordi@tandem.blog> # Throw when subtotal is empty string
|
||||||
|
@v2 2024-08-04T05:21:18Z jordi fita mas <jordi@tandem.blog> # Tag version 2
|
||||||
|
|
||||||
|
payment_account_type [roles schema_numerus] 2024-08-01T23:00:18Z jordi fita mas <jordi@tandem.blog> # Add payment_account_type enum
|
||||||
|
payment_account_type_i18n [roles schema_numerus payment_account_type language] 2024-08-08T17:05:28Z jordi fita mas <jordi@tandem.blog> # Add relation for payment account type’s translations
|
||||||
|
available_payment_account_types [schema_numerus payment_account_type payment_account_type_i18n] 2024-08-08T17:09:24Z jordi fita mas <jordi@tandem.blog> # Add the list of available payment account types
|
||||||
|
payment_account [roles schema_numerus company payment_account_type extension_pgcrypto] 2024-08-01T23:11:54Z jordi fita mas <jordi@tandem.blog> # Add relation of payment account
|
||||||
|
payment_account_bank [roles schema_numerus payment_account extension_iban] 2024-08-01T23:40:34Z jordi fita mas <jordi@tandem.blog> # Add relation for payment account bank
|
||||||
|
payment_account_card [roles schema_numerus payment_account] 2024-08-02T00:10:54Z jordi fita mas <jordi@tandem.blog> # Add relation for payment account card
|
||||||
|
add_payment_account_bank [roles schema_numerus payment_account payment_account_bank] 2024-08-03T00:24:18Z jordi fita mas <jordi@tandem.blog> # Add function to insert bank payment accounts
|
||||||
|
edit_payment_account_bank [roles schema_numerus payment_account payment_account_bank extension_pgcrypto extension_iban] 2024-08-10T00:04:03Z jordi fita mas <jordi@tandem.blog> # Add function to update bank payment accounts
|
||||||
|
add_payment_account_card [roles schema_numerus payment_account payment_account_card] 2024-08-03T00:41:18Z jordi fita mas <jordi@tandem.blog> # Add function to insert card payment accounts
|
||||||
|
edit_payment_account_card [roles schema_numerus payment_account payment_account_card extension_pgcrypto] 2024-08-10T00:22:37Z jordi fita mas <jordi@tandem.blog> # Add function to update card payment accounts
|
||||||
|
add_payment_account_cash [roles schema_numerus payment_account] 2024-08-03T00:49:07Z jordi fita mas <jordi@tandem.blog> # Add function to insert cash payment accounts
|
||||||
|
edit_payment_account_cash [roles schema_numerus payment_account extension_pgcrypto] 2024-08-10T00:34:19Z jordi fita mas <jordi@tandem.blog> # Add function to update cash payment accounts
|
||||||
|
add_payment_account_other [roles schema_numerus payment_account] 2024-08-03T00:49:15Z jordi fita mas <jordi@tandem.blog> # Add function to insert other payment accounts
|
||||||
|
edit_payment_account_other [roles schema_numerus payment_account extension_pgcrypto] 2024-08-10T00:41:38Z jordi fita mas <jordi@tandem.blog> # Add function to update other payment accounts
|
||||||
|
payment_status [roles schema_numerus] 2024-08-04T03:02:06Z jordi fita mas <jordi@tandem.blog> # Add relation of payment status
|
||||||
|
payment_status_i18n [roles schema_numerus payment_status language] 2024-08-04T03:05:41Z jordi fita mas <jordi@tandem.blog> # Add relation of payment status’ translated name
|
||||||
|
available_payment_status [schema_numerus payment_status payment_status_i18n] 2024-08-04T03:08:42Z jordi fita mas <jordi@tandem.blog> # Add the list of available payment status
|
||||||
|
payment [roles schema_numerus company payment_account currency tag_name payment_status extension_pgcrypto] 2024-08-01T01:28:59Z jordi fita mas <jordi@tandem.blog> # Add relation for accounts payable
|
||||||
|
expense_payment [roles schema_numerus expense payment] 2024-08-04T03:44:30Z jordi fita mas <jordi@tandem.blog> # Add relation of expense payments
|
||||||
|
available_expense_status [available_expense_status@v2] 2024-08-04T05:24:08Z jordi fita mas <jordi@tandem.blog> # Add “partial” expense status
|
||||||
|
update_expense_payment_status [roles schema_numerus expense payment expense_payment available_expense_status available_payment_status] 2024-08-04T06:36:00Z jordi fita mas <jordi@tandem.blog> # Add function to update payment and expense status
|
||||||
|
add_payment [roles schema_numerus payment expense_payment company currency parse_price tag_name update_expense_payment_status] 2024-08-04T03:16:55Z jordi fita mas <jordi@tandem.blog> # Add function to insert new payments
|
||||||
|
edit_payment [roles schema_numerus payment expense_payment currency parse_price tag_name update_expense_payment_status] 2024-08-04T03:31:45Z jordi fita mas <jordi@tandem.blog> # Add function to update payments
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
-- Test add_payment
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(17);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'add_payment', array['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]']);
|
||||||
|
select function_lang_is('numerus', 'add_payment', array['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'add_payment', array['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'add_payment', array['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]']);
|
||||||
|
select volatility_is('numerus', 'add_payment', array['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'add_payment', array ['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'add_payment', array ['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment', array ['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment', array ['integer', 'integer', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate expense_payment cascade;
|
||||||
|
truncate payment cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate expense cascade;
|
||||||
|
truncate contact cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 222)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into contact (contact_id, company_id, name)
|
||||||
|
values ( 9, 1, 'Customer 1')
|
||||||
|
, (10, 2, 'Customer 2')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense (expense_id, company_id, invoice_number, contact_id, invoice_date, amount, currency_code)
|
||||||
|
values (12, 1, 'REF123', 9, '2011-01-11', 111, 'EUR')
|
||||||
|
, (13, 2, 'INV001', 10, '2011-01-11', 111, 'USD')
|
||||||
|
, (14, 2, 'INV002', 10, '2022-02-22', 222, 'USD')
|
||||||
|
, (15, 2, 'INV003', 10, '2022-02-22', 222, 'USD')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values (11, 1, 'other', 'Other 1')
|
||||||
|
, (22, 2, 'cash', 'Cash 2')
|
||||||
|
;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment(1, null, '2023-05-02', 11, '“Protection”', '11.11', array['tag1', 'tag2']) $$,
|
||||||
|
'Should be able to insert a payment, unrelated to any expense, for the first company'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment(2, 13, '2023-05-03', 22, 'Payment of INV001', '1.11', array[]::tag_name[]) $$,
|
||||||
|
'Should be able to insert a complete payment for the first expense'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment(2, 14, '2023-05-04', 22, 'First payment of INV002', '1.00', array[]::tag_name[]) $$,
|
||||||
|
'Should be able to insert a partial payment for the second expense'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment(2, 14, '2023-05-05', 22, 'Second payment of INV002', '1.22', array[]::tag_name[]) $$,
|
||||||
|
'Should be able to insert a partial, and final, payment for the second expense'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment(2, 15, '2023-05-06', 22, 'Partial payment of INV003', '1.11', array[]::tag_name[]) $$,
|
||||||
|
'Should be able to insert a partial payment for the third expense'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select company_id, description, payment_date::text, payment_account_id, amount, currency_code, payment_status, tags::text, created_at from payment $$,
|
||||||
|
$$ values (1, '“Protection”', '2023-05-02', 11, 1111, 'EUR', 'complete', '{tag1,tag2}', current_timestamp)
|
||||||
|
, (2, 'Payment of INV001', '2023-05-03', 22, 111, 'USD', 'complete', '{}', current_timestamp)
|
||||||
|
, (2, 'First payment of INV002', '2023-05-04', 22, 100, 'USD', 'partial', '{}', current_timestamp)
|
||||||
|
, (2, 'Second payment of INV002', '2023-05-05', 22, 122, 'USD', 'partial', '{}', current_timestamp)
|
||||||
|
, (2, 'Partial payment of INV003', '2023-05-06', 22, 111, 'USD', 'partial', '{}', current_timestamp)
|
||||||
|
$$,
|
||||||
|
'Should have created all payments'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select expense_id, description from expense_payment join payment using (payment_id) $$,
|
||||||
|
$$ values (13, 'Payment of INV001')
|
||||||
|
, (14, 'First payment of INV002')
|
||||||
|
, (14, 'Second payment of INV002')
|
||||||
|
, (15, 'Partial payment of INV003')
|
||||||
|
$$,
|
||||||
|
'Should have linked all expenses to payments'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select expense_id, expense_status from expense $$,
|
||||||
|
$$ values (12, 'pending')
|
||||||
|
, (13, 'paid')
|
||||||
|
, (14, 'paid')
|
||||||
|
, (15, 'partial')
|
||||||
|
$$,
|
||||||
|
'Should have updated the status of expenses'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,67 @@
|
||||||
|
-- Test add_payment_account_bank
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(12);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban']);
|
||||||
|
select function_lang_is('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban']);
|
||||||
|
select volatility_is('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_bank', array['integer', 'text', 'iban'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_bank cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 222)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment_account_bank(1, 'Bank A', 'ES2820958297603648596978') $$,
|
||||||
|
'Should be able to insert a first bank payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select add_payment_account_bank(1, 'Bank 2', 'DE68500105178297336485') $$,
|
||||||
|
'Should be able to insert a second bank payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select company_id, payment_account_type::text, name, iban::text from payment_account join payment_account_bank using (payment_account_id, payment_account_type) $$,
|
||||||
|
$$ values (1, 'bank', 'Bank A', 'ES2820958297603648596978')
|
||||||
|
, (1, 'bank', 'Bank 2', 'DE68500105178297336485')
|
||||||
|
$$,
|
||||||
|
'Should have created all payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,66 @@
|
||||||
|
-- Test add_payment_account_card
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(12);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date']);
|
||||||
|
select function_lang_is('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date']);
|
||||||
|
select volatility_is('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_card', array['integer', 'text', 'text', 'date'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_card cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 222)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment_account_card(1, 'Card A', '1234', '2024-04-04') $$,
|
||||||
|
'Should be able to insert a first card payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select add_payment_account_card(1, 'Card 2', '2345', '2025-05-05') $$,
|
||||||
|
'Should be able to insert a second card payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select company_id, payment_account_type::text, name, last_four_digits, expiration_date::text from payment_account join payment_account_card using (payment_account_id, payment_account_type) $$,
|
||||||
|
$$ values (1, 'card', 'Card A', '1234', '2024-04-04')
|
||||||
|
, (1, 'card', 'Card 2', '2345', '2025-05-05')
|
||||||
|
$$,
|
||||||
|
'Should have created all payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,65 @@
|
||||||
|
-- Test add_payment_account_cash
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(12);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'add_payment_account_cash', array['integer', 'text']);
|
||||||
|
select function_lang_is('numerus', 'add_payment_account_cash', array['integer', 'text'], 'sql');
|
||||||
|
select function_returns('numerus', 'add_payment_account_cash', array['integer', 'text'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'add_payment_account_cash', array['integer', 'text']);
|
||||||
|
select volatility_is('numerus', 'add_payment_account_cash', array['integer', 'text'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_cash', array['integer', 'text'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_cash', array['integer', 'text'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_cash', array['integer', 'text'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_cash', array['integer', 'text'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 222)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment_account_cash(1, 'Cash A') $$,
|
||||||
|
'Should be able to insert a first cash payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select add_payment_account_cash(1, 'Cash 2') $$,
|
||||||
|
'Should be able to insert a second cash payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select company_id, payment_account_type::text, name from payment_account $$,
|
||||||
|
$$ values (1, 'cash', 'Cash A')
|
||||||
|
, (1, 'cash', 'Cash 2')
|
||||||
|
$$,
|
||||||
|
'Should have created all payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,65 @@
|
||||||
|
-- Test add_payment_account_other
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(12);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'add_payment_account_other', array['integer', 'text']);
|
||||||
|
select function_lang_is('numerus', 'add_payment_account_other', array['integer', 'text'], 'sql');
|
||||||
|
select function_returns('numerus', 'add_payment_account_other', array['integer', 'text'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'add_payment_account_other', array['integer', 'text']);
|
||||||
|
select volatility_is('numerus', 'add_payment_account_other', array['integer', 'text'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_other', array['integer', 'text'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_other', array['integer', 'text'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_other', array['integer', 'text'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'add_payment_account_other', array['integer', 'text'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
, (2, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 222)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select add_payment_account_other(1, 'Other A') $$,
|
||||||
|
'Should be able to insert a first payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select add_payment_account_other(1, 'Other 2') $$,
|
||||||
|
'Should be able to insert a second payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select company_id, payment_account_type::text, name from payment_account $$,
|
||||||
|
$$ values (1, 'other', 'Other A')
|
||||||
|
, (1, 'other', 'Other 2')
|
||||||
|
$$,
|
||||||
|
'Should have created all payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,115 @@
|
||||||
|
-- Test edit_payment
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(14);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'edit_payment', array['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]']);
|
||||||
|
select function_lang_is('numerus', 'edit_payment', array['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'edit_payment', array['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'edit_payment', array['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]']);
|
||||||
|
select volatility_is('numerus', 'edit_payment', array['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'edit_payment', array ['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'edit_payment', array ['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment', array ['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment', array ['uuid', 'date', 'integer', 'text', 'text', 'tag_name[]'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate expense_payment cascade;
|
||||||
|
truncate payment cascade;
|
||||||
|
truncate expense cascade;
|
||||||
|
truncate contact cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into contact (contact_id, company_id, name)
|
||||||
|
values ( 9, 1, 'Customer 1')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense (expense_id, company_id, invoice_number, contact_id, invoice_date, amount, currency_code, expense_status)
|
||||||
|
values (13, 1, 'INV001', 9, '2011-01-11', 111, 'EUR', 'paid')
|
||||||
|
, (14, 1, 'INV002', 9, '2022-02-22', 222, 'EUR', 'paid')
|
||||||
|
, (15, 1, 'INV003', 9, '2022-02-22', 333, 'EUR', 'partial')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values (11, 1, 'cash', 'Cash 1')
|
||||||
|
, (12, 1, 'cash', 'Cash 2')
|
||||||
|
, (13, 1, 'other', 'Other')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment (payment_id, company_id, slug, description, payment_date, payment_account_id, amount, currency_code, payment_status, tags)
|
||||||
|
values (16, 1, '7ac3ae0e-b0c1-4206-a19b-0be20835edd4', 'Payment INV001', '2023-05-04', 12, 111, 'EUR', 'complete', '{tag1}')
|
||||||
|
, (17, 1, 'b57b980b-247b-4be4-a0b7-03a7819c53ae', 'First INV002', '2023-05-05', 13, 100, 'EUR', 'partial', '{tag2}')
|
||||||
|
, (18, 1, '3bdad7a8-4a1e-4ae0-b5c6-015e51ee0502', 'Second INV002', '2023-05-06', 13, 122, 'EUR', 'partial', '{tag1,tag3}')
|
||||||
|
, (19, 1, '5a524bee-8311-4d13-9adf-ef6310b26990', 'Partial INV003', '2023-05-07', 11, 123, 'EUR', 'partial', '{}')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense_payment (expense_id, payment_id)
|
||||||
|
values (13, 16)
|
||||||
|
, (14, 17)
|
||||||
|
, (14, 18)
|
||||||
|
, (15, 19)
|
||||||
|
;
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment('7ac3ae0e-b0c1-4206-a19b-0be20835edd4', '2023-05-06', 13, 'Partial INV001', '1.00', array['tag1']) $$,
|
||||||
|
'Should be able to change a complete payment to partial'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment('b57b980b-247b-4be4-a0b7-03a7819c53ae', '2023-05-07', 12, 'First INV002', '0.50', array['tag1', 'tag3']) $$,
|
||||||
|
'Should be able to adjust a partial payment, that is still partial, and the expense now becomes partial'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment('5a524bee-8311-4d13-9adf-ef6310b26990', '2023-05-01', 11, 'Complete INV003', '3.33', array[]::tag_name[]) $$,
|
||||||
|
'Should be able to complete a previously partial payment'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select description, payment_date::text, payment_account_id, amount, payment_status, tags::text from payment $$,
|
||||||
|
$$ values ('Partial INV001', '2023-05-06', 13, 100, 'partial', '{tag1}')
|
||||||
|
, ('First INV002', '2023-05-07', 12, 50, 'partial', '{tag1,tag3}')
|
||||||
|
, ('Second INV002', '2023-05-06', 13, 122, 'partial', '{tag1,tag3}')
|
||||||
|
, ('Complete INV003', '2023-05-01', 11, 333, 'complete', '{}')
|
||||||
|
$$,
|
||||||
|
'Should have updated all payments'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select expense_id, expense_status from expense $$,
|
||||||
|
$$ values (13, 'partial')
|
||||||
|
, (14, 'partial')
|
||||||
|
, (15, 'paid')
|
||||||
|
$$,
|
||||||
|
'Should have updated expenses too'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,84 @@
|
||||||
|
-- Test edit_payment_account_bank
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(13);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban']);
|
||||||
|
select function_lang_is('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban']);
|
||||||
|
select volatility_is('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_bank', array['uuid', 'text', 'iban'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_bank cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, slug, payment_account_type, name)
|
||||||
|
values (11, 1, '81c478ab-395c-44aa-a5b4-3489e5349a0b', 'bank', 'Bank 1')
|
||||||
|
, (12, 1, '84e84788-54f1-4796-b93d-dfa2c9adc072', 'bank', 'Bank 2')
|
||||||
|
, (13, 1, 'afb774a5-0c38-480c-bef2-fe03465071cd', 'other', 'Other')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account_bank (payment_account_id, iban)
|
||||||
|
values (11, 'MR1765838885255712383711884')
|
||||||
|
, (12, 'UA709147419869457296562612646')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment_account_bank('81c478ab-395c-44aa-a5b4-3489e5349a0b', 'Piggy Bank', 'ES2820958297603648596978') $$,
|
||||||
|
'Should be able to edit the first bank payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select edit_payment_account_bank('84e84788-54f1-4796-b93d-dfa2c9adc072', 'Totally Secure', 'DE68500105178297336485') $$,
|
||||||
|
'Should be able to edit the second bank payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select results_eq (
|
||||||
|
$$ select edit_payment_account_bank('afb774a5-0c38-480c-bef2-fe03465071cd', 'Huh?', 'ES3720951423184941926287')::text $$,
|
||||||
|
$$ values (null::text) $$,
|
||||||
|
'Should do nothing to an account that is not of type bank'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_account_id, payment_account_type::text, name, iban::text from payment_account left join payment_account_bank using (payment_account_id, payment_account_type) $$,
|
||||||
|
$$ values (11, 'bank', 'Piggy Bank', 'ES2820958297603648596978')
|
||||||
|
, (12, 'bank', 'Totally Secure', 'DE68500105178297336485')
|
||||||
|
, (13, 'other', 'Other', null)
|
||||||
|
$$,
|
||||||
|
'Should have update all bank payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,84 @@
|
||||||
|
-- Test edit_payment_account_card
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(13);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date']);
|
||||||
|
select function_lang_is('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'plpgsql');
|
||||||
|
select function_returns('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date']);
|
||||||
|
select volatility_is('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_card', array['uuid', 'text', 'text', 'date'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_card cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, slug, payment_account_type, name)
|
||||||
|
values (11, 1, '81c478ab-395c-44aa-a5b4-3489e5349a0b', 'card', 'Card 1')
|
||||||
|
, (12, 1, '84e84788-54f1-4796-b93d-dfa2c9adc072', 'card', 'Card 2')
|
||||||
|
, (13, 1, 'afb774a5-0c38-480c-bef2-fe03465071cd', 'other', 'Other')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account_card (payment_account_id, last_four_digits, expiration_date)
|
||||||
|
values (11, '1234', '2022-04-02')
|
||||||
|
, (12, '2345', '2024-05-02')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment_account_card('81c478ab-395c-44aa-a5b4-3489e5349a0b', 'Gold Card', '9999', '2022-12-22') $$,
|
||||||
|
'Should be able to edit the first card payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select edit_payment_account_card('84e84788-54f1-4796-b93d-dfa2c9adc072', 'Scurvy Card', '7777', '2025-08-25') $$,
|
||||||
|
'Should be able to edit the second card payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select results_eq (
|
||||||
|
$$ select edit_payment_account_card('afb774a5-0c38-480c-bef2-fe03465071cd', 'Huh?', '1234', '2006-01-02')::text $$,
|
||||||
|
$$ values (null::text) $$,
|
||||||
|
'Should do nothing to an account that is not of type card'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_account_id, payment_account_type::text, name, last_four_digits, expiration_date::text from payment_account left join payment_account_card using (payment_account_id, payment_account_type) $$,
|
||||||
|
$$ values (11, 'card', 'Gold Card', '9999', '2022-12-22')
|
||||||
|
, (12, 'card', 'Scurvy Card', '7777', '2025-08-25')
|
||||||
|
, (13, 'other', 'Other', null::text, null::text)
|
||||||
|
$$,
|
||||||
|
'Should have update all card payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,77 @@
|
||||||
|
-- Test edit_payment_account_cash
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(13);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'edit_payment_account_cash', array['uuid', 'text']);
|
||||||
|
select function_lang_is('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'sql');
|
||||||
|
select function_returns('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'edit_payment_account_cash', array['uuid', 'text']);
|
||||||
|
select volatility_is('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_cash', array['uuid', 'text'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, slug, payment_account_type, name)
|
||||||
|
values (11, 1, '81c478ab-395c-44aa-a5b4-3489e5349a0b', 'cash', 'Cash 1')
|
||||||
|
, (12, 1, '84e84788-54f1-4796-b93d-dfa2c9adc072', 'cash', 'Cash 2')
|
||||||
|
, (13, 1, 'afb774a5-0c38-480c-bef2-fe03465071cd', 'other', 'Other')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment_account_cash('81c478ab-395c-44aa-a5b4-3489e5349a0b', 'My stash') $$,
|
||||||
|
'Should be able to edit the first cash payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select edit_payment_account_cash('84e84788-54f1-4796-b93d-dfa2c9adc072', 'Under mattress') $$,
|
||||||
|
'Should be able to edit the second cash payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select results_eq (
|
||||||
|
$$ select edit_payment_account_cash('afb774a5-0c38-480c-bef2-fe03465071cd', 'Huh?')::text $$,
|
||||||
|
$$ values (null::text) $$,
|
||||||
|
'Should do nothing to an account that is not of type cash'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_account_id, payment_account_type::text, name from payment_account $$,
|
||||||
|
$$ values (11, 'cash', 'My stash')
|
||||||
|
, (12, 'cash', 'Under mattress')
|
||||||
|
, (13, 'other', 'Other')
|
||||||
|
$$,
|
||||||
|
'Should have update all cash payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,77 @@
|
||||||
|
-- Test edit_payment_account_other
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(13);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'edit_payment_account_other', array['uuid', 'text']);
|
||||||
|
select function_lang_is('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'sql');
|
||||||
|
select function_returns('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'uuid');
|
||||||
|
select isnt_definer('numerus', 'edit_payment_account_other', array['uuid', 'text']);
|
||||||
|
select volatility_is('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'edit_payment_account_other', array['uuid', 'text'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (1, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 111)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (111, 1, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, slug, payment_account_type, name)
|
||||||
|
values (11, 1, '81c478ab-395c-44aa-a5b4-3489e5349a0b', 'other', 'Other 1')
|
||||||
|
, (12, 1, '84e84788-54f1-4796-b93d-dfa2c9adc072', 'other', 'Other 2')
|
||||||
|
, (13, 1, 'afb774a5-0c38-480c-bef2-fe03465071cd', 'cash', 'Cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
select lives_ok(
|
||||||
|
$$ select edit_payment_account_other('81c478ab-395c-44aa-a5b4-3489e5349a0b', 'Something') $$,
|
||||||
|
'Should be able to edit the first other payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select lives_ok (
|
||||||
|
$$ select edit_payment_account_other('84e84788-54f1-4796-b93d-dfa2c9adc072', 'And something else') $$,
|
||||||
|
'Should be able to edit the second other payment account'
|
||||||
|
);
|
||||||
|
|
||||||
|
select results_eq (
|
||||||
|
$$ select edit_payment_account_other('afb774a5-0c38-480c-bef2-fe03465071cd', 'Huh?')::text $$,
|
||||||
|
$$ values (null::text) $$,
|
||||||
|
'Should do nothing to an account that is not of type other'
|
||||||
|
);
|
||||||
|
|
||||||
|
select bag_eq(
|
||||||
|
$$ select payment_account_id, payment_account_type::text, name from payment_account $$,
|
||||||
|
$$ values (11, 'other', 'Something')
|
||||||
|
, (12, 'other', 'And something else')
|
||||||
|
, (13, 'cash', 'Cash')
|
||||||
|
$$,
|
||||||
|
'Should have update all other payment accounts'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,136 @@
|
||||||
|
-- Test expense_payment
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(23);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('expense_payment');
|
||||||
|
select has_pk('expense_payment');
|
||||||
|
select col_is_pk('expense_payment', array['expense_id', 'payment_id']);
|
||||||
|
select table_privs_are('expense_payment', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('expense_payment', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('expense_payment', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('expense_payment', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('expense_payment', 'expense_id');
|
||||||
|
select col_is_fk('expense_payment', 'expense_id');
|
||||||
|
select fk_ok('expense_payment', 'expense_id', 'expense', 'expense_id');
|
||||||
|
select col_type_is('expense_payment', 'expense_id', 'integer');
|
||||||
|
select col_not_null('expense_payment', 'expense_id');
|
||||||
|
select col_hasnt_default('expense_payment', 'expense_id');
|
||||||
|
|
||||||
|
select has_column('expense_payment', 'payment_id');
|
||||||
|
select col_is_fk('expense_payment', 'payment_id');
|
||||||
|
select fk_ok('expense_payment', 'payment_id', 'payment', 'payment_id');
|
||||||
|
select col_type_is('expense_payment', 'payment_id', 'integer');
|
||||||
|
select col_not_null('expense_payment', 'payment_id');
|
||||||
|
select col_hasnt_default('expense_payment', 'payment_id');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate expense_payment cascade;
|
||||||
|
truncate payment cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate expense cascade;
|
||||||
|
truncate contact cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 222)
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 444)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (444, 4, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into contact (contact_id, company_id, name)
|
||||||
|
values ( 9, 2, 'Customer 1')
|
||||||
|
, (10, 4, 'Customer 2')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense (expense_id, company_id, invoice_number, contact_id, invoice_date, amount, currency_code)
|
||||||
|
values (13, 2, 'INV001', 9, '2011-01-11', 111, 'EUR')
|
||||||
|
, (14, 4, 'INV002', 10, '2022-02-22', 222, 'EUR')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values (17, 2, 'cash', 'Cash 2')
|
||||||
|
, (18, 4, 'cash', 'Cash 4')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment (payment_id, company_id, description, payment_date, payment_account_id, amount, currency_code)
|
||||||
|
values (21, 2, 'Payment INV001', '2022-01-11', 17, 111, 'EUR')
|
||||||
|
, (22, 4, 'Payment INV002', '2022-02-23', 18, 222, 'EUR')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into expense_payment (expense_id, payment_id)
|
||||||
|
values (13, 21)
|
||||||
|
, (14, 22)
|
||||||
|
;
|
||||||
|
|
||||||
|
prepare expense_payment_data as
|
||||||
|
select expense_id, payment_id
|
||||||
|
from expense_payment
|
||||||
|
order by expense_id, payment_id;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('expense_payment_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'expense_payment_data',
|
||||||
|
$$ values (13, 21)
|
||||||
|
$$,
|
||||||
|
'Should only list tax of products of the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'expense_payment_data',
|
||||||
|
$$ values (14, 22)
|
||||||
|
$$,
|
||||||
|
'Should only list tax of products of the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'expense_payment_data',
|
||||||
|
'42501', 'permission denied for table expense_payment',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
-- Test payment
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(68);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('payment');
|
||||||
|
select has_pk('payment');
|
||||||
|
select table_privs_are('payment', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('payment', 'payment_id');
|
||||||
|
select col_type_is('payment', 'payment_id', 'integer');
|
||||||
|
select col_not_null('payment', 'payment_id');
|
||||||
|
select col_hasnt_default('payment', 'payment_id');
|
||||||
|
|
||||||
|
select has_column('payment', 'company_id');
|
||||||
|
select col_is_fk('payment', 'company_id');
|
||||||
|
select fk_ok('payment', 'company_id', 'company', 'company_id');
|
||||||
|
select col_type_is('payment', 'company_id', 'integer');
|
||||||
|
select col_not_null('payment', 'company_id');
|
||||||
|
select col_hasnt_default('payment', 'company_id');
|
||||||
|
|
||||||
|
select has_column('payment', 'slug');
|
||||||
|
select col_is_unique('payment', 'slug');
|
||||||
|
select col_type_is('payment', 'slug', 'uuid');
|
||||||
|
select col_not_null('payment', 'slug');
|
||||||
|
select col_has_default('payment', 'slug');
|
||||||
|
select col_default_is('payment', 'slug', 'gen_random_uuid()');
|
||||||
|
|
||||||
|
select has_column('payment', 'description');
|
||||||
|
select col_type_is('payment', 'description', 'text');
|
||||||
|
select col_not_null('payment', 'description');
|
||||||
|
select col_hasnt_default('payment', 'description');
|
||||||
|
|
||||||
|
select has_column('payment', 'payment_date');
|
||||||
|
select col_type_is('payment', 'payment_date', 'date');
|
||||||
|
select col_not_null('payment', 'payment_date');
|
||||||
|
select col_has_default('payment', 'payment_date');
|
||||||
|
select col_default_is('payment', 'payment_date', 'CURRENT_DATE');
|
||||||
|
|
||||||
|
select has_column('payment', 'payment_account_id');
|
||||||
|
select col_is_fk('payment', 'payment_account_id');
|
||||||
|
select fk_ok('payment', 'payment_account_id', 'payment_account', 'payment_account_id');
|
||||||
|
select col_type_is('payment', 'payment_account_id', 'integer');
|
||||||
|
select col_not_null('payment', 'payment_account_id');
|
||||||
|
select col_hasnt_default('payment', 'payment_account_id');
|
||||||
|
|
||||||
|
select has_column('payment', 'amount');
|
||||||
|
select col_type_is('payment', 'amount', 'integer');
|
||||||
|
select col_not_null('payment', 'amount');
|
||||||
|
select col_hasnt_default('payment', 'amount');
|
||||||
|
|
||||||
|
select has_column('payment', 'currency_code');
|
||||||
|
select col_is_fk('payment', 'currency_code');
|
||||||
|
select fk_ok('payment', 'currency_code', 'currency', 'currency_code');
|
||||||
|
select col_type_is('payment', 'currency_code', 'text');
|
||||||
|
select col_not_null('payment', 'currency_code');
|
||||||
|
select col_hasnt_default('payment', 'currency_code');
|
||||||
|
|
||||||
|
select has_column('payment', 'tags');
|
||||||
|
select col_type_is('payment', 'tags', 'tag_name[]');
|
||||||
|
select col_not_null('payment', 'tags');
|
||||||
|
select col_has_default('payment', 'tags');
|
||||||
|
select col_default_is('payment', 'tags', '{}');
|
||||||
|
|
||||||
|
select has_column('payment', 'payment_status');
|
||||||
|
select col_is_fk('payment', 'payment_status');
|
||||||
|
select fk_ok('payment', 'payment_status', 'payment_status', 'payment_status');
|
||||||
|
select col_type_is('payment', 'payment_status', 'text');
|
||||||
|
select col_not_null('payment', 'payment_status');
|
||||||
|
select col_has_default('payment', 'payment_status');
|
||||||
|
select col_default_is('payment', 'payment_status', 'complete');
|
||||||
|
|
||||||
|
select has_column('payment', 'created_at');
|
||||||
|
select col_type_is('payment', 'created_at', 'timestamp with time zone');
|
||||||
|
select col_not_null('payment', 'created_at');
|
||||||
|
select col_has_default('payment', 'created_at');
|
||||||
|
select col_default_is('payment', 'created_at', 'CURRENT_TIMESTAMP');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 222)
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 444)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (444, 4, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values (221, 2, 'other', 'Other 2')
|
||||||
|
, (441, 4, 'other', 'Other 4')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment (company_id, description, payment_account_id, amount, currency_code)
|
||||||
|
values (2, 'Payment 20001', 221, 333, 'EUR')
|
||||||
|
, (4, 'Payment 40001', 441, 555, 'EUR')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
prepare payment_data as
|
||||||
|
select company_id, description
|
||||||
|
from payment
|
||||||
|
order by company_id, description;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('payment_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_data',
|
||||||
|
$$ values (2, 'Payment 20001')
|
||||||
|
$$,
|
||||||
|
'Should only list payments from the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_data',
|
||||||
|
$$ values (4, 'Payment 40001')
|
||||||
|
$$,
|
||||||
|
'Should only list payments from the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'payment_data',
|
||||||
|
'42501', 'permission denied for table payment',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
-- Test payment_account
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(38);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('payment_account');
|
||||||
|
select has_pk('payment_account');
|
||||||
|
select table_privs_are('payment_account', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_account', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
|
||||||
|
select has_column('payment_account', 'payment_account_id');
|
||||||
|
select col_is_pk('payment_account', 'payment_account_id');
|
||||||
|
select col_type_is('payment_account', 'payment_account_id', 'integer');
|
||||||
|
select col_not_null('payment_account', 'payment_account_id');
|
||||||
|
select col_hasnt_default('payment_account', 'payment_account_id');
|
||||||
|
|
||||||
|
select has_column('payment_account', 'company_id');
|
||||||
|
select col_is_fk('payment_account', 'company_id');
|
||||||
|
select fk_ok('payment_account', 'company_id', 'company', 'company_id');
|
||||||
|
select col_type_is('payment_account', 'company_id', 'integer');
|
||||||
|
select col_not_null('payment_account', 'company_id');
|
||||||
|
select col_hasnt_default('payment_account', 'company_id');
|
||||||
|
|
||||||
|
select has_column('payment_account', 'slug');
|
||||||
|
select col_is_unique('payment_account', 'slug');
|
||||||
|
select col_type_is('payment_account', 'slug', 'uuid');
|
||||||
|
select col_not_null('payment_account', 'slug');
|
||||||
|
select col_has_default('payment_account', 'slug');
|
||||||
|
select col_default_is('payment_account', 'slug', 'gen_random_uuid()');
|
||||||
|
|
||||||
|
select has_column('payment_account', 'payment_account_type');
|
||||||
|
select col_type_is('payment_account', 'payment_account_type', 'text');
|
||||||
|
select col_is_fk('payment_account', 'payment_account_type');
|
||||||
|
select fk_ok('payment_account', 'payment_account_type', 'payment_account_type', 'payment_account_type');
|
||||||
|
select col_not_null('payment_account', 'payment_account_type');
|
||||||
|
select col_hasnt_default('payment_account', 'payment_account_type');
|
||||||
|
|
||||||
|
select has_column('payment_account', 'name');
|
||||||
|
select col_type_is('payment_account', 'name', 'text');
|
||||||
|
select col_not_null('payment_account', 'name');
|
||||||
|
select col_hasnt_default('payment_account', 'name');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 222)
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 444)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (444, 4, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
values (2, 'bank', 'Bank A')
|
||||||
|
, (4, 'cash', 'Cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
prepare payment_account_data as
|
||||||
|
select company_id, name
|
||||||
|
from payment_account
|
||||||
|
order by company_id, name;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('payment_account_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (2, 'Bank A')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts from the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (4, 'Cash')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts from the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'payment_account_data',
|
||||||
|
'42501', 'permission denied for table payment_account',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account (company_id, payment_account_type, name)
|
||||||
|
values (2, 'cash', ' ')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account" violates check constraint "payment_account_name_not_empty"',
|
||||||
|
'Should not allow payment accounts with a blank name'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
-- Test payment_account_bank
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(29);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('payment_account_bank');
|
||||||
|
select has_pk('payment_account_bank');
|
||||||
|
select table_privs_are('payment_account_bank', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_account_bank', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account_bank', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account_bank', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select col_is_fk('payment_account_bank', array['payment_account_id', 'payment_account_type']);
|
||||||
|
select fk_ok('payment_account_bank', array['payment_account_id', 'payment_account_type'], 'payment_account', array['payment_account_id', 'payment_account_type']);
|
||||||
|
|
||||||
|
select has_column('payment_account_bank', 'payment_account_id');
|
||||||
|
select col_is_pk('payment_account_bank', 'payment_account_id');
|
||||||
|
select col_type_is('payment_account_bank', 'payment_account_id', 'integer');
|
||||||
|
select col_not_null('payment_account_bank', 'payment_account_id');
|
||||||
|
select col_hasnt_default('payment_account_bank', 'payment_account_id');
|
||||||
|
|
||||||
|
select has_column('payment_account_bank', 'payment_account_type');
|
||||||
|
select col_type_is('payment_account_bank', 'payment_account_type', 'text');
|
||||||
|
select col_not_null('payment_account_bank', 'payment_account_type');
|
||||||
|
select col_has_default('payment_account_bank', 'payment_account_type');
|
||||||
|
select col_default_is('payment_account_bank', 'payment_account_type', 'bank');
|
||||||
|
|
||||||
|
select has_column('payment_account_bank', 'iban');
|
||||||
|
select col_type_is('payment_account_bank', 'iban', 'iban');
|
||||||
|
select col_not_null('payment_account_bank', 'iban');
|
||||||
|
select col_hasnt_default('payment_account_bank', 'iban');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_bank cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 222)
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 444)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (444, 4, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values ( 6, 2, 'bank', 'Bank 2')
|
||||||
|
, ( 7, 2, 'card', 'Credit card 2')
|
||||||
|
, ( 8, 2, 'cash', 'Cash 2')
|
||||||
|
, ( 9, 2, 'other', 'Other 2')
|
||||||
|
, (10, 4, 'bank', 'Bank 4')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account_bank (payment_account_id, iban)
|
||||||
|
values ( 6, 'NL35INGB5262865534')
|
||||||
|
, (10, 'MT47JQRS54557143744629565915326')
|
||||||
|
;
|
||||||
|
|
||||||
|
prepare payment_account_data as
|
||||||
|
select company_id, iban::text
|
||||||
|
from payment_account
|
||||||
|
join payment_account_bank using (payment_account_id)
|
||||||
|
order by payment_account_id, iban;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('payment_account_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (2, 'NL35INGB5262865534')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts of the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (4, 'MT47JQRS54557143744629565915326')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts of the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'payment_account_data',
|
||||||
|
'42501', 'permission denied for table payment_account',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_bank (payment_account_id, payment_account_type, iban)
|
||||||
|
values (7, 'card', 'ES2820958297603648596978')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_bank" violates check constraint "payment_account_type_is_bank"',
|
||||||
|
'Should not allow payment accounts of type card'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_bank (payment_account_id, payment_account_type, iban)
|
||||||
|
values (8, 'cash', 'ES2820958297603648596978')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_bank" violates check constraint "payment_account_type_is_bank"',
|
||||||
|
'Should not allow payment accounts of type cash'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_bank (payment_account_id, payment_account_type, iban)
|
||||||
|
values (9, 'other', 'ES2820958297603648596978')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_bank" violates check constraint "payment_account_type_is_bank"',
|
||||||
|
'Should not allow payment accounts of type other'
|
||||||
|
);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
-- Test payment_account_card
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(39);
|
||||||
|
|
||||||
|
set search_path to numerus, auth, public;
|
||||||
|
|
||||||
|
select has_table('payment_account_card');
|
||||||
|
select has_pk('payment_account_card');
|
||||||
|
select table_privs_are('payment_account_card', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_account_card', 'invoicer', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account_card', 'admin', array ['SELECT', 'INSERT', 'UPDATE', 'DELETE']);
|
||||||
|
select table_privs_are('payment_account_card', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select col_is_fk('payment_account_card', array['payment_account_id', 'payment_account_type']);
|
||||||
|
select fk_ok('payment_account_card', array['payment_account_id', 'payment_account_type'], 'payment_account', array['payment_account_id', 'payment_account_type']);
|
||||||
|
|
||||||
|
select has_column('payment_account_card', 'payment_account_id');
|
||||||
|
select col_is_pk('payment_account_card', 'payment_account_id');
|
||||||
|
select col_type_is('payment_account_card', 'payment_account_id', 'integer');
|
||||||
|
select col_not_null('payment_account_card', 'payment_account_id');
|
||||||
|
select col_hasnt_default('payment_account_card', 'payment_account_id');
|
||||||
|
|
||||||
|
select has_column('payment_account_card', 'payment_account_type');
|
||||||
|
select col_type_is('payment_account_card', 'payment_account_type', 'text');
|
||||||
|
select col_not_null('payment_account_card', 'payment_account_type');
|
||||||
|
select col_has_default('payment_account_card', 'payment_account_type');
|
||||||
|
select col_default_is('payment_account_card', 'payment_account_type', 'card');
|
||||||
|
|
||||||
|
select has_column('payment_account_card', 'last_four_digits');
|
||||||
|
select col_type_is('payment_account_card', 'last_four_digits', 'text');
|
||||||
|
select col_not_null('payment_account_card', 'last_four_digits');
|
||||||
|
select col_hasnt_default('payment_account_card', 'last_four_digits');
|
||||||
|
|
||||||
|
select has_column('payment_account_card', 'expiration_date');
|
||||||
|
select col_type_is('payment_account_card', 'expiration_date', 'date');
|
||||||
|
select col_not_null('payment_account_card', 'expiration_date');
|
||||||
|
select col_hasnt_default('payment_account_card', 'expiration_date');
|
||||||
|
|
||||||
|
|
||||||
|
set client_min_messages to warning;
|
||||||
|
truncate payment_account_card cascade;
|
||||||
|
truncate payment_account cascade;
|
||||||
|
truncate company_user cascade;
|
||||||
|
truncate payment_method cascade;
|
||||||
|
truncate company cascade;
|
||||||
|
truncate auth."user" cascade;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" deferred;
|
||||||
|
|
||||||
|
insert into auth."user" (user_id, email, name, password, role, cookie, cookie_expires_at)
|
||||||
|
values (1, 'demo@tandem.blog', 'Demo', 'test', 'invoicer', '44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e', current_timestamp + interval '1 month')
|
||||||
|
, (5, 'admin@tandem.blog', 'Demo', 'test', 'admin', '12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524', current_timestamp + interval '1 month')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into company (company_id, business_name, vatin, trade_name, phone, email, web, address, city, province, postal_code, country_code, currency_code, default_payment_method_id)
|
||||||
|
values (2, 'Company 2', 'XX123', '', '555-555-555', 'a@a', '', '', '', '', '', 'ES', 'EUR', 222)
|
||||||
|
, (4, 'Company 4', 'XX234', '', '666-666-666', 'b@b', '', '', '', '', '', 'FR', 'USD', 444)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_method (payment_method_id, company_id, name, instructions)
|
||||||
|
values (444, 4, 'cash', 'cash')
|
||||||
|
, (222, 2, 'cash', 'cash')
|
||||||
|
;
|
||||||
|
|
||||||
|
set constraints "company_default_payment_method_id_fkey" immediate;
|
||||||
|
|
||||||
|
insert into company_user (company_id, user_id)
|
||||||
|
values (2, 1)
|
||||||
|
, (4, 5)
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account (payment_account_id, company_id, payment_account_type, name)
|
||||||
|
values ( 6, 2, 'bank', 'Bank 2')
|
||||||
|
, ( 7, 2, 'card', 'Credit card 2')
|
||||||
|
, ( 8, 2, 'cash', 'Cash 2')
|
||||||
|
, ( 9, 2, 'other', 'Other 2')
|
||||||
|
, (10, 4, 'card', 'Card 4')
|
||||||
|
;
|
||||||
|
|
||||||
|
insert into payment_account_card (payment_account_id, last_four_digits, expiration_date)
|
||||||
|
values ( 7, '1234', '2024-07-09')
|
||||||
|
, (10, '4321', '2025-09-07')
|
||||||
|
;
|
||||||
|
|
||||||
|
prepare payment_account_data as
|
||||||
|
select company_id, last_four_digits
|
||||||
|
from payment_account
|
||||||
|
join payment_account_card using (payment_account_id)
|
||||||
|
order by payment_account_id, last_four_digits;
|
||||||
|
|
||||||
|
set role invoicer;
|
||||||
|
select is_empty('payment_account_data', 'Should show no data when cookie is not set yet');
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('44facbb30d8a419dfd4bfbc44a4b5539d4970148dfc84bed0e/demo@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (2, '1234')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts of the companies where demo@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('12af4c88b528c2ad4222e3740496ecbc58e76e26f087657524/admin@tandem.blog');
|
||||||
|
select bag_eq(
|
||||||
|
'payment_account_data',
|
||||||
|
$$ values (4, '4321')
|
||||||
|
$$,
|
||||||
|
'Should only list payment_accounts of the companies where admin@tandem.blog is user of'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select set_cookie('not-a-cookie');
|
||||||
|
select throws_ok(
|
||||||
|
'payment_account_data',
|
||||||
|
'42501', 'permission denied for table payment_account',
|
||||||
|
'Should not allow select to guest users'
|
||||||
|
);
|
||||||
|
reset role;
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_card (payment_account_id, payment_account_type, last_four_digits, expiration_date)
|
||||||
|
values (6, 'bank', '1111', '2025-05-05')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "payment_account_type_is_card"',
|
||||||
|
'Should not allow payment accounts of type bank'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_card (payment_account_id, payment_account_type, last_four_digits, expiration_date)
|
||||||
|
values (8, 'cash', '1111', '2025-05-05')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "payment_account_type_is_card"',
|
||||||
|
'Should not allow payment accounts of type cash'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok( $$
|
||||||
|
insert into payment_account_card (payment_account_id, payment_account_type, last_four_digits, expiration_date)
|
||||||
|
values (9, 'other', '1111', '2025-05-05')
|
||||||
|
$$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "payment_account_type_is_card"',
|
||||||
|
'Should not allow payment accounts of type other'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = 'a234' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be all digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = '1a34' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be all digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = '12a4' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be all digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = '123a' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be all digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = '12345' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be not have more than four digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
select throws_ok (
|
||||||
|
$$ update payment_account_card set last_four_digits = '123' where payment_account_id = 7 $$,
|
||||||
|
'23514', 'new row for relation "payment_account_card" violates check constraint "last_four_digits_are_digits"',
|
||||||
|
'Last four digits of a credit card number should be not have less than four digits'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
-- Test payment_account_type
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(15);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_table('payment_account_type');
|
||||||
|
select has_pk('payment_account_type' );
|
||||||
|
select table_privs_are('payment_account_type', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_account_type', 'invoicer', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_account_type', 'admin', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_account_type', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('payment_account_type', 'payment_account_type');
|
||||||
|
select col_is_pk('payment_account_type', 'payment_account_type');
|
||||||
|
select col_type_is('payment_account_type', 'payment_account_type', 'text');
|
||||||
|
select col_not_null('payment_account_type', 'payment_account_type');
|
||||||
|
select col_hasnt_default('payment_account_type', 'payment_account_type');
|
||||||
|
|
||||||
|
select has_column('payment_account_type', 'name');
|
||||||
|
select col_type_is('payment_account_type', 'name', 'text');
|
||||||
|
select col_not_null('payment_account_type', 'name');
|
||||||
|
select col_hasnt_default('payment_account_type', 'name');
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,44 @@
|
||||||
|
-- Test payment_account_type_i18n
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(23);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_table('payment_account_type_i18n');
|
||||||
|
select has_pk('payment_account_type_i18n');
|
||||||
|
select col_is_pk('payment_account_type_i18n', array['payment_account_type', 'lang_tag']);
|
||||||
|
select table_privs_are('payment_account_type_i18n', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_account_type_i18n', 'invoicer', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_account_type_i18n', 'admin', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_account_type_i18n', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('payment_account_type_i18n', 'payment_account_type');
|
||||||
|
select col_is_fk('payment_account_type_i18n', 'payment_account_type');
|
||||||
|
select fk_ok('payment_account_type_i18n', 'payment_account_type', 'payment_account_type', 'payment_account_type');
|
||||||
|
select col_type_is('payment_account_type_i18n', 'payment_account_type', 'text');
|
||||||
|
select col_not_null('payment_account_type_i18n', 'payment_account_type');
|
||||||
|
select col_hasnt_default('payment_account_type_i18n', 'payment_account_type');
|
||||||
|
|
||||||
|
select has_column('payment_account_type_i18n', 'lang_tag');
|
||||||
|
select col_is_fk('payment_account_type_i18n', 'lang_tag');
|
||||||
|
select fk_ok('payment_account_type_i18n', 'lang_tag', 'language', 'lang_tag');
|
||||||
|
select col_type_is('payment_account_type_i18n', 'lang_tag', 'text');
|
||||||
|
select col_not_null('payment_account_type_i18n', 'lang_tag');
|
||||||
|
select col_hasnt_default('payment_account_type_i18n', 'lang_tag');
|
||||||
|
|
||||||
|
select has_column('payment_account_type_i18n', 'name');
|
||||||
|
select col_type_is('payment_account_type_i18n', 'name', 'text');
|
||||||
|
select col_not_null('payment_account_type_i18n', 'name');
|
||||||
|
select col_hasnt_default('payment_account_type_i18n', 'name');
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
-- Test payment_status
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(15);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_table('payment_status');
|
||||||
|
select has_pk('payment_status');
|
||||||
|
select table_privs_are('payment_status', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_status', 'invoicer', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_status', 'admin', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_status', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('payment_status', 'payment_status');
|
||||||
|
select col_is_pk('payment_status', 'payment_status');
|
||||||
|
select col_type_is('payment_status', 'payment_status', 'text');
|
||||||
|
select col_not_null('payment_status', 'payment_status');
|
||||||
|
select col_hasnt_default('payment_status', 'payment_status');
|
||||||
|
|
||||||
|
select has_column('payment_status', 'name');
|
||||||
|
select col_type_is('payment_status', 'name', 'text');
|
||||||
|
select col_not_null('payment_status', 'name');
|
||||||
|
select col_hasnt_default('payment_status', 'name');
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
-- Test payment_status_i18n
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(23);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_table('payment_status_i18n');
|
||||||
|
select has_pk('payment_status_i18n');
|
||||||
|
select col_is_pk('payment_status_i18n', array['payment_status', 'lang_tag']);
|
||||||
|
select table_privs_are('payment_status_i18n', 'guest', array []::text[]);
|
||||||
|
select table_privs_are('payment_status_i18n', 'invoicer', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_status_i18n', 'admin', array ['SELECT']);
|
||||||
|
select table_privs_are('payment_status_i18n', 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select has_column('payment_status_i18n', 'payment_status');
|
||||||
|
select col_is_fk('payment_status_i18n', 'payment_status');
|
||||||
|
select fk_ok('payment_status_i18n', 'payment_status', 'payment_status', 'payment_status');
|
||||||
|
select col_type_is('payment_status_i18n', 'payment_status', 'text');
|
||||||
|
select col_not_null('payment_status_i18n', 'payment_status');
|
||||||
|
select col_hasnt_default('payment_status_i18n', 'payment_status');
|
||||||
|
|
||||||
|
select has_column('payment_status_i18n', 'lang_tag');
|
||||||
|
select col_is_fk('payment_status_i18n', 'lang_tag');
|
||||||
|
select fk_ok('payment_status_i18n', 'lang_tag', 'language', 'lang_tag');
|
||||||
|
select col_type_is('payment_status_i18n', 'lang_tag', 'text');
|
||||||
|
select col_not_null('payment_status_i18n', 'lang_tag');
|
||||||
|
select col_hasnt_default('payment_status_i18n', 'lang_tag');
|
||||||
|
|
||||||
|
select has_column('payment_status_i18n', 'name');
|
||||||
|
select col_type_is('payment_status_i18n', 'name', 'text');
|
||||||
|
select col_not_null('payment_status_i18n', 'name');
|
||||||
|
select col_hasnt_default('payment_status_i18n', 'name');
|
||||||
|
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
-- Test update_expense_payment_status
|
||||||
|
set client_min_messages to warning;
|
||||||
|
create extension if not exists pgtap;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select plan(9);
|
||||||
|
|
||||||
|
set search_path to numerus, public;
|
||||||
|
|
||||||
|
select has_function('numerus', 'update_expense_payment_status', array['integer', 'integer', 'integer']);
|
||||||
|
select function_lang_is('numerus', 'update_expense_payment_status', array['integer', 'integer', 'integer'], 'sql');
|
||||||
|
select function_returns('numerus', 'update_expense_payment_status', array['integer', 'integer', 'integer'], 'void');
|
||||||
|
select isnt_definer('numerus', 'update_expense_payment_status', array['integer', 'integer', 'integer']);
|
||||||
|
select volatility_is('numerus', 'update_expense_payment_status', array['integer', 'integer', 'integer'], 'volatile');
|
||||||
|
|
||||||
|
select function_privs_are('numerus', 'update_expense_payment_status', array ['integer', 'integer', 'integer'], 'guest', array []::text[]);
|
||||||
|
select function_privs_are('numerus', 'update_expense_payment_status', array ['integer', 'integer', 'integer'], 'invoicer', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'update_expense_payment_status', array ['integer', 'integer', 'integer'], 'admin', array ['EXECUTE']);
|
||||||
|
select function_privs_are('numerus', 'update_expense_payment_status', array ['integer', 'integer', 'integer'], 'authenticator', array []::text[]);
|
||||||
|
|
||||||
|
select *
|
||||||
|
from finish();
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:add_payment on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.add_payment(integer, integer, date, integer, text, text, numerus.tag_name[])', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:add_payment_account_bank on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.add_payment_account_bank(integer, text, iban)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:add_payment_account_card on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.add_payment_account_card(integer, text, text, date)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:add_payment_account_cash on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.add_payment_account_cash(integer, text)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:add_payment_account_other on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.add_payment_account_other(integer, text)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -5,10 +5,13 @@ begin;
|
||||||
set search_path to numerus;
|
set search_path to numerus;
|
||||||
|
|
||||||
select 1 / count(*) from expense_status where expense_status = 'pending' and name ='Pending';
|
select 1 / count(*) from expense_status where expense_status = 'pending' and name ='Pending';
|
||||||
|
select 1 / count(*) from expense_status where expense_status = 'partial' and name ='Partial';
|
||||||
select 1 / count(*) from expense_status where expense_status = 'paid' and name ='Paid';
|
select 1 / count(*) from expense_status where expense_status = 'paid' and name ='Paid';
|
||||||
|
|
||||||
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendent' and lang_tag = 'ca';
|
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendent' and lang_tag = 'ca';
|
||||||
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendiente' and lang_tag = 'es';
|
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendiente' and lang_tag = 'es';
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'partial' and name ='Parcial' and lang_tag = 'ca';
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'partial' and name ='Parcial' and lang_tag = 'es';
|
||||||
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'ca';
|
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'ca';
|
||||||
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'es';
|
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'es';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- Verify numerus:available_expense_status on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
select 1 / count(*) from expense_status where expense_status = 'pending' and name ='Pending';
|
||||||
|
select 1 / count(*) from expense_status where expense_status = 'paid' and name ='Paid';
|
||||||
|
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendent' and lang_tag = 'ca';
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'pending' and name ='Pendiente' and lang_tag = 'es';
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'ca';
|
||||||
|
select 1 / count(*) from expense_status_i18n where expense_status = 'paid' and name ='Pagada' and lang_tag= 'es';
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- Verify numerus:available_payment_account_types on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
select 1 / count(*) from payment_account_type where payment_account_type = 'bank' and name ='Bank';
|
||||||
|
select 1 / count(*) from payment_account_type where payment_account_type = 'card' and name ='Credit Card';
|
||||||
|
select 1 / count(*) from payment_account_type where payment_account_type = 'cash' and name ='Cash';
|
||||||
|
select 1 / count(*) from payment_account_type where payment_account_type = 'other' and name ='Other';
|
||||||
|
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'bank' and name ='Banc' and lang_tag = 'ca';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'bank' and name ='Banco' and lang_tag = 'es';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'card' and name ='Targeta de crèdit' and lang_tag= 'ca';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'card' and name ='Tarjeta de crédito' and lang_tag= 'es';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'cash' and name ='Efectiu' and lang_tag= 'ca';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'cash' and name ='Efectivo' and lang_tag= 'es';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'other' and name ='Altres' and lang_tag= 'ca';
|
||||||
|
select 1 / count(*) from payment_account_type_i18n where payment_account_type = 'other' and name ='Otros' and lang_tag= 'es';
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- Verify numerus:available_payment_status on pg
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
set search_path to numerus;
|
||||||
|
|
||||||
|
select 1 / count(*) from payment_status where payment_status = 'partial' and name ='Partial';
|
||||||
|
select 1 / count(*) from payment_status where payment_status = 'complete' and name ='Complete';
|
||||||
|
|
||||||
|
select 1 / count(*) from payment_status_i18n where payment_status = 'partial' and name ='Parcial' and lang_tag = 'ca';
|
||||||
|
select 1 / count(*) from payment_status_i18n where payment_status = 'partial' and name ='Parcial' and lang_tag = 'es';
|
||||||
|
select 1 / count(*) from payment_status_i18n where payment_status = 'complete' and name ='Complet' and lang_tag= 'ca';
|
||||||
|
select 1 / count(*) from payment_status_i18n where payment_status = 'complete' and name ='Completo' and lang_tag= 'es';
|
||||||
|
|
||||||
|
ROLLBACK;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:edit_payment on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.edit_payment(uuid, date, integer, text, text, numerus.tag_name[])', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:edit_payment_account_bank on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.edit_payment_account_bank(uuid, text, iban)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:edit_payment_account_card on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.edit_payment_account_card(uuid, text, text, date)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:edit_payment_account_cash on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.edit_payment_account_cash(uuid, text)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:edit_payment_account_other on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.edit_payment_account_other(uuid, text)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,13 @@
|
||||||
|
-- Verify numerus:expense_payment on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select expense_id
|
||||||
|
, payment_id
|
||||||
|
from numerus.expense_payment
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.expense_payment'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.expense_payment'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- Verify numerus:payment on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_id
|
||||||
|
, company_id
|
||||||
|
, slug
|
||||||
|
, description
|
||||||
|
, payment_date
|
||||||
|
, payment_account_id
|
||||||
|
, amount
|
||||||
|
, currency_code
|
||||||
|
, tags
|
||||||
|
, payment_status
|
||||||
|
, created_at
|
||||||
|
from numerus.payment
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.payment'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.payment'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,16 @@
|
||||||
|
-- Verify numerus:payment_account on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_account_id
|
||||||
|
, company_id
|
||||||
|
, slug
|
||||||
|
, payment_account_type
|
||||||
|
, name
|
||||||
|
from numerus.payment_account
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.payment_account'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.payment_account'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,14 @@
|
||||||
|
-- Verify numerus:payment_account_bank on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_account_id
|
||||||
|
, payment_account_type
|
||||||
|
, iban
|
||||||
|
from numerus.payment_account_bank
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.payment_account_bank'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.payment_account_bank'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- Verify numerus:payment_account_card on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_account_id
|
||||||
|
, payment_account_type
|
||||||
|
, last_four_digits
|
||||||
|
, expiration_date
|
||||||
|
from numerus.payment_account_card
|
||||||
|
where false;
|
||||||
|
|
||||||
|
select 1 / count(*) from pg_class where oid = 'numerus.payment_account_card'::regclass and relrowsecurity;
|
||||||
|
select 1 / count(*) from pg_policy where polname = 'company_policy' and polrelid = 'numerus.payment_account_card'::regclass;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- Verify numerus:payment_account_type on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_account_type
|
||||||
|
, name
|
||||||
|
from numerus.payment_account_type
|
||||||
|
where false;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- Verify numerus:payment_account_type_i18n on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_account_type
|
||||||
|
, lang_tag
|
||||||
|
, name
|
||||||
|
from numerus.payment_account_type_i18n
|
||||||
|
where false;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- Verify numerus:payment_status on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_status
|
||||||
|
, name
|
||||||
|
from numerus.payment_status
|
||||||
|
where false;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,11 @@
|
||||||
|
-- Verify numerus:payment_status_i18n on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select payment_status
|
||||||
|
, lang_tag
|
||||||
|
, name
|
||||||
|
from numerus.payment_status_i18n
|
||||||
|
where false;
|
||||||
|
|
||||||
|
rollback;
|
|
@ -0,0 +1,7 @@
|
||||||
|
-- Verify numerus:update_expense_payment_status on pg
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
select has_function_privilege('numerus.update_expense_payment_status(integer, integer, integer)', 'execute');
|
||||||
|
|
||||||
|
rollback;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue