From d7db9a2eb1211123d3d3d54100e995375fab7fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20=22flowdy=22=20He=C3=9F?= Date: Sun, 29 Jan 2017 15:57:34 +0100 Subject: [PATCH] Added categories and Filter widget --- TrsrDB.pm | 2 +- TrsrDB/Credit.pm | 6 +++ TrsrDB/Debit.pm | 6 +++ TrsrDB/HTTP.pm | 53 +++++++++++++++++-- TrsrDB/HTTP/Account.pm | 14 +++-- TrsrDB/HTTP/Credit.pm | 14 +++-- TrsrDB/HTTP/Debit.pm | 15 ++++-- TrsrDB/History.pm | 2 +- TrsrDB/ReconstructedBankStatement.pm | 2 +- schema/tables.sql | 10 ++++ schema/views/03_History.sql | 2 + .../views/05_ReconstructedBankStatement.sql | 2 + t/schema.out | 6 +-- t/schema.sql | 33 ++++++------ templates/account/history.html.ep | 2 + templates/account/list.html.ep | 2 +- templates/account/transfer.html.ep | 4 +- templates/bankStatement.html.ep | 2 + templates/credit/list.html.ep | 2 + templates/credit/upsert.html.ep | 11 ++++ templates/debit/list.html.ep | 2 + templates/debit/upsert.html.ep | 13 +++++ templates/layouts/default.html.ep | 2 +- 23 files changed, 167 insertions(+), 40 deletions(-) diff --git a/TrsrDB.pm b/TrsrDB.pm index a70b8ee..f3c13fe 100644 --- a/TrsrDB.pm +++ b/TrsrDB.pm @@ -6,7 +6,7 @@ use Carp qw/croak/; __PACKAGE__->load_classes(qw| Account Debit Credit Transfer CurrentArrears AvailableCredits - Balance Report ReconstructedBankStatement History User + Category Balance Report ReconstructedBankStatement History User |); sub import { diff --git a/TrsrDB/Credit.pm b/TrsrDB/Credit.pm index 42994bf..458ad2e 100644 --- a/TrsrDB/Credit.pm +++ b/TrsrDB/Credit.pm @@ -8,6 +8,7 @@ __PACKAGE__->add_column("credId" => { data_type => 'INTEGER' }); __PACKAGE__->add_column("account"); __PACKAGE__->add_column("date" => { data_type => 'DATE' }); __PACKAGE__->add_column("purpose"); +__PACKAGE__->add_column("category", { is_nullable => 1 }); __PACKAGE__->add_column("value" => { data_type => 'INTEGER' }); __PACKAGE__->add_column("spent" => { data_type => 'INTEGER', default => 0 }); __PACKAGE__->set_primary_key("credId"); @@ -26,6 +27,11 @@ __PACKAGE__->has_many( { 'foreign.targetCredit' => 'self.credId' } ); +__PACKAGE__->belongs_to( + category_row => 'TrsrDB::Category', + { 'foreign.ID' => 'self.category' } +); + __PACKAGE__->many_to_many( paid_bills => 'outgoings' => 'debit' ); diff --git a/TrsrDB/Debit.pm b/TrsrDB/Debit.pm index 81da591..cc8697c 100644 --- a/TrsrDB/Debit.pm +++ b/TrsrDB/Debit.pm @@ -8,6 +8,7 @@ __PACKAGE__->add_column("billId"); __PACKAGE__->add_column("debtor"); __PACKAGE__->add_column("date" => { data_type => 'DATE' }); __PACKAGE__->add_column("purpose"); +__PACKAGE__->add_column("category", { is_nullable => 1 }); __PACKAGE__->add_column("value" => { data_type => 'INTEGER' }); __PACKAGE__->add_column("paid" => { data_type => 'INTEGER', default => 0 }); __PACKAGE__->set_primary_key("billId"); @@ -26,6 +27,11 @@ __PACKAGE__->belongs_to( { 'foreign.credId' => 'self.targetCredit' } ); +__PACKAGE__->belongs_to( + category_row => 'TrsrDB::Category', + { 'foreign.ID' => 'self.category' } +); + __PACKAGE__->has_many( incomings => 'TrsrDB::Transfer', 'billId' ); diff --git a/TrsrDB/HTTP.pm b/TrsrDB/HTTP.pm index dc02dd6..c74fec2 100644 --- a/TrsrDB/HTTP.pm +++ b/TrsrDB/HTTP.pm @@ -58,10 +58,7 @@ sub startup { $self->helper(sql_trace => \&get_trace); } else { - $self->helper(sql_trace => sub { - return "No SQL trace shown here, because environment variable " - . "DBIC_TRACE is not set." - }); + $self->helper(sql_trace => \&_get_trace_placeholder); } if ( my $l = $ENV{LOG} ) { @@ -90,7 +87,9 @@ sub startup { })->get('/'); $check->get('/bankStatement' => sub { my $c = shift; - $c->stash( records => $c->app->db->resultset("ReconstructedBankStatement") ); + my $records = $c->app->db->resultset("ReconstructedBankStatement") + ->search( process_table_filter_widget($c) ); + $c->stash( records => $records ); $c->render('bankStatement'); }); @@ -299,6 +298,50 @@ sub render_online_help { } +sub process_table_filter_widget { + my $c = shift; + my %query = $_[0] ? %{$_[0]} : (); + my %options = $_[1] ? %{$_[1]} : (); + $options{rows} //= $c->param("rows") // 100; + + if ( my $category = $c->param('category') ) { + $query{category} = $category; + } + + if ( my $purpose = $c->param('purpose') ) { + $query{purpose} //= { -like => "%$purpose%" }; + } + + my $until; + if ( $until = $c->param('until') ) { + $query{date} = { '<=' => $until }; + } + + if ( my $from = $c->param('from') ) { + if ( $until ) { + $query{date}{'>='} = $from; + } + elsif ( $from =~ m{ \A \d{4} (-\d\d)? }xms ) { + $query{date} = { -like => "$from%" }; + } + else { + $query{date} = { '>=' => $from }; + } + } + + if ( my $page = $c->param("page") ) { + $options{page} = $page; + } + + return \%query, \%options; + +} + +sub _get_trace_placeholder { \<<'EOF' +In this area, the server can trace SQL commands executed to fulfill your request. If the admin wants that, they can run the server with environment variable DBIC_TRACE=1. +All substantial logic of Treasure DB is done in the scope of the database itself. In consequence, you could do without this HTTP interface and input all SQL commands shown here directly in a general-purpose SQLite3 user interface. Thus you will get roughly the same results. +EOF +} 1; __END__ diff --git a/TrsrDB/HTTP/Account.pm b/TrsrDB/HTTP/Account.pm index b482723..aadfe56 100644 --- a/TrsrDB/HTTP/Account.pm +++ b/TrsrDB/HTTP/Account.pm @@ -59,9 +59,17 @@ sub upsert { sub history { my $self = shift; - my $history = $self->app->db->resultset("History")->search({ - account => $self->stash("account") - }, { order_by => { -desc => [qw/date/] } }); + my %query = ( account => $self->stash("account") ); + if ( my $p = $self->param("purpose") ) { + # ... + } + my $history = $self->app->db->resultset("History")->search( + TrsrDB::HTTP::process_table_filter_widget( + $self, \%query, + { order_by => { -desc => [qw/date/] } } + ) + ); + $self->stash( history => $history ); } diff --git a/TrsrDB/HTTP/Credit.pm b/TrsrDB/HTTP/Credit.pm index 425208d..a2144bd 100644 --- a/TrsrDB/HTTP/Credit.pm +++ b/TrsrDB/HTTP/Credit.pm @@ -20,7 +20,9 @@ sub list { } my $rs = $account->search_related( - credits => {}, { order_by => { -desc => [qw/date/] } } + credits => TrsrDB::HTTP::process_table_filter_widget( + $self, {}, { order_by => { -desc => [qw/date/] }} + ) ); $self->stash( credits => $rs ); @@ -39,14 +41,20 @@ sub upsert { account => $self->stash("account"), date => strftime("%Y-%m-%d", localtime) }); - $self->stash( credit => $credit ); + $self->stash( + credit => $credit, + categories => $db->resultset("Category")->search_rs({}, { + order_by => { -asc => [qw/ID/] } + }) + ); if ( $self->req->method eq 'GET' ) { return; } - for my $field ( qw/account date purpose value/ ) { + for my $field ( qw/account date purpose category value/ ) { my $value = $self->param($field); + $value = undef if !length $value; $credit->$field($value); } $credit->update_or_insert(); diff --git a/TrsrDB/HTTP/Debit.pm b/TrsrDB/HTTP/Debit.pm index 1ba1bbb..4b26e4a 100644 --- a/TrsrDB/HTTP/Debit.pm +++ b/TrsrDB/HTTP/Debit.pm @@ -20,7 +20,9 @@ sub list { } my $rs = $account->search_related( - debits => {}, { order_by => { -desc => [qw/date/] }} + debits => TrsrDB::HTTP::process_table_filter_widget( + $self, {}, { order_by => { -desc => [qw/date/] }} + ) ); $self->stash( debits => $rs ); @@ -33,7 +35,7 @@ sub upsert { my $db = $self->app->db; my $id = $self->stash("id"); - my @FIELDS = qw/billId date purpose value targetCredit/; + my @FIELDS = qw/billId date purpose category value targetCredit/; my $debtor = $self->stash("account") // $self->param("debtor"); if ( $self->req->method eq 'POST' && $debtor =~ s{^@}{} ) { @@ -74,7 +76,14 @@ sub upsert { } ); my @targets = map { [ $_->credId, $_->account->ID, $_->purpose ] } $targets->all; - $self->stash( targets => \@targets, targets_count => $targets->count ); + my $categories = $db->resultset("Category")->search_rs({}, { + order_by => { -asc => [qw/ID/] } + }); + $self->stash( + categories => $categories, + targets => \@targets, + targets_count => $targets->count + ); return; } diff --git a/TrsrDB/History.pm b/TrsrDB/History.pm index 2a38408..f998cd1 100644 --- a/TrsrDB/History.pm +++ b/TrsrDB/History.pm @@ -4,7 +4,7 @@ package TrsrDB::History; use base qw/DBIx::Class::Core/; __PACKAGE__->table('History'); -__PACKAGE__->add_columns(qw/date purpose account credId credit debit contra billId note/); +__PACKAGE__->add_columns(qw/date purpose category account credId credit debit contra billId note/); __PACKAGE__->belongs_to( account => 'TrsrDB::Account', diff --git a/TrsrDB/ReconstructedBankStatement.pm b/TrsrDB/ReconstructedBankStatement.pm index 0ed4639..c45d83c 100644 --- a/TrsrDB/ReconstructedBankStatement.pm +++ b/TrsrDB/ReconstructedBankStatement.pm @@ -4,6 +4,6 @@ package TrsrDB::ReconstructedBankStatement; use base qw/DBIx::Class::Core/; __PACKAGE__->table('ReconstructedBankStatement'); -__PACKAGE__->add_columns(qw/date purpose account credit debit/); +__PACKAGE__->add_columns(qw/date purpose category account credit debit/); 1; diff --git a/schema/tables.sql b/schema/tables.sql index 0a2e1e1..c3f097a 100644 --- a/schema/tables.sql +++ b/schema/tables.sql @@ -5,6 +5,12 @@ CREATE TABLE Account ( IBAN -- target account for returned payments (set '' to enable -- outgoing bank transfers to commercial partners from that account). ); + +CREATE TABLE Category ( + ID INTEGER PRIMARY KEY, + label +); + CREATE TABLE Debit ( billId PRIMARY KEY NOT NULL, debtor NOT NULL, -- Account charged @@ -13,10 +19,12 @@ CREATE TABLE Debit ( -- NULL when debit is a bank transfer from the club account date DATE NOT NULL, purpose NOT NULL, -- description of receipt + category, value INTEGER NOT NULL, -- Euro-Cent paid INTEGER DEFAULT 0, -- Euro-Cent, set and changed automatically (Cache) FOREIGN KEY (debtor) REFERENCES Account(ID), FOREIGN KEY (targetCredit) REFERENCES Credit(credId), + FOREIGN KEY (category) REFERENCES Category(ID), CHECK ( abs(cast(value as integer)) == value AND abs(cast( paid as integer)) == paid AND value > 0 AND value >= paid @@ -28,11 +36,13 @@ CREATE TABLE Credit ( account NOT NULL, -- Account des Begünstigten date DATE NOT NULL, purpose NOT NULL, -- as originally indicated in statement of bank account + category, value INTEGER NOT NULL, -- Euro-Cent. Caution, two distinct cases need to be considered: -- Either deposit by bank transfer (>0) or target of internal payments (=0) spent INTEGER DEFAULT 0, -- Euro-Cent, set and changed automatically (Cache) -- for later traceability, necessary when revoking transfers FOREIGN KEY (account) REFERENCES Account(ID), + FOREIGN KEY (category) REFERENCES Category(ID), CHECK ( abs(cast(value as integer)) == value AND abs(cast(spent as integer)) == spent AND value >= spent diff --git a/schema/views/03_History.sql b/schema/views/03_History.sql index 698a7fa..a72f14f 100644 --- a/schema/views/03_History.sql +++ b/schema/views/03_History.sql @@ -4,6 +4,7 @@ CREATE VIEW History AS -- internal transfers with account as source SELECT DATE(timestamp) AS date, d.purpose AS purpose, + d.category AS category, d.debtor AS account, t.credId AS credId, t.amount AS debit, @@ -17,6 +18,7 @@ CREATE VIEW History AS UNION SELECT DATE(timestamp) AS date, d.purpose AS purpose, + d.category AS category, c.account AS account, d.targetCredit AS credId, NULL AS debit, diff --git a/schema/views/05_ReconstructedBankStatement.sql b/schema/views/05_ReconstructedBankStatement.sql index ca8c07c..afef37e 100644 --- a/schema/views/05_ReconstructedBankStatement.sql +++ b/schema/views/05_ReconstructedBankStatement.sql @@ -2,6 +2,7 @@ DROP VIEW IF EXISTS ReconstructedBankStatement; CREATE VIEW ReconstructedBankStatement AS SELECT c.date AS date, c.purpose AS purpose, + c.category AS category, account, c.value AS credit, NULL AS debit @@ -12,6 +13,7 @@ CREATE VIEW ReconstructedBankStatement AS UNION SELECT date, purpose, + category AS category, debtor AS account, NULL AS credit, value AS debit diff --git a/t/schema.out b/t/schema.out index b5fbeeb..a20aa92 100644 --- a/t/schema.out +++ b/t/schema.out @@ -9,9 +9,9 @@ john: 0 +0 0 Club: 0 +0 -16250 alex: 7200 +16250 0 # Some updates and deletes that could, unless denied, destroy consistency ... -Error: near line 41: paid is set and adjusted automatically according to added Transfer records -Error: near line 42: Debt is involved in transfers to revoke at first -Error: near line 43: FOREIGN KEY constraint failed +Error: near line 42: paid is set and adjusted automatically according to added Transfer records +Error: near line 43: Debt is involved in transfers to revoke at first +Error: near line 44: FOREIGN KEY constraint failed # After revoking transactions, you are free to change or delete debts and credits ... Club: 7200 +0 0 alex: 0 +0 0 diff --git a/t/schema.sql b/t/schema.sql index 3762307..225d893 100644 --- a/t/schema.sql +++ b/t/schema.sql @@ -4,24 +4,25 @@ PRAGMA recursive_triggers = ON; -- To understand the sql below, see the schema.sql file. INSERT INTO Account VALUES ("Club", "eV", 1, NULL), ("john", "Member", 44, NULL), ("alex", "Member", 6, "DE1234567890123456"); +INSERT INTO Category ("label") VALUES ("Membership fees"), ("Service"); -INSERT INTO Credit VALUES (1, "Club", "2016-01-01", "Membership fees May 2016 until incl. April 2017", 0, 0), - (2, "john", "2016-04-23", "Membership fee 2016f.", 7200, 0), - (3, "alex", "2016-01-15", "Payment for Server Hosting 2016", 0, 0); +INSERT INTO Credit VALUES (1, "Club", "2016-01-01", "Membership fees May 2016 until incl. April 2017", 1, 0, 0), + (2, "john", "2016-04-23", "Membership fee 2016f.", 1, 7200, 0), + (3, "alex", "2016-01-15", "Payment for Server Hosting 2016", 1, 0, 0); -INSERT INTO Debit VALUES ("MB1605-john", "john", 1, "2016-05-01", "Membership fee May 2016", 600, 0), - ("MB1606-john", "john", 1, "2016-05-01", "Membership fee June 2016", 600, 0), - ("MB1607-john", "john", 1, "2016-05-01", "Membership fee July 2016", 600, 0), - ("MB1608-john", "john", 1, "2016-05-01", "Membership fee August 2016", 600, 0), - ("MB1609-john", "john", 1, "2016-05-01", "Membership fee September 2016", 600, 0), - ("MB1610-john", "john", 1, "2016-05-01", "Membership fee October 2016", 600, 0), - ("MB1611-john", "john", 1, "2016-05-01", "Membership fee November 2016", 600, 0), - ("MB1612-john", "john", 1, "2016-05-01", "Membership fee December 2016", 600, 0), - ("MB1701-john", "john", 1, "2016-05-01", "Membership fee January 2017", 600, 0), - ("MB1702-john", "john", 1, "2016-05-01", "Membership fee February 2017", 600, 0), - ("MB1703-john", "john", 1, "2016-05-01", "Membership fee March 2017", 600, 0), - ("MB1704-john", "john", 1, "2016-05-01", "Membership fee April 2017", 600, 0), - ("TWX2016/123", "Club", 3, "2016-01-15", "Server Hosting 2016", 23450, 0); +INSERT INTO Debit VALUES ("MB1605-john", "john", 1, "2016-05-01", "Membership fee May 2016", 1, 600, 0), + ("MB1606-john", "john", 1, "2016-05-01", "Membership fee June 2016", 1, 600, 0), + ("MB1607-john", "john", 1, "2016-05-01", "Membership fee July 2016", 1, 600, 0), + ("MB1608-john", "john", 1, "2016-05-01", "Membership fee August 2016", 1, 600, 0), + ("MB1609-john", "john", 1, "2016-05-01", "Membership fee September 2016", 1, 600, 0), + ("MB1610-john", "john", 1, "2016-05-01", "Membership fee October 2016", 1, 600, 0), + ("MB1611-john", "john", 1, "2016-05-01", "Membership fee November 2016", 1, 600, 0), + ("MB1612-john", "john", 1, "2016-05-01", "Membership fee December 2016", 1, 600, 0), + ("MB1701-john", "john", 1, "2016-05-01", "Membership fee January 2017", 1, 600, 0), + ("MB1702-john", "john", 1, "2016-05-01", "Membership fee February 2017", 1, 600, 0), + ("MB1703-john", "john", 1, "2016-05-01", "Membership fee March 2017", 1, 600, 0), + ("MB1704-john", "john", 1, "2016-05-01", "Membership fee April 2017", 1, 600, 0), + ("TWX2016/123", "Club", 3, "2016-01-15", "Server Hosting 2016", 2, 23450, 0); .separator " " SELECT "ID: availbl promise debt"; diff --git a/templates/account/history.html.ep b/templates/account/history.html.ep index 15aeeee..cbb9da4 100644 --- a/templates/account/history.html.ep +++ b/templates/account/history.html.ep @@ -14,3 +14,5 @@ <%== money $hr->debit %><%== money $hr->credit %><%= $hr->note %> % } + +%= include 'filter-widget' diff --git a/templates/account/list.html.ep b/templates/account/list.html.ep index b51eaa1..39ba6ee 100644 --- a/templates/account/list.html.ep +++ b/templates/account/list.html.ep @@ -7,7 +7,7 @@ % my $inter_header = begin % my $group = shift; <%= $group || 'Club management accounts' %> -Chargeall +Charge all at once % end % while ( my $account = $accounts->next ) { % my $bal = $account->balance; diff --git a/templates/account/transfer.html.ep b/templates/account/transfer.html.ep index 6eb4c56..fcf919a 100644 --- a/templates/account/transfer.html.ep +++ b/templates/account/transfer.html.ep @@ -1,12 +1,12 @@ % title 'Make transfers for ' . $account; -

Check at least one item of each table that belong together.

+

Check at least one item of both tables. Make sure they correspond in regard to their purposes. Caution: When you do not check any items in either table, this effectively is to check all in it!

Available credits

-

Check credits you want to spend for the arrear(s) below with.

+

Check credits you want to spend for the arrear(s) below:

diff --git a/templates/bankStatement.html.ep b/templates/bankStatement.html.ep index 0f9c091..7dbd3cb 100644 --- a/templates/bankStatement.html.ep +++ b/templates/bankStatement.html.ep @@ -10,3 +10,5 @@ % }
?datepurposeto spend
Current balance:<%== $total_debit ? money $total_debit : '' %><%== $total_credit ? money $total_credit : '' %>
+ +%= include 'filter-widget' diff --git a/templates/credit/list.html.ep b/templates/credit/list.html.ep index aaa47f0..661b0b4 100644 --- a/templates/credit/list.html.ep +++ b/templates/credit/list.html.ep @@ -8,3 +8,5 @@ <%= $credit->credId %><%= $credit->date %><%== nl2br $credit->purpose %><%== money $credit->value %>"><%== money $credit->spent %> % } + +%= include 'filter-widget' diff --git a/templates/credit/upsert.html.ep b/templates/credit/upsert.html.ep index 570e86b..23caa30 100644 --- a/templates/credit/upsert.html.ep +++ b/templates/credit/upsert.html.ep @@ -11,6 +11,17 @@ % $r{purpose} = begin % end +% $r{category} = begin +% my $category = $credit->category // ''; + +% end % $r{value} = begin Cent (declare target credit with "0") % end diff --git a/templates/debit/list.html.ep b/templates/debit/list.html.ep index bd527ae..e16948c 100644 --- a/templates/debit/list.html.ep +++ b/templates/debit/list.html.ep @@ -9,3 +9,5 @@ <%= $debit->billId %><%= $debit->date %><%== nl2br $debit->purpose %><%== money $debit->value %>"><%== money $debit->paid %><%= $tgt->account->ID %> % } + +%= include 'filter-widget' diff --git a/templates/debit/upsert.html.ep b/templates/debit/upsert.html.ep index 78096bd..9d1072e 100644 --- a/templates/debit/upsert.html.ep +++ b/templates/debit/upsert.html.ep @@ -14,6 +14,17 @@ % $r{purpose} = begin % end +% $r{category} = begin +% my $category = $debit->category // ''; + +% end % $r{value} = begin Cent % end @@ -42,10 +53,12 @@ oops % end +% if ( !stash 'account' ) { % $r{debtor} = begin % my $g = param 'group'; debtor %>"> % end +% }
% for my $f ( $debit->result_source->columns ) { diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep index 019d218..15885da 100644 --- a/templates/layouts/default.html.ep +++ b/templates/layouts/default.html.ep @@ -39,7 +39,7 @@ % } % if ( defined $sql ) {
-

In case you are interested, this is what is executed in the database in order to process your request and to render this page. All essential logic and consistency checking is done on database level via triggers and views, so you could execute these SQL statements e.g. in the console and would get the same results. Note that, if any POST requests redirected here, SQL commands of those come first:

+

Please note that, to run the SQL commands directly in another tool, you might need to resolve the prepared statements manually. Just replace all question marks by the values listed after the colon in each line.