Merge pull request #98 from Pear-Trading/finn/categorylist

Category budget view added with test
This commit is contained in:
Finn 2018-01-25 16:22:45 +00:00 committed by GitHub
commit 9f3971815e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 237 additions and 1 deletions

View file

@ -149,6 +149,7 @@ sub startup {
$api->post('/user/account')->to('api-user#post_account_update'); $api->post('/user/account')->to('api-user#post_account_update');
$api->post('/user-history')->to('api-user#post_user_history'); $api->post('/user-history')->to('api-user#post_user_history');
$api->post('/stats')->to('api-stats#post_index'); $api->post('/stats')->to('api-stats#post_index');
$api->post('/stats/category')->to('api-categories#post_category_list');
$api->post('/stats/customer')->to('api-stats#post_customer'); $api->post('/stats/customer')->to('api-stats#post_customer');
$api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards');
$api->post('/stats/leaderboard/paged')->to('api-stats#post_leaderboards_paged'); $api->post('/stats/leaderboard/paged')->to('api-stats#post_leaderboards_paged');

View file

@ -57,6 +57,7 @@ sub read {
sub update { sub update {
my $c = shift; my $c = shift;
my $validation = $c->validation; my $validation = $c->validation;
$validation->required('id');
$validation->required('category', 'trim')->like(qr/^[\w]*$/); $validation->required('category', 'trim')->like(qr/^[\w]*$/);
my $id = $c->param('id'); my $id = $c->param('id');
@ -67,10 +68,11 @@ sub update {
$c->redirect_to( '/admin/categories/' . $id ); $c->redirect_to( '/admin/categories/' . $id );
} elsif ( my $category = $c->result_set->find($id) ) { } elsif ( my $category = $c->result_set->find($id) ) {
$category->update({ $category->update({
id => $validation->param('id'),
name => $validation->param('category'), name => $validation->param('category'),
}); });
$c->flash( success => 'Category Updated' ); $c->flash( success => 'Category Updated' );
$c->redirect_to( '/admin/categories/' . $id ); $c->redirect_to( '/admin/categories/' . $validation->param('id') );
} else { } else {
$c->flash( error => 'No Category found' ); $c->flash( error => 'No Category found' );
$c->redirect_to( '/admin/categories' ); $c->redirect_to( '/admin/categories' );

View file

@ -0,0 +1,78 @@
package Pear::LocalLoop::Controller::Api::Categories;
use Mojo::Base 'Mojolicious::Controller';
use List::Util qw/ max /;
sub post_category_list {
my $c = shift;
my $entity = $c->stash->{api_user}->entity;
my $duration = DateTime::Duration->new( days => 28 );
my $end = DateTime->today;
my $start = $end->clone->subtract_duration( $duration );
my $dtf = $c->schema->storage->datetime_parser;
my $driver = $c->schema->storage->dbh->{Driver}->{Name};
my $month_transaction_rs = $c->schema->resultset('ViewQuantisedTransactionCategory' . $driver)->search(
{
purchase_time => {
-between => [
$dtf->format_datetime($start),
$dtf->format_datetime($end),
],
},
buyer_id => $entity->id,
},
{
columns => [
{
quantised => 'quantised_weeks',
value => 'value',
category_id => 'category_id',
}
],
group_by => [ qw/ category_id quantised_weeks / ],
order_by => { '-desc' => 'quantised_weeks' },
}
);
my $data = {};
for ( $month_transaction_rs->all ) {
my $quantised = $c->db_datetime_parser->parse_datetime($_->get_column('quantised'));
my $days = $c->format_iso_date( $quantised ) || 0;
my $category = $_->get_column('category_id') || 0;
my $value = ($_->get_column('value') || 0) / 100000;
$data->{$days} = [] unless exists $data->{$days};
push @{ $data->{$days} }, {
days => $days,
value => $value,
category => $category,
};
}
return $c->render(
json => {
success => Mojo::JSON->true,
data => $data,
}
);
}
sub pg_or_sqlite {
my ( $c, $pg_sql, $sqlite_sql ) = @_;
my $driver = $c->schema->storage->dbh->{Driver}->{Name};
if ( $driver eq 'Pg' ) {
return \$pg_sql;
} elsif ( $driver eq 'SQLite' ) {
return \$sqlite_sql;
} else {
$c->app->log->warn('Unknown Driver Used');
return undef;
}
}
1;

View file

@ -0,0 +1,26 @@
package Pear::LocalLoop::Schema::Result::ViewQuantisedTransactionCategoryPg;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__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 "transactions.value",
"transactions.distance",
"transactions.purchase_time",
"transactions.buyer_id",
"transactions.seller_id",
"transaction_category.category_id",
DATE_TRUNC('hour', "transactions.purchase_time") AS "quantised_hours",
DATE_TRUNC('day', "transactions.purchase_time") AS "quantised_days",
DATE_TRUNC('week', "transactions.purchase_time") AS "quantised_weeks"
FROM "transactions"
LEFT JOIN "transaction_category" ON "transactions.id" = "transaction_category.transaction_id"
/);
1;

View file

@ -0,0 +1,26 @@
package Pear::LocalLoop::Schema::Result::ViewQuantisedTransactionCategorySQLite;
use strict;
use warnings;
use base 'DBIx::Class::Core';
__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 "transactions"."value",
"transactions"."distance",
"transactions"."purchase_time",
"transactions"."buyer_id",
"transactions"."seller_id",
"transaction_category"."category_id",
DATETIME(STRFTIME('%Y-%m-%d %H:00:00',"transactions"."purchase_time")) AS "quantised_hours",
DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"transactions"."purchase_time")) AS "quantised_days",
DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"transactions"."purchase_time", 'weekday 1')) AS "quantised_weeks"
FROM "transactions"
LEFT JOIN "transaction_category" ON "transactions"."id" = "transaction_category"."transaction_id"
/);
1;

