Merge pull request #98 from Pear-Trading/finn/categorylist
Category budget view added with test
This commit is contained in:
commit
9f3971815e
7 changed files with 237 additions and 1 deletions
|
@ -149,6 +149,7 @@ sub startup {
|
|||
$api->post('/user/account')->to('api-user#post_account_update');
|
||||
$api->post('/user-history')->to('api-user#post_user_history');
|
||||
$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/leaderboard')->to('api-stats#post_leaderboards');
|
||||
$api->post('/stats/leaderboard/paged')->to('api-stats#post_leaderboards_paged');
|
||||
|
|
|
@ -57,6 +57,7 @@ sub read {
|
|||
sub update {
|
||||
my $c = shift;
|
||||
my $validation = $c->validation;
|
||||
$validation->required('id');
|
||||
$validation->required('category', 'trim')->like(qr/^[\w]*$/);
|
||||
|
||||
my $id = $c->param('id');
|
||||
|
@ -67,10 +68,11 @@ sub update {
|
|||
$c->redirect_to( '/admin/categories/' . $id );
|
||||
} elsif ( my $category = $c->result_set->find($id) ) {
|
||||
$category->update({
|
||||
id => $validation->param('id'),
|
||||
name => $validation->param('category'),
|
||||
});
|
||||
$c->flash( success => 'Category Updated' );
|
||||
$c->redirect_to( '/admin/categories/' . $id );
|
||||
$c->redirect_to( '/admin/categories/' . $validation->param('id') );
|
||||
} else {
|
||||
$c->flash( error => 'No Category found' );
|
||||
$c->redirect_to( '/admin/categories' );
|
||||
|
|
78
lib/Pear/LocalLoop/Controller/Api/Categories.pm
Normal file
78
lib/Pear/LocalLoop/Controller/Api/Categories.pm
Normal 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;
|
|
@ -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;
|
|
@ -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
98
t/api/categories.t
Normal 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;
|
|
@ -16,6 +16,11 @@
|
|||
<label for="category-name">Token Name</label>
|
||||
<input id="category-name" type="text" class="form-control" placeholder="Token Text" name="category" value="<%= $category->name %>">
|
||||
</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">
|
||||
<button class="btn btn-primary form-control" type="submit">Update</button>
|
||||
</div>
|
||||
|
|
Reference in a new issue