From 0cb3426825c006c870ef144bcd69759e061075ff Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 13 Mar 2018 12:55:13 +0000 Subject: [PATCH 01/27] amended upload to allow for validation changes --- .../LocalLoop/Controller/Api/Transactions.pm | 19 ++++++++++++++++++- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 6 +++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index 4a0ae8c..9273c2d 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -30,7 +30,11 @@ sub post_transaction_list_purchases { }, ); -# purchase_time needs timezone attached to it + my $recurring_transactions = $c->schema->resultset('TransactionRecurring')->search({ + buyer_id => $user->id, + }); + + # purchase_time needs timezone attached to it my @transaction_list = ( map {{ seller => $_->seller->name, @@ -39,9 +43,22 @@ sub post_transaction_list_purchases { }} $transactions->all ); + my @recurring_transaction_list = ( + map {{ + seller => $_->seller->name, + value => $_->value / 100000, + start_time => $c->format_iso_datetime($_->start_time), + last_updated => $c->format_iso_datetime($_->last_updated), + essential => $_->essential, + category => $_->category->category->name, + recurring_period => $_->recurring_period, + }} $recurring_transactions->all + ); + return $c->render( json => { success => Mojo::JSON->true, transactions => \@transaction_list, + recurring_transactions => \@recurring_transaction_list, page_no => $transactions->pager->total_entries, }); } diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index dea5678..61f1d2b 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -147,7 +147,7 @@ sub post_upload { # Unknown Organisation $validation->required('organisation_name'); $validation->optional('street_name'); - $validation->required('town'); + $validation->optional('town'); $validation->optional('postcode')->postcode; return $c->api_validation_error if $validation->has_error; @@ -198,7 +198,7 @@ sub post_upload { ( defined $file ? ( proof_image => $file ) : () ), purchase_time => $c->format_db_datetime($purchase_time), essential => ( defined $essential ? $essential : 0 ), - distance => $distance, + distance => ( defined $category ? $category : undef ), } ); @@ -227,7 +227,7 @@ sub post_upload { value => $transaction_value * 100000, start_time => $c->format_db_datetime($purchase_time), essential => ( defined $essential ? $essential : 0 ), - distance => $distance, + distance => ( defined $category ? $category : undef ), category_id => ( defined $category ? $category : undef ), recurring_period => $recurring_period, }); From d5e03cc9e3ac1ac4a25662941f0409aeee8c0f97 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 14 Mar 2018 17:55:24 +0000 Subject: [PATCH 02/27] amended api for recurring transaction list --- lib/Pear/LocalLoop/Controller/Api/Transactions.pm | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index 9273c2d..8f4f2d0 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -45,12 +45,13 @@ sub post_transaction_list_purchases { my @recurring_transaction_list = ( map {{ + id => $_->id, seller => $_->seller->name, value => $_->value / 100000, start_time => $c->format_iso_datetime($_->start_time), last_updated => $c->format_iso_datetime($_->last_updated), essential => $_->essential, - category => $_->category->category->name, + category => ( defined $_->category ? $_->category->name : 'Uncategorised' ), recurring_period => $_->recurring_period, }} $recurring_transactions->all ); @@ -63,4 +64,16 @@ sub post_transaction_list_purchases { }); } +sub update_recurring { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + + $validation->input( $c->stash->{api_json} ); + #TODO check that user matches seller on database before updating for that id + +} + 1; From 551a40a9a03924dc11e79b0c613c4da1e70d9c73 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 14 Mar 2018 19:38:05 +0000 Subject: [PATCH 03/27] fixed critical bugs introduced earlier and changed category viewing --- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 22 ++++++++++++--------- lib/Pear/LocalLoop/Plugin/Datetime.pm | 1 + 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 61f1d2b..dea1f10 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -198,7 +198,7 @@ sub post_upload { ( defined $file ? ( proof_image => $file ) : () ), purchase_time => $c->format_db_datetime($purchase_time), essential => ( defined $essential ? $essential : 0 ), - distance => ( defined $category ? $category : undef ), + distance => $distance, } ); @@ -227,7 +227,7 @@ sub post_upload { value => $transaction_value * 100000, start_time => $c->format_db_datetime($purchase_time), essential => ( defined $essential ? $essential : 0 ), - distance => ( defined $category ? $category : undef ), + distance => $distance, category_id => ( defined $category ? $category : undef ), recurring_period => $recurring_period, }); @@ -243,18 +243,22 @@ sub post_category { my $c = shift; my $self = $c; - my $categories = { ids => [], names => [] }; - my $category_rs = $c->schema->resultset('Category'); - for ( $category_rs->all ) { - push @{ $categories->{ ids } }, $_->get_column('id'); - push @{ $categories->{ names } }, $_->get_column('name'); - } + # for ( $category_rs->all ) { + # push @{ $categories->{ ids } }, $_->get_column('id'); + # push @{ $categories->{ names } }, $_->get_column('name'); + # } + my @category_list = ( + map {{ + id => $_->id, + name => $_->name, + }} $category_rs->all + ); return $self->render( json => { success => Mojo::JSON->true, - categories => $categories, + categories => \@category_list, }); } diff --git a/lib/Pear/LocalLoop/Plugin/Datetime.pm b/lib/Pear/LocalLoop/Plugin/Datetime.pm index 1f79e45..c6f2e55 100644 --- a/lib/Pear/LocalLoop/Plugin/Datetime.pm +++ b/lib/Pear/LocalLoop/Plugin/Datetime.pm @@ -66,6 +66,7 @@ sub register { $app->helper( format_iso_datetime => sub { my ( $c, $datetime_obj ) = @_; + return unless defined $datetime_obj; return $c->iso_datetime_parser->format_datetime( $datetime_obj, ); From 60438ea51c4a6781e076bd8043153842b31db451 Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 15 Mar 2018 13:06:50 +0000 Subject: [PATCH 04/27] amended transactionlist code --- lib/Pear/LocalLoop/Controller/Api/Transactions.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index 8f4f2d0..a2458d6 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -42,16 +42,16 @@ sub post_transaction_list_purchases { purchase_time => $c->format_iso_datetime($_->purchase_time), }} $transactions->all ); - + my @recurring_transaction_list = ( map {{ id => $_->id, seller => $_->seller->name, value => $_->value / 100000, start_time => $c->format_iso_datetime($_->start_time), - last_updated => $c->format_iso_datetime($_->last_updated), + last_updated => $c->format_iso_datetime($_->last_updated) || undef, essential => $_->essential, - category => ( defined $_->category ? $_->category->name : 'Uncategorised' ), + category => $_->category_id, recurring_period => $_->recurring_period, }} $recurring_transactions->all ); From 97462df1a27cf38fae6338b56bd4038f06acd023 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 19 Mar 2018 13:36:51 +0000 Subject: [PATCH 05/27] Fix to add org submission --- templates/admin/organisations/add_org.html.ep | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/admin/organisations/add_org.html.ep b/templates/admin/organisations/add_org.html.ep index 7a964a8..427d12d 100644 --- a/templates/admin/organisations/add_org.html.ep +++ b/templates/admin/organisations/add_org.html.ep @@ -59,8 +59,8 @@
@@ -68,8 +68,8 @@
From 2cf0678126bd5d3285a33eac90e772ee054cdf3b Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 20 Mar 2018 12:19:04 +0000 Subject: [PATCH 06/27] fixed to category viewing and recurring transaction data --- lib/Pear/LocalLoop/Controller/Api/Categories.pm | 2 +- lib/Pear/LocalLoop/Controller/Api/Transactions.pm | 4 ++-- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 11 +++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Categories.pm b/lib/Pear/LocalLoop/Controller/Api/Categories.pm index 9913f42..95f9db5 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Categories.pm @@ -43,7 +43,7 @@ sub post_category_list { for my $cat_trans ( $month_transaction_category_rs->all ) { my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); my $days = $c->format_iso_date( $quantised ) || 0; - my $category = $cat_trans->get_column('category_id') || 0; + my $category = $cat_trans->get_column('category_id') || undef; my $value = ($cat_trans->get_column('value') || 0) / 100000; $data->{categories}->{$days} = [] unless exists $data->{categories}->{$days}; push @{ $data->{categories}->{$days} }, { diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index a2458d6..e5bbc94 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -42,7 +42,7 @@ sub post_transaction_list_purchases { purchase_time => $c->format_iso_datetime($_->purchase_time), }} $transactions->all ); - + my @recurring_transaction_list = ( map {{ id => $_->id, @@ -51,7 +51,7 @@ sub post_transaction_list_purchases { start_time => $c->format_iso_datetime($_->start_time), last_updated => $c->format_iso_datetime($_->last_updated) || undef, essential => $_->essential, - category => $_->category_id, + category => $_->category_id || 0, recurring_period => $_->recurring_period, }} $recurring_transactions->all ); diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index dea1f10..31fa234 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -249,16 +249,15 @@ sub post_category { # push @{ $categories->{ ids } }, $_->get_column('id'); # push @{ $categories->{ names } }, $_->get_column('name'); # } - my @category_list = ( - map {{ - id => $_->id, - name => $_->name, - }} $category_rs->all + my %category_list = ( + map { + $_->id => $_->name, + } $category_rs->all ); return $self->render( json => { success => Mojo::JSON->true, - categories => \@category_list, + categories => \%category_list, }); } From 73d44feaced188add64c128154d1c4d2ac782360 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 20 Mar 2018 18:43:00 +0000 Subject: [PATCH 07/27] added deleting and updating transactions --- lib/Pear/LocalLoop.pm | 2 + .../LocalLoop/Controller/Api/Transactions.pm | 94 ++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 5bd5e26..c996567 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -154,6 +154,8 @@ sub startup { $api->post('/stats/leaderboard')->to('api-stats#post_leaderboards'); $api->post('/stats/leaderboard/paged')->to('api-stats#post_leaderboards_paged'); $api->post('/outgoing-transactions')->to('api-transactions#post_transaction_list_purchases'); + $api->post('/recurring-transactions')->to('api-transactions#update_recurring'); + $api->post('/recurring-transactions/delete')->to('api-transactions#delete_recurring'); my $api_v1 = $api->under('/v1'); diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index e5bbc94..e2c4c18 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -8,6 +8,21 @@ has error_messages => sub { required => { message => 'No email sent.', status => 400 }, email => { message => 'Email is invalid.', status => 400 }, }, + value => { + required => { message => 'transaction amount is missing', status => 400 }, + number => { message => 'transaction amount does not look like a number', status => 400 }, + gt_num => { message => 'transaction amount cannot be equal to or less than zero', status => 400 }, + }, + apply_time => { + required => { message => 'purchase time is missing', status => 400 }, + is_full_iso_datetime => { message => 'time is in incorrect format', status => 400 }, + }, + id => { + required => { message => 'Recurring Transaction not found', status => 400 }, + }, + category => { + in_resultset => { message => 'Category is invalid', status => 400 }, + }, }; }; @@ -70,9 +85,84 @@ sub update_recurring { my $user = $c->stash->{api_user}; my $validation = $c->validation; - $validation->input( $c->stash->{api_json} ); - #TODO check that user matches seller on database before updating for that id + $validation->required('id'); + + return $c->api_validation_error if $validation->has_error; + + my $id = $validation->param('id'); + + my $recur_transaction = $c->schema->resultset('TransactionRecurring')->find($id); + unless ( $recur_transaction ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Error Finding Recurring Transaction', + error => 'recurring_error', + }, + status => 400, + ); + } + + $validation->required('recurring_period'); + $validation->required('apply_time')->is_full_iso_datetime; + $validation->optional('category')->in_resultset( 'id', $c->schema->resultset('Category')); + $validation->optional('essential'); + $validation->required('value'); + + return $c->api_validation_error if $validation->has_error; + + my $apply_time = $c->parse_iso_datetime($validation->param('apply_time')); + + $c->schema->storage->txn_do( sub { + $recur_transaction->update({ + start_time => $c->format_db_datetime($apply_time), + last_updated => undef, + category_id => $validation->param('category'), + essential => $validation->param('essential'), + value => $validation->param('value') * 100000, + recurring_period => $validation->param('recurring_period'), + }); + }); + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Recurring Transaction Updated Successfully', + }); + +} + +sub delete_recurring { + my $c = shift; + + my $user = $c->stash->{api_user}; + + my $validation = $c->validation; + $validation->input( $c->stash->{api_json} ); + $validation->required('id'); + + return $c->api_validation_error if $validation->has_error; + + my $id = $validation->param('id'); + + my $recur_transaction = $c->schema->resultset('TransactionRecurring')->find($id); + unless ( $recur_transaction ) { + return $c->render( + json => { + success => Mojo::JSON->false, + message => 'Error Finding Recurring Transaction', + error => 'recurring_error', + }, + status => 400, + ); + } + + $recur_transaction->delete; + + return $c->render( json => { + success => Mojo::JSON->true, + message => 'Recurring Transaction Delete Successfully', + }); } From 49e5e9186066bae76d461e946f64f09ab35f07f7 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 20 Mar 2018 18:46:50 +0000 Subject: [PATCH 08/27] made tests sane --- lib/Test/Pear/LocalLoop.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Test/Pear/LocalLoop.pm b/lib/Test/Pear/LocalLoop.pm index 490aa1a..deffc44 100644 --- a/lib/Test/Pear/LocalLoop.pm +++ b/lib/Test/Pear/LocalLoop.pm @@ -114,6 +114,8 @@ sub dump_error { my $self = shift; if ( my $error = $self->tx->res->dom->at('pre[id="error"]') ) { diag $error->text; + } elsif ( my $route_error = $self->tx->res->dom->at('div[id="routes"] > p') ) { + diag $route_error->content; } else { diag $self->tx->res->to_string; } From 4ff3f07f9ad85d80c7b3343fc9cb55b922699d5b Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 20 Mar 2018 18:54:55 +0000 Subject: [PATCH 09/27] fixed transaction test for updating and deleting --- .../LocalLoop/Controller/Api/Transactions.pm | 2 +- t/api/transactions.t | 40 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm index e2c4c18..84bb0da 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Transactions.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Transactions.pm @@ -161,7 +161,7 @@ sub delete_recurring { return $c->render( json => { success => Mojo::JSON->true, - message => 'Recurring Transaction Delete Successfully', + message => 'Recurring Transaction Deleted Successfully', }); } diff --git a/t/api/transactions.t b/t/api/transactions.t index 849a2a8..1cd62f4 100644 --- a/t/api/transactions.t +++ b/t/api/transactions.t @@ -38,8 +38,6 @@ my $session_key = $framework->login({ password => 'abc123', }); -use Data::Dumper; - $t->post_ok('/api/outgoing-transactions' => json => { session_key => $session_key, }) @@ -50,6 +48,36 @@ $t->post_ok('/api/outgoing-transactions' => json => { ->json_has('/transactions/1/value') ->json_has('/transactions/1/purchase_time'); +my $test_purchase_time = "2017-08-14T11:29:07.965+01:00"; + +$t->post_ok('/api/recurring-transactions' => json => { + session_key => $session_key, + id => 1, + apply_time => $test_purchase_time, + essential => "false", + value => 5, + recurring_period => 'daily', + }) + ->status_is(200)->or($framework->dump_error) + ->json_is({ + success => Mojo::JSON->true, + message => 'Recurring Transaction Updated Successfully', + }); + +is $schema->resultset('TransactionRecurring')->count, 87; + +$t->post_ok('/api/recurring-transactions/delete' => json => { + session_key => $session_key, + id => 1, + }) + ->status_is(200)->or($framework->dump_error) + ->json_is({ + success => Mojo::JSON->true, + message => 'Recurring Transaction Deleted Successfully', + }); + +is $schema->resultset('TransactionRecurring')->count, 86; + sub create_random_transaction { my $buyer = shift; @@ -64,6 +92,14 @@ sub create_random_transaction { proof_image => 'a', purchase_time => $time, }); + $schema->resultset('TransactionRecurring')->create({ + buyer => $buyer_result, + seller => $seller_result, + value => 10, + start_time => $time, + essential => 1, + recurring_period => 'weekly', + }); } done_testing; From fb60ba4c0fe2c106e227c3399d37081d450835e6 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 20 Mar 2018 19:24:04 +0000 Subject: [PATCH 10/27] Amended changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f712caa..64eafb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ # Next Release +# v0.10.6 + +* Fixed organisation submission +* Changed category listing code +* Made transaction upload code more lenient +* Added API ability to edit and delete transactions +* Added test for above +* Made test dumping more sane + # v0.10.5 * **Admin Feature** Removed generic Transaction List, replaced with a new From 6527d1e36c36581eef2a12900694a36c3faeecbe Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 21 Mar 2018 15:52:00 +0000 Subject: [PATCH 11/27] fixed category list on postgres --- CHANGELOG.md | 1 + .../LocalLoop/Controller/Api/Categories.pm | 4 ++-- .../ViewQuantisedTransactionCategoryPg.pm | 22 +++++++++--------- .../ViewQuantisedTransactionCategorySQLite.pm | 2 +- t/api/categories.t | 23 +++++++++---------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64eafb4..f51a1fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Added API ability to edit and delete transactions * Added test for above * Made test dumping more sane +* Fixed category view on postgres # v0.10.5 diff --git a/lib/Pear/LocalLoop/Controller/Api/Categories.pm b/lib/Pear/LocalLoop/Controller/Api/Categories.pm index 95f9db5..ed5b0c1 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Categories.pm @@ -31,9 +31,9 @@ sub post_category_list { value => { sum => 'value' }, category_id => 'category_id', essential => 'essential', - } + }, ], - group_by => [ qw/ category_id quantised_weeks / ], + group_by => [ qw/ category_id quantised_weeks essential value / ], order_by => { '-desc' => 'value' }, } ); diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm index b288c65..0d2739b 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategoryPg.pm @@ -10,18 +10,18 @@ __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", - "transactions.essential", - "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" +SELECT "transactions"."value", + "transactions"."distance", + "transactions"."purchase_time", + "transactions"."buyer_id", + "transactions"."seller_id", + "transactions"."essential", + "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" +LEFT JOIN "transaction_category" ON "transactions"."id" = "transaction_category"."transaction_id" /); 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm index 7992458..958ea59 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionCategorySQLite.pm @@ -19,7 +19,7 @@ SELECT "transactions"."value", "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" + DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"transactions"."purchase_time", 'weekday 0','-6 days')) AS "quantised_weeks" FROM "transactions" LEFT JOIN "transaction_category" ON "transactions"."id" = "transaction_category"."transaction_id" /); diff --git a/t/api/categories.t b/t/api/categories.t index 0f48620..10d11ab 100644 --- a/t/api/categories.t +++ b/t/api/categories.t @@ -19,6 +19,11 @@ $framework->install_fixtures('users'); my $t = $framework->framework; my $schema = $t->app->schema; +$schema->resultset('Category')->create({ + id => 1, + name => 'test', +}); + set_absolute_time('2017-01-02T00:00:00Z'); my $start = DateTime->today->subtract( hours => 12 ); @@ -52,7 +57,7 @@ $t->post_ok('/api/stats/category' => json => { categories => { "2016-12-05" => [{ days => "2016-12-05", - value => 30, + value => 210, category => 1, }], "2016-12-12" => [{ @@ -62,7 +67,7 @@ $t->post_ok('/api/stats/category' => json => { }], "2016-12-19" => [{ days => "2016-12-19", - value => 220, + value => 210, category => 1, }], "2016-12-26" => [{ @@ -70,28 +75,20 @@ $t->post_ok('/api/stats/category' => json => { value => 190, category => 1, }], - "2017-01-02" => [{ - days => "2017-01-02", - value => 170, - category => 1, - }], }, essentials => { "2016-12-05" => { - value => 30, + value => 210, }, "2016-12-12" => { value => 200, }, "2016-12-19" => { - value => 220, + value => 210, }, "2016-12-26" => { value => 190, }, - "2017-01-02" => { - value => 170, - }, } })->or($framework->dump_error); @@ -99,6 +96,7 @@ 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({ @@ -109,6 +107,7 @@ sub create_random_transaction { purchase_time => $time, essential => 1, }); + $schema->resultset('TransactionCategory')->create({ category_id => 1, transaction_id => $test_transaction->id, From c5341af3e756416fcfcbdea0bb2acaddbf860484 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 21 Mar 2018 16:01:46 +0000 Subject: [PATCH 12/27] customer stats test fixed --- .../Schema/Result/ViewQuantisedTransactionSQLite.pm | 2 +- t/api/stats.t | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm index abf95dd..1c908fd 100644 --- a/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm +++ b/lib/Pear/LocalLoop/Schema/Result/ViewQuantisedTransactionSQLite.pm @@ -17,7 +17,7 @@ SELECT "value", "seller_id", DATETIME(STRFTIME('%Y-%m-%d %H:00:00',"purchase_time")) AS "quantised_hours", DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"purchase_time")) AS "quantised_days", - DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"purchase_time", 'weekday 1')) AS "quantised_weeks" + DATETIME(STRFTIME('%Y-%m-%d 00:00:00',"purchase_time",'weekday 0','-6 days')) AS "quantised_weeks" FROM "transactions" /); diff --git a/t/api/stats.t b/t/api/stats.t index 67e8705..2fa8a9a 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -49,11 +49,11 @@ $t->post_ok('/api/stats/customer' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/weeks', { - first => 2, - second => 21, + first => 20, + second => 20, max => 22, sum => 118, - count => 7, + count => 6, }) ->or($framework->dump_error) ->json_is('/sectors', { From 055b95e2fcc17a3cb8fde5a4deae48485eec8dfc Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 21 Mar 2018 16:37:40 +0000 Subject: [PATCH 13/27] customer snippet test amended --- CHANGELOG.md | 3 ++- t/api/v1/customer/snippets.t | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f51a1fa..fb8bb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ * Added API ability to edit and delete transactions * Added test for above * Made test dumping more sane -* Fixed category view on postgres +* Fixed quantised transaction calcuations for weeks on sqlite +* Amended customer snippet, category list and customer stats tests # v0.10.5 diff --git a/t/api/v1/customer/snippets.t b/t/api/v1/customer/snippets.t index 4a3ae8c..07c3e9a 100644 --- a/t/api/v1/customer/snippets.t +++ b/t/api/v1/customer/snippets.t @@ -1,5 +1,9 @@ use Mojo::Base -strict; +BEGIN { + use Test::MockTime qw/ set_absolute_time /; +} + use FindBin qw/ $Bin /; use Test::More; @@ -15,7 +19,7 @@ $framework->install_fixtures('users'); my $t = $framework->framework; my $schema = $t->app->schema; -$t->app->schema->resultset('Leaderboard')->create_new( 'monthly_total', DateTime->now->truncate(to => 'month' )->subtract( months => 1) ); +set_absolute_time('2017-01-02T00:00:00Z'); my $start = DateTime->today->subtract( hours => 12 ); @@ -25,15 +29,19 @@ for my $count ( 0 .. 60 ) { create_random_transaction( 'test1@example.com', $trans_day ); if ( $count % 2 ) { - create_random_transaction( 'test2@example.com', $trans_day ); + create_random_transaction( 'test1@example.com', $trans_day ); } if ( $count % 3 ) { - create_random_transaction( 'test3@example.com', $trans_day ); + create_random_transaction( 'test1@example.com', $trans_day ); } if ( $count % 4 ) { - create_random_transaction( 'test4@example.com', $trans_day ); + create_random_transaction( 'test1@example.com', $trans_day ); } } +my $lb_start = $start->clone->truncate( to => 'month' )->subtract( months => 1); + +#use Devel::Dwarn; Dwarn({ $_->get_columns }) for $schema->resultset('Transaction')->all; +$schema->resultset('Leaderboard')->create_new( 'monthly_total', $lb_start ); my $session_key = $framework->login({ email => 'test1@example.com', @@ -45,7 +53,7 @@ $t->post_ok('/api/v1/customer/snippets' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/snippets', { - user_sum => 610, + user_sum => 1760, user_position => 1, }); From 2d03d25916cabb2d75cb6fa75132c107f39e67f5 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Wed, 21 Mar 2018 17:24:13 +0000 Subject: [PATCH 14/27] Set secrets with decent default for production --- lib/Pear/LocalLoop.pm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index c996567..db7bba8 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -34,6 +34,13 @@ sub startup { }); my $config = $self->config; + if ( defined $config->{secret} ) { + $self->secrets([ $config->{secret} ]); + } elsif ( $self->mode eq 'production' ) { + # Just incase we end up in production and it hasnt been set! + $self->secrets([ Data::UUID->new->create() ]); + } + push @{ $self->commands->namespaces }, __PACKAGE__ . '::Command'; $self->plugin('Pear::LocalLoop::Plugin::BootstrapPagination', { bootstrap4 => 1 } ); @@ -247,9 +254,9 @@ sub startup { # $portal_api->post('/search')->to('api-upload#post_search'); $self->hook( before_dispatch => sub { - my $self = shift; + my $c = shift; - $self->res->headers->header('Access-Control-Allow-Origin' => '*') if $self->app->mode eq 'development'; + $c->res->headers->header('Access-Control-Allow-Origin' => '*') if $c->app->mode eq 'development'; }); $self->helper( copy_transactions_and_delete => sub { From 2b5bb9cd8cd4ed5810582467891056b5fb998aee Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Wed, 21 Mar 2018 17:24:41 +0000 Subject: [PATCH 15/27] Stop error on large csv exceeding size of cookies --- lib/Pear/LocalLoop/Controller/Admin/Import.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Admin/Import.pm b/lib/Pear/LocalLoop/Controller/Admin/Import.pm index 0416012..630bf84 100644 --- a/lib/Pear/LocalLoop/Controller/Admin/Import.pm +++ b/lib/Pear/LocalLoop/Controller/Admin/Import.pm @@ -144,7 +144,8 @@ sub _csv_flash_error { $c->flash( error => $error, - csv_data => $c->param('csv'), + # If csv info is huge, this fails epically + #csv_data => $c->param('csv'), date_format => $c->param('date_format'), ); } From 2286e541049bba466be3885f15bdd311f37ef091 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Wed, 21 Mar 2018 17:24:55 +0000 Subject: [PATCH 16/27] Allow for parsing currency without a currency sign in front --- lib/Pear/LocalLoop/Plugin/Currency.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Pear/LocalLoop/Plugin/Currency.pm b/lib/Pear/LocalLoop/Plugin/Currency.pm index f256f80..fa5333f 100644 --- a/lib/Pear/LocalLoop/Plugin/Currency.pm +++ b/lib/Pear/LocalLoop/Plugin/Currency.pm @@ -9,6 +9,8 @@ sub register { my $value; if ( $currency_string =~ /^£([\d.]+)/ ) { $value = $1 * 1; + } elsif ( $currency_string =~ /^([\d.]+)/ ) { + $value = $1 * 1; } return $value; }); From 8a2aa3a73a09666edc8d0b163691b2a8da608d2f Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Wed, 21 Mar 2018 17:49:00 +0000 Subject: [PATCH 17/27] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb8bb99..a033783 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ # Next Release +* **Admin Fix** Parse currency without a currency symbol on import +* **Admin Fix** Fix large CSV issue on import +* Use custom secrets for encryption + # v0.10.6 * Fixed organisation submission From e817dc29b114f85bf730af9c27f13dbc95d43bf1 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 21 Mar 2018 17:58:50 +0000 Subject: [PATCH 18/27] fixed display error --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index cd348c3..711de88 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -92,7 +92,7 @@ sub post_customer { ); my @all_weeks = $week_transaction_rs->all; - my $first = $all_weeks[0]->get_column('count') || 0; + my $first = defined $all_weeks[0] ? $all_weeks[0]->get_column('count') || 0 : 0; my $second = defined $all_weeks[1] ? $all_weeks[1]->get_column('count') || 0 : 0; my $max = max( map { $_->get_column('count') } @all_weeks ); my $sum = sum( map { $_->get_column('count') } @all_weeks ); From 4b98de9075ff19b54a90eff845e144631c532292 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 26 Mar 2018 14:26:02 +0100 Subject: [PATCH 19/27] Added new Daily Cron script --- script/cron_daily | 10 ++++++++++ script/recalc_leaderboards | 5 ----- 2 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 script/cron_daily delete mode 100755 script/recalc_leaderboards diff --git a/script/cron_daily b/script/cron_daily new file mode 100644 index 0000000..1f53201 --- /dev/null +++ b/script/cron_daily @@ -0,0 +1,10 @@ +#! /bin/bash + +# Scripts to run daily. +# This will be run sometime between 2 & 3AM every morning. +# If order matters, make sure they are in the right place. + +eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) + +MOJO_MODE=production ./script/pear-local_loop recur_transactions --force +MOJO_MODE=production ./script/pear-local_loop recalc_leaderboards diff --git a/script/recalc_leaderboards b/script/recalc_leaderboards deleted file mode 100755 index 73ce46c..0000000 --- a/script/recalc_leaderboards +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/bash - -eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) - -MOJO_MODE=production ./script/pear-local_loop recalc_leaderboards From b22b85e0f27c74ab4ecbd482d707b0c415c5c880 Mon Sep 17 00:00:00 2001 From: Thomas Bloor Date: Mon, 26 Mar 2018 14:27:04 +0100 Subject: [PATCH 20/27] Updated Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a033783..b673ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ # Next Release +* Added `cron_daily` script for holding all daily cronjobs * **Admin Fix** Parse currency without a currency symbol on import * **Admin Fix** Fix large CSV issue on import * Use custom secrets for encryption From 4b4d50de076668a5019ba8e04f6deb3ed1aa2fb5 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 26 Mar 2018 14:42:18 +0100 Subject: [PATCH 21/27] Amended category listing --- .../LocalLoop/Controller/Api/Categories.pm | 21 +++++++++--------- lib/Pear/LocalLoop/Controller/Api/Upload.pm | 15 +++---------- .../LocalLoop/Schema/ResultSet/Category.pm | 22 +++++++++++++++++++ 3 files changed, 36 insertions(+), 22 deletions(-) create mode 100644 lib/Pear/LocalLoop/Schema/ResultSet/Category.pm diff --git a/lib/Pear/LocalLoop/Controller/Api/Categories.pm b/lib/Pear/LocalLoop/Controller/Api/Categories.pm index ed5b0c1..0ffeae7 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Categories.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Categories.pm @@ -33,30 +33,31 @@ sub post_category_list { essential => 'essential', }, ], - group_by => [ qw/ category_id quantised_weeks essential value / ], - order_by => { '-desc' => 'value' }, + group_by => [ qw/ category_id quantised_weeks essential / ], } ); my $data = { categories => {}, essentials => {} }; + my $category_list = $c->schema->resultset('Category')->as_hash; + for my $cat_trans ( $month_transaction_category_rs->all ) { my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); my $days = $c->format_iso_date( $quantised ) || 0; - my $category = $cat_trans->get_column('category_id') || undef; + my $category = $cat_trans->get_column('category_id') || 0; my $value = ($cat_trans->get_column('value') || 0) / 100000; - $data->{categories}->{$days} = [] unless exists $data->{categories}->{$days}; - push @{ $data->{categories}->{$days} }, { - days => $days, - value => $value, - category => $category, - }; + $data->{categories}->{$days}->{$category_list->{$category}} += $value; next unless $cat_trans->get_column('essential'); $data->{essentials}->{$days}->{value} += $value; } for my $day ( keys %{ $data->{categories} } ) { - $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @{ $data->{categories}->{$day} } ]; + my @days = ( map{ { + days => $day, + value => $data->{categories}->{$day}->{$_}, + category => $_, + } } keys %{ $data->{categories}->{$day} } ); + $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; } return $c->render( diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index 31fa234..c638645 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -243,21 +243,12 @@ sub post_category { my $c = shift; my $self = $c; - my $category_rs = $c->schema->resultset('Category'); - - # for ( $category_rs->all ) { - # push @{ $categories->{ ids } }, $_->get_column('id'); - # push @{ $categories->{ names } }, $_->get_column('name'); - # } - my %category_list = ( - map { - $_->id => $_->name, - } $category_rs->all - ); + my $category_list = $c->schema->resultset('Category')->as_hash; + delete $category_list->{0}; return $self->render( json => { success => Mojo::JSON->true, - categories => \%category_list, + categories => $category_list, }); } diff --git a/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm new file mode 100644 index 0000000..59f9b98 --- /dev/null +++ b/lib/Pear/LocalLoop/Schema/ResultSet/Category.pm @@ -0,0 +1,22 @@ +package Pear::LocalLoop::Schema::ResultSet::Category; + +use strict; +use warnings; + +use base 'DBIx::Class::ResultSet'; + +sub as_hash { + my ( $self ) = @_; + + my %category_list = ( + ( + map { + $_->id => $_->name, + } $self->all + ), + 0 => 'Uncategorised', + ); + return \%category_list; +} + +1; From b036d5494beb798537365d6be235702bc6d9bdd0 Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 26 Mar 2018 14:44:03 +0100 Subject: [PATCH 22/27] changing pie format (broken) --- .../Controller/Api/V1/Customer/Pies.pm | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 06c57b1..ebaf866 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -6,6 +6,8 @@ sub index { my $entity = $c->stash->{api_user}->entity; + my $data = { local_all => {}, categories => {}, essentials => {} }; + my $purchase_rs = $entity->purchases; my $local_org_local_purchase = $purchase_rs->search({ "me.distance" => { '<', 20000 }, @@ -43,17 +45,67 @@ sub index { } ); - my $data = { + $data->{local_all} = { 'Local shop local purchaser' => $local_org_local_purchase->count, 'Local shop non-local purchaser' => $local_org_non_local_purchase->count, 'Non-local shop local purchaser' => $non_local_org_local_purchase->count, 'Non-local shop non-local purchaser' => $non_local_org_non_local_purchase->count, }; - + + 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_category_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 => { sum => 'value' }, + category_id => 'category_id', + essential => 'essential', + }, + ], + group_by => [ qw/ category_id quantised_weeks essential / ], + } + ); + + my $category_list = $c->schema->resultset('Category')->as_hash; + + for my $cat_trans ( $month_transaction_category_rs->all ) { + my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); + my $days = $c->format_iso_date( $quantised ) || 0; + my $category = $cat_trans->get_column('category_id') || 0; + my $value = ($cat_trans->get_column('value') || 0) / 100000; + $data->{categories}->{$days}->{$category_list->{$category}} += $value; + next unless $cat_trans->get_column('essential'); + $data->{essentials}->{$days}->{value} += $value; + } + + for my $day ( keys %{ $data->{categories} } ) { + my @days = ( map{ { + days => $day, + value => $data->{categories}->{$day}->{$_}, + category => $_, + } } keys %{ $data->{categories}->{$day} } ); + $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; + } + return $c->render( json => { success => Mojo::JSON->true, - pie => $data, + data => $data, } ); From ec9fac293dbda27a0a0bd6923c7b43636cc173ab Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 26 Mar 2018 15:13:35 +0100 Subject: [PATCH 23/27] fixed category list API --- t/api/categories.t | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/t/api/categories.t b/t/api/categories.t index 10d11ab..93c1f3d 100644 --- a/t/api/categories.t +++ b/t/api/categories.t @@ -24,7 +24,7 @@ $schema->resultset('Category')->create({ name => 'test', }); -set_absolute_time('2017-01-02T00:00:00Z'); +set_absolute_time('2018-01-08T00:00:00Z'); my $start = DateTime->today->subtract( hours => 12 ); @@ -55,38 +55,38 @@ $t->post_ok('/api/stats/category' => json => { ->status_is(200)->or($framework->dump_error) ->json_is('/data', { categories => { - "2016-12-05" => [{ - days => "2016-12-05", + "2017-12-11" => [{ + days => "2017-12-11", value => 210, - category => 1, + category => 'test', }], - "2016-12-12" => [{ - days => "2016-12-12", + "2017-12-18" => [{ + days => "2017-12-18", value => 200, - category => 1, + category => 'test', }], - "2016-12-19" => [{ - days => "2016-12-19", + "2017-12-25" => [{ + days => "2017-12-25", value => 210, - category => 1, + category => 'test', }], - "2016-12-26" => [{ - days => "2016-12-26", + "2018-01-01" => [{ + days => "2018-01-01", value => 190, - category => 1, + category => 'test', }], }, essentials => { - "2016-12-05" => { + "2017-12-11" => { value => 210, }, - "2016-12-12" => { + "2017-12-18" => { value => 200, }, - "2016-12-19" => { + "2017-12-25" => { value => 210, }, - "2016-12-26" => { + "2018-01-01" => { value => 190, }, } From 9284218431938991354cdd72645f73daa94edd6d Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 5 Apr 2018 17:19:53 +0100 Subject: [PATCH 24/27] changed pie data structure --- .../Controller/Api/V1/Customer/Pies.pm | 56 +------------------ 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index ebaf866..9f9ef0c 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -6,8 +6,6 @@ sub index { my $entity = $c->stash->{api_user}->entity; - my $data = { local_all => {}, categories => {}, essentials => {} }; - my $purchase_rs = $entity->purchases; my $local_org_local_purchase = $purchase_rs->search({ "me.distance" => { '<', 20000 }, @@ -45,67 +43,17 @@ sub index { } ); - $data->{local_all} = { + my $data = { 'Local shop local purchaser' => $local_org_local_purchase->count, 'Local shop non-local purchaser' => $local_org_non_local_purchase->count, 'Non-local shop local purchaser' => $non_local_org_local_purchase->count, 'Non-local shop non-local purchaser' => $non_local_org_non_local_purchase->count, }; - 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_category_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 => { sum => 'value' }, - category_id => 'category_id', - essential => 'essential', - }, - ], - group_by => [ qw/ category_id quantised_weeks essential / ], - } - ); - - my $category_list = $c->schema->resultset('Category')->as_hash; - - for my $cat_trans ( $month_transaction_category_rs->all ) { - my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); - my $days = $c->format_iso_date( $quantised ) || 0; - my $category = $cat_trans->get_column('category_id') || 0; - my $value = ($cat_trans->get_column('value') || 0) / 100000; - $data->{categories}->{$days}->{$category_list->{$category}} += $value; - next unless $cat_trans->get_column('essential'); - $data->{essentials}->{$days}->{value} += $value; - } - - for my $day ( keys %{ $data->{categories} } ) { - my @days = ( map{ { - days => $day, - value => $data->{categories}->{$day}->{$_}, - category => $_, - } } keys %{ $data->{categories}->{$day} } ); - $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; - } - return $c->render( json => { success => Mojo::JSON->true, - data => $data, + pie => $data, } ); From bc92d2eb113befc99351528f72d30b8c369f0b1c Mon Sep 17 00:00:00 2001 From: Finn Date: Mon, 9 Apr 2018 19:21:14 +0100 Subject: [PATCH 25/27] essential data added for bar chart --- .../Controller/Api/V1/Customer/Pies.pm | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 9f9ef0c..8a1210f 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -6,7 +6,19 @@ sub index { my $entity = $c->stash->{api_user}->entity; + my $data = { local_all => {}, categories => {}, essentials => {} }; + my $purchase_rs = $entity->purchases; + + my $purchase_no_essential_rs = $purchase_rs->search({ + "me.essential" => 1, + }); + + $data->{essentials} = { + purchase_no_total => $purchase_rs->count, + purchase_no_essential_total => $purchase_no_essential_rs->count, + }; + my $local_org_local_purchase = $purchase_rs->search({ "me.distance" => { '<', 20000 }, 'organisation.is_local' => 1, @@ -43,17 +55,67 @@ sub index { } ); - my $data = { + $data->{local_all} = { 'Local shop local purchaser' => $local_org_local_purchase->count, 'Local shop non-local purchaser' => $local_org_non_local_purchase->count, 'Non-local shop local purchaser' => $non_local_org_local_purchase->count, 'Non-local shop non-local purchaser' => $non_local_org_non_local_purchase->count, }; + 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_category_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 => { sum => 'value' }, + category_id => 'category_id', + essential => 'essential', + }, + ], + group_by => [ qw/ category_id quantised_weeks essential / ], + } + ); + + my $category_list = $c->schema->resultset('Category')->as_hash; + + for my $cat_trans ( $month_transaction_category_rs->all ) { + my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); + my $days = $c->format_iso_date( $quantised ) || 0; + my $category = $cat_trans->get_column('category_id') || 0; + my $value = ($cat_trans->get_column('value') || 0) / 100000; + $data->{categories}->{$days}->{$category_list->{$category}} += $value; + next unless $cat_trans->get_column('essential'); + $data->{essentials}->{$days}->{value} += $value; + } + + for my $day ( keys %{ $data->{categories} } ) { + my @days = ( map{ { + days => $day, + value => $data->{categories}->{$day}->{$_}, + category => $_, + } } keys %{ $data->{categories}->{$day} } ); + $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; + } + return $c->render( json => { success => Mojo::JSON->true, - pie => $data, + data => $data, } ); From 78fdfc1e1d14207ba61d36fedfc3f8360fe311c1 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 11 Apr 2018 19:10:19 +0100 Subject: [PATCH 26/27] added month listing --- lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 8a1210f..2ae26cb 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -6,7 +6,7 @@ sub index { my $entity = $c->stash->{api_user}->entity; - my $data = { local_all => {}, categories => {}, essentials => {} }; + my $data = { local_all => {}, cat_total => {}, categories => {}, essentials => {} }; my $purchase_rs = $entity->purchases; @@ -98,6 +98,7 @@ sub index { my $days = $c->format_iso_date( $quantised ) || 0; my $category = $cat_trans->get_column('category_id') || 0; my $value = ($cat_trans->get_column('value') || 0) / 100000; + $data->{cat_total}->{$category_list->{$category}} += $value; $data->{categories}->{$days}->{$category_list->{$category}} += $value; next unless $cat_trans->get_column('essential'); $data->{essentials}->{$days}->{value} += $value; From a4bcd9c6d7342901f01007b18ae65e3b3a24305a Mon Sep 17 00:00:00 2001 From: Finn Date: Fri, 13 Apr 2018 18:08:10 +0100 Subject: [PATCH 27/27] changed stat viewing and amended tests --- lib/Pear/LocalLoop/Controller/Api/Stats.pm | 67 ++++++++++++++++++- .../Controller/Api/V1/Customer/Pies.pm | 66 +----------------- t/api/stats.t | 43 ++++++++++-- t/api/v1/customer/pies.t | 2 +- 4 files changed, 105 insertions(+), 73 deletions(-) diff --git a/lib/Pear/LocalLoop/Controller/Api/Stats.pm b/lib/Pear/LocalLoop/Controller/Api/Stats.pm index 711de88..3a7579d 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Stats.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Stats.pm @@ -63,9 +63,9 @@ sub post_customer { my $entity = $c->stash->{api_user}->entity; - my $duration = DateTime::Duration->new( weeks => 7 ); + my $duration_weeks = DateTime::Duration->new( weeks => 7 ); my $end = DateTime->today; - my $start = $end->clone->subtract_duration( $duration ); + my $start_weeks = $end->clone->subtract_duration( $duration_weeks ); my $dtf = $c->schema->storage->datetime_parser; my $driver = $c->schema->storage->dbh->{Driver}->{Name}; @@ -73,7 +73,7 @@ sub post_customer { { purchase_time => { -between => [ - $dtf->format_datetime($start), + $dtf->format_datetime($start_weeks), $dtf->format_datetime($end), ], }, @@ -125,8 +125,69 @@ sub post_customer { push @{ $sectors->{ purchases } }, ($_->get_column('count') || 0); } + my $data = { cat_total => {}, categories => {}, essentials => {} }; + + my $purchase_rs = $entity->purchases; + + my $purchase_no_essential_rs = $purchase_rs->search({ + "me.essential" => 1, + }); + + $data->{essentials} = { + purchase_no_total => $purchase_rs->count, + purchase_no_essential_total => $purchase_no_essential_rs->count, + }; + + my $duration_month = DateTime::Duration->new( days => 28 ); + my $start_month = $end->clone->subtract_duration( $duration_month ); + my $month_transaction_category_rs = $c->schema->resultset('ViewQuantisedTransactionCategory' . $driver)->search( + { + purchase_time => { + -between => [ + $dtf->format_datetime($start_month), + $dtf->format_datetime($end), + ], + }, + buyer_id => $entity->id, + }, + { + columns => [ + { + quantised => 'quantised_weeks', + value => { sum => 'value' }, + category_id => 'category_id', + essential => 'essential', + }, + ], + group_by => [ qw/ category_id quantised_weeks essential / ], + } + ); + + my $category_list = $c->schema->resultset('Category')->as_hash; + + for my $cat_trans ( $month_transaction_category_rs->all ) { + my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); + my $days = $c->format_iso_date( $quantised ) || 0; + my $category = $cat_trans->get_column('category_id') || 0; + my $value = ($cat_trans->get_column('value') || 0) / 100000; + $data->{cat_total}->{$category_list->{$category}} += $value; + $data->{categories}->{$days}->{$category_list->{$category}} += $value; + next unless $cat_trans->get_column('essential'); + $data->{essentials}->{$days}->{value} += $value; + } + + for my $day ( keys %{ $data->{categories} } ) { + my @days = ( map{ { + days => $day, + value => $data->{categories}->{$day}->{$_}, + category => $_, + } } keys %{ $data->{categories}->{$day} } ); + $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; + } + return $c->render( json => { success => Mojo::JSON->true, + data => $data, weeks => $weeks, sectors => $sectors, }); diff --git a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm index 2ae26cb..353ab06 100644 --- a/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm +++ b/lib/Pear/LocalLoop/Controller/Api/V1/Customer/Pies.pm @@ -6,19 +6,8 @@ sub index { my $entity = $c->stash->{api_user}->entity; - my $data = { local_all => {}, cat_total => {}, categories => {}, essentials => {} }; - my $purchase_rs = $entity->purchases; - my $purchase_no_essential_rs = $purchase_rs->search({ - "me.essential" => 1, - }); - - $data->{essentials} = { - purchase_no_total => $purchase_rs->count, - purchase_no_essential_total => $purchase_no_essential_rs->count, - }; - my $local_org_local_purchase = $purchase_rs->search({ "me.distance" => { '<', 20000 }, 'organisation.is_local' => 1, @@ -55,68 +44,17 @@ sub index { } ); - $data->{local_all} = { + my $local_all = { 'Local shop local purchaser' => $local_org_local_purchase->count, 'Local shop non-local purchaser' => $local_org_non_local_purchase->count, 'Non-local shop local purchaser' => $non_local_org_local_purchase->count, 'Non-local shop non-local purchaser' => $non_local_org_non_local_purchase->count, }; - 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_category_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 => { sum => 'value' }, - category_id => 'category_id', - essential => 'essential', - }, - ], - group_by => [ qw/ category_id quantised_weeks essential / ], - } - ); - - my $category_list = $c->schema->resultset('Category')->as_hash; - - for my $cat_trans ( $month_transaction_category_rs->all ) { - my $quantised = $c->db_datetime_parser->parse_datetime($cat_trans->get_column('quantised')); - my $days = $c->format_iso_date( $quantised ) || 0; - my $category = $cat_trans->get_column('category_id') || 0; - my $value = ($cat_trans->get_column('value') || 0) / 100000; - $data->{cat_total}->{$category_list->{$category}} += $value; - $data->{categories}->{$days}->{$category_list->{$category}} += $value; - next unless $cat_trans->get_column('essential'); - $data->{essentials}->{$days}->{value} += $value; - } - - for my $day ( keys %{ $data->{categories} } ) { - my @days = ( map{ { - days => $day, - value => $data->{categories}->{$day}->{$_}, - category => $_, - } } keys %{ $data->{categories}->{$day} } ); - $data->{categories}->{$day} = [ sort { $b->{value} <=> $a->{value} } @days ]; - } - return $c->render( json => { success => Mojo::JSON->true, - data => $data, + local_all => $local_all, } ); diff --git a/t/api/stats.t b/t/api/stats.t index 2fa8a9a..c7922af 100644 --- a/t/api/stats.t +++ b/t/api/stats.t @@ -19,7 +19,7 @@ $framework->install_fixtures('users'); my $t = $framework->framework; my $schema = $t->app->schema; -set_absolute_time('2017-01-01T00:00:00Z'); +set_absolute_time('2018-01-08T00:00:00Z'); my $start = DateTime->today->subtract( hours => 12 ); @@ -49,17 +49,50 @@ $t->post_ok('/api/stats/customer' => json => { }) ->status_is(200)->or($framework->dump_error) ->json_is('/weeks', { - first => 20, + first => 17, second => 20, - max => 22, + max => 21, sum => 118, count => 6, }) - ->or($framework->dump_error) ->json_is('/sectors', { sectors => ['A'], purchases => [118], - }); + }) + ->json_is('/data', { + cat_total => { + Uncategorised => 810, + }, + categories => { + "2017-12-11" => [{ + days => "2017-12-11", + value => 210, + category => 'Uncategorised', + }], + "2017-12-18" => [{ + days => "2017-12-18", + value => 200, + category => 'Uncategorised', + }], + "2017-12-25" => [{ + days => "2017-12-25", + value => 210, + category => 'Uncategorised', + }], + "2018-01-01" => [{ + days => "2018-01-01", + value => 190, + category => 'Uncategorised', + }], + }, + cat_total => { + Uncategorised => 810, + }, + essentials => { + purchase_no_essential_total => 0, + purchase_no_total => 118, + }, + })->or($framework->dump_error); sub create_random_transaction { my $buyer = shift; diff --git a/t/api/v1/customer/pies.t b/t/api/v1/customer/pies.t index 53fdd8f..babd443 100644 --- a/t/api/v1/customer/pies.t +++ b/t/api/v1/customer/pies.t @@ -42,7 +42,7 @@ $t->post_ok('/api/v1/customer/pies' => json => { session_key => $session_key, }) ->status_is(200)->or($framework->dump_error) - ->json_is('/pie', { + ->json_is('/local_all', { 'Local shop local purchaser' => 0, 'Local shop non-local purchaser' => 0, 'Non-local shop local purchaser' => 0,