98
t/api/categories.t Normal file
View file

@ -0,0 +1,98 @@
use Mojo::Base -strict;
BEGIN {
use Test::MockTime qw/ set_absolute_time /;
}
use FindBin qw/ $Bin /;
use Test::More;
use Mojo::JSON;
use Test::Pear::LocalLoop;
use DateTime;
my $framework = Test::Pear::LocalLoop->new(
etc_dir => "$Bin/../etc",
);
$framework->install_fixtures('users');
my $t = $framework->framework;
my $schema = $t->app->schema;
set_absolute_time('2017-01-02T00:00:00Z');
my $start = DateTime->today->subtract( hours => 12 );
# create 40 days worth of data
for my $count ( 0 .. 28 ) {
my $trans_day = $start->clone->subtract( days => $count );
create_random_transaction( 'test1@example.com', $trans_day );
if ( $count % 2 ) {
create_random_transaction( 'test1@example.com', $trans_day );
}
if ( $count % 3 ) {
create_random_transaction( 'test1@example.com', $trans_day );
}
if ( $count % 4 ) {
create_random_transaction( 'test1@example.com', $trans_day );
}
}
my $session_key = $framework->login({
email => 'test1@example.com',
password => 'abc123',
});
$t->post_ok('/api/stats/category' => json => {
session_key => $session_key,
})
->status_is(200)->or($framework->dump_error)
->json_is('/data', {
"2016-12-05" => [{
days => "2016-12-05",
value => 10,
category => 1,
}],
"2016-12-12" => [{
days => "2016-12-12",
value => 10,
category => 1,
}],
"2016-12-19" => [{
days => "2016-12-19",
value => 10,
category => 1,
}],
"2016-12-26" => [{
days => "2016-12-26",
value => 10,
category => 1,
}],
"2017-01-02" => [{
days => "2017-01-02",
value => 10,
category => 1,
}]
})->or($framework->dump_error);
sub create_random_transaction {
my $buyer = shift;
my $time = shift;
my $buyer_result = $schema->resultset('User')->find({ email => $buyer })->entity;
my $seller_result = $schema->resultset('Organisation')->find({ name => 'Test Org' })->entity;
my $test_transaction = $schema->resultset('Transaction')->create({
buyer => $buyer_result,
seller => $seller_result,
value => 10 * 100000,
proof_image => 'a',
purchase_time => $time,
});
$schema->resultset('TransactionCategory')->create({
category_id => 1,
transaction_id => $test_transaction->id,
});
}
done_testing;

View file

@ -16,6 +16,11 @@
<label for="category-name">Token Name</label> <label for="category-name">Token Name</label>
<input id="category-name" type="text" class="form-control" placeholder="Token Text" name="category" value="<%= $category->name %>"> <input id="category-name" type="text" class="form-control" placeholder="Token Text" name="category" value="<%= $category->name %>">
</div> </div>
<div class="form-group">
<label for="category-id">Token ID</label>
<input id="category-id" type="text" class="form-control" placeholder="Token ID" name="id" value="<%= $category->id %>">
<p class="help-block">Do not change the ID unless <strong>absolutely</strong> necessary.</p>
</div>
<div class="form-group"> <div class="form-group">
<button class="btn btn-primary form-control" type="submit">Update</button> <button class="btn btn-primary form-control" type="submit">Update</button>
</div> </div>