From 9e127b8851ae2f8a9c3323098a56fb1595d6d6ad Mon Sep 17 00:00:00 2001 From: Tom Bloor Date: Mon, 2 Oct 2017 14:08:24 +0100 Subject: [PATCH] Finalised Transaction report graph and test --- .../LocalLoop/Controller/Admin/Reports.pm | 27 +++- .../Result/ViewQuantisedTransactionPg.pm | 9 ++ t/admin/reports/transactions.t | 141 ++++++++++++++++++ 3 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 t/admin/reports/transactions.t diff --git a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm index 94351d6..aff6bc9 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Reports.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Reports.pm @@ -20,19 +20,19 @@ sub transaction_data { quantised => $quantised_column, count => \"COUNT(*)", sum_distance => $c->pg_or_sqlite( - '', + 'SUM("me"."distance")', 'SUM("me"."distance")', ), average_distance => $c->pg_or_sqlite( - '', + 'AVG("me"."distance")', 'AVG("me"."distance")', ), sum_value => $c->pg_or_sqlite( - '', + 'SUM("me"."value")', 'SUM("me"."value")', ), average_value => $c->pg_or_sqlite( - '', + 'AVG("me"."value")', 'AVG("me"."value")', ), } @@ -42,10 +42,23 @@ sub transaction_data { } ); - $transaction_rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); + my $transaction_data = [ + map{ + my $quantised = $c->db_datetime_parser->parse_datetime($_->get_column('quantised')); + { + sum_value => ($_->get_column('sum_value') || 0) * 1, + sum_distance => ($_->get_column('sum_distance') || 0) * 1, + average_value => ($_->get_column('average_value') || 0) * 1, + average_distance => ($_->get_column('average_distance') || 0) * 1, + count => $_->get_column('count'), + quantised => $c->format_iso_datetime($quantised), + } + } $transaction_rs->all + ]; - $c->stash( - transaction_rs => encode_json( [$transaction_rs->all] ), + $c->respond_to( + json => { json => { data => $transaction_data } }, + html => { transaction_rs => encode_json( $transaction_data ) }, ); } diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm index adfcd7a..fabbd38 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionPg.pm @@ -9,4 +9,13 @@ __PACKAGE__->table_class('DBIx::Class::ResultSource::View'); __PACKAGE__->table('view_quantised_transactions'); __PACKAGE__->result_source_instance->is_virtual(1); +__PACKAGE__->result_source_instance->view_definition( qq/ +SELECT "value", + "distance", + "purchase_time", + DATE_TRUNC('hour', "purchase_time") AS "quantised_hours", + DATE_TRUNC('day', "purchase_time") AS "quantised_days" + FROM "transactions" +/); + 1; diff --git a/t/admin/reports/transactions.t b/t/admin/reports/transactions.t new file mode 100644 index 0000000..8269c5c --- /dev/null +++ b/t/admin/reports/transactions.t @@ -0,0 +1,141 @@ +use Mojo::Base -strict; + +use FindBin qw/ $Bin /; + +use Test::More; +use Test::Pear::LocalLoop; +use DateTime; + +my $framework = Test::Pear::LocalLoop->new( + etc_dir => "$Bin/../../etc", +); +$framework->install_fixtures('full'); +my $t = $framework->framework; +my $schema = $t->app->schema; + +my $dt_today = DateTime->today; +my $dt_start = $dt_today->clone->subtract( 'minutes' => 30 ); + +use Devel::Dwarn; + +my $session_key = $framework->login({ + email => 'test1@example.com', + password => 'abc123', +}); + +sub create_transaction { + my ( $value, $time ) = @_; + $t->ua->post('/api/upload' => json => { + transaction_value => $value, + transaction_type => 1, + purchase_time => $time, + organisation_id => 1, + session_key => $session_key, + }); +} + +my $expected_days = {}; +my $expected_hours = {}; + +sub increment_day { + my ( $value, $day, $distance ) = @_; + $value *= 100000; + $distance //= 0; + $expected_days->{$day} = { + quantised => $day, + sum_value => ($expected_days->{$day}->{sum_value} || 0) + $value, + sum_distance => ($expected_days->{$day}->{sum_distance} || 0) + $distance, + count => ++$expected_days->{$day}->{count}, + }; +} + +sub increment_hour { + my ( $value, $day, $distance ) = @_; + $value *= 100000; + $distance //= 0; + $expected_hours->{$day} = { + quantised => $day, + sum_value => ($expected_hours->{$day}->{sum_value} || 0) + $value, + sum_distance => ($expected_hours->{$day}->{sum_distance} || 0) + $distance, + count => ++$expected_hours->{$day}->{count}, + }; +} + +for my $i ( 0 .. 48 ) { + my $dt = $dt_start->clone->subtract( 'minutes' => 60 * $i ); + my $purchase_time = $t->app->format_iso_datetime($dt); + my $quantised_day = $t->app->format_iso_datetime($dt->clone->truncate(to => 'day')); + my $quantised_hour = $t->app->format_iso_datetime($dt->clone->truncate(to => 'hour')); + create_transaction(10, $purchase_time); + increment_day(10, $quantised_day); + increment_hour(10, $quantised_hour); + if ( $i % 2 == 0 ) { + create_transaction(20, $purchase_time); + increment_day(20, $quantised_day); + increment_hour(20, $quantised_hour); + } + if ( $i % 3 == 0 ) { + create_transaction(30, $purchase_time); + increment_day(30, $quantised_day); + increment_hour(30, $quantised_hour); + } + if ( $i % 5 == 0 ) { + create_transaction(50, $purchase_time); + increment_day(50, $quantised_day); + increment_hour(50, $quantised_hour); + } + if ( $i % 7 == 0 ) { + create_transaction(70, $purchase_time); + increment_day(70, $quantised_day); + increment_hour(70, $quantised_hour); + } +} + +my $expected_days_array = [ map { + my $data = $expected_days->{$_}; + { + quantised => $data->{quantised}, + count => $data->{count}, + sum_value => $data->{sum_value}, + sum_distance => $data->{sum_distance}, + average_value => $data->{sum_value} / $data->{count}, + average_distance => $data->{sum_distance} / $data->{count}, + } +} sort keys %$expected_days ]; + +my $expected_hours_array = [ map { + my $data = $expected_hours->{$_}; + { + quantised => $data->{quantised}, + count => $data->{count}, + sum_value => $data->{sum_value}, + sum_distance => $data->{sum_distance}, + average_value => $data->{sum_value} / $data->{count}, + average_distance => $data->{sum_distance} / $data->{count}, + } +} sort keys %$expected_hours ]; + +is $t->app->schema->resultset('Transaction')->count, 108, 'Transactions created'; + +#login to admin +$t->post_ok('/admin', form => { + email => 'admin@example.com', + password => 'abc123', +})->status_is(302); + +$t->get_ok( + '/admin/reports/transactions', + { Accept => 'application/json' } + ) + ->status_is(200) + ->json_is('/data', $expected_hours_array)->or($framework->dump_error); + +$t->get_ok( + '/admin/reports/transactions', + { Accept => 'application/json' }, + form => { scale => 'days' } + ) + ->status_is(200) + ->json_is('/data', $expected_days_array)->or($framework->dump_error); + +done_testing